Repository: kayak/pypika
Pull request #385 (2020-03-23 13:12:09)

Support dialects in Table
Thanks for sharing this nice library!

I like the pattern of creating instances of the `Table` class (typically at module level) and using the `select` method as entry point to a query builder. However, this does not seem to support other query dialects than the standard, unless I'm mistaken? This pull request tries to address that. I'd be happy if you would consider it, or let me know how I can achieve the same effect without it.

---

This commit allows the `Table` class to be initialized with an optional
`query_cls` parameter, which is used in place of the standard `Query`
class by the `select`, `update` and `insert` methods.

This commit also adds a couple of new convenience methods on the `Query`
class to allow easier creation of tables that use a specific `Query`
subclass.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/29550316/badge)](https://coveralls.io/builds/29550316)

Coverage decreased (-0.002%) to 97.72% when pulling **e329405eba0aeab0f693598c80f00ee5c61ea72f on jimorie:support_dialects_in_table** into **89f70a756913b9ddcfa53448a9e73562c69a93e5 on kayak:master**.


Patch:
diff --git a/pypika/queries.py b/pypika/queries.py
index 593a88b..7605ee9 100644
--- a/pypika/queries.py
+++ b/pypika/queries.py
@@ -131,10 +131,13 @@ class Table(Selectable):
             return Schema(schema)
         return None
 
-    def __init__(self, name, schema=None, alias=None):
+    def __init__(self, name, schema=None, alias=None, query_cls=None):
         super(Table, self).__init__(alias)
         self._table_name = name
         self._schema = self._init_schema(schema)
+        self._query_cls = query_cls or Query
+        if not issubclass(self._query_cls, Query):
+            raise TypeError("Expected 'query_cls' to be subclass of Query")
 
     def get_table_name(self):
         return self.alias or self._table_name
@@ -191,7 +194,7 @@ class Table(Selectable):
 
         :return:  QueryBuilder
         """
-        return Query.from_(self).select(*terms)
+        return self._query_cls.from_(self).select(*terms)
 
     def update(self):
         """
@@ -199,7 +202,7 @@ class Table(Selectable):
 
         :return: QueryBuilder
         """
-        return Query.update(self)
+        return self._query_cls.update(self)
 
     def insert(self, *terms):
         """
@@ -212,7 +215,7 @@ class Table(Selectable):
 
         :return: QueryBuilder
         """
-        return Query.into(self).insert(*terms)
+        return self._query_cls.into(self).insert(*terms)
 
 
 def make_tables(*names, **kwargs):
@@ -224,9 +227,15 @@ def make_tables(*names, **kwargs):
     tables = []
     for name in names:
         if isinstance(name, tuple) and len(name) == 2:
-            t = Table(name=name[0], alias=name[1], schema=kwargs.get("schema"))
+            t = Table(
+                name=name[0], alias=name[1], schema=kwargs.get("schema"),
+                query_cls=kwargs.get("query_cls"),
+            )
         else:
-            t = Table(name=name, schema=kwargs.get("schema"))
+            t = Table(
+                name=name, schema=kwargs.get("schema"),
+                query_cls=kwargs.get("query_cls"),
+            )
         tables.append(t)
     return tables
 
@@ -357,6 +366,37 @@ class Query:
         """
         return cls._builder(**kwargs).update(table)
 
+    @classmethod
+    def Table(cls, table_name, **kwargs):
+        """
+        Convenience method for creating a Table that uses this Query class.
+
+        :param table_name:
+            Type: str
+
+            A string table name.
+
+        :returns Table
+        """
+        kwargs["query_cls"] = cls
+        return Table(table_name, **kwargs)
+
+    @classmethod
+    def Tables(cls, *names, **kwargs):
+        """
+        Convenience method for creating many tables that uses this Query class.
+        See ``Query.make_tables`` for details.
+
+        :param names:
+            Type: list[str or tuple]
+
+            A list of string table names, or name and alias tuples.
+
+        :returns Table
+        """
+        kwargs["query_cls"] = cls
+        return make_tables(*names, **kwargs)
+
 
 class _UnionQuery(Selectable, Term):
     """


Test patch:
diff --git a/pypika/tests/test_tables.py b/pypika/tests/test_tables.py
index 15ed617..98de7c6 100644
--- a/pypika/tests/test_tables.py
+++ b/pypika/tests/test_tables.py
@@ -2,9 +2,12 @@ import unittest
 
 from pypika import (
     Database,
+    Dialects,
     Schema,
+    SQLLiteQuery,
     Table,
     Tables,
+    Query,
 )
 
 __author__ = "Timothy Heys"
@@ -115,3 +118,43 @@ class TableEqualityTests(unittest.TestCase):
                 self.assertIsNotNone(tables[i].alias)
             else:
                 self.assertIsNone(tables[i].alias)
+
+
+class TableDialectTests(unittest.TestCase):
+    def test_table_with_default_query_cls(self):
+        table = Table("abc")
+        q = table.select("1")
+        self.assertIs(q.dialect, None)
+
+    def test_table_with_dialect_query_cls(self):
+        table = Table("abc", query_cls=SQLLiteQuery)
+        q = table.select("1")
+        self.assertIs(q.dialect, Dialects.SQLLITE)
+
+    def test_table_factory_with_default_query_cls(self):
+        table = Query.Table("abc")
+        q = table.select("1")
+        self.assertIs(q.dialect, None)
+
+    def test_table_factory_with_dialect_query_cls(self):
+        table = SQLLiteQuery.Table("abc")
+        q = table.select("1")
+        self.assertIs(q.dialect, Dialects.SQLLITE)
+
+    def test_make_tables_factory_with_default_query_cls(self):
+        t1, t2 = Query.Tables("abc", "def")
+        q1 = t1.select("1")
+        q2 = t2.select("2")
+        self.assertIs(q1.dialect, None)
+        self.assertIs(q2.dialect, None)
+
+    def test_make_tables_factory_with_dialect_query_cls(self):
+        t1, t2 = SQLLiteQuery.Tables("abc", "def")
+        q1 = t1.select("1")
+        q2 = t2.select("2")
+        self.assertIs(q1.dialect, Dialects.SQLLITE)
+        self.assertIs(q2.dialect, Dialects.SQLLITE)
+
+    def test_table_with_bad_query_cls(self):
+        with self.assertRaises(TypeError):
+            Table("abc", query_cls=object)