summaryrefslogtreecommitdiffstats
path: root/sqlglot/expressions.py
diff options
context:
space:
mode:
Diffstat (limited to 'sqlglot/expressions.py')
-rw-r--r--sqlglot/expressions.py107
1 files changed, 76 insertions, 31 deletions
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
index 6bb083a..6800cd5 100644
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -6,6 +6,7 @@ Every AST node in SQLGlot is represented by a subclass of `Expression`.
This module contains the implementation of all supported `Expression` types. Additionally,
it exposes a number of helper functions, which are mainly used to programmatically build
SQL expressions, such as `sqlglot.expressions.select`.
+
----
"""
@@ -137,6 +138,8 @@ class Expression(metaclass=_Expression):
return field
if isinstance(field, (Identifier, Literal, Var)):
return field.this
+ if isinstance(field, (Star, Null)):
+ return field.name
return ""
@property
@@ -176,13 +179,11 @@ class Expression(metaclass=_Expression):
return self.text("alias")
@property
- def name(self):
+ def name(self) -> str:
return self.text("this")
@property
def alias_or_name(self):
- if isinstance(self, Null):
- return "NULL"
return self.alias or self.name
@property
@@ -589,12 +590,11 @@ class Expression(metaclass=_Expression):
return load(obj)
-if t.TYPE_CHECKING:
- IntoType = t.Union[
- str,
- t.Type[Expression],
- t.Collection[t.Union[str, t.Type[Expression]]],
- ]
+IntoType = t.Union[
+ str,
+ t.Type[Expression],
+ t.Collection[t.Union[str, t.Type[Expression]]],
+]
class Condition(Expression):
@@ -939,7 +939,7 @@ class EncodeColumnConstraint(ColumnConstraintKind):
class GeneratedAsIdentityColumnConstraint(ColumnConstraintKind):
# this: True -> ALWAYS, this: False -> BY DEFAULT
- arg_types = {"this": True, "start": False, "increment": False}
+ arg_types = {"this": False, "start": False, "increment": False}
class NotNullColumnConstraint(ColumnConstraintKind):
@@ -2390,7 +2390,7 @@ class Star(Expression):
arg_types = {"except": False, "replace": False}
@property
- def name(self):
+ def name(self) -> str:
return "*"
@property
@@ -2413,6 +2413,10 @@ class Placeholder(Expression):
class Null(Condition):
arg_types: t.Dict[str, t.Any] = {}
+ @property
+ def name(self) -> str:
+ return "NULL"
+
class Boolean(Condition):
pass
@@ -2644,7 +2648,9 @@ class Div(Binary):
class Dot(Binary):
- pass
+ @property
+ def name(self) -> str:
+ return self.expression.name
class DPipe(Binary):
@@ -2961,7 +2967,7 @@ class Cast(Func):
arg_types = {"this": True, "to": True}
@property
- def name(self):
+ def name(self) -> str:
return self.this.name
@property
@@ -4027,17 +4033,39 @@ def paren(expression) -> Paren:
SAFE_IDENTIFIER_RE = re.compile(r"^[_a-zA-Z][\w]*$")
-def to_identifier(alias, quoted=None) -> t.Optional[Identifier]:
- if alias is None:
+@t.overload
+def to_identifier(name: None, quoted: t.Optional[bool] = None) -> None:
+ ...
+
+
+@t.overload
+def to_identifier(name: str | Identifier, quoted: t.Optional[bool] = None) -> Identifier:
+ ...
+
+
+def to_identifier(name, quoted=None):
+ """Builds an identifier.
+
+ Args:
+ name: The name to turn into an identifier.
+ quoted: Whether or not force quote the identifier.
+
+ Returns:
+ The identifier ast node.
+ """
+
+ if name is None:
return None
- if isinstance(alias, Identifier):
- identifier = alias
- elif isinstance(alias, str):
- if quoted is None:
- quoted = not re.match(SAFE_IDENTIFIER_RE, alias)
- identifier = Identifier(this=alias, quoted=quoted)
+
+ if isinstance(name, Identifier):
+ identifier = name
+ elif isinstance(name, str):
+ identifier = Identifier(
+ this=name,
+ quoted=not re.match(SAFE_IDENTIFIER_RE, name) if quoted is None else quoted,
+ )
else:
- raise ValueError(f"Alias needs to be a string or an Identifier, got: {alias.__class__}")
+ raise ValueError(f"Name needs to be a string or an Identifier, got: {name.__class__}")
return identifier
@@ -4112,20 +4140,31 @@ def to_column(sql_path: str | Column, **kwargs) -> Column:
return Column(this=column_name, table=table_name, **kwargs)
-def alias_(expression, alias, table=False, dialect=None, quoted=None, **opts):
- """
- Create an Alias expression.
+def alias_(
+ expression: str | Expression,
+ alias: str | Identifier,
+ table: bool | t.Sequence[str | Identifier] = False,
+ quoted: t.Optional[bool] = None,
+ dialect: DialectType = None,
+ **opts,
+):
+ """Create an Alias expression.
+
Example:
>>> alias_('foo', 'bar').sql()
'foo AS bar'
+ >>> alias_('(select 1, 2)', 'bar', table=['a', 'b']).sql()
+ '(SELECT 1, 2) AS bar(a, b)'
+
Args:
- expression (str | Expression): the SQL code strings to parse.
+ expression: the SQL code strings to parse.
If an Expression instance is passed, this is used as-is.
- alias (str | Identifier): the alias name to use. If the name has
+ alias: the alias name to use. If the name has
special characters it is quoted.
- table (bool): create a table alias, default false
- dialect (str): the dialect used to parse the input expression.
+ table: Whether or not to create a table alias, can also be a list of columns.
+ quoted: whether or not to quote the alias
+ dialect: the dialect used to parse the input expression.
**opts: other options to use to parse the input expressions.
Returns:
@@ -4135,8 +4174,14 @@ def alias_(expression, alias, table=False, dialect=None, quoted=None, **opts):
alias = to_identifier(alias, quoted=quoted)
if table:
- expression.set("alias", TableAlias(this=alias))
- return expression
+ table_alias = TableAlias(this=alias)
+ exp.set("alias", table_alias)
+
+ if not isinstance(table, bool):
+ for column in table:
+ table_alias.append("columns", to_identifier(column, quoted=quoted))
+
+ return exp
# We don't set the "alias" arg for Window expressions, because that would add an IDENTIFIER node in
# the AST, representing a "named_window" [1] construct (eg. bigquery). What we want is an ALIAS node