summaryrefslogtreecommitdiffstats
path: root/sqlglot/expressions.py
diff options
context:
space:
mode:
Diffstat (limited to 'sqlglot/expressions.py')
-rw-r--r--sqlglot/expressions.py137
1 files changed, 131 insertions, 6 deletions
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
index f2ffd12..39f4452 100644
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -1,3 +1,4 @@
+import datetime
import numbers
import re
from collections import deque
@@ -508,7 +509,7 @@ class DerivedTable(Expression):
return [select.alias_or_name for select in self.selects]
-class Unionable:
+class Unionable(Expression):
def union(self, expression, distinct=True, dialect=None, **opts):
"""
Builds a UNION expression.
@@ -614,6 +615,10 @@ class Create(Expression):
}
+class Describe(Expression):
+ pass
+
+
class UserDefinedFunction(Expression):
arg_types = {"this": True, "expressions": False}
@@ -741,6 +746,11 @@ class Check(Expression):
pass
+class Directory(Expression):
+ # https://spark.apache.org/docs/3.0.0-preview/sql-ref-syntax-dml-insert-overwrite-directory-hive.html
+ arg_types = {"this": True, "local": False, "row_format": False}
+
+
class ForeignKey(Expression):
arg_types = {
"expressions": True,
@@ -804,6 +814,18 @@ class Introducer(Expression):
arg_types = {"this": True, "expression": True}
+class LoadData(Expression):
+ arg_types = {
+ "this": True,
+ "local": False,
+ "overwrite": False,
+ "inpath": True,
+ "partition": False,
+ "input_format": False,
+ "serde": False,
+ }
+
+
class Partition(Expression):
pass
@@ -1037,6 +1059,18 @@ class Reference(Expression):
arg_types = {"this": True, "expressions": True}
+class RowFormat(Expression):
+ # https://cwiki.apache.org/confluence/display/hive/languagemanual+dml
+ arg_types = {
+ "fields": False,
+ "escaped": False,
+ "collection_items": False,
+ "map_keys": False,
+ "lines": False,
+ "null": False,
+ }
+
+
class Tuple(Expression):
arg_types = {"expressions": False}
@@ -1071,6 +1105,14 @@ class Subqueryable(Unionable):
return []
return with_.expressions
+ @property
+ def selects(self):
+ raise NotImplementedError("Subqueryable objects must implement `selects`")
+
+ @property
+ def named_selects(self):
+ raise NotImplementedError("Subqueryable objects must implement `named_selects`")
+
def with_(
self,
alias,
@@ -1158,7 +1200,7 @@ class Table(Expression):
}
-class Union(Subqueryable, Expression):
+class Union(Subqueryable):
arg_types = {
"with": False,
"this": True,
@@ -1169,7 +1211,11 @@ class Union(Subqueryable, Expression):
@property
def named_selects(self):
- return self.args["this"].unnest().named_selects
+ return self.this.unnest().named_selects
+
+ @property
+ def selects(self):
+ return self.this.unnest().selects
@property
def left(self):
@@ -1222,7 +1268,7 @@ class Schema(Expression):
arg_types = {"this": False, "expressions": True}
-class Select(Subqueryable, Expression):
+class Select(Subqueryable):
arg_types = {
"with": False,
"expressions": False,
@@ -2075,7 +2121,7 @@ class Bracket(Condition):
class Distinct(Expression):
- arg_types = {"this": False, "on": False}
+ arg_types = {"expressions": False, "on": False}
class In(Predicate):
@@ -2233,6 +2279,14 @@ class Case(Func):
class Cast(Func):
arg_types = {"this": True, "to": True}
+ @property
+ def name(self):
+ return self.this.name
+
+ @property
+ def to(self):
+ return self.args["to"]
+
class TryCast(Cast):
pass
@@ -2666,7 +2720,7 @@ def _norm_args(expression):
else:
arg = _norm_arg(arg)
- if arg is not None:
+ if arg is not None and arg is not False:
args[k] = arg
return args
@@ -3012,6 +3066,30 @@ def update(table, properties, where=None, from_=None, dialect=None, **opts):
return update
+def delete(table, where=None, dialect=None, **opts):
+ """
+ Builds a delete statement.
+
+ Example:
+ >>> delete("my_table", where="id > 1").sql()
+ 'DELETE FROM my_table WHERE id > 1'
+
+ Args:
+ where (str|Condition): sql conditional parsed into a WHERE statement
+ dialect (str): the dialect used to parse the input expressions.
+ **opts: other options to use to parse the input expressions.
+
+ Returns:
+ Delete: the syntax tree for the DELETE statement.
+ """
+ return Delete(
+ this=maybe_parse(table, into=Table, dialect=dialect, **opts),
+ where=Where(this=where)
+ if isinstance(where, Condition)
+ else maybe_parse(where, into=Where, dialect=dialect, prefix="WHERE", **opts),
+ )
+
+
def condition(expression, dialect=None, **opts):
"""
Initialize a logical condition expression.
@@ -3131,6 +3209,25 @@ def to_identifier(alias, quoted=None):
return identifier
+def to_table(sql_path, **kwargs):
+ """
+ Create a table expression from a `[catalog].[schema].[table]` sql path. Catalog and schema are optional.
+ Example:
+ >>> to_table('catalog.db.table_name').sql()
+ 'catalog.db.table_name'
+
+ Args:
+ sql_path(str): `[catalog].[schema].[table]` string
+ Returns:
+ Table: A table expression
+ """
+ table_parts = sql_path.split(".")
+ catalog, db, table_name = [
+ to_identifier(x) if x is not None else x for x in [None] * (3 - len(table_parts)) + table_parts
+ ]
+ return Table(this=table_name, db=db, catalog=catalog, **kwargs)
+
+
def alias_(expression, alias, table=False, dialect=None, quoted=None, **opts):
"""
Create an Alias expression.
@@ -3216,6 +3313,28 @@ def table_(table, db=None, catalog=None, quoted=None):
)
+def values(values, alias=None):
+ """Build VALUES statement.
+
+ Example:
+ >>> values([(1, '2')]).sql()
+ "VALUES (1, '2')"
+
+ Args:
+ values (list[tuple[str | Expression]]): values statements that will be converted to SQL
+ alias (str): optional alias
+ dialect (str): the dialect used to parse the input expression.
+ **opts: other options to use to parse the input expressions.
+
+ Returns:
+ Values: the Values expression object
+ """
+ return Values(
+ expressions=[convert(tup) for tup in values],
+ alias=to_identifier(alias) if alias else None,
+ )
+
+
def convert(value):
"""Convert a python value into an expression object.
@@ -3246,6 +3365,12 @@ def convert(value):
keys=[convert(k) for k in value.keys()],
values=[convert(v) for v in value.values()],
)
+ if isinstance(value, datetime.datetime):
+ datetime_literal = Literal.string(value.strftime("%Y-%m-%d %H:%M:%S"))
+ return TimeStrToTime(this=datetime_literal)
+ if isinstance(value, datetime.date):
+ date_literal = Literal.string(value.strftime("%Y-%m-%d"))
+ return DateStrToDate(this=date_literal)
raise ValueError(f"Cannot convert {value}")