Skip to content

Commit

Permalink
Merge pull request #74 from mikeengland/add-redshift
Browse files Browse the repository at this point in the history
Added Amazon Redshift dialect and timestamp/date add functions
  • Loading branch information
mikeengland authored Sep 29, 2017
2 parents 941b7d8 + ba7aad4 commit e484cf5
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 37 deletions.
56 changes: 34 additions & 22 deletions pypika/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,40 @@
This contains all of the utility classes such as exceptions and decorators.
"""
from .enums import (Order,
JoinType,
DatePart)
from .queries import (Query,
Table,
make_tables as Tables,
Tuple)
from .terms import (Field,
Case,
Not,
Interval,
Rollup)
from .utils import (JoinException,
GroupingException,
CaseException,
UnionException,
RollupException)
from .dialects import (MSSQLQuery,
MySQLQuery,
OracleQuery,
PostgreSQLQuery,
VerticaQuery)
from .dialects import (
Dialects,
MSSQLQuery,
MySQLQuery,
OracleQuery,
PostgreSQLQuery,
RedshiftQuery,
VerticaQuery,
)
from .enums import (
DatePart,
JoinType,
Order,
)
from .queries import (
Query,
Table,
Tuple,
make_tables as Tables,
)
from .terms import (
Case,
Field,
Interval,
Not,
Rollup,
)
from .utils import (
CaseException,
GroupingException,
JoinException,
RollupException,
UnionException,
)

__author__ = "Timothy Heys"
__email__ = "[email protected]"
Expand Down
10 changes: 10 additions & 0 deletions pypika/dialects.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ def _builder(cls):
return QueryBuilder(dialect=Dialects.POSTGRESQL)


class RedshiftQuery(Query):
"""
Defines a query class for use with Amazon Redshift.
"""

@classmethod
def _builder(cls):
return QueryBuilder(dialect=Dialects.REDSHIFT)


class MSSQLQuery(Query):
"""
Defines a query class for use with Microsoft SQL Server.
Expand Down
1 change: 1 addition & 0 deletions pypika/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ class Dialects(Enum):
MSSQL = 'mssql'
MYSQL = 'mysql'
POSTGRESQL = 'postgressql'
REDSHIFT = 'redshift'
10 changes: 10 additions & 0 deletions pypika/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,21 @@ def __init__(self, interval, start_date, end_date, alias=None):
super(DateDiff, self).__init__('DATEDIFF', interval, start_date, end_date, alias=alias)


class DateAdd(Function):
def __init__(self, date_part, interval, term, alias=None):
super(DateAdd, self).__init__('DATE_ADD', date_part, interval, term, alias=alias)


class Timestamp(Function):
def __init__(self, term, alias=None):
super(Timestamp, self).__init__('TIMESTAMP', term, alias=alias)


class TimestampAdd(Function):
def __init__(self, date_part, interval, term, alias=None):
super(TimestampAdd, self).__init__('TIMESTAMPADD', date_part, interval, term, alias=alias)


# String Functions
class Ascii(Function):
def __init__(self, term, alias=None):
Expand Down
11 changes: 9 additions & 2 deletions pypika/terms.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,9 @@ class Interval(object):

trim_pattern = re.compile(r'^[0\-\.: ]+|[0\-\.: ]+$')

def __init__(self, years=0, months=0, days=0, hours=0, minutes=0, seconds=0, microseconds=0, quarters=0, weeks=0):
def __init__(self, years=0, months=0, days=0, hours=0, minutes=0, seconds=0, microseconds=0, quarters=0, weeks=0,
dialect=None):
self.dialect = dialect
self.largest = None
self.smallest = None

Expand All @@ -847,7 +849,7 @@ def fields(self):
return []

def get_sql(self, **kwargs):
dialect = kwargs.get('dialect')
dialect = self.dialect or kwargs.get('dialect')

if hasattr(self, 'quarters'):
expr = getattr(self, 'quarters')
Expand Down Expand Up @@ -880,6 +882,11 @@ def get_sql(self, **kwargs):
# MySQL requires no single quotes around the expr and unit
Dialects.MYSQL: 'INTERVAL {expr} {unit}',

# PostgreSQL, Redshift and Vertica require quotes around the expr and unit e.g. INTERVAL '1 week'
Dialects.POSTGRESQL: 'INTERVAL \'{expr} {unit}\'',
Dialects.REDSHIFT: 'INTERVAL \'{expr} {unit}\'',
Dialects.VERTICA: 'INTERVAL \'{expr} {unit}\'',

# Oracle requires just single quotes around the expr
Dialects.ORACLE: 'INTERVAL \'{expr}\' {unit}'
}
Expand Down
16 changes: 16 additions & 0 deletions pypika/tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,14 @@ def test_vertica_dialect_uses_single_quotes_around_interval(self):
c = Interval(days=1).get_sql(dialect=Dialects.VERTICA)
self.assertEqual("INTERVAL '1 DAY'", str(c))

def test_redshift_dialect_uses_single_quotes_around_interval(self):
c = Interval(days=1).get_sql(dialect=Dialects.REDSHIFT)
self.assertEqual("INTERVAL '1 DAY'", str(c))

def test_postgresql_dialect_uses_single_quotes_around_interval(self):
c = Interval(days=1).get_sql(dialect=Dialects.POSTGRESQL)
self.assertEqual("INTERVAL '1 DAY'", str(c))

def _test_extract_datepart(self, date_part):
q = Q.from_(self.t).select(fn.Extract(date_part, self.t.foo))

Expand Down Expand Up @@ -562,3 +570,11 @@ def test_extract_quarter(self):

def test_extract_year(self):
self._test_extract_datepart(DatePart.year)

def test_timestampadd(self):
a = fn.TimestampAdd('year', 1, '2017-10-01')
self.assertEqual(str(a), "TIMESTAMPADD('year',1,'2017-10-01')")

def test_date_add(self):
a = fn.DateAdd('year', 1, '2017-10-01')
self.assertEqual(str(a), "DATE_ADD('year',1,'2017-10-01')")
49 changes: 36 additions & 13 deletions pypika/tests/test_selects.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
# coding: utf8
import unittest

from pypika import (Query,
Table,
Tables,
Field as F,
Case,
functions as fn,
Order,
MySQLQuery,
VerticaQuery,
MSSQLQuery,
PostgreSQLQuery,
OracleQuery)
from pypika import (
Query,
Table,
Tables,
Field as F,
Case,
functions as fn,
Order,
MySQLQuery,
VerticaQuery,
MSSQLQuery,
PostgreSQLQuery,
OracleQuery,
RedshiftQuery,
)

__author__ = "Timothy Heys"
__email__ = "[email protected]"
Expand Down Expand Up @@ -159,11 +162,16 @@ def test_oracle_query_uses_double_quote_chars(self):

self.assertEqual('SELECT "foo","bar" FROM "abc"', str(q))

def test_postgres_query_uses_double_quote_chars(self):
def test_postgresql_query_uses_double_quote_chars(self):
q = PostgreSQLQuery.from_('abc').select('foo', 'bar')

self.assertEqual('SELECT "foo","bar" FROM "abc"', str(q))

def test_redshift_query_uses_double_quote_chars(self):
q = RedshiftQuery.from_('abc').select('foo', 'bar')

self.assertEqual('SELECT "foo","bar" FROM "abc"', str(q))


class WhereTests(unittest.TestCase):
t = Table('abc')
Expand Down Expand Up @@ -307,6 +315,11 @@ def test_postgres_query_uses_double_quote_chars(self):

self.assertEqual('SELECT "foo" FROM "abc" GROUP BY "foo"', str(q))

def test_redshift_query_uses_double_quote_chars(self):
q = RedshiftQuery.from_(self.t).groupby(self.t.foo).select(self.t.foo)

self.assertEqual('SELECT "foo" FROM "abc" GROUP BY "foo"', str(q))


class HavingTests(unittest.TestCase):
table_abc, table_efg = Tables('abc', 'efg')
Expand Down Expand Up @@ -404,6 +417,16 @@ def test_postgres_query_uses_double_quote_chars(self):
)
self.assertEqual("SELECT \"foo\" FROM \"abc\" GROUP BY \"foo\" HAVING \"buz\"='fiz'", str(q))

def test_redshift_query_uses_double_quote_chars(self):
q = RedshiftQuery.from_(self.table_abc).select(
self.table_abc.foo
).groupby(
self.table_abc.foo
).having(
self.table_abc.buz == 'fiz'
)
self.assertEqual("SELECT \"foo\" FROM \"abc\" GROUP BY \"foo\" HAVING \"buz\"='fiz'", str(q))


class OrderByTests(unittest.TestCase):
t = Table('abc')
Expand Down

0 comments on commit e484cf5

Please sign in to comment.