Repository: kayak/pypika (python)

Issue:
Extraneous quotes when using passing Field to between
[System Environment]

Windows 10
Python: 3.6.4
PyPika: 0.15.7

[Overview]
When doing a join based on a table field's value being between values derived from another field (or set of fields), the `start` and `end` portions get wrapped in quotes. 

```
t1 = Table('Table1', alias='t1')
t2 = Table('Table2', alias='t2')

Query.from_(t1).join(t2).on(t1.Value.between(t2.Start, t2.End)).select(t1.value).get_sql()
```

yields:

`'SELECT t1.value FROM Table1 t1 JOIN Table2 t2 ON t1.Value BETWEEN "t2"."Start" AND "t2"."End"'`


Looking at `BetweenCriterion` it seems like, if `self.start` and/or `self.stop` are instances of `Term` then `get_sql(**kwargs)` should be called (as is done with `self.term`). Unless this is intended behavior? 

Pull request description:
Add support for nested Schema namespaces.
Fixes #168 Enhanced the schema attribute in Table to support multiple levels of depth for the schema. Now schema can be defined as either a string, or a tuple/list of strings, and the quotes will be applied properly.

The schema attribute on Table now accepts both string and list/tuple arguments:
`Query.from_(Table('abc', ['schema1', 'schema2'])).select('*')`

Patch:
diff --git a/pypika/queries.py b/pypika/queries.py
index 882e34e..563cfb3 100644
--- a/pypika/queries.py
+++ b/pypika/queries.py
@@ -65,6 +65,7 @@ class AliasedQuery(Selectable):
     def __hash__(self):
         return hash(str(self.name))
 
+
 class Table(Selectable):
     def __init__(self, name, schema=None, alias=None):
         super(Table, self).__init__(alias)
@@ -74,18 +75,19 @@ class Table(Selectable):
     def get_sql(self, quote_char=None, **kwargs):
         # FIXME escape
 
+        parts = []
         if self._schema:
-            table_sql = "{quote}{schema}{quote}.{quote}{name}{quote}".format(
-                  schema=self._schema,
-                  name=self._table_name,
-                  quote=quote_char or ''
-            )
+            schema = (self._schema,) \
+                if not isinstance(self._schema, (list, tuple)) \
+                else self._schema
 
-        else:
-            table_sql = "{quote}{name}{quote}".format(
-                  name=self._table_name,
-                  quote=quote_char or ''
-            )
+            parts += [s for s in schema]
+
+        parts.append(self._table_name)
+
+        table_sql = '.'.join("{quote}{part}{quote}".format(part=part,
+                                                           quote=quote_char or '')
+                             for part in parts)
 
         return alias_sql(table_sql, self.alias, quote_char)
 


Test patch:
diff --git a/pypika/tests/test_selects.py b/pypika/tests/test_selects.py
index c1d673f..c23f788 100644
--- a/pypika/tests/test_selects.py
+++ b/pypika/tests/test_selects.py
@@ -40,6 +40,16 @@ class SelectTests(unittest.TestCase):
 
         self.assertEqual('SELECT * FROM "schema1"."abc"', str(q))
 
+    def test_select__table_schema_with_multiple_levels_as_tuple(self):
+        q = Query.from_(Table('abc', ('schema1', 'schema2'))).select('*')
+
+        self.assertEqual('SELECT * FROM "schema1"."schema2"."abc"', str(q))
+
+    def test_select__table_schema_with_multiple_levels_as_list(self):
+        q = Query.from_(Table('abc', ['schema1', 'schema2'])).select('*')
+
+        self.assertEqual('SELECT * FROM "schema1"."schema2"."abc"', str(q))
+
     def test_select__star__replacement(self):
         q = Query.from_('abc').select('foo').select('*')
 
@@ -779,7 +789,7 @@ class SubqueryTests(unittest.TestCase):
             'SELECT * FROM "abc" JOIN an_alias ON "an_alias"."fizz"="abc"."buzz"',
             str(test_query))
 
-        
+
 class QuoteTests(unittest.TestCase):
     def test_extraneous_quotes(self):
         t1 = Table('table1', alias='t1')