// Expression builders used by the generator (ports of helpers from
// sqlglot/expressions/core.py, builders.py and query.py).
///|
/// Python `to_identifier(name, quoted, copy)` for an identifier or a string value.
pub fn to_identifier_value(
name : Value,
quoted? : Bool,
copy? : Bool = true,
) -> Expr raise SqlglotError {
match name {
Node(e) if e.kind == Identifier => maybe_copy(e, copy)
Str(s) => to_identifier(s, quoted?)
Node(e) =>
raise ValueError(
"Name needs to be a string or an Identifier, got: ",
)
_ => raise ValueError("Name needs to be a string or an Identifier")
}
}
///|
/// Python `_wrap(expression, kind)`: wraps in a `Paren` if it is a `kind`.
pub fn exp_wrap(expression : Expr, kind : Kind) -> Expr {
if expression.kind.is_a(kind) {
mk1(Paren, expression)
} else {
expression
}
}
///|
/// Python `Expr._binop(klass, other)`.
pub fn exp_binop(kind : Kind, this : Expr, other : Expr) -> Expr {
let mut this = this.copy()
let mut other = other.copy()
if !this.kind.is_a(kind) && !other.kind.is_a(kind) {
this = exp_wrap(this, Binary)
other = exp_wrap(other, Binary)
}
mk2(kind, this, other)
}
///|
/// Python `this.is_(other)`.
pub fn exp_is(this : Expr, other : Expr) -> Expr {
exp_binop(Is, this, other)
}
///|
/// Python `this.eq(other)`.
pub fn exp_eq(this : Expr, other : Expr) -> Expr {
exp_binop(EQ, this, other)
}
///|
/// Python `this.neq(other)`.
pub fn exp_neq(this : Expr, other : Expr) -> Expr {
exp_binop(NEQ, this, other)
}
///|
/// Python `this / other`.
pub fn exp_div(this : Expr, other : Expr) -> Expr {
exp_binop(Div, this, other)
}
///|
/// Python `this + other`.
pub fn exp_add(this : Expr, other : Expr) -> Expr {
exp_binop(Add, this, other)
}
///|
/// Python `paren(expression, copy)`.
pub fn exp_paren(expression : Expr, copy? : Bool = true) -> Expr {
mk1(Paren, maybe_copy(expression, copy))
}
///|
/// Python `not_(expression, copy)`.
pub fn exp_not(expression : Expr, copy? : Bool = true) -> Expr {
mk1(Not, exp_wrap(maybe_copy(expression, copy), Connector))
}
///|
/// Python `_combine(expressions, operator, copy, wrap)`.
fn exp_combine(
expressions : Array[Expr],
operator : Kind,
copy : Bool,
wrap : Bool,
) -> Expr {
let conditions = expressions.map(e => maybe_copy(e, copy))
let mut this = conditions[0]
if conditions.length() > 1 && wrap {
this = exp_wrap(this, Connector)
}
for i in 1.. Expr {
exp_combine(expressions, And, copy, wrap)
}
///|
/// Python `or_(*expressions)`.
pub fn exp_or(
expressions : Array[Expr],
copy? : Bool = true,
wrap? : Bool = true,
) -> Expr {
exp_combine(expressions, Or, copy, wrap)
}
///|
/// Python `alias_(expression, alias)` with `table=False`.
pub fn exp_alias(
expression : Expr,
alias_ : Value,
quoted? : Bool,
copy? : Bool = true,
) -> Expr raise SqlglotError {
let e = maybe_copy(expression, copy)
let alias_ = to_identifier_value(alias_, quoted?)
if e.kind.has_arg("alias") && e.kind != Window {
e.set("alias", alias_)
return e
}
mk(Alias, [("this", e), ("alias", alias_)])
}
///|
/// Python `exp.cast(expression, to, copy, dialect)` with a DataType expression.
pub fn exp_cast_to(
expression : Expr,
to : Expr,
copy? : Bool = true,
dialect? : Dialect,
) -> Expr {
let expr = maybe_copy(expression, copy)
let data_type = maybe_copy(to, copy)
if expr.kind.is_a(Cast) {
let target_dialect = match dialect {
Some(d) => d
None => base_dialect()
}
let type_mapping = target_dialect.gen_cfg.type_mapping
let existing = match expr.arg("to") {
Some(t) => t.datatype_this()
None => None
}
let new_type = data_type.datatype_this()
let types_are_equivalent = match (existing, new_type) {
(Some(a), Some(b)) => {
let ma = match type_mapping.get(a) {
Some(v) => v
None => a.value()
}
let mb = match type_mapping.get(b) {
Some(v) => v
None => b.value()
}
ma == mb
}
_ => false
}
if expr.is_type_expr(data_type) || types_are_equivalent {
return expr
}
}
let cast = mk(Cast, [("this", expr), ("to", data_type)])
cast.set_type(Some(data_type))
cast
}
///|
/// Python `exp.cast(expression, dtype, copy, dialect)` with a `DType`.
pub fn exp_cast(
expression : Expr,
to : DType,
copy? : Bool = true,
dialect? : Dialect,
) -> Expr {
exp_cast_to(expression, datatype_of(to), copy~, dialect?)
}
///|
/// Python `Query.subquery(alias, copy)`.
pub fn exp_subquery_of(
query : Expr,
alias_? : String,
copy? : Bool = true,
) -> Expr {
let instance = maybe_copy(query, copy)
match alias_ {
Some(a) if a != "" =>
mk(Subquery, [
("this", instance),
("alias", mk1(TableAlias, to_identifier(a))),
])
_ => mk1(Subquery, instance)
}
}
///|
/// Python `Query.subquery(alias_expr, copy)` where alias is already an expression.
pub fn exp_subquery_with_alias_expr(
query : Expr,
alias_ : Expr?,
copy? : Bool = true,
) -> Expr {
let instance = maybe_copy(query, copy)
mk(Subquery, [("this", instance), ("alias", alias_)])
}
///|
/// Python `exp.select(*projections).from_(from_expr, copy=False)`.
pub fn exp_select_from(projections : Array[Expr], from_expr : Expr) -> Expr {
let from_node = if from_expr.kind == From {
from_expr
} else {
mk1(From, from_expr)
}
mk(Select, [("expressions", projections), ("from_", from_node)])
}
///|
/// Python `exp.union(left, right, distinct=distinct, copy=False)`.
pub fn exp_union(left : Expr, right : Expr, distinct? : Bool = true) -> Expr {
mk(Union, [("this", left), ("expression", right), ("distinct", distinct)])
}
///|
/// Python `exp.case()`.
pub fn exp_case() -> Expr {
mk(Case, [("ifs", ([] : Array[Expr]))])
}
///|
/// Python `Case.when(condition, then, copy)`.
pub fn case_when(
case_ : Expr,
condition : Expr,
then : Expr,
copy? : Bool = true,
) -> Expr {
let instance = maybe_copy(case_, copy)
instance.append(
"ifs",
mk(If, [
("this", maybe_copy(condition, copy)),
("true", maybe_copy(then, copy)),
]),
)
instance
}
///|
/// Python `Case.else_(value, copy)`.
pub fn case_else(case_ : Expr, value : Expr, copy? : Bool = true) -> Expr {
let instance = maybe_copy(case_, copy)
instance.set("default", maybe_copy(value, copy))
instance
}
///|
/// Python `maybe_parse(sql, dialect=dialect)` for a SQL string.
pub fn maybe_parse_str(
sql : String,
dialect? : Dialect,
) -> Expr raise SqlglotError {
parse_one(sql, dialect?)
}
///|
/// Python `exp.table_(name)` for an identifier expression.
pub fn exp_table_from_identifier(table : Expr?) -> Expr raise SqlglotError {
match table {
Some(t) => mk1(Table, to_identifier_value(Node(t)))
None => mk0(Table)
}
}