correct line_ending
This commit is contained in:
+88
-88
@@ -1,88 +1,88 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
import json
|
||||
from threading import Lock
|
||||
|
||||
from aquery_parser.sql_parser import scrub
|
||||
from aquery_parser.utils import ansi_string, simple_op, normal_op
|
||||
|
||||
parse_locker = Lock() # ENSURE ONLY ONE PARSING AT A TIME
|
||||
common_parser = None
|
||||
mysql_parser = None
|
||||
sqlserver_parser = None
|
||||
|
||||
SQL_NULL = {"null": {}}
|
||||
|
||||
|
||||
def parse(sql, null=SQL_NULL, calls=simple_op):
|
||||
"""
|
||||
:param sql: String of SQL
|
||||
:param null: What value to use as NULL (default is the null function `{"null":{}}`)
|
||||
:return: parse tree
|
||||
"""
|
||||
global common_parser
|
||||
|
||||
with parse_locker:
|
||||
if not common_parser:
|
||||
common_parser = sql_parser.common_parser()
|
||||
result = _parse(common_parser, sql, null, calls)
|
||||
return result
|
||||
|
||||
|
||||
def parse_mysql(sql, null=SQL_NULL, calls=simple_op):
|
||||
"""
|
||||
PARSE MySQL ASSUME DOUBLE QUOTED STRINGS ARE LITERALS
|
||||
:param sql: String of SQL
|
||||
:param null: What value to use as NULL (default is the null function `{"null":{}}`)
|
||||
:return: parse tree
|
||||
"""
|
||||
global mysql_parser
|
||||
|
||||
with parse_locker:
|
||||
if not mysql_parser:
|
||||
mysql_parser = sql_parser.mysql_parser()
|
||||
return _parse(mysql_parser, sql, null, calls)
|
||||
|
||||
|
||||
def parse_sqlserver(sql, null=SQL_NULL, calls=simple_op):
|
||||
"""
|
||||
PARSE MySQL ASSUME DOUBLE QUOTED STRINGS ARE LITERALS
|
||||
:param sql: String of SQL
|
||||
:param null: What value to use as NULL (default is the null function `{"null":{}}`)
|
||||
:return: parse tree
|
||||
"""
|
||||
global sqlserver_parser
|
||||
|
||||
with parse_locker:
|
||||
if not sqlserver_parser:
|
||||
sqlserver_parser = sql_parser.sqlserver_parser()
|
||||
return _parse(sqlserver_parser, sql, null, calls)
|
||||
|
||||
|
||||
parse_bigquery = parse_mysql
|
||||
|
||||
|
||||
def _parse(parser, sql, null, calls):
|
||||
utils.null_locations = []
|
||||
utils.scrub_op = calls
|
||||
sql = sql.rstrip().rstrip(";")
|
||||
parse_result = parser.parse_string(sql, parse_all=True)
|
||||
output = scrub(parse_result)
|
||||
for o, n in utils.null_locations:
|
||||
o[n] = null
|
||||
return output
|
||||
|
||||
|
||||
|
||||
_ = json.dumps
|
||||
|
||||
__all__ = ["parse", "format", "parse_mysql", "parse_bigquery", "normal_op", "simple_op"]
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
import json
|
||||
from threading import Lock
|
||||
|
||||
from aquery_parser.sql_parser import scrub
|
||||
from aquery_parser.utils import ansi_string, simple_op, normal_op
|
||||
|
||||
parse_locker = Lock() # ENSURE ONLY ONE PARSING AT A TIME
|
||||
common_parser = None
|
||||
mysql_parser = None
|
||||
sqlserver_parser = None
|
||||
|
||||
SQL_NULL = {"null": {}}
|
||||
|
||||
|
||||
def parse(sql, null=SQL_NULL, calls=simple_op):
|
||||
"""
|
||||
:param sql: String of SQL
|
||||
:param null: What value to use as NULL (default is the null function `{"null":{}}`)
|
||||
:return: parse tree
|
||||
"""
|
||||
global common_parser
|
||||
|
||||
with parse_locker:
|
||||
if not common_parser:
|
||||
common_parser = sql_parser.common_parser()
|
||||
result = _parse(common_parser, sql, null, calls)
|
||||
return result
|
||||
|
||||
|
||||
def parse_mysql(sql, null=SQL_NULL, calls=simple_op):
|
||||
"""
|
||||
PARSE MySQL ASSUME DOUBLE QUOTED STRINGS ARE LITERALS
|
||||
:param sql: String of SQL
|
||||
:param null: What value to use as NULL (default is the null function `{"null":{}}`)
|
||||
:return: parse tree
|
||||
"""
|
||||
global mysql_parser
|
||||
|
||||
with parse_locker:
|
||||
if not mysql_parser:
|
||||
mysql_parser = sql_parser.mysql_parser()
|
||||
return _parse(mysql_parser, sql, null, calls)
|
||||
|
||||
|
||||
def parse_sqlserver(sql, null=SQL_NULL, calls=simple_op):
|
||||
"""
|
||||
PARSE MySQL ASSUME DOUBLE QUOTED STRINGS ARE LITERALS
|
||||
:param sql: String of SQL
|
||||
:param null: What value to use as NULL (default is the null function `{"null":{}}`)
|
||||
:return: parse tree
|
||||
"""
|
||||
global sqlserver_parser
|
||||
|
||||
with parse_locker:
|
||||
if not sqlserver_parser:
|
||||
sqlserver_parser = sql_parser.sqlserver_parser()
|
||||
return _parse(sqlserver_parser, sql, null, calls)
|
||||
|
||||
|
||||
parse_bigquery = parse_mysql
|
||||
|
||||
|
||||
def _parse(parser, sql, null, calls):
|
||||
utils.null_locations = []
|
||||
utils.scrub_op = calls
|
||||
sql = sql.rstrip().rstrip(";")
|
||||
parse_result = parser.parse_string(sql, parse_all=True)
|
||||
output = scrub(parse_result)
|
||||
for o, n in utils.null_locations:
|
||||
o[n] = null
|
||||
return output
|
||||
|
||||
|
||||
|
||||
_ = json.dumps
|
||||
|
||||
__all__ = ["parse", "format", "parse_mysql", "parse_bigquery", "normal_op", "simple_op"]
|
||||
|
||||
+417
-417
@@ -1,417 +1,417 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
# SQL CONSTANTS
|
||||
from mo_parsing import *
|
||||
|
||||
from aquery_parser.utils import SQL_NULL, keyword
|
||||
|
||||
NULL = keyword("null") / (lambda: SQL_NULL)
|
||||
TRUE = keyword("true") / (lambda: True)
|
||||
FALSE = keyword("false") / (lambda: False)
|
||||
NOCASE = keyword("nocase")
|
||||
ASC = keyword("asc")
|
||||
DESC = keyword("desc")
|
||||
|
||||
# SIMPLE KEYWORDS
|
||||
AS = keyword("as").suppress()
|
||||
ASSUMING = keyword("assuming")
|
||||
ALL = keyword("all")
|
||||
BY = keyword("by").suppress()
|
||||
CAST = keyword("cast")
|
||||
CONSTRAINT = keyword("constraint").suppress()
|
||||
CREATE = keyword("create").suppress()
|
||||
CROSS = keyword("cross")
|
||||
DISTINCT = keyword("distinct")
|
||||
EXCEPT = keyword("except")
|
||||
FETCH = keyword("fetch").suppress()
|
||||
FROM = keyword("from").suppress()
|
||||
FULL = keyword("full")
|
||||
FUNCTION = keyword("function").suppress()
|
||||
AGGREGATION = keyword("aggregation").suppress()
|
||||
GROUP = keyword("group").suppress()
|
||||
HAVING = keyword("having").suppress()
|
||||
INNER = keyword("inner")
|
||||
INTERVAL = keyword("interval")
|
||||
JOIN = keyword("join")
|
||||
LEFT = keyword("left")
|
||||
LIKE = keyword("like")
|
||||
LIMIT = keyword("limit").suppress()
|
||||
MINUS = keyword("minus")
|
||||
OFFSET = keyword("offset").suppress()
|
||||
ON = keyword("on").suppress()
|
||||
ORDER = keyword("order").suppress()
|
||||
OUTER = keyword("outer")
|
||||
OVER = keyword("over").suppress()
|
||||
PARTITION = keyword("partition").suppress()
|
||||
# PERCENT = keyword("percent").suppress()
|
||||
RIGHT = keyword("right")
|
||||
RLIKE = keyword("rlike")
|
||||
SELECT = keyword("select").suppress()
|
||||
TABLE = keyword("table").suppress()
|
||||
THEN = keyword("then").suppress()
|
||||
TOP = keyword("top").suppress()
|
||||
UNION = keyword("union")
|
||||
INTERSECT = keyword("intersect")
|
||||
USING = keyword("using").suppress()
|
||||
WHEN = keyword("when").suppress()
|
||||
WHERE = keyword("where").suppress()
|
||||
WITH = keyword("with").suppress()
|
||||
WITHIN = keyword("within").suppress()
|
||||
PRIMARY = keyword("primary").suppress()
|
||||
FOREIGN = keyword("foreign").suppress()
|
||||
KEY = keyword("key").suppress()
|
||||
UNIQUE = keyword("unique").suppress()
|
||||
INDEX = keyword("index").suppress()
|
||||
REFERENCES = keyword("references").suppress()
|
||||
RECURSIVE = keyword("recursive").suppress()
|
||||
VALUES = keyword("values").suppress()
|
||||
WINDOW = keyword("window")
|
||||
INTO = keyword("into").suppress()
|
||||
IF = keyword("if").suppress()
|
||||
STATIC = keyword("static").suppress()
|
||||
ELIF = keyword("elif").suppress()
|
||||
ELSE = keyword("else").suppress()
|
||||
FOR = keyword("for").suppress()
|
||||
|
||||
PRIMARY_KEY = Group(PRIMARY + KEY).set_parser_name("primary_key")
|
||||
FOREIGN_KEY = Group(FOREIGN + KEY).set_parser_name("foreign_key")
|
||||
|
||||
# SIMPLE OPERATORS
|
||||
CONCAT = Literal("||").set_parser_name("concat")
|
||||
MUL = Literal("*").set_parser_name("mul")
|
||||
DIV = Literal("/").set_parser_name("div")
|
||||
MOD = Literal("%").set_parser_name("mod")
|
||||
NEG = Literal("-").set_parser_name("neg")
|
||||
ADD = Literal("+").set_parser_name("add")
|
||||
SUB = Literal("-").set_parser_name("sub")
|
||||
BINARY_NOT = Literal("~").set_parser_name("binary_not")
|
||||
BINARY_AND = Literal("&").set_parser_name("binary_and")
|
||||
BINARY_OR = Literal("|").set_parser_name("binary_or")
|
||||
GTE = Literal(">=").set_parser_name("gte")
|
||||
LTE = Literal("<=").set_parser_name("lte")
|
||||
LT = Literal("<").set_parser_name("lt")
|
||||
GT = Literal(">").set_parser_name("gt")
|
||||
EEQ = (
|
||||
# conservative equality https://github.com/klahnakoski/jx-sqlite/blob/dev/docs/Logical%20Equality.md#definitions
|
||||
Literal("==") | Literal("=")
|
||||
).set_parser_name("eq")
|
||||
DEQ = (
|
||||
# decisive equality
|
||||
# https://sparkbyexamples.com/apache-hive/hive-relational-arithmetic-logical-operators/
|
||||
Literal("<=>").set_parser_name("eq!")
|
||||
)
|
||||
IDF = (
|
||||
# decisive equality
|
||||
# https://prestodb.io/docs/current/functions/comparison.html#is-distinct-from-and-is-not-distinct-from
|
||||
keyword("is distinct from").set_parser_name("eq!")
|
||||
)
|
||||
INDF = (
|
||||
# decisive equality
|
||||
# https://prestodb.io/docs/current/functions/comparison.html#is-distinct-from-and-is-not-distinct-from
|
||||
keyword("is not distinct from").set_parser_name("ne!")
|
||||
)
|
||||
FASSIGN = Literal(":=").set_parser_name("fassign") # Assignment in UDFs
|
||||
PASSIGN = Literal("+=").set_parser_name("passign")
|
||||
MASSIGN = Literal("-=").set_parser_name("massign")
|
||||
MULASSIGN = Literal("*=").set_parser_name("mulassign")
|
||||
DASSIGN = Literal("/=").set_parser_name("dassign")
|
||||
COLON = Literal(":").set_parser_name("colon")
|
||||
NEQ = (Literal("!=") | Literal("<>")).set_parser_name("neq")
|
||||
LAMBDA = Literal("->").set_parser_name("lambda")
|
||||
DOT = Literal(".").set_parser_name("dot")
|
||||
|
||||
AND = keyword("and")
|
||||
BETWEEN = keyword("between")
|
||||
CASE = keyword("case").suppress()
|
||||
COLLATE = keyword("collate")
|
||||
END = keyword("end")
|
||||
ELSE = keyword("else").suppress()
|
||||
IN = keyword("in")
|
||||
IS = keyword("is")
|
||||
NOT = keyword("not")
|
||||
OR = keyword("or")
|
||||
LATERAL = keyword("lateral")
|
||||
VIEW = keyword("view")
|
||||
|
||||
# COMPOUND KEYWORDS
|
||||
|
||||
|
||||
joins = (
|
||||
(
|
||||
Optional(CROSS | OUTER | INNER | ((FULL | LEFT | RIGHT) + Optional(INNER | OUTER)))
|
||||
+ JOIN
|
||||
+ Optional(LATERAL)
|
||||
)
|
||||
| LATERAL + VIEW + Optional(OUTER)
|
||||
) / (lambda tokens: " ".join(tokens).lower())
|
||||
|
||||
UNION_ALL = (UNION + ALL).set_parser_name("union_all")
|
||||
WITHIN_GROUP = Group(WITHIN + GROUP).set_parser_name("within_group")
|
||||
SELECT_DISTINCT = Group(SELECT + DISTINCT).set_parser_name("select distinct")
|
||||
PARTITION_BY = Group(PARTITION + BY).set_parser_name("partition by")
|
||||
GROUP_BY = Group(GROUP + BY).set_parser_name("group by")
|
||||
ORDER_BY = Group(ORDER + BY).set_parser_name("order by")
|
||||
|
||||
# COMPOUND OPERATORS
|
||||
AT_TIME_ZONE = Group(keyword("at") + keyword("time") + keyword("zone"))
|
||||
NOT_BETWEEN = Group(NOT + BETWEEN).set_parser_name("not_between")
|
||||
NOT_LIKE = Group(NOT + LIKE).set_parser_name("not_like")
|
||||
NOT_RLIKE = Group(NOT + RLIKE).set_parser_name("not_rlike")
|
||||
NOT_IN = Group(NOT + IN).set_parser_name("nin")
|
||||
IS_NOT = Group(IS + NOT).set_parser_name("is_not")
|
||||
|
||||
_SIMILAR = keyword("similar")
|
||||
_TO = keyword("to")
|
||||
SIMILAR_TO = Group(_SIMILAR + _TO).set_parser_name("similar_to")
|
||||
NOT_SIMILAR_TO = Group(NOT + _SIMILAR + _TO).set_parser_name("not_similar_to")
|
||||
|
||||
RESERVED = MatchFirst([
|
||||
# ONY INCLUDE SINGLE WORDS
|
||||
ALL,
|
||||
AND,
|
||||
AS,
|
||||
ASC,
|
||||
ASSUMING,
|
||||
BETWEEN,
|
||||
BY,
|
||||
CASE,
|
||||
COLLATE,
|
||||
CONSTRAINT,
|
||||
CREATE,
|
||||
CROSS,
|
||||
DESC,
|
||||
DISTINCT,
|
||||
EXCEPT,
|
||||
ELSE,
|
||||
END,
|
||||
FALSE,
|
||||
FETCH,
|
||||
FOREIGN,
|
||||
FROM,
|
||||
FULL,
|
||||
FUNCTION,
|
||||
GROUP_BY,
|
||||
GROUP,
|
||||
HAVING,
|
||||
IN,
|
||||
INDEX,
|
||||
INNER,
|
||||
INTERSECT,
|
||||
INTERVAL,
|
||||
IS_NOT,
|
||||
IS,
|
||||
JOIN,
|
||||
KEY,
|
||||
LATERAL,
|
||||
LEFT,
|
||||
LIKE,
|
||||
LIMIT,
|
||||
MINUS,
|
||||
NOCASE,
|
||||
NOT,
|
||||
NULL,
|
||||
OFFSET,
|
||||
ON,
|
||||
OR,
|
||||
ORDER,
|
||||
OUTER,
|
||||
OVER,
|
||||
PARTITION,
|
||||
PRIMARY,
|
||||
REFERENCES,
|
||||
RIGHT,
|
||||
RLIKE,
|
||||
SELECT,
|
||||
THEN,
|
||||
TRUE,
|
||||
UNION,
|
||||
UNIQUE,
|
||||
USING,
|
||||
WHEN,
|
||||
WHERE,
|
||||
WINDOW,
|
||||
WITH,
|
||||
WITHIN,
|
||||
INTO,
|
||||
])
|
||||
L_INLINE = Literal("<k>").suppress()
|
||||
R_INLINE = Literal("</k>").suppress()
|
||||
LBRACE = Literal("{").suppress()
|
||||
RBRACE = Literal("}").suppress()
|
||||
LSB = Literal("[").suppress()
|
||||
RSB = Literal("]").suppress()
|
||||
LB = Literal("(").suppress()
|
||||
RB = Literal(")").suppress()
|
||||
EQ = Char("=").suppress()
|
||||
|
||||
join_keywords = {
|
||||
"join",
|
||||
"full join",
|
||||
"cross join",
|
||||
"inner join",
|
||||
"left join",
|
||||
"right join",
|
||||
"full outer join",
|
||||
"right outer join",
|
||||
"left outer join",
|
||||
}
|
||||
|
||||
precedence = {
|
||||
# https://www.sqlite.org/lang_expr.html
|
||||
"literal": -1,
|
||||
"interval": 0,
|
||||
"cast": 0,
|
||||
"collate": 0,
|
||||
"concat": 1,
|
||||
"mul": 2,
|
||||
"div": 1.5,
|
||||
"mod": 2,
|
||||
"neg": 3,
|
||||
"add": 3,
|
||||
"sub": 2.5,
|
||||
"binary_not": 4,
|
||||
"binary_and": 4,
|
||||
"binary_or": 4,
|
||||
"gte": 5,
|
||||
"lte": 5,
|
||||
"lt": 5,
|
||||
"gt": 6,
|
||||
"eq": 7,
|
||||
"neq": 7,
|
||||
"missing": 7,
|
||||
"exists": 7,
|
||||
"at_time_zone": 8,
|
||||
"between": 8,
|
||||
"not_between": 8,
|
||||
"in": 8,
|
||||
"nin": 8,
|
||||
"is": 8,
|
||||
"like": 8,
|
||||
"not_like": 8,
|
||||
"rlike": 8,
|
||||
"not_rlike": 8,
|
||||
"similar_to": 8,
|
||||
"not_similar_to": 8,
|
||||
"and": 10,
|
||||
"or": 11,
|
||||
"lambda": 12,
|
||||
"join": 18,
|
||||
"list": 18,
|
||||
"function": 30,
|
||||
"select": 30,
|
||||
"from": 30,
|
||||
"window": 35,
|
||||
"union": 40,
|
||||
"union_all": 40,
|
||||
"except": 40,
|
||||
"minus": 40,
|
||||
"intersect": 40,
|
||||
"order": 50,
|
||||
}
|
||||
|
||||
KNOWN_OPS = [
|
||||
COLLATE,
|
||||
CONCAT,
|
||||
MUL | DIV | MOD,
|
||||
NEG,
|
||||
ADD | SUB,
|
||||
BINARY_NOT,
|
||||
BINARY_AND,
|
||||
BINARY_OR,
|
||||
GTE | LTE | LT | GT,
|
||||
EEQ | NEQ | DEQ | IDF | INDF,
|
||||
AT_TIME_ZONE,
|
||||
(BETWEEN, AND),
|
||||
(NOT_BETWEEN, AND),
|
||||
IN,
|
||||
NOT_IN,
|
||||
IS_NOT,
|
||||
IS,
|
||||
LIKE,
|
||||
NOT_LIKE,
|
||||
RLIKE,
|
||||
NOT_RLIKE,
|
||||
SIMILAR_TO,
|
||||
NOT_SIMILAR_TO,
|
||||
NOT,
|
||||
AND,
|
||||
OR,
|
||||
LAMBDA,
|
||||
]
|
||||
|
||||
times = ["now", "today", "tomorrow", "eod"]
|
||||
|
||||
durations = {
|
||||
"microseconds": "microsecond",
|
||||
"microsecond": "microsecond",
|
||||
"microsecs": "microsecond",
|
||||
"microsec": "microsecond",
|
||||
"useconds": "microsecond",
|
||||
"usecond": "microsecond",
|
||||
"usecs": "microsecond",
|
||||
"usec": "microsecond",
|
||||
"us": "microsecond",
|
||||
"milliseconds": "millisecond",
|
||||
"millisecond": "millisecond",
|
||||
"millisecon": "millisecond",
|
||||
"mseconds": "millisecond",
|
||||
"msecond": "millisecond",
|
||||
"millisecs": "millisecond",
|
||||
"millisec": "millisecond",
|
||||
"msecs": "millisecond",
|
||||
"msec": "millisecond",
|
||||
"ms": "millisecond",
|
||||
"seconds": "second",
|
||||
"second": "second",
|
||||
"secs": "second",
|
||||
"sec": "second",
|
||||
"s": "second",
|
||||
"minutes": "minute",
|
||||
"minute": "minute",
|
||||
"mins": "minute",
|
||||
"min": "minute",
|
||||
"m": "minute",
|
||||
"hours": "hour",
|
||||
"hour": "hour",
|
||||
"hrs": "hour",
|
||||
"hr": "hour",
|
||||
"h": "hour",
|
||||
"days": "day",
|
||||
"day": "day",
|
||||
"d": "day",
|
||||
"dayofweek": "dow",
|
||||
"dow": "dow",
|
||||
"weekday": "dow",
|
||||
"weeks": "week",
|
||||
"week": "week",
|
||||
"w": "week",
|
||||
"months": "month",
|
||||
"month": "month",
|
||||
"mons": "month",
|
||||
"mon": "month",
|
||||
"quarters": "quarter",
|
||||
"quarter": "quarter",
|
||||
"years": "year",
|
||||
"year": "year",
|
||||
"decades": "decade",
|
||||
"decade": "decade",
|
||||
"decs": "decade",
|
||||
"dec": "decade",
|
||||
"centuries": "century",
|
||||
"century": "century",
|
||||
"cents": "century",
|
||||
"cent": "century",
|
||||
"c": "century",
|
||||
"millennia": "millennium",
|
||||
"millennium": "millennium",
|
||||
"mils": "millennium",
|
||||
"mil": "millennium",
|
||||
"epoch": "epoch",
|
||||
}
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
# SQL CONSTANTS
|
||||
from mo_parsing import *
|
||||
|
||||
from aquery_parser.utils import SQL_NULL, keyword
|
||||
|
||||
NULL = keyword("null") / (lambda: SQL_NULL)
|
||||
TRUE = keyword("true") / (lambda: True)
|
||||
FALSE = keyword("false") / (lambda: False)
|
||||
NOCASE = keyword("nocase")
|
||||
ASC = keyword("asc")
|
||||
DESC = keyword("desc")
|
||||
|
||||
# SIMPLE KEYWORDS
|
||||
AS = keyword("as").suppress()
|
||||
ASSUMING = keyword("assuming")
|
||||
ALL = keyword("all")
|
||||
BY = keyword("by").suppress()
|
||||
CAST = keyword("cast")
|
||||
CONSTRAINT = keyword("constraint").suppress()
|
||||
CREATE = keyword("create").suppress()
|
||||
CROSS = keyword("cross")
|
||||
DISTINCT = keyword("distinct")
|
||||
EXCEPT = keyword("except")
|
||||
FETCH = keyword("fetch").suppress()
|
||||
FROM = keyword("from").suppress()
|
||||
FULL = keyword("full")
|
||||
FUNCTION = keyword("function").suppress()
|
||||
AGGREGATION = keyword("aggregation").suppress()
|
||||
GROUP = keyword("group").suppress()
|
||||
HAVING = keyword("having").suppress()
|
||||
INNER = keyword("inner")
|
||||
INTERVAL = keyword("interval")
|
||||
JOIN = keyword("join")
|
||||
LEFT = keyword("left")
|
||||
LIKE = keyword("like")
|
||||
LIMIT = keyword("limit").suppress()
|
||||
MINUS = keyword("minus")
|
||||
OFFSET = keyword("offset").suppress()
|
||||
ON = keyword("on").suppress()
|
||||
ORDER = keyword("order").suppress()
|
||||
OUTER = keyword("outer")
|
||||
OVER = keyword("over").suppress()
|
||||
PARTITION = keyword("partition").suppress()
|
||||
# PERCENT = keyword("percent").suppress()
|
||||
RIGHT = keyword("right")
|
||||
RLIKE = keyword("rlike")
|
||||
SELECT = keyword("select").suppress()
|
||||
TABLE = keyword("table").suppress()
|
||||
THEN = keyword("then").suppress()
|
||||
TOP = keyword("top").suppress()
|
||||
UNION = keyword("union")
|
||||
INTERSECT = keyword("intersect")
|
||||
USING = keyword("using").suppress()
|
||||
WHEN = keyword("when").suppress()
|
||||
WHERE = keyword("where").suppress()
|
||||
WITH = keyword("with").suppress()
|
||||
WITHIN = keyword("within").suppress()
|
||||
PRIMARY = keyword("primary").suppress()
|
||||
FOREIGN = keyword("foreign").suppress()
|
||||
KEY = keyword("key").suppress()
|
||||
UNIQUE = keyword("unique").suppress()
|
||||
INDEX = keyword("index").suppress()
|
||||
REFERENCES = keyword("references").suppress()
|
||||
RECURSIVE = keyword("recursive").suppress()
|
||||
VALUES = keyword("values").suppress()
|
||||
WINDOW = keyword("window")
|
||||
INTO = keyword("into").suppress()
|
||||
IF = keyword("if").suppress()
|
||||
STATIC = keyword("static").suppress()
|
||||
ELIF = keyword("elif").suppress()
|
||||
ELSE = keyword("else").suppress()
|
||||
FOR = keyword("for").suppress()
|
||||
|
||||
PRIMARY_KEY = Group(PRIMARY + KEY).set_parser_name("primary_key")
|
||||
FOREIGN_KEY = Group(FOREIGN + KEY).set_parser_name("foreign_key")
|
||||
|
||||
# SIMPLE OPERATORS
|
||||
CONCAT = Literal("||").set_parser_name("concat")
|
||||
MUL = Literal("*").set_parser_name("mul")
|
||||
DIV = Literal("/").set_parser_name("div")
|
||||
MOD = Literal("%").set_parser_name("mod")
|
||||
NEG = Literal("-").set_parser_name("neg")
|
||||
ADD = Literal("+").set_parser_name("add")
|
||||
SUB = Literal("-").set_parser_name("sub")
|
||||
BINARY_NOT = Literal("~").set_parser_name("binary_not")
|
||||
BINARY_AND = Literal("&").set_parser_name("binary_and")
|
||||
BINARY_OR = Literal("|").set_parser_name("binary_or")
|
||||
GTE = Literal(">=").set_parser_name("gte")
|
||||
LTE = Literal("<=").set_parser_name("lte")
|
||||
LT = Literal("<").set_parser_name("lt")
|
||||
GT = Literal(">").set_parser_name("gt")
|
||||
EEQ = (
|
||||
# conservative equality https://github.com/klahnakoski/jx-sqlite/blob/dev/docs/Logical%20Equality.md#definitions
|
||||
Literal("==") | Literal("=")
|
||||
).set_parser_name("eq")
|
||||
DEQ = (
|
||||
# decisive equality
|
||||
# https://sparkbyexamples.com/apache-hive/hive-relational-arithmetic-logical-operators/
|
||||
Literal("<=>").set_parser_name("eq!")
|
||||
)
|
||||
IDF = (
|
||||
# decisive equality
|
||||
# https://prestodb.io/docs/current/functions/comparison.html#is-distinct-from-and-is-not-distinct-from
|
||||
keyword("is distinct from").set_parser_name("eq!")
|
||||
)
|
||||
INDF = (
|
||||
# decisive equality
|
||||
# https://prestodb.io/docs/current/functions/comparison.html#is-distinct-from-and-is-not-distinct-from
|
||||
keyword("is not distinct from").set_parser_name("ne!")
|
||||
)
|
||||
FASSIGN = Literal(":=").set_parser_name("fassign") # Assignment in UDFs
|
||||
PASSIGN = Literal("+=").set_parser_name("passign")
|
||||
MASSIGN = Literal("-=").set_parser_name("massign")
|
||||
MULASSIGN = Literal("*=").set_parser_name("mulassign")
|
||||
DASSIGN = Literal("/=").set_parser_name("dassign")
|
||||
COLON = Literal(":").set_parser_name("colon")
|
||||
NEQ = (Literal("!=") | Literal("<>")).set_parser_name("neq")
|
||||
LAMBDA = Literal("->").set_parser_name("lambda")
|
||||
DOT = Literal(".").set_parser_name("dot")
|
||||
|
||||
AND = keyword("and")
|
||||
BETWEEN = keyword("between")
|
||||
CASE = keyword("case").suppress()
|
||||
COLLATE = keyword("collate")
|
||||
END = keyword("end")
|
||||
ELSE = keyword("else").suppress()
|
||||
IN = keyword("in")
|
||||
IS = keyword("is")
|
||||
NOT = keyword("not")
|
||||
OR = keyword("or")
|
||||
LATERAL = keyword("lateral")
|
||||
VIEW = keyword("view")
|
||||
|
||||
# COMPOUND KEYWORDS
|
||||
|
||||
|
||||
joins = (
|
||||
(
|
||||
Optional(CROSS | OUTER | INNER | ((FULL | LEFT | RIGHT) + Optional(INNER | OUTER)))
|
||||
+ JOIN
|
||||
+ Optional(LATERAL)
|
||||
)
|
||||
| LATERAL + VIEW + Optional(OUTER)
|
||||
) / (lambda tokens: " ".join(tokens).lower())
|
||||
|
||||
UNION_ALL = (UNION + ALL).set_parser_name("union_all")
|
||||
WITHIN_GROUP = Group(WITHIN + GROUP).set_parser_name("within_group")
|
||||
SELECT_DISTINCT = Group(SELECT + DISTINCT).set_parser_name("select distinct")
|
||||
PARTITION_BY = Group(PARTITION + BY).set_parser_name("partition by")
|
||||
GROUP_BY = Group(GROUP + BY).set_parser_name("group by")
|
||||
ORDER_BY = Group(ORDER + BY).set_parser_name("order by")
|
||||
|
||||
# COMPOUND OPERATORS
|
||||
AT_TIME_ZONE = Group(keyword("at") + keyword("time") + keyword("zone"))
|
||||
NOT_BETWEEN = Group(NOT + BETWEEN).set_parser_name("not_between")
|
||||
NOT_LIKE = Group(NOT + LIKE).set_parser_name("not_like")
|
||||
NOT_RLIKE = Group(NOT + RLIKE).set_parser_name("not_rlike")
|
||||
NOT_IN = Group(NOT + IN).set_parser_name("nin")
|
||||
IS_NOT = Group(IS + NOT).set_parser_name("is_not")
|
||||
|
||||
_SIMILAR = keyword("similar")
|
||||
_TO = keyword("to")
|
||||
SIMILAR_TO = Group(_SIMILAR + _TO).set_parser_name("similar_to")
|
||||
NOT_SIMILAR_TO = Group(NOT + _SIMILAR + _TO).set_parser_name("not_similar_to")
|
||||
|
||||
RESERVED = MatchFirst([
|
||||
# ONY INCLUDE SINGLE WORDS
|
||||
ALL,
|
||||
AND,
|
||||
AS,
|
||||
ASC,
|
||||
ASSUMING,
|
||||
BETWEEN,
|
||||
BY,
|
||||
CASE,
|
||||
COLLATE,
|
||||
CONSTRAINT,
|
||||
CREATE,
|
||||
CROSS,
|
||||
DESC,
|
||||
DISTINCT,
|
||||
EXCEPT,
|
||||
ELSE,
|
||||
END,
|
||||
FALSE,
|
||||
FETCH,
|
||||
FOREIGN,
|
||||
FROM,
|
||||
FULL,
|
||||
FUNCTION,
|
||||
GROUP_BY,
|
||||
GROUP,
|
||||
HAVING,
|
||||
IN,
|
||||
INDEX,
|
||||
INNER,
|
||||
INTERSECT,
|
||||
INTERVAL,
|
||||
IS_NOT,
|
||||
IS,
|
||||
JOIN,
|
||||
KEY,
|
||||
LATERAL,
|
||||
LEFT,
|
||||
LIKE,
|
||||
LIMIT,
|
||||
MINUS,
|
||||
NOCASE,
|
||||
NOT,
|
||||
NULL,
|
||||
OFFSET,
|
||||
ON,
|
||||
OR,
|
||||
ORDER,
|
||||
OUTER,
|
||||
OVER,
|
||||
PARTITION,
|
||||
PRIMARY,
|
||||
REFERENCES,
|
||||
RIGHT,
|
||||
RLIKE,
|
||||
SELECT,
|
||||
THEN,
|
||||
TRUE,
|
||||
UNION,
|
||||
UNIQUE,
|
||||
USING,
|
||||
WHEN,
|
||||
WHERE,
|
||||
WINDOW,
|
||||
WITH,
|
||||
WITHIN,
|
||||
INTO,
|
||||
])
|
||||
L_INLINE = Literal("<k>").suppress()
|
||||
R_INLINE = Literal("</k>").suppress()
|
||||
LBRACE = Literal("{").suppress()
|
||||
RBRACE = Literal("}").suppress()
|
||||
LSB = Literal("[").suppress()
|
||||
RSB = Literal("]").suppress()
|
||||
LB = Literal("(").suppress()
|
||||
RB = Literal(")").suppress()
|
||||
EQ = Char("=").suppress()
|
||||
|
||||
join_keywords = {
|
||||
"join",
|
||||
"full join",
|
||||
"cross join",
|
||||
"inner join",
|
||||
"left join",
|
||||
"right join",
|
||||
"full outer join",
|
||||
"right outer join",
|
||||
"left outer join",
|
||||
}
|
||||
|
||||
precedence = {
|
||||
# https://www.sqlite.org/lang_expr.html
|
||||
"literal": -1,
|
||||
"interval": 0,
|
||||
"cast": 0,
|
||||
"collate": 0,
|
||||
"concat": 1,
|
||||
"mul": 2,
|
||||
"div": 1.5,
|
||||
"mod": 2,
|
||||
"neg": 3,
|
||||
"add": 3,
|
||||
"sub": 2.5,
|
||||
"binary_not": 4,
|
||||
"binary_and": 4,
|
||||
"binary_or": 4,
|
||||
"gte": 5,
|
||||
"lte": 5,
|
||||
"lt": 5,
|
||||
"gt": 6,
|
||||
"eq": 7,
|
||||
"neq": 7,
|
||||
"missing": 7,
|
||||
"exists": 7,
|
||||
"at_time_zone": 8,
|
||||
"between": 8,
|
||||
"not_between": 8,
|
||||
"in": 8,
|
||||
"nin": 8,
|
||||
"is": 8,
|
||||
"like": 8,
|
||||
"not_like": 8,
|
||||
"rlike": 8,
|
||||
"not_rlike": 8,
|
||||
"similar_to": 8,
|
||||
"not_similar_to": 8,
|
||||
"and": 10,
|
||||
"or": 11,
|
||||
"lambda": 12,
|
||||
"join": 18,
|
||||
"list": 18,
|
||||
"function": 30,
|
||||
"select": 30,
|
||||
"from": 30,
|
||||
"window": 35,
|
||||
"union": 40,
|
||||
"union_all": 40,
|
||||
"except": 40,
|
||||
"minus": 40,
|
||||
"intersect": 40,
|
||||
"order": 50,
|
||||
}
|
||||
|
||||
KNOWN_OPS = [
|
||||
COLLATE,
|
||||
CONCAT,
|
||||
MUL | DIV | MOD,
|
||||
NEG,
|
||||
ADD | SUB,
|
||||
BINARY_NOT,
|
||||
BINARY_AND,
|
||||
BINARY_OR,
|
||||
GTE | LTE | LT | GT,
|
||||
EEQ | NEQ | DEQ | IDF | INDF,
|
||||
AT_TIME_ZONE,
|
||||
(BETWEEN, AND),
|
||||
(NOT_BETWEEN, AND),
|
||||
IN,
|
||||
NOT_IN,
|
||||
IS_NOT,
|
||||
IS,
|
||||
LIKE,
|
||||
NOT_LIKE,
|
||||
RLIKE,
|
||||
NOT_RLIKE,
|
||||
SIMILAR_TO,
|
||||
NOT_SIMILAR_TO,
|
||||
NOT,
|
||||
AND,
|
||||
OR,
|
||||
LAMBDA,
|
||||
]
|
||||
|
||||
times = ["now", "today", "tomorrow", "eod"]
|
||||
|
||||
durations = {
|
||||
"microseconds": "microsecond",
|
||||
"microsecond": "microsecond",
|
||||
"microsecs": "microsecond",
|
||||
"microsec": "microsecond",
|
||||
"useconds": "microsecond",
|
||||
"usecond": "microsecond",
|
||||
"usecs": "microsecond",
|
||||
"usec": "microsecond",
|
||||
"us": "microsecond",
|
||||
"milliseconds": "millisecond",
|
||||
"millisecond": "millisecond",
|
||||
"millisecon": "millisecond",
|
||||
"mseconds": "millisecond",
|
||||
"msecond": "millisecond",
|
||||
"millisecs": "millisecond",
|
||||
"millisec": "millisecond",
|
||||
"msecs": "millisecond",
|
||||
"msec": "millisecond",
|
||||
"ms": "millisecond",
|
||||
"seconds": "second",
|
||||
"second": "second",
|
||||
"secs": "second",
|
||||
"sec": "second",
|
||||
"s": "second",
|
||||
"minutes": "minute",
|
||||
"minute": "minute",
|
||||
"mins": "minute",
|
||||
"min": "minute",
|
||||
"m": "minute",
|
||||
"hours": "hour",
|
||||
"hour": "hour",
|
||||
"hrs": "hour",
|
||||
"hr": "hour",
|
||||
"h": "hour",
|
||||
"days": "day",
|
||||
"day": "day",
|
||||
"d": "day",
|
||||
"dayofweek": "dow",
|
||||
"dow": "dow",
|
||||
"weekday": "dow",
|
||||
"weeks": "week",
|
||||
"week": "week",
|
||||
"w": "week",
|
||||
"months": "month",
|
||||
"month": "month",
|
||||
"mons": "month",
|
||||
"mon": "month",
|
||||
"quarters": "quarter",
|
||||
"quarter": "quarter",
|
||||
"years": "year",
|
||||
"year": "year",
|
||||
"decades": "decade",
|
||||
"decade": "decade",
|
||||
"decs": "decade",
|
||||
"dec": "decade",
|
||||
"centuries": "century",
|
||||
"century": "century",
|
||||
"cents": "century",
|
||||
"cent": "century",
|
||||
"c": "century",
|
||||
"millennia": "millennium",
|
||||
"millennium": "millennium",
|
||||
"mils": "millennium",
|
||||
"mil": "millennium",
|
||||
"epoch": "epoch",
|
||||
}
|
||||
|
||||
+723
-723
File diff suppressed because it is too large
Load Diff
+223
-223
@@ -1,223 +1,223 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
|
||||
# KNOWN TYPES
|
||||
from mo_parsing import Forward, Group, Optional, MatchFirst, Literal, ZeroOrMore, export
|
||||
from mo_parsing.infix import delimited_list, RIGHT_ASSOC, LEFT_ASSOC
|
||||
|
||||
from aquery_parser.keywords import (
|
||||
RB,
|
||||
LB,
|
||||
NEG,
|
||||
NOT,
|
||||
BINARY_NOT,
|
||||
NULL,
|
||||
EQ,
|
||||
KNOWN_OPS,
|
||||
LT,
|
||||
GT,
|
||||
)
|
||||
from aquery_parser.utils import (
|
||||
keyword,
|
||||
to_json_call,
|
||||
int_num,
|
||||
ansi_string,
|
||||
ansi_ident,
|
||||
assign,
|
||||
flag,
|
||||
)
|
||||
|
||||
_size = Optional(LB + int_num("params") + RB)
|
||||
_sizes = Optional(LB + delimited_list(int_num("params")) + RB)
|
||||
|
||||
simple_types = Forward()
|
||||
|
||||
BIGINT = Group(keyword("bigint")("op") + Optional(_size)+Optional(flag("unsigned"))) / to_json_call
|
||||
BOOL = Group(keyword("bool")("op")) / to_json_call
|
||||
BOOLEAN = Group(keyword("boolean")("op")) / to_json_call
|
||||
DOUBLE = Group(keyword("double")("op")) / to_json_call
|
||||
FLOAT64 = Group(keyword("float64")("op")) / to_json_call
|
||||
FLOAT = Group(keyword("float")("op")) / to_json_call
|
||||
GEOMETRY = Group(keyword("geometry")("op")) / to_json_call
|
||||
INTEGER = Group(keyword("integer")("op")) / to_json_call
|
||||
INT = (keyword("int")("op") + _size) / to_json_call
|
||||
INT32 = Group(keyword("int32")("op")) / to_json_call
|
||||
INT64 = Group(keyword("int64")("op")) / to_json_call
|
||||
REAL = Group(keyword("real")("op")) / to_json_call
|
||||
TEXT = Group(keyword("text")("op")) / to_json_call
|
||||
SMALLINT = Group(keyword("smallint")("op")) / to_json_call
|
||||
STRING = Group(keyword("string")("op")) / to_json_call
|
||||
|
||||
BLOB = (keyword("blob")("op") + _size) / to_json_call
|
||||
BYTES = (keyword("bytes")("op") + _size) / to_json_call
|
||||
CHAR = (keyword("char")("op") + _size) / to_json_call
|
||||
NCHAR = (keyword("nchar")("op") + _size) / to_json_call
|
||||
VARCHAR = (keyword("varchar")("op") + _size) / to_json_call
|
||||
VARCHAR2 = (keyword("varchar2")("op") + _size) / to_json_call
|
||||
VARBINARY = (keyword("varbinary")("op") + _size) / to_json_call
|
||||
TINYINT = (keyword("tinyint")("op") + _size) / to_json_call
|
||||
UUID = Group(keyword("uuid")("op")) / to_json_call
|
||||
|
||||
DECIMAL = (keyword("decimal")("op") + _sizes) / to_json_call
|
||||
DOUBLE_PRECISION = (
|
||||
Group((keyword("double precision") / (lambda: "double_precision"))("op"))
|
||||
/ to_json_call
|
||||
)
|
||||
NUMERIC = (keyword("numeric")("op") + _sizes) / to_json_call
|
||||
NUMBER = (keyword("number")("op") + _sizes) / to_json_call
|
||||
|
||||
MAP_TYPE = (
|
||||
keyword("map")("op") + LB + delimited_list(simple_types("params")) + RB
|
||||
) / to_json_call
|
||||
ARRAY_TYPE = (keyword("array")("op") + LB + simple_types("params") + RB) / to_json_call
|
||||
|
||||
DATE = keyword("date")
|
||||
DATETIME = keyword("datetime")
|
||||
DATETIME_W_TIMEZONE = keyword("datetime with time zone")
|
||||
TIME = keyword("time")
|
||||
TIMESTAMP = keyword("timestamp")
|
||||
TIMESTAMP_W_TIMEZONE = keyword("timestamp with time zone")
|
||||
TIMESTAMPTZ = keyword("timestamptz")
|
||||
TIMETZ = keyword("timetz")
|
||||
|
||||
time_functions = DATE | DATETIME | TIME | TIMESTAMP | TIMESTAMPTZ | TIMETZ
|
||||
|
||||
# KNOWNN TIME TYPES
|
||||
_format = Optional((ansi_string | ansi_ident)("params"))
|
||||
|
||||
DATE_TYPE = (DATE("op") + _format) / to_json_call
|
||||
DATETIME_TYPE = (DATETIME("op") + _format) / to_json_call
|
||||
DATETIME_W_TIMEZONE_TYPE = (DATETIME_W_TIMEZONE("op") + _format) / to_json_call
|
||||
TIME_TYPE = (TIME("op") + _format) / to_json_call
|
||||
TIMESTAMP_TYPE = (TIMESTAMP("op") + _format) / to_json_call
|
||||
TIMESTAMP_W_TIMEZONE_TYPE = (TIMESTAMP_W_TIMEZONE("op") + _format) / to_json_call
|
||||
TIMESTAMPTZ_TYPE = (TIMESTAMPTZ("op") + _format) / to_json_call
|
||||
TIMETZ_TYPE = (TIMETZ("op") + _format) / to_json_call
|
||||
|
||||
simple_types << MatchFirst([
|
||||
ARRAY_TYPE,
|
||||
BIGINT,
|
||||
BOOL,
|
||||
BOOLEAN,
|
||||
BLOB,
|
||||
BYTES,
|
||||
CHAR,
|
||||
DATE_TYPE,
|
||||
DATETIME_W_TIMEZONE_TYPE,
|
||||
DATETIME_TYPE,
|
||||
DECIMAL,
|
||||
DOUBLE_PRECISION,
|
||||
DOUBLE,
|
||||
FLOAT64,
|
||||
FLOAT,
|
||||
GEOMETRY,
|
||||
MAP_TYPE,
|
||||
INTEGER,
|
||||
INT,
|
||||
INT32,
|
||||
INT64,
|
||||
NCHAR,
|
||||
NUMBER,
|
||||
NUMERIC,
|
||||
REAL,
|
||||
TEXT,
|
||||
SMALLINT,
|
||||
STRING,
|
||||
TIME_TYPE,
|
||||
TIMESTAMP_W_TIMEZONE_TYPE,
|
||||
TIMESTAMP_TYPE,
|
||||
TIMESTAMPTZ_TYPE,
|
||||
TIMETZ_TYPE,
|
||||
TINYINT,
|
||||
UUID,
|
||||
VARCHAR,
|
||||
VARCHAR2,
|
||||
VARBINARY,
|
||||
])
|
||||
|
||||
CASTING = (Literal("::").suppress() + simple_types("params")).set_parser_name("cast")
|
||||
KNOWN_OPS.insert(0, CASTING)
|
||||
|
||||
unary_ops = {
|
||||
NEG: RIGHT_ASSOC,
|
||||
NOT: RIGHT_ASSOC,
|
||||
BINARY_NOT: RIGHT_ASSOC,
|
||||
CASTING: LEFT_ASSOC,
|
||||
}
|
||||
|
||||
|
||||
def get_column_type(expr, var_name, literal_string):
|
||||
column_definition = Forward()
|
||||
column_type = Forward().set_parser_name("column type")
|
||||
|
||||
struct_type = (
|
||||
keyword("struct")("op")
|
||||
+ LT.suppress()
|
||||
+ Group(delimited_list(column_definition))("params")
|
||||
+ GT.suppress()
|
||||
) / to_json_call
|
||||
|
||||
row_type = (
|
||||
keyword("row")("op")
|
||||
+ LB
|
||||
+ Group(delimited_list(column_definition))("params")
|
||||
+ RB
|
||||
) / to_json_call
|
||||
|
||||
array_type = (
|
||||
keyword("array")("op")
|
||||
+ (
|
||||
(
|
||||
LT.suppress()
|
||||
+ Group(delimited_list(column_type))("params")
|
||||
+ GT.suppress()
|
||||
)
|
||||
| (LB + Group(delimited_list(column_type))("params") + RB)
|
||||
)
|
||||
) / to_json_call
|
||||
|
||||
column_type << (struct_type | row_type | array_type | simple_types)
|
||||
|
||||
column_def_identity = (
|
||||
assign(
|
||||
"generated",
|
||||
(keyword("always") | keyword("by default") / (lambda: "by_default")),
|
||||
)
|
||||
+ keyword("as identity").suppress()
|
||||
+ Optional(assign("start with", int_num))
|
||||
+ Optional(assign("increment by", int_num))
|
||||
)
|
||||
|
||||
column_def_references = assign(
|
||||
"references", var_name("table") + LB + delimited_list(var_name)("columns") + RB,
|
||||
)
|
||||
|
||||
column_options = ZeroOrMore(
|
||||
((NOT + NULL) / (lambda: False))("nullable")
|
||||
| (NULL / (lambda t: True))("nullable")
|
||||
| flag("unique")
|
||||
| flag("auto_increment")
|
||||
| assign("comment", literal_string)
|
||||
| assign("collate", Optional(EQ) + var_name)
|
||||
| flag("primary key")
|
||||
| column_def_identity("identity")
|
||||
| column_def_references
|
||||
| assign("check", LB + expr + RB)
|
||||
| assign("default", expr)
|
||||
).set_parser_name("column_options")
|
||||
|
||||
column_definition << Group(
|
||||
var_name("name") + (column_type | var_name)("type") + column_options
|
||||
).set_parser_name("column_definition")
|
||||
|
||||
return column_type, column_definition, column_def_references
|
||||
|
||||
|
||||
export("aquery_parser.utils", unary_ops)
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
|
||||
# KNOWN TYPES
|
||||
from mo_parsing import Forward, Group, Optional, MatchFirst, Literal, ZeroOrMore, export
|
||||
from mo_parsing.infix import delimited_list, RIGHT_ASSOC, LEFT_ASSOC
|
||||
|
||||
from aquery_parser.keywords import (
|
||||
RB,
|
||||
LB,
|
||||
NEG,
|
||||
NOT,
|
||||
BINARY_NOT,
|
||||
NULL,
|
||||
EQ,
|
||||
KNOWN_OPS,
|
||||
LT,
|
||||
GT,
|
||||
)
|
||||
from aquery_parser.utils import (
|
||||
keyword,
|
||||
to_json_call,
|
||||
int_num,
|
||||
ansi_string,
|
||||
ansi_ident,
|
||||
assign,
|
||||
flag,
|
||||
)
|
||||
|
||||
_size = Optional(LB + int_num("params") + RB)
|
||||
_sizes = Optional(LB + delimited_list(int_num("params")) + RB)
|
||||
|
||||
simple_types = Forward()
|
||||
|
||||
BIGINT = Group(keyword("bigint")("op") + Optional(_size)+Optional(flag("unsigned"))) / to_json_call
|
||||
BOOL = Group(keyword("bool")("op")) / to_json_call
|
||||
BOOLEAN = Group(keyword("boolean")("op")) / to_json_call
|
||||
DOUBLE = Group(keyword("double")("op")) / to_json_call
|
||||
FLOAT64 = Group(keyword("float64")("op")) / to_json_call
|
||||
FLOAT = Group(keyword("float")("op")) / to_json_call
|
||||
GEOMETRY = Group(keyword("geometry")("op")) / to_json_call
|
||||
INTEGER = Group(keyword("integer")("op")) / to_json_call
|
||||
INT = (keyword("int")("op") + _size) / to_json_call
|
||||
INT32 = Group(keyword("int32")("op")) / to_json_call
|
||||
INT64 = Group(keyword("int64")("op")) / to_json_call
|
||||
REAL = Group(keyword("real")("op")) / to_json_call
|
||||
TEXT = Group(keyword("text")("op")) / to_json_call
|
||||
SMALLINT = Group(keyword("smallint")("op")) / to_json_call
|
||||
STRING = Group(keyword("string")("op")) / to_json_call
|
||||
|
||||
BLOB = (keyword("blob")("op") + _size) / to_json_call
|
||||
BYTES = (keyword("bytes")("op") + _size) / to_json_call
|
||||
CHAR = (keyword("char")("op") + _size) / to_json_call
|
||||
NCHAR = (keyword("nchar")("op") + _size) / to_json_call
|
||||
VARCHAR = (keyword("varchar")("op") + _size) / to_json_call
|
||||
VARCHAR2 = (keyword("varchar2")("op") + _size) / to_json_call
|
||||
VARBINARY = (keyword("varbinary")("op") + _size) / to_json_call
|
||||
TINYINT = (keyword("tinyint")("op") + _size) / to_json_call
|
||||
UUID = Group(keyword("uuid")("op")) / to_json_call
|
||||
|
||||
DECIMAL = (keyword("decimal")("op") + _sizes) / to_json_call
|
||||
DOUBLE_PRECISION = (
|
||||
Group((keyword("double precision") / (lambda: "double_precision"))("op"))
|
||||
/ to_json_call
|
||||
)
|
||||
NUMERIC = (keyword("numeric")("op") + _sizes) / to_json_call
|
||||
NUMBER = (keyword("number")("op") + _sizes) / to_json_call
|
||||
|
||||
MAP_TYPE = (
|
||||
keyword("map")("op") + LB + delimited_list(simple_types("params")) + RB
|
||||
) / to_json_call
|
||||
ARRAY_TYPE = (keyword("array")("op") + LB + simple_types("params") + RB) / to_json_call
|
||||
|
||||
DATE = keyword("date")
|
||||
DATETIME = keyword("datetime")
|
||||
DATETIME_W_TIMEZONE = keyword("datetime with time zone")
|
||||
TIME = keyword("time")
|
||||
TIMESTAMP = keyword("timestamp")
|
||||
TIMESTAMP_W_TIMEZONE = keyword("timestamp with time zone")
|
||||
TIMESTAMPTZ = keyword("timestamptz")
|
||||
TIMETZ = keyword("timetz")
|
||||
|
||||
time_functions = DATE | DATETIME | TIME | TIMESTAMP | TIMESTAMPTZ | TIMETZ
|
||||
|
||||
# KNOWNN TIME TYPES
|
||||
_format = Optional((ansi_string | ansi_ident)("params"))
|
||||
|
||||
DATE_TYPE = (DATE("op") + _format) / to_json_call
|
||||
DATETIME_TYPE = (DATETIME("op") + _format) / to_json_call
|
||||
DATETIME_W_TIMEZONE_TYPE = (DATETIME_W_TIMEZONE("op") + _format) / to_json_call
|
||||
TIME_TYPE = (TIME("op") + _format) / to_json_call
|
||||
TIMESTAMP_TYPE = (TIMESTAMP("op") + _format) / to_json_call
|
||||
TIMESTAMP_W_TIMEZONE_TYPE = (TIMESTAMP_W_TIMEZONE("op") + _format) / to_json_call
|
||||
TIMESTAMPTZ_TYPE = (TIMESTAMPTZ("op") + _format) / to_json_call
|
||||
TIMETZ_TYPE = (TIMETZ("op") + _format) / to_json_call
|
||||
|
||||
simple_types << MatchFirst([
|
||||
ARRAY_TYPE,
|
||||
BIGINT,
|
||||
BOOL,
|
||||
BOOLEAN,
|
||||
BLOB,
|
||||
BYTES,
|
||||
CHAR,
|
||||
DATE_TYPE,
|
||||
DATETIME_W_TIMEZONE_TYPE,
|
||||
DATETIME_TYPE,
|
||||
DECIMAL,
|
||||
DOUBLE_PRECISION,
|
||||
DOUBLE,
|
||||
FLOAT64,
|
||||
FLOAT,
|
||||
GEOMETRY,
|
||||
MAP_TYPE,
|
||||
INTEGER,
|
||||
INT,
|
||||
INT32,
|
||||
INT64,
|
||||
NCHAR,
|
||||
NUMBER,
|
||||
NUMERIC,
|
||||
REAL,
|
||||
TEXT,
|
||||
SMALLINT,
|
||||
STRING,
|
||||
TIME_TYPE,
|
||||
TIMESTAMP_W_TIMEZONE_TYPE,
|
||||
TIMESTAMP_TYPE,
|
||||
TIMESTAMPTZ_TYPE,
|
||||
TIMETZ_TYPE,
|
||||
TINYINT,
|
||||
UUID,
|
||||
VARCHAR,
|
||||
VARCHAR2,
|
||||
VARBINARY,
|
||||
])
|
||||
|
||||
CASTING = (Literal("::").suppress() + simple_types("params")).set_parser_name("cast")
|
||||
KNOWN_OPS.insert(0, CASTING)
|
||||
|
||||
unary_ops = {
|
||||
NEG: RIGHT_ASSOC,
|
||||
NOT: RIGHT_ASSOC,
|
||||
BINARY_NOT: RIGHT_ASSOC,
|
||||
CASTING: LEFT_ASSOC,
|
||||
}
|
||||
|
||||
|
||||
def get_column_type(expr, var_name, literal_string):
|
||||
column_definition = Forward()
|
||||
column_type = Forward().set_parser_name("column type")
|
||||
|
||||
struct_type = (
|
||||
keyword("struct")("op")
|
||||
+ LT.suppress()
|
||||
+ Group(delimited_list(column_definition))("params")
|
||||
+ GT.suppress()
|
||||
) / to_json_call
|
||||
|
||||
row_type = (
|
||||
keyword("row")("op")
|
||||
+ LB
|
||||
+ Group(delimited_list(column_definition))("params")
|
||||
+ RB
|
||||
) / to_json_call
|
||||
|
||||
array_type = (
|
||||
keyword("array")("op")
|
||||
+ (
|
||||
(
|
||||
LT.suppress()
|
||||
+ Group(delimited_list(column_type))("params")
|
||||
+ GT.suppress()
|
||||
)
|
||||
| (LB + Group(delimited_list(column_type))("params") + RB)
|
||||
)
|
||||
) / to_json_call
|
||||
|
||||
column_type << (struct_type | row_type | array_type | simple_types)
|
||||
|
||||
column_def_identity = (
|
||||
assign(
|
||||
"generated",
|
||||
(keyword("always") | keyword("by default") / (lambda: "by_default")),
|
||||
)
|
||||
+ keyword("as identity").suppress()
|
||||
+ Optional(assign("start with", int_num))
|
||||
+ Optional(assign("increment by", int_num))
|
||||
)
|
||||
|
||||
column_def_references = assign(
|
||||
"references", var_name("table") + LB + delimited_list(var_name)("columns") + RB,
|
||||
)
|
||||
|
||||
column_options = ZeroOrMore(
|
||||
((NOT + NULL) / (lambda: False))("nullable")
|
||||
| (NULL / (lambda t: True))("nullable")
|
||||
| flag("unique")
|
||||
| flag("auto_increment")
|
||||
| assign("comment", literal_string)
|
||||
| assign("collate", Optional(EQ) + var_name)
|
||||
| flag("primary key")
|
||||
| column_def_identity("identity")
|
||||
| column_def_references
|
||||
| assign("check", LB + expr + RB)
|
||||
| assign("default", expr)
|
||||
).set_parser_name("column_options")
|
||||
|
||||
column_definition << Group(
|
||||
var_name("name") + (column_type | var_name)("type") + column_options
|
||||
).set_parser_name("column_definition")
|
||||
|
||||
return column_type, column_definition, column_def_references
|
||||
|
||||
|
||||
export("aquery_parser.utils", unary_ops)
|
||||
|
||||
+618
-618
File diff suppressed because it is too large
Load Diff
+107
-107
@@ -1,107 +1,107 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from mo_parsing.infix import delimited_list
|
||||
|
||||
from aquery_parser.keywords import *
|
||||
from aquery_parser.utils import *
|
||||
|
||||
|
||||
# https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql?view=sql-server-ver15
|
||||
|
||||
|
||||
def _to_bound_call(tokens):
|
||||
zero = tokens["zero"]
|
||||
if zero:
|
||||
return {"min": 0, "max": 0}
|
||||
|
||||
direction = scrub(tokens["direction"])
|
||||
limit = scrub(tokens["limit"])
|
||||
if direction == "preceding":
|
||||
if limit == "unbounded":
|
||||
return {"max": 0}
|
||||
elif is_data(limit):
|
||||
return {"min": {"neg": limit}, "max": 0}
|
||||
else:
|
||||
return {"min": -limit, "max": 0}
|
||||
else: # following
|
||||
if limit == "unbounded":
|
||||
return {"min": 0}
|
||||
elif is_data(limit):
|
||||
return {"min": {"neg": limit}, "max": 0}
|
||||
else:
|
||||
return {"min": 0, "max": limit}
|
||||
|
||||
|
||||
def _to_between_call(tokens):
|
||||
minn = scrub(tokens["min"])
|
||||
maxx = scrub(tokens["max"])
|
||||
|
||||
if maxx.get("max") == 0:
|
||||
# following
|
||||
return {
|
||||
"min": minn.get("min"),
|
||||
"max": maxx.get("min"),
|
||||
}
|
||||
elif minn.get("min") == 0:
|
||||
# preceding
|
||||
return {"min": minn.get("max"), "max": maxx.get("max")}
|
||||
else:
|
||||
return {
|
||||
"min": minn.get("min"),
|
||||
"max": maxx.get("max"),
|
||||
}
|
||||
|
||||
|
||||
UNBOUNDED = keyword("unbounded")
|
||||
PRECEDING = keyword("preceding")
|
||||
FOLLOWING = keyword("following")
|
||||
CURRENT_ROW = keyword("current row")
|
||||
ROWS = keyword("rows")
|
||||
RANGE = keyword("range")
|
||||
|
||||
|
||||
def window(expr, var_name, sort_column):
|
||||
bound_row = (
|
||||
CURRENT_ROW("zero")
|
||||
| (UNBOUNDED | int_num)("limit") + (PRECEDING | FOLLOWING)("direction")
|
||||
) / _to_bound_call
|
||||
bound_expr = (
|
||||
CURRENT_ROW("zero")
|
||||
| (UNBOUNDED | expr)("limit") + (PRECEDING | FOLLOWING)("direction")
|
||||
) / _to_bound_call
|
||||
between_row = (
|
||||
BETWEEN + bound_row("min") + AND + bound_row("max")
|
||||
) / _to_between_call
|
||||
between_expr = (
|
||||
BETWEEN + bound_expr("min") + AND + bound_expr("max")
|
||||
) / _to_between_call
|
||||
|
||||
row_clause = (ROWS.suppress() + (between_row | bound_row)) | (
|
||||
RANGE.suppress() + (between_expr | bound_expr)
|
||||
)
|
||||
|
||||
over_clause = (
|
||||
LB
|
||||
+ Optional(PARTITION_BY + delimited_list(Group(expr))("partitionby"))
|
||||
+ Optional(ORDER_BY + delimited_list(Group(sort_column))("orderby"))
|
||||
+ Optional(row_clause("range"))
|
||||
+ RB
|
||||
)
|
||||
|
||||
window_clause = Optional((
|
||||
WITHIN_GROUP
|
||||
+ LB
|
||||
+ Optional(ORDER_BY + delimited_list(Group(sort_column))("orderby"))
|
||||
+ RB
|
||||
)("within")) + ((OVER + (over_clause | var_name) / to_over)("over"))
|
||||
|
||||
return window_clause, over_clause
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
|
||||
#
|
||||
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from mo_parsing.infix import delimited_list
|
||||
|
||||
from aquery_parser.keywords import *
|
||||
from aquery_parser.utils import *
|
||||
|
||||
|
||||
# https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql?view=sql-server-ver15
|
||||
|
||||
|
||||
def _to_bound_call(tokens):
|
||||
zero = tokens["zero"]
|
||||
if zero:
|
||||
return {"min": 0, "max": 0}
|
||||
|
||||
direction = scrub(tokens["direction"])
|
||||
limit = scrub(tokens["limit"])
|
||||
if direction == "preceding":
|
||||
if limit == "unbounded":
|
||||
return {"max": 0}
|
||||
elif is_data(limit):
|
||||
return {"min": {"neg": limit}, "max": 0}
|
||||
else:
|
||||
return {"min": -limit, "max": 0}
|
||||
else: # following
|
||||
if limit == "unbounded":
|
||||
return {"min": 0}
|
||||
elif is_data(limit):
|
||||
return {"min": {"neg": limit}, "max": 0}
|
||||
else:
|
||||
return {"min": 0, "max": limit}
|
||||
|
||||
|
||||
def _to_between_call(tokens):
|
||||
minn = scrub(tokens["min"])
|
||||
maxx = scrub(tokens["max"])
|
||||
|
||||
if maxx.get("max") == 0:
|
||||
# following
|
||||
return {
|
||||
"min": minn.get("min"),
|
||||
"max": maxx.get("min"),
|
||||
}
|
||||
elif minn.get("min") == 0:
|
||||
# preceding
|
||||
return {"min": minn.get("max"), "max": maxx.get("max")}
|
||||
else:
|
||||
return {
|
||||
"min": minn.get("min"),
|
||||
"max": maxx.get("max"),
|
||||
}
|
||||
|
||||
|
||||
UNBOUNDED = keyword("unbounded")
|
||||
PRECEDING = keyword("preceding")
|
||||
FOLLOWING = keyword("following")
|
||||
CURRENT_ROW = keyword("current row")
|
||||
ROWS = keyword("rows")
|
||||
RANGE = keyword("range")
|
||||
|
||||
|
||||
def window(expr, var_name, sort_column):
|
||||
bound_row = (
|
||||
CURRENT_ROW("zero")
|
||||
| (UNBOUNDED | int_num)("limit") + (PRECEDING | FOLLOWING)("direction")
|
||||
) / _to_bound_call
|
||||
bound_expr = (
|
||||
CURRENT_ROW("zero")
|
||||
| (UNBOUNDED | expr)("limit") + (PRECEDING | FOLLOWING)("direction")
|
||||
) / _to_bound_call
|
||||
between_row = (
|
||||
BETWEEN + bound_row("min") + AND + bound_row("max")
|
||||
) / _to_between_call
|
||||
between_expr = (
|
||||
BETWEEN + bound_expr("min") + AND + bound_expr("max")
|
||||
) / _to_between_call
|
||||
|
||||
row_clause = (ROWS.suppress() + (between_row | bound_row)) | (
|
||||
RANGE.suppress() + (between_expr | bound_expr)
|
||||
)
|
||||
|
||||
over_clause = (
|
||||
LB
|
||||
+ Optional(PARTITION_BY + delimited_list(Group(expr))("partitionby"))
|
||||
+ Optional(ORDER_BY + delimited_list(Group(sort_column))("orderby"))
|
||||
+ Optional(row_clause("range"))
|
||||
+ RB
|
||||
)
|
||||
|
||||
window_clause = Optional((
|
||||
WITHIN_GROUP
|
||||
+ LB
|
||||
+ Optional(ORDER_BY + delimited_list(Group(sort_column))("orderby"))
|
||||
+ RB
|
||||
)("within")) + ((OVER + (over_clause | var_name) / to_over)("over"))
|
||||
|
||||
return window_clause, over_clause
|
||||
|
||||
Reference in New Issue
Block a user