Repository: kayak/pypika
Pull request #138 (2018-07-02 15:29:26)

Added ability to do `CROSS JOIN`.
Hello,

This is a PR for adding `CROSS JOINS` (#137).

This is my first PR for this project, so let me know if I should follow some process or requirements. I couldn't find any contribution guide guidelines so I just free-styled it :)

Thank you!

Mark


Patch:
diff --git a/pypika/enums.py b/pypika/enums.py
index 4048a89..493f6e1 100644
--- a/pypika/enums.py
+++ b/pypika/enums.py
@@ -53,6 +53,7 @@ class JoinType(Enum):
     left_outer = 'LEFT OUTER'
     right_outer = 'RIGHT OUTER'
     full_outer = 'FULL OUTER'
+    cross = 'CROSS'
 
 
 class UnionType(Enum):
diff --git a/pypika/queries.py b/pypika/queries.py
index f184781..e9c2da7 100644
--- a/pypika/queries.py
+++ b/pypika/queries.py
@@ -887,6 +887,11 @@ class Joiner(object):
         self.query.do_join(JoinUsing(self.item, self.how, [Field(field) for field in fields]))
         return self.query
 
+    def cross(self):
+        """Return cross join"""
+        self.query.do_join(Join(self.item, JoinType.cross))
+
+        return self.query
 
 class Join(object):
     def __init__(self, item, how):
@@ -902,6 +907,9 @@ class Join(object):
             return '{type} {join}'.format(join=sql, type=self.how.value)
         return sql
 
+    def validate(self, _from, _joins):
+        pass
+
 
 class JoinOn(Join):
     def __init__(self, item, how, criteria):


Test patch:
diff --git a/pypika/tests/test_joins.py b/pypika/tests/test_joins.py
index 761f422..60bdb53 100644
--- a/pypika/tests/test_joins.py
+++ b/pypika/tests/test_joins.py
@@ -92,6 +92,14 @@ class JoinTypeTests(unittest.TestCase):
 
         self.assertEqual('SELECT * FROM "abc" JOIN "efg" USING ("foo","bar")', str(query))
 
+    def test_join_using_without_fields_raises_exception(self):
+        with self.assertRaises(JoinException):
+            query = Query.from_(self.table0).join(self.table1).using()
+
+    def test_join_on_field_without_fields_raises_exception(self):
+        with self.assertRaises(JoinException):
+            query = Query.from_(self.table0).join(self.table1).on_field()
+
     def test_join_arithmetic_field(self):
         q = Query.from_(self.table0).join(self.table1).on(
             self.table0.dt == (self.table1.dt - Interval(weeks=1))).select('*')
@@ -132,6 +140,21 @@ class JoinTypeTests(unittest.TestCase):
                          'FROM "a","b" '
                          'JOIN "c" ON "b"."c_id"="c"."id"', str(q))
 
+    def test_cross_join_on_table(self):
+        table_a, table_b = Tables('a', 'b')
+        q = Query.from_(table_a).join(table_b).cross().select('*')
+
+        self.assertEqual('SELECT * FROM "a" CROSS JOIN "b"', str(q))
+
+    def test_cross_join_on_subquery(self):
+        table_a, table_b = Tables('a', 'b')
+        q_a = Query.from_(table_a).select('*')
+        q_b = Query.from_(table_b).select('*').join(q_a).cross().select('*')
+
+        self.assertEqual(
+            'SELECT * FROM "b" CROSS JOIN (SELECT * FROM "a") "sq0"',
+            str(q_b)
+        )
 
 class JoinBehaviorTests(unittest.TestCase):
     table_abc, table_efg, table_hij, table_klm = Tables('abc', 'efg', 'hij', 'klm')