diff --git a/partiql-ast/api/partiql-ast.api b/partiql-ast/api/partiql-ast.api index 070e1e998..1193bc812 100644 --- a/partiql-ast/api/partiql-ast.api +++ b/partiql-ast/api/partiql-ast.api @@ -20,7 +20,7 @@ public final class org/partiql/ast/Ast { public static final fun exprInCollection (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Z)Lorg/partiql/ast/expr/ExprInCollection; public static final fun exprIsType (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/DataType;Z)Lorg/partiql/ast/expr/ExprIsType; public static final fun exprLike (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Z)Lorg/partiql/ast/expr/ExprLike; - public static final fun exprLit (Lorg/partiql/value/PartiQLValue;)Lorg/partiql/ast/expr/ExprLit; + public static final fun exprLit (Lorg/partiql/ast/literal/Literal;)Lorg/partiql/ast/expr/ExprLit; public static final fun exprMatch (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/graph/GraphMatch;)Lorg/partiql/ast/expr/ExprMatch; public static final fun exprNot (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprNot; public static final fun exprNullIf (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprNullIf; @@ -72,6 +72,15 @@ public final class org/partiql/ast/Ast { public static final fun identifierChain (Lorg/partiql/ast/Identifier;Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/IdentifierChain; public static final fun let (Ljava/util/List;)Lorg/partiql/ast/Let; public static final fun letBinding (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/Let$Binding; + public static final fun literalBool (Z)Lorg/partiql/ast/literal/LiteralBool; + public static final fun literalDecimal (Ljava/math/BigDecimal;)Lorg/partiql/ast/literal/LiteralDecimal; + public static final fun literalFloat (Ljava/lang/String;)Lorg/partiql/ast/literal/LiteralDouble; + public static final fun literalInt (I)Lorg/partiql/ast/literal/LiteralInt; + public static final fun literalLong (J)Lorg/partiql/ast/literal/LiteralLong; + public static final fun literalMissing ()Lorg/partiql/ast/literal/LiteralMissing; + public static final fun literalNull ()Lorg/partiql/ast/literal/LiteralNull; + public static final fun literalString (Ljava/lang/String;)Lorg/partiql/ast/literal/LiteralString; + public static final fun literalTypedString (Lorg/partiql/ast/DataType;Ljava/lang/String;)Lorg/partiql/ast/literal/LiteralTypedString; public static final fun orderBy (Ljava/util/List;)Lorg/partiql/ast/OrderBy; public static final fun query (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/Query; public static final fun queryBodySFW (Lorg/partiql/ast/Select;Lorg/partiql/ast/Exclude;Lorg/partiql/ast/From;Lorg/partiql/ast/Let;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/GroupBy;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/QueryBody$SFW; @@ -1477,22 +1486,15 @@ public class org/partiql/ast/expr/ExprLike$Builder { } public class org/partiql/ast/expr/ExprLit : org/partiql/ast/expr/Expr { - public final field value Lorg/partiql/value/PartiQLValue; - public fun (Lorg/partiql/value/PartiQLValue;)V + public field lit Lorg/partiql/ast/literal/Literal; + public fun (Lorg/partiql/ast/literal/Literal;)V public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; - public static fun builder ()Lorg/partiql/ast/expr/ExprLit$Builder; protected fun canEqual (Ljava/lang/Object;)Z public fun children ()Ljava/util/Collection; public fun equals (Ljava/lang/Object;)Z public fun hashCode ()I } -public class org/partiql/ast/expr/ExprLit$Builder { - public fun build ()Lorg/partiql/ast/expr/ExprLit; - public fun toString ()Ljava/lang/String; - public fun value (Lorg/partiql/value/PartiQLValue;)Lorg/partiql/ast/expr/ExprLit$Builder; -} - public class org/partiql/ast/expr/ExprMatch : org/partiql/ast/expr/Expr { public final field expr Lorg/partiql/ast/expr/Expr; public final field pattern Lorg/partiql/ast/graph/GraphMatch; @@ -2389,6 +2391,82 @@ public class org/partiql/ast/graph/GraphSelector$ShortestKGroup$Builder { public fun toString ()Ljava/lang/String; } +public abstract class org/partiql/ast/literal/Literal { + public final field text Ljava/lang/String; + protected fun (Ljava/lang/String;)V +} + +public class org/partiql/ast/literal/LiteralBool : org/partiql/ast/literal/Literal { + public field value Z + public fun (Z)V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralDecimal : org/partiql/ast/literal/Literal { + public field value Ljava/math/BigDecimal; + public fun (Ljava/math/BigDecimal;)V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralDouble : org/partiql/ast/literal/Literal { + public field value D + public fun (Ljava/lang/String;)V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralInt : org/partiql/ast/literal/Literal { + public field value I + public fun (I)V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralLong : org/partiql/ast/literal/Literal { + public field value J + public fun (J)V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralMissing : org/partiql/ast/literal/Literal { + public fun ()V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralNull : org/partiql/ast/literal/Literal { + public fun ()V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralString : org/partiql/ast/literal/Literal { + public field value Ljava/lang/String; + public fun (Ljava/lang/String;)V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/literal/LiteralTypedString : org/partiql/ast/literal/Literal { + public field type Lorg/partiql/ast/DataType; + public field value Ljava/lang/String; + public fun (Lorg/partiql/ast/DataType;Ljava/lang/String;)V + protected fun canEqual (Ljava/lang/Object;)Z + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + public abstract class org/partiql/ast/sql/SqlBlock { public static final field Companion Lorg/partiql/ast/sql/SqlBlock$Companion; public field next Lorg/partiql/ast/sql/SqlBlock; diff --git a/partiql-ast/build.gradle.kts b/partiql-ast/build.gradle.kts index 7d99c0b8c..f930fe36e 100644 --- a/partiql-ast/build.gradle.kts +++ b/partiql-ast/build.gradle.kts @@ -20,10 +20,6 @@ plugins { dependencies { api(Deps.ionElement) - api(project(":partiql-types")) - // TODO REMOVE ME ONCE PartiQLValue IS REMOVED - // THE AST NEEDS ITS OWN "VALUE" REPRESENTATION - api(project(":partiql-spi")) compileOnly(Deps.lombok) annotationProcessor(Deps.lombok) } diff --git a/partiql-ast/src/main/java/org/partiql/ast/Explain.java b/partiql-ast/src/main/java/org/partiql/ast/Explain.java index 888208624..e660fedf4 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/Explain.java +++ b/partiql-ast/src/main/java/org/partiql/ast/Explain.java @@ -3,7 +3,7 @@ import lombok.Builder; import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; -import org.partiql.value.PartiQLValue; +import org.partiql.ast.literal.Literal; import java.util.ArrayList; import java.util.Collection; @@ -16,14 +16,13 @@ @Builder(builderClassName = "Builder") @EqualsAndHashCode(callSuper = false) public class Explain extends Statement { - // TODO get rid of PartiQLValue once https://github.com/partiql/partiql-lang-kotlin/issues/1589 is resolved @NotNull - public final Map options; + public final Map options; @NotNull public final Statement statement; - public Explain(@NotNull Map options, @NotNull Statement statement) { + public Explain(@NotNull Map options, @NotNull Statement statement) { this.options = options; this.statement = statement; } diff --git a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java index fbb790854..a20e5f148 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java +++ b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java @@ -1,11 +1,10 @@ package org.partiql.ast.expr; -import lombok.Builder; import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; import org.partiql.ast.AstNode; import org.partiql.ast.AstVisitor; -import org.partiql.value.PartiQLValue; +import org.partiql.ast.literal.Literal; import java.util.Collection; import java.util.Collections; @@ -13,18 +12,17 @@ /** * TODO docs, equals, hashcode */ -@Builder(builderClassName = "Builder") @EqualsAndHashCode(callSuper = false) public class ExprLit extends Expr { @NotNull - public final PartiQLValue value; // This representation be changed in https://github.com/partiql/partiql-lang-kotlin/issues/1589 + public Literal lit; - public ExprLit(@NotNull PartiQLValue value) { - this.value = value; + public ExprLit(@NotNull Literal lit) { + this.lit = lit; } - @Override @NotNull + @Override public Collection children() { return Collections.emptyList(); } diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/Literal.java b/partiql-ast/src/main/java/org/partiql/ast/literal/Literal.java new file mode 100644 index 000000000..e249d96d2 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/Literal.java @@ -0,0 +1,15 @@ +package org.partiql.ast.literal; + +import org.jetbrains.annotations.NotNull; + +/** + * TODO docs + */ +public abstract class Literal { + @NotNull + public final String text; + + protected Literal(@NotNull String _text) { + this.text = _text; + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralBool.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralBool.java new file mode 100644 index 000000000..af752f989 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralBool.java @@ -0,0 +1,16 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralBool extends Literal { + public boolean value; + + public LiteralBool(boolean value) { + super(String.valueOf(value)); + this.value = value; + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralDecimal.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralDecimal.java new file mode 100644 index 000000000..c43e6520a --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralDecimal.java @@ -0,0 +1,20 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; + +import java.math.BigDecimal; + +/** + * TODO DOCS + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralDecimal extends Literal { + @NotNull + public BigDecimal value; + + public LiteralDecimal(@NotNull BigDecimal value) { + super(value.toString()); + this.value = value; + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralDouble.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralDouble.java new file mode 100644 index 000000000..e988c0a88 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralDouble.java @@ -0,0 +1,17 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralDouble extends Literal { + public double value; + + public LiteralDouble(@NotNull String text) { + super(text); + this.value = Double.parseDouble(text); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralInt.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralInt.java new file mode 100644 index 000000000..0724dc4cd --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralInt.java @@ -0,0 +1,16 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralInt extends Literal { + public int value; + + public LiteralInt(int value) { + super(String.format("%d", value)); + this.value = value; + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralLong.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralLong.java new file mode 100644 index 000000000..d0d5a4f26 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralLong.java @@ -0,0 +1,16 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralLong extends Literal { + public long value; + + public LiteralLong(long value) { + super(String.format("%d", value)); + this.value = value; + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralMissing.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralMissing.java new file mode 100644 index 000000000..72579ec00 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralMissing.java @@ -0,0 +1,13 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralMissing extends Literal { + public LiteralMissing() { + super("MISSING"); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralNull.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralNull.java new file mode 100644 index 000000000..9d7a369de --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralNull.java @@ -0,0 +1,13 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralNull extends Literal { + public LiteralNull() { + super("NULL"); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralString.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralString.java new file mode 100644 index 000000000..ec8d38788 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralString.java @@ -0,0 +1,18 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralString extends Literal { + @NotNull + public String value; + + public LiteralString(@NotNull String value) { + super(String.format("'%s'", value)); + this.value = value; + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralTypedString.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralTypedString.java new file mode 100644 index 000000000..e608c89a0 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralTypedString.java @@ -0,0 +1,24 @@ +package org.partiql.ast.literal; + +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.partiql.ast.DataType; + +/** + * TODO docs + * Represent type + 'some string value' + */ +@EqualsAndHashCode(callSuper = false) +public class LiteralTypedString extends Literal { + @NotNull + public DataType type; + + @NotNull + public String value; + + public LiteralTypedString(@NotNull DataType type, @NotNull String value) { + super(String.format("%s '%s'", type.name(), value)); + this.type = type; + this.value = value; + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt b/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt index f1fa4945e..21035f91d 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt +++ b/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt @@ -14,7 +14,9 @@ package org.partiql.ast.sql -import org.partiql.ast.Ast.exprLit +import org.partiql.ast.Ast.exprVarRef +import org.partiql.ast.Ast.identifier +import org.partiql.ast.Ast.identifierChain import org.partiql.ast.AstNode import org.partiql.ast.AstVisitor import org.partiql.ast.DataType @@ -78,14 +80,7 @@ import org.partiql.ast.expr.ExprVarRef import org.partiql.ast.expr.ExprVariant import org.partiql.ast.expr.PathStep import org.partiql.ast.expr.Scope -import org.partiql.value.MissingValue -import org.partiql.value.NullValue -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.StringValue -import org.partiql.value.io.PartiQLValueTextWriter -import org.partiql.value.symbolValue -import java.io.ByteArrayOutputStream -import java.io.PrintStream +import org.partiql.ast.literal.LiteralString /** * SqlDialect represents the base behavior for transforming an [AstNode] tree into a [SqlBlock] tree. @@ -211,9 +206,9 @@ public abstract class SqlDialect : AstVisitor() { // no params DataType.DATE -> tail concat node.name() // with params - DataType.TIME, DataType.TIMESTAMP -> tail concat type(node.name(), node.precision) - DataType.TIME_WITH_TIME_ZONE -> tail concat type("TIME WITH TIMEZONE", node.precision, gap = true) - DataType.TIMESTAMP_WITH_TIME_ZONE -> tail concat type("TIMESTAMP WITH TIMEZONE", node.precision, gap = true) + DataType.TIME, DataType.TIMESTAMP -> tail concat type(node.name(), node.precision, gap = true) + DataType.TIME_WITH_TIME_ZONE -> tail concat type("TIME", node.precision, gap = true) concat(" WITH TIME ZONE") + DataType.TIMESTAMP_WITH_TIME_ZONE -> tail concat type("TIMESTAMP", node.precision, gap = true) concat(" WITH TIME ZONE") // DataType.INTERVAL -> tail concat type("INTERVAL", node.precision) // @@ -228,20 +223,8 @@ public abstract class SqlDialect : AstVisitor() { // Expressions - @OptIn(PartiQLValueExperimental::class) override fun visitExprLit(node: ExprLit, tail: SqlBlock): SqlBlock { - // Simplified PartiQL Value writing, as this intentionally omits formatting - val value = when (node.value) { - is MissingValue -> "MISSING" // force uppercase - is NullValue -> "NULL" // force uppercase - else -> { - val buffer = ByteArrayOutputStream() - val valueWriter = PartiQLValueTextWriter(PrintStream(buffer), false) - valueWriter.append(node.value) - buffer.toString() - } - } - return tail concat value + return tail concat node.lit.text } override fun visitExprVariant(node: ExprVariant, tail: SqlBlock): SqlBlock { @@ -333,7 +316,6 @@ public abstract class SqlDialect : AstVisitor() { override fun visitPathStepAllFields(node: PathStep.AllFields, tail: SqlBlock): SqlBlock = tail concat ".*" - @OptIn(PartiQLValueExperimental::class) override fun visitExprCall(node: ExprCall, tail: SqlBlock): SqlBlock { var t = tail val f = node.function @@ -343,13 +325,14 @@ public abstract class SqlDialect : AstVisitor() { } // Special case -- DATE_ADD('', , ) -> DATE_ADD(, , ) // Special case -- DATE_DIFF('', , ) -> DATE_DIFF(, , ) - // TODO this will need to be rewritten once PartiQLValue is removed from AST if (f.next == null && (f.root.symbol.uppercase() == "DATE_ADD" || f.root.symbol.uppercase() == "DATE_DIFF") && node.args.size == 3 ) { - val dtField = ((node.args[0] as ExprLit).value as StringValue).value!! - val newArgs = listOf(exprLit(symbolValue(dtField))) + node.args.drop(1) + val dtField = ((node.args[0] as ExprLit).lit as LiteralString).value + // Represent as an `ExprVarRef` to mimic a literal symbol. + // TODO consider some other representation for unquoted strings + val newArgs = listOf(exprVarRef(identifierChain(identifier(dtField, isDelimited = false), next = null), scope = Scope.DEFAULT())) + node.args.drop(1) t = visitIdentifierChain(f, t) t = t concat list { newArgs } return t diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt index d6b23c4a5..b574cb08b 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt @@ -47,8 +47,17 @@ import org.partiql.ast.graph.GraphPattern import org.partiql.ast.graph.GraphQuantifier import org.partiql.ast.graph.GraphRestrictor import org.partiql.ast.graph.GraphSelector -import org.partiql.value.PartiQLValue -import org.partiql.value.PartiQLValueExperimental +import org.partiql.ast.literal.Literal +import org.partiql.ast.literal.LiteralBool +import org.partiql.ast.literal.LiteralDecimal +import org.partiql.ast.literal.LiteralDouble +import org.partiql.ast.literal.LiteralInt +import org.partiql.ast.literal.LiteralLong +import org.partiql.ast.literal.LiteralMissing +import org.partiql.ast.literal.LiteralNull +import org.partiql.ast.literal.LiteralString +import org.partiql.ast.literal.LiteralTypedString +import java.math.BigDecimal // TODO docs for all factory methods // Also consider defaults for nullable. Need to look more into backwards compatibility. @@ -120,10 +129,8 @@ public object Ast { return ExprLike(value, pattern, escape, not) } - // This representation will be changed in https://github.com/partiql/partiql-lang-kotlin/issues/1589 - @OptIn(PartiQLValueExperimental::class) @JvmStatic - public fun exprLit(value: PartiQLValue): ExprLit { + public fun exprLit(value: Literal): ExprLit { return ExprLit(value) } @@ -356,6 +363,52 @@ public object Ast { return GraphSelector.ShortestKGroup(k) } + // Literal + @JvmStatic + public fun literalBool(value: Boolean): LiteralBool { + return LiteralBool(value) + } + + @JvmStatic + public fun literalDecimal(value: BigDecimal): LiteralDecimal { + return LiteralDecimal(value) + } + + @JvmStatic + public fun literalFloat(text: String): LiteralDouble { + return LiteralDouble(text) + } + + @JvmStatic + public fun literalInt(value: Int): LiteralInt { + return LiteralInt(value) + } + + @JvmStatic + public fun literalLong(value: Long): LiteralLong { + return LiteralLong(value) + } + + @JvmStatic + public fun literalNull(): LiteralNull { + return LiteralNull() + } + + @JvmStatic + public fun literalMissing(): LiteralMissing { + return LiteralMissing() + } + + @JvmStatic + public fun literalString(value: String): LiteralString { + return LiteralString(value) + } + + @JvmStatic + public fun literalTypedString(type: DataType, value: String): LiteralTypedString { + return LiteralTypedString(type, value) + } + // Other @JvmStatic public fun exclude(excludePaths: List): Exclude { @@ -387,10 +440,8 @@ public object Ast { return ExcludeStep.CollWildcard() } - // This representation will be changed in https://github.com/partiql/partiql-lang-kotlin/issues/1589 - @OptIn(PartiQLValueExperimental::class) @JvmStatic - public fun explain(options: Map, statement: Statement): Explain { + public fun explain(options: Map, statement: Statement): Explain { return Explain(options, statement) } diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt index cf98c8b15..107dd0738 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt @@ -42,7 +42,6 @@ import org.partiql.ast.graph.GraphMatch import org.partiql.ast.graph.GraphPattern import org.partiql.ast.graph.GraphQuantifier import org.partiql.ast.graph.GraphSelector -import org.partiql.value.PartiQLValueExperimental // TODO docs public abstract class AstRewriter : AstVisitor() { @@ -200,9 +199,7 @@ public abstract class AstRewriter : AstVisitor() { } } - @OptIn(PartiQLValueExperimental::class) override fun visitExprLit(node: ExprLit, ctx: C): AstNode { - val value = node.value return node } @@ -551,7 +548,6 @@ public abstract class AstRewriter : AstVisitor() { return node } - @OptIn(PartiQLValueExperimental::class) override fun visitExplain(node: Explain, ctx: C): AstNode { val statement = visitStatement(node.statement, ctx) as Statement return if (statement !== node.statement) { diff --git a/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt b/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt index d8bcd4258..81d4bb4dc 100644 --- a/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt +++ b/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt @@ -61,6 +61,15 @@ import org.partiql.ast.Ast.groupByKey import org.partiql.ast.Ast.identifier import org.partiql.ast.Ast.identifierChain import org.partiql.ast.Ast.letBinding +import org.partiql.ast.Ast.literalBool +import org.partiql.ast.Ast.literalDecimal +import org.partiql.ast.Ast.literalFloat +import org.partiql.ast.Ast.literalInt +import org.partiql.ast.Ast.literalLong +import org.partiql.ast.Ast.literalMissing +import org.partiql.ast.Ast.literalNull +import org.partiql.ast.Ast.literalString +import org.partiql.ast.Ast.literalTypedString import org.partiql.ast.Ast.orderBy import org.partiql.ast.Ast.queryBodySFW import org.partiql.ast.Ast.queryBodySetOp @@ -94,27 +103,7 @@ import org.partiql.ast.SetQuantifier import org.partiql.ast.expr.Expr import org.partiql.ast.expr.Scope import org.partiql.ast.expr.TrimSpec -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.boolValue -import org.partiql.value.dateValue -import org.partiql.value.datetime.DateTimeValue -import org.partiql.value.datetime.TimeZone -import org.partiql.value.decimalValue -import org.partiql.value.float32Value -import org.partiql.value.float64Value -import org.partiql.value.int16Value -import org.partiql.value.int32Value -import org.partiql.value.int64Value -import org.partiql.value.int8Value -import org.partiql.value.intValue -import org.partiql.value.missingValue -import org.partiql.value.nullValue -import org.partiql.value.stringValue -import org.partiql.value.symbolValue -import org.partiql.value.timeValue -import org.partiql.value.timestampValue import java.math.BigDecimal -import java.math.BigInteger import kotlin.test.assertFails /** @@ -122,7 +111,6 @@ import kotlin.test.assertFails * * It does NOT test formatted output. */ -@OptIn(PartiQLValueExperimental::class) class SqlDialectTest { // Identifiers & Paths @@ -245,7 +233,7 @@ class SqlDialectTest { companion object { - private val NULL = exprLit(nullValue()) + private val NULL = exprLit(literalNull()) @JvmStatic fun types() = listOf( @@ -272,9 +260,9 @@ class SqlDialectTest { expect("CLOB", DataType.CLOB()), expect("DATE", DataType.DATE()), expect("TIME", DataType.TIME()), - expect("TIME(1)", DataType.TIME(1)), - expect("TIME WITH TIMEZONE", DataType.TIME_WITH_TIME_ZONE()), - expect("TIME WITH TIMEZONE (1)", DataType.TIME_WITH_TIME_ZONE(1)), + expect("TIME (1)", DataType.TIME(1)), + expect("TIME WITH TIME ZONE", DataType.TIME_WITH_TIME_ZONE()), + expect("TIME (1) WITH TIME ZONE", DataType.TIME_WITH_TIME_ZONE(1)), // TODO TIMESTAMP // TODO INTERVAL // TODO other types in `DataType` @@ -415,58 +403,52 @@ class SqlDialectTest { // Expressions - @OptIn(PartiQLValueExperimental::class) @JvmStatic fun exprLitCases() = listOf( expect( - "NULL", exprLit(nullValue()) + "NULL", exprLit(literalNull()) ), expect( - "MISSING", exprLit(missingValue()) + "MISSING", exprLit(literalMissing()) ), expect( - "true", exprLit(boolValue(true)) + "true", exprLit(literalBool(true)) ), expect( - "1", exprLit(int8Value(1)) + "1", exprLit(literalInt(1)) ), expect( - "2", exprLit(int16Value(2)) + "2", exprLit(literalInt(2)) ), expect( - "3", exprLit(int32Value(3)) + "3", exprLit(literalInt(3)) ), expect( - "4", exprLit(int64Value(4)) + "4", exprLit(literalLong(4)) ), expect( - "5", exprLit(intValue(BigInteger.valueOf(5))) + "5", exprLit(literalDecimal(BigDecimal.valueOf(5))) ), - // TODO fix PartiQL Text writer for floats - // expect("1.1e0") { - expect("1.1", exprLit(float32Value(1.1f))), - // TODO fix PartiQL Text writer for floats - // expect("1.2e0") { + expect("1.1e0", exprLit(literalFloat("1.1e0"))), + expect("1.2e0", exprLit(literalFloat("1.2e0"))), + expect("1.2345E-5", exprLit(literalFloat("1.2345E-5"))), expect( - "1.2", exprLit(float64Value(1.2)) + "1.3", exprLit(literalDecimal(BigDecimal.valueOf(1.3))) ), expect( - "1.3", exprLit(decimalValue(BigDecimal.valueOf(1.3))) + """'hello'""", exprLit(literalString("hello")) ), expect( - """'hello'""", exprLit(stringValue("hello")) + """hello""", id("hello") ), expect( - """hello""", exprLit(symbolValue("hello")) + "DATE '0001-02-03'", exprLit(literalTypedString(DataType.DATE(), "0001-02-03")) ), expect( - "DATE '0001-02-03'", exprLit(dateValue(DateTimeValue.date(1, 2, 3))) + "TIME '01:02:03.456-00:30'", exprLit(literalTypedString(DataType.TIME(), "01:02:03.456-00:30")) ), expect( - "TIME '01:02:03.456-00:30'", exprLit(timeValue(DateTimeValue.time(1, 2, BigDecimal.valueOf(3.456), TimeZone.UtcOffset.of(-30)))) - ), - expect( - "TIMESTAMP '0001-02-03 04:05:06.78-00:30'", exprLit(timestampValue(DateTimeValue.timestamp(1, 2, 3, 4, 5, BigDecimal.valueOf(6.78), TimeZone.UtcOffset.of(-30)))) + "TIMESTAMP '0001-02-03 04:05:06.78-00:30'", exprLit(literalTypedString(DataType.TIMESTAMP(), "0001-02-03 04:05:06.78-00:30")) ), // expect("""{{ '''Hello''' '''World''' }}""") { @@ -699,7 +681,7 @@ class SqlDialectTest { next = exprPathStepElement( element = exprOperator( symbol = "+", - lhs = exprLit(int32Value(1)), + lhs = exprLit(literalInt(1)), rhs = exprVarRef( identifierChain = idChain(id("a")), scope = Scope.DEFAULT() @@ -716,7 +698,7 @@ class SqlDialectTest { identifierChain = idChain(id("x")), scope = Scope.DEFAULT() ), - next = exprPathStepElement(exprLit(stringValue("y")), next = null) + next = exprPathStepElement(exprLit(literalString("y")), next = null) ) ), ) @@ -727,7 +709,7 @@ class SqlDialectTest { "foo(1)", exprCall( function = idChain(id("foo")), - args = listOf(exprLit(int32Value(1))), + args = listOf(exprLit(literalInt(1))), setq = null ) ), @@ -736,8 +718,8 @@ class SqlDialectTest { exprCall( function = idChain(id("foo")), args = listOf( - exprLit(int32Value(1)), - exprLit(int32Value(2)), + exprLit(literalInt(1)), + exprLit(literalInt(2)), ), setq = null ) @@ -749,7 +731,7 @@ class SqlDialectTest { root = id("foo"), next = idChain(id("bar")) ), - args = listOf(exprLit(int32Value(1))), + args = listOf(exprLit(literalInt(1))), setq = null ) ), @@ -761,8 +743,8 @@ class SqlDialectTest { next = idChain(id("bar")) ), args = listOf( - exprLit(int32Value(1)), - exprLit(int32Value(2)) + exprLit(literalInt(1)), + exprLit(literalInt(2)) ), setq = null ) @@ -848,9 +830,9 @@ class SqlDialectTest { "<<1, 2, 3>>", exprBag( values = listOf( - exprLit(int32Value(1)), - exprLit(int32Value(2)), - exprLit(int32Value(3)) + exprLit(literalInt(1)), + exprLit(literalInt(2)), + exprLit(literalInt(3)) ) ) ), @@ -862,9 +844,9 @@ class SqlDialectTest { "[1, 2, 3]", exprArray( values = listOf( - exprLit(int32Value(1)), - exprLit(int32Value(2)), - exprLit(int32Value(3)) + exprLit(literalInt(1)), + exprLit(literalInt(2)), + exprLit(literalInt(3)) ) ) ), @@ -884,9 +866,9 @@ class SqlDialectTest { rows = listOf( exprRowValue( values = listOf( - exprLit(int32Value(1)), - exprLit(int32Value(2)), - exprLit(int32Value(3)) + exprLit(literalInt(1)), + exprLit(literalInt(2)), + exprLit(literalInt(3)) ) ) ) @@ -902,9 +884,9 @@ class SqlDialectTest { "(1, 2, 3)", exprRowValue( values = listOf( - exprLit(int32Value(1)), - exprLit(int32Value(2)), - exprLit(int32Value(3)) + exprLit(literalInt(1)), + exprLit(literalInt(2)), + exprLit(literalInt(3)) ) ) ), @@ -919,9 +901,9 @@ class SqlDialectTest { // "SEXP (1, 2, 3)", // exprCollection { // type = Expr.Collection.Type.SEXP -// values += exprLit(int32Value(1)) -// values += exprLit(int32Value(2)) -// values += exprLit(int32Value(3)) +// values += exprLit(literalInt(1)) +// values += exprLit(literalInt(2)) +// values += exprLit(literalInt(3)) // } // ), ) @@ -934,8 +916,8 @@ class SqlDialectTest { exprStruct( fields = listOf( exprStructField( - name = exprLit(symbolValue("a")), - value = exprLit(int32Value(1)) + name = v("a"), + value = exprLit(literalInt(1)) ) ) ) @@ -945,12 +927,12 @@ class SqlDialectTest { exprStruct( fields = listOf( exprStructField( - name = exprLit(symbolValue("a")), - value = exprLit(int32Value(1)) + name = v("a"), + value = exprLit(literalInt(1)) ), exprStructField( - name = exprLit(symbolValue("b")), - value = exprLit(boolValue(false)) + name = v("b"), + value = exprLit(literalBool(false)) ) ) ) @@ -1157,7 +1139,7 @@ class SqlDialectTest { exprCall( function = idChain(id("DATE_ADD")), args = listOf( - exprLit(stringValue("MINUTE")), + exprLit(literalString("MINUTE")), v("x"), v("y") ), @@ -1169,7 +1151,7 @@ class SqlDialectTest { exprCall( function = idChain(id("DATE_DIFF")), args = listOf( - exprLit(stringValue("MINUTE")), + exprLit(literalString("MINUTE")), v("x"), v("y") ), @@ -1966,7 +1948,7 @@ class SqlDialectTest { select = select("a"), from = table("T") ), - limit = exprLit(int32Value(1)) + limit = exprLit(literalInt(1)) ) ), expect( @@ -1976,7 +1958,7 @@ class SqlDialectTest { select = select("a"), from = table("T") ), - offset = exprLit(int32Value(2)) + offset = exprLit(literalInt(2)) ) ), expect( @@ -1986,8 +1968,8 @@ class SqlDialectTest { select = select("a"), from = table("T") ), - limit = exprLit(int32Value(1)), - offset = exprLit(int32Value(2)) + limit = exprLit(literalInt(1)), + offset = exprLit(literalInt(2)) ) ), expect( @@ -2408,7 +2390,7 @@ class SqlDialectTest { ) ) ), - limit = exprLit(int32Value(1)) // LIMIT associated with SQL set op + limit = exprLit(literalInt(1)) // LIMIT associated with SQL set op ) ), expect( @@ -2428,7 +2410,7 @@ class SqlDialectTest { select = select("b"), from = table("S"), ), - limit = exprLit(int32Value(1)) // LIMIT associated with rhs SFW query + limit = exprLit(literalInt(1)) // LIMIT associated with rhs SFW query ) ) ) @@ -2556,7 +2538,7 @@ class SqlDialectTest { "1 = (SELECT a FROM T)", exprOperator( symbol = "=", - lhs = exprLit(int32Value(1)), + lhs = exprLit(literalInt(1)), rhs = qSet( body = sfw( select = select("a"), @@ -2571,8 +2553,8 @@ class SqlDialectTest { symbol = "=", lhs = exprRowValue( values = listOf( - exprLit(int32Value(1)), - exprLit(int32Value(2)) + exprLit(literalInt(1)), + exprLit(literalInt(2)) ) ), rhs = qSet( diff --git a/partiql-parser/build.gradle.kts b/partiql-parser/build.gradle.kts index 46c5032e8..eb98d6ad8 100644 --- a/partiql-parser/build.gradle.kts +++ b/partiql-parser/build.gradle.kts @@ -22,6 +22,7 @@ plugins { dependencies { antlr(Deps.antlr) api(project(":partiql-ast")) + api(project(":partiql-spi")) api(project(":partiql-types")) implementation(Deps.ionElement) shadow(Deps.antlrRuntime) diff --git a/partiql-parser/src/main/antlr/PartiQLParser.g4 b/partiql-parser/src/main/antlr/PartiQLParser.g4 index 358ad0c77..47cb9c7d1 100644 --- a/partiql-parser/src/main/antlr/PartiQLParser.g4 +++ b/partiql-parser/src/main/antlr/PartiQLParser.g4 @@ -842,6 +842,7 @@ literal | LITERAL_STRING # LiteralString | LITERAL_INTEGER # LiteralInteger | LITERAL_DECIMAL # LiteralDecimal + | LITERAL_FLOAT # LiteralFloat | ION_CLOSURE # LiteralIon | DATE LITERAL_STRING # LiteralDate | TIME ( PAREN_LEFT LITERAL_INTEGER PAREN_RIGHT )? (WITH TIME ZONE)? LITERAL_STRING # LiteralTime diff --git a/partiql-parser/src/main/antlr/PartiQLTokens.g4 b/partiql-parser/src/main/antlr/PartiQLTokens.g4 index ed63635c2..7dce7de54 100644 --- a/partiql-parser/src/main/antlr/PartiQLTokens.g4 +++ b/partiql-parser/src/main/antlr/PartiQLTokens.g4 @@ -388,12 +388,16 @@ LITERAL_STRING : '\'' ( ('\'\'') | ~('\'') )* '\''; LITERAL_INTEGER - : DIGIT DIGIT*; + : DIGIT+; -LITERAL_DECIMAL: - DIGIT+ '.' DIGIT* ([e] [+-]? DIGIT+)? - | '.' DIGIT DIGIT* ([e] [+-]? DIGIT+)? - | DIGIT DIGIT* ([e] [+-]? DIGIT+)? +LITERAL_DECIMAL + : DIGIT+ '.' DIGIT* + | '.' DIGIT+ + ; + +LITERAL_FLOAT + : DIGIT+ ('.' DIGIT*)? 'E' [+-]? DIGIT+ + | '.' DIGIT+ 'E' [+-]? DIGIT+ ; IDENTIFIER diff --git a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt index da9376fe1..3a925ffde 100644 --- a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt +++ b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt @@ -100,6 +100,15 @@ import org.partiql.ast.Ast.groupByKey import org.partiql.ast.Ast.identifier import org.partiql.ast.Ast.identifierChain import org.partiql.ast.Ast.letBinding +import org.partiql.ast.Ast.literalBool +import org.partiql.ast.Ast.literalDecimal +import org.partiql.ast.Ast.literalFloat +import org.partiql.ast.Ast.literalInt +import org.partiql.ast.Ast.literalLong +import org.partiql.ast.Ast.literalMissing +import org.partiql.ast.Ast.literalNull +import org.partiql.ast.Ast.literalString +import org.partiql.ast.Ast.literalTypedString import org.partiql.ast.Ast.orderBy import org.partiql.ast.Ast.query import org.partiql.ast.Ast.queryBodySFW @@ -156,7 +165,6 @@ import org.partiql.parser.PartiQLLexerException import org.partiql.parser.PartiQLParser import org.partiql.parser.PartiQLParserException import org.partiql.parser.internal.antlr.PartiQLParserBaseVisitor -import org.partiql.parser.internal.util.DateTimeUtils import org.partiql.spi.Context import org.partiql.spi.SourceLocation import org.partiql.spi.SourceLocations @@ -164,29 +172,12 @@ import org.partiql.spi.errors.PError import org.partiql.spi.errors.PErrorKind import org.partiql.spi.errors.PErrorListener import org.partiql.spi.errors.PErrorListenerException -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.boolValue -import org.partiql.value.dateValue -import org.partiql.value.datetime.DateTimeException -import org.partiql.value.datetime.DateTimeValue -import org.partiql.value.decimalValue -import org.partiql.value.int32Value -import org.partiql.value.int64Value -import org.partiql.value.intValue -import org.partiql.value.missingValue -import org.partiql.value.nullValue -import org.partiql.value.stringValue -import org.partiql.value.timeValue -import org.partiql.value.timestampValue import java.math.BigDecimal import java.math.BigInteger import java.math.MathContext import java.math.RoundingMode import java.nio.channels.ClosedByInterruptException import java.nio.charset.StandardCharsets -import java.time.LocalDate -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeParseException import org.partiql.parser.internal.antlr.PartiQLParser as GeneratedParser import org.partiql.parser.internal.antlr.PartiQLTokens as GeneratedLexer @@ -208,7 +199,6 @@ import org.partiql.parser.internal.antlr.PartiQLTokens as GeneratedLexer */ internal class PartiQLParserDefault : PartiQLParser { - @OptIn(PartiQLValueExperimental::class) @Throws(PErrorListenerException::class) override fun parse(source: String, ctx: Context): PartiQLParser.Result { try { @@ -220,7 +210,7 @@ internal class PartiQLParserDefault : PartiQLParser { ctx.errorListener.report(error) val locations = SourceLocations() return PartiQLParser.Result( - mutableListOf(org.partiql.ast.Query(org.partiql.ast.expr.ExprLit(nullValue()))) as List, + mutableListOf(org.partiql.ast.Query(exprLit(literalNull()))) as List, locations ) } @@ -350,7 +340,6 @@ internal class PartiQLParserDefault : PartiQLParser { /** * Translate an ANTLR ParseTree to a PartiQL AST */ - @OptIn(PartiQLValueExperimental::class) private class Visitor( private val tokens: CommonTokenStream, private val locations: MutableMap, @@ -463,10 +452,9 @@ internal class PartiQLParserDefault : PartiQLParser { } } explain( - // TODO get rid of usage of PartiQLValue https://github.com/partiql/partiql-lang-kotlin/issues/1589 options = mapOf( - "type" to stringValue(type), - "format" to stringValue(format) + "type" to (type?.let { literalString(it) } ?: literalNull()), + "format" to (format?.let { literalString(it) } ?: literalNull()) ), statement = visit(ctx.statement()) as Statement, ) @@ -1628,7 +1616,6 @@ internal class PartiQLParserDefault : PartiQLParser { } val lhs = visitExpr(ctx.expr(0)) val rhs = visitExpr(ctx.expr(1)) - // TODO change to not use PartiQLValue -- https://github.com/partiql/partiql-lang-kotlin/issues/1589 val fieldLit = ctx.dt.text.lowercase() // TODO error on invalid datetime fields like TIMEZONE_HOUR and TIMEZONE_MINUTE when { @@ -1777,7 +1764,12 @@ internal class PartiQLParserDefault : PartiQLParser { } catch (e: NumberFormatException) { throw error(ctx, "Invalid decimal literal", e) } - exprLit(decimalValue(decimal)) + exprLit(literalDecimal(decimal)) + } + + override fun visitLiteralFloat(ctx: GeneratedParser.LiteralFloatContext) = translate(ctx) { + val v = ctx.LITERAL_FLOAT().text.trim() + exprLit(literalFloat(v)) } override fun visitArray(ctx: GeneratedParser.ArrayContext) = translate(ctx) { @@ -1786,19 +1778,19 @@ internal class PartiQLParserDefault : PartiQLParser { } override fun visitLiteralNull(ctx: GeneratedParser.LiteralNullContext) = translate(ctx) { - exprLit(nullValue()) + exprLit(literalNull()) } override fun visitLiteralMissing(ctx: GeneratedParser.LiteralMissingContext) = translate(ctx) { - exprLit(missingValue()) + exprLit(literalMissing()) } override fun visitLiteralTrue(ctx: GeneratedParser.LiteralTrueContext) = translate(ctx) { - exprLit(boolValue(true)) + exprLit(literalBool(value = true)) } override fun visitLiteralFalse(ctx: GeneratedParser.LiteralFalseContext) = translate(ctx) { - exprLit(boolValue(false)) + exprLit(literalBool(value = false)) } override fun visitLiteralIon(ctx: GeneratedParser.LiteralIonContext) = translate(ctx) { @@ -1809,32 +1801,31 @@ internal class PartiQLParserDefault : PartiQLParser { override fun visitLiteralString(ctx: GeneratedParser.LiteralStringContext) = translate(ctx) { val value = ctx.LITERAL_STRING().getStringValue() - exprLit(stringValue(value)) + exprLit(literalString(value)) } override fun visitLiteralInteger(ctx: GeneratedParser.LiteralIntegerContext) = translate(ctx) { val n = ctx.LITERAL_INTEGER().text - - // 1st, try parse as int + // 1st, try parse as int32 try { val v = n.toInt(10) - return@translate exprLit(int32Value(v)) + return@translate exprLit(literalInt((v))) } catch (ex: NumberFormatException) { // ignore } - // 2nd, try parse as long + // 2nd, try parse as int64 try { val v = n.toLong(10) - return@translate exprLit(int64Value(v)) + return@translate exprLit(literalLong(v)) } catch (ex: NumberFormatException) { // ignore } - // 3rd, try parse as BigInteger + // 3rd, try parse as numeric (decimal) try { - val v = BigInteger(n) - return@translate exprLit(intValue(v)) + val dec = BigDecimal(n, MathContext(38, RoundingMode.HALF_EVEN)) + return@translate exprLit(literalDecimal(dec)) } catch (ex: NumberFormatException) { throw ex } @@ -1846,37 +1837,49 @@ internal class PartiQLParserDefault : PartiQLParser { if (DATE_PATTERN_REGEX.matches(dateString).not()) { throw error(pattern, "Expected DATE string to be of the format yyyy-MM-dd") } - val value = try { - LocalDate.parse(dateString, DateTimeFormatter.ISO_LOCAL_DATE) - } catch (e: DateTimeParseException) { - throw error(pattern, e.localizedMessage, e) - } catch (e: IndexOutOfBoundsException) { - throw error(pattern, e.localizedMessage, e) - } - val date = DateTimeValue.date(value.year, value.monthValue, value.dayOfMonth) - exprLit(dateValue(date)) + exprLit(literalTypedString(type = DataType.DATE(), dateString)) } override fun visitLiteralTime(ctx: GeneratedParser.LiteralTimeContext) = translate(ctx) { val (timeString, precision) = getTimeStringAndPrecision(ctx.LITERAL_STRING(), ctx.LITERAL_INTEGER()) - val time = try { - DateTimeUtils.parseTimeLiteral(timeString) - } catch (e: DateTimeException) { - throw error(ctx, "Invalid Date Time Literal", e) + val type = when (ctx.ZONE()) { + null -> { + if (precision == null) { + DataType.TIME() + } else { + DataType.TIME(precision) + } + } + else -> { + if (precision == null) { + DataType.TIME_WITH_TIME_ZONE() + } else { + DataType.TIME_WITH_TIME_ZONE(precision) + } + } } - val value = time.toPrecision(precision) - exprLit(timeValue(value)) + exprLit(literalTypedString(type = type, timeString)) } override fun visitLiteralTimestamp(ctx: GeneratedParser.LiteralTimestampContext) = translate(ctx) { - val (timeString, precision) = getTimeStringAndPrecision(ctx.LITERAL_STRING(), ctx.LITERAL_INTEGER()) - val timestamp = try { - DateTimeUtils.parseTimestamp(timeString) - } catch (e: DateTimeException) { - throw error(ctx, "Invalid Date Time Literal", e) + val (timestampString, precision) = getTimeStringAndPrecision(ctx.LITERAL_STRING(), ctx.LITERAL_INTEGER()) + val type = when (ctx.ZONE()) { + null -> { + if (precision == null) { + DataType.TIMESTAMP() + } else { + DataType.TIMESTAMP(precision) + } + } + else -> { + if (precision == null) { + DataType.TIMESTAMP_WITH_TIME_ZONE() + } else { + DataType.TIMESTAMP_WITH_TIME_ZONE(precision) + } + } } - val value = timestamp.toPrecision(precision) - exprLit(timestampValue(value)) + exprLit(literalTypedString(type = type, timestampString)) } override fun visitTuple(ctx: GeneratedParser.TupleContext) = translate(ctx) { @@ -2059,7 +2062,7 @@ internal class PartiQLParserDefault : PartiQLParser { private fun getTimeStringAndPrecision( stringNode: TerminalNode, integerNode: TerminalNode?, - ): Pair { + ): Pair { val timeString = stringNode.getStringValue() val precision = when (integerNode) { null -> { diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt index e7a3aa9d8..ea8c04650 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt @@ -8,6 +8,8 @@ import org.partiql.ast.Ast.exprStruct import org.partiql.ast.Ast.exprStructField import org.partiql.ast.Ast.from import org.partiql.ast.Ast.fromExpr +import org.partiql.ast.Ast.literalInt +import org.partiql.ast.Ast.literalString import org.partiql.ast.Ast.query import org.partiql.ast.Ast.queryBodySFW import org.partiql.ast.Ast.queryBodySetOp @@ -19,9 +21,6 @@ import org.partiql.ast.SetOpType import org.partiql.ast.SetQuantifier import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprQuerySet -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.int32Value -import org.partiql.value.stringValue import kotlin.test.assertEquals class PartiQLParserBagOpTests { @@ -30,7 +29,6 @@ class PartiQLParserBagOpTests { private fun queryBody(body: () -> Expr) = query(body()) - @OptIn(PartiQLValueExperimental::class) private fun createSFW(i: Int): ExprQuerySet = exprQuerySet( body = queryBodySFW( @@ -43,8 +41,8 @@ class PartiQLParserBagOpTests { exprStruct( fields = mutableListOf( exprStructField( - name = exprLit(value = stringValue("a")), - value = exprLit(value = int32Value(i)) + name = exprLit(literalString("a")), + value = exprLit(literalInt(i)) ) ) ) @@ -67,8 +65,7 @@ class PartiQLParserBagOpTests { offset = null ) - @OptIn(PartiQLValueExperimental::class) - private fun createLit(i: Int) = exprLit(int32Value(i)) + private fun createLit(i: Int) = exprLit(literalInt(i)) // SQL Union @Test diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt index 3742b57b1..4685e396b 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt @@ -3,11 +3,11 @@ package org.partiql.parser.internal import org.junit.jupiter.api.Test import org.partiql.ast.Ast.exprLit import org.partiql.ast.Ast.exprOperator +import org.partiql.ast.Ast.literalInt import org.partiql.ast.Ast.query import org.partiql.ast.AstNode import org.partiql.ast.expr.Expr import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.int32Value import kotlin.test.assertEquals @OptIn(PartiQLValueExperimental::class) @@ -24,7 +24,7 @@ class PartiQLParserOperatorTests { exprOperator( symbol = "-", lhs = null, - rhs = exprLit(int32Value(2)) + rhs = exprLit(literalInt(2)) ) } ) @@ -35,8 +35,8 @@ class PartiQLParserOperatorTests { queryBody { exprOperator( symbol = "<=", - lhs = exprLit(int32Value(1)), - rhs = exprLit(int32Value(2)) + lhs = exprLit(literalInt(1)), + rhs = exprLit(literalInt(2)) ) } ) @@ -48,7 +48,7 @@ class PartiQLParserOperatorTests { exprOperator( symbol = "==!", lhs = null, - rhs = exprLit(int32Value(2)) + rhs = exprLit(literalInt(2)) ) } ) @@ -59,8 +59,8 @@ class PartiQLParserOperatorTests { queryBody { exprOperator( symbol = "==!", - lhs = exprLit(int32Value(1)), - rhs = exprLit(int32Value(2)) + lhs = exprLit(literalInt(1)), + rhs = exprLit(literalInt(2)) ) } ) diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt index 09c9f0dc6..266475294 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt @@ -4,15 +4,13 @@ import org.junit.jupiter.api.Test import org.partiql.ast.Ast.exprLit import org.partiql.ast.Ast.exprOperator import org.partiql.ast.Ast.exprSessionAttribute +import org.partiql.ast.Ast.literalInt import org.partiql.ast.Ast.query import org.partiql.ast.AstNode import org.partiql.ast.expr.Expr import org.partiql.ast.expr.SessionAttribute -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.int32Value import kotlin.test.assertEquals -@OptIn(PartiQLValueExperimental::class) class PartiQLParserSessionAttributeTests { private val parser = PartiQLParserDefault() @@ -49,7 +47,7 @@ class PartiQLParserSessionAttributeTests { queryBody { exprOperator( symbol = "=", - lhs = exprLit(int32Value(1)), + lhs = exprLit(literalInt(1)), rhs = exprSessionAttribute(SessionAttribute.CURRENT_USER()) ) } diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt index 316693c48..206231cb6 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt @@ -10,8 +10,7 @@ import org.partiql.ast.expr.ExprPath import org.partiql.ast.expr.ExprSessionAttribute import org.partiql.ast.expr.ExprVarRef import org.partiql.ast.expr.PathStep -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.StringValue +import org.partiql.ast.literal.LiteralString private val col = { index: () -> Int -> "_${index()}" } @@ -58,7 +57,6 @@ private fun IdentifierChain.toBinder(): Identifier { private fun Identifier.toBinder(): Identifier = symbol.toBinder() -@OptIn(PartiQLValueExperimental::class) private fun ExprPath.toBinder(index: () -> Int): Identifier { if (next == null) return root.toBinder(index) var cur = next @@ -71,8 +69,8 @@ private fun ExprPath.toBinder(index: () -> Int): Identifier { is PathStep.Field -> prev.field.toBinder() is PathStep.Element -> { val k = prev.element - if (k is ExprLit && k.value is StringValue) { - (k.value as StringValue).value!!.toBinder() + if (k is ExprLit && k.lit is LiteralString) { + (k.lit as LiteralString).value.toBinder() } else { col(index).toBinder() } diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt index cd01ce157..41311b11a 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt @@ -25,6 +25,7 @@ import org.partiql.ast.Ast.exprStructField import org.partiql.ast.Ast.exprVarRef import org.partiql.ast.Ast.identifier import org.partiql.ast.Ast.identifierChain +import org.partiql.ast.Ast.literalString import org.partiql.ast.Ast.queryBodySFW import org.partiql.ast.Ast.queryBodySetOp import org.partiql.ast.Ast.selectItemExpr @@ -44,14 +45,11 @@ import org.partiql.ast.SelectStar import org.partiql.ast.SelectValue import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprCase -import org.partiql.ast.expr.ExprLit import org.partiql.ast.expr.ExprQuerySet import org.partiql.ast.expr.ExprStruct import org.partiql.ast.expr.ExprVarRef import org.partiql.ast.expr.Scope import org.partiql.planner.internal.helpers.toBinder -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.stringValue /** * Converts SQL-style SELECT to PartiQL SELECT VALUE. @@ -315,12 +313,11 @@ internal object NormalizeSelect { ) } - @OptIn(PartiQLValueExperimental::class) private fun visitSelectProjectWithoutProjectAll(node: SelectList): SelectValue { val structFields = node.items.map { item -> val itemExpr = item as? SelectItem.Expr ?: error("Expected the projection to be an expression.") exprStructField( - name = exprLit(stringValue(itemExpr.asAlias?.symbol!!)), + name = exprLit(literalString(itemExpr.asAlias?.symbol!!)), value = item.expr ) } @@ -343,19 +340,17 @@ internal object NormalizeSelect { defaultExpr = buildSimpleStruct(expr, col(index)) ) - @OptIn(PartiQLValueExperimental::class) private fun buildSimpleStruct(expr: Expr, name: String): ExprStruct = exprStruct( fields = listOf( exprStructField( - name = exprLit(stringValue(name)), + name = exprLit(literalString(name)), value = expr ) ) ) - @OptIn(PartiQLValueExperimental::class) private fun structField(name: String, expr: Expr): ExprStruct.Field = exprStructField( - name = ExprLit(stringValue(name)), + name = exprLit(literalString(name)), value = expr ) diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt index f3c054637..3af5083bc 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt @@ -20,6 +20,7 @@ import org.partiql.ast.Ast.exprLit import org.partiql.ast.Ast.exprVarRef import org.partiql.ast.Ast.identifier import org.partiql.ast.Ast.identifierChain +import org.partiql.ast.Ast.literalInt import org.partiql.ast.AstNode import org.partiql.ast.AstRewriter import org.partiql.ast.AstVisitor @@ -88,7 +89,6 @@ import org.partiql.planner.internal.typer.CompilerType import org.partiql.types.PType import org.partiql.value.PartiQLValueExperimental import org.partiql.value.boolValue -import org.partiql.value.int32Value import org.partiql.value.stringValue /** @@ -439,7 +439,7 @@ internal object RelConverter { relOpAggregateCallUnresolved( name, org.partiql.planner.internal.ir.SetQuantifier.ALL, - args = listOf(exprLit(int32Value(1)).toRex(env)) + args = listOf(exprLit(literalInt(1)).toRex(env)) ) } else { val setq = when (expr.setq?.code()) { diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt index ed96bf983..31e58f5fb 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt @@ -54,6 +54,16 @@ import org.partiql.ast.expr.ExprVariant import org.partiql.ast.expr.PathStep import org.partiql.ast.expr.Scope import org.partiql.ast.expr.TrimSpec +import org.partiql.ast.literal.Literal +import org.partiql.ast.literal.LiteralBool +import org.partiql.ast.literal.LiteralDecimal +import org.partiql.ast.literal.LiteralDouble +import org.partiql.ast.literal.LiteralInt +import org.partiql.ast.literal.LiteralLong +import org.partiql.ast.literal.LiteralMissing +import org.partiql.ast.literal.LiteralNull +import org.partiql.ast.literal.LiteralString +import org.partiql.ast.literal.LiteralTypedString import org.partiql.errors.TypeCheckException import org.partiql.planner.internal.Env import org.partiql.planner.internal.ir.Rel @@ -84,18 +94,26 @@ import org.partiql.planner.internal.ir.rexOpVarLocal import org.partiql.planner.internal.ir.rexOpVarUnresolved import org.partiql.planner.internal.typer.CompilerType import org.partiql.planner.internal.typer.PlanTyper.Companion.toCType +import org.partiql.planner.internal.utils.DateTimeUtils import org.partiql.spi.catalog.Identifier import org.partiql.types.PType -import org.partiql.value.DecimalValue -import org.partiql.value.MissingValue +import org.partiql.value.PartiQLValue import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.StringValue import org.partiql.value.boolValue +import org.partiql.value.dateValue +import org.partiql.value.datetime.DateTimeValue +import org.partiql.value.decimalValue +import org.partiql.value.float64Value import org.partiql.value.int32Value import org.partiql.value.int64Value import org.partiql.value.io.PartiQLValueIonReaderBuilder +import org.partiql.value.missingValue import org.partiql.value.nullValue import org.partiql.value.stringValue +import org.partiql.value.timeValue +import org.partiql.value.timestampValue +import java.time.LocalDate +import java.time.format.DateTimeFormatter import org.partiql.ast.SetQuantifier as AstSetQuantifier /** @@ -126,26 +144,92 @@ internal object RexConverter { throw IllegalArgumentException("unsupported rex $node") override fun visitExprLit(node: ExprLit, context: Env): Rex { - val type = when (val value = node.value) { - // Specifically handle the lack of an infinite precision/scale - // TODO: PartiQLValue won't be in AST soon - is DecimalValue -> { - when (val decimal = value.value) { - null -> PType.decimal() - else -> PType.decimal(decimal.precision(), decimal.scale()) - } - } - else -> value.type.toPType() - } val cType = CompilerType( - _delegate = type, - isNullValue = node.value.isNull, - isMissingValue = node.value is MissingValue + _delegate = node.lit.toPType(), + isNullValue = node.lit is LiteralNull, + isMissingValue = node.lit is LiteralMissing ) - val op = rexOpLit(node.value) + val op = rexOpLit(node.lit.toPartiQLValue()) return rex(cType, op) } + private fun Literal.toPType(): PType { + return when (this) { + is LiteralNull, is LiteralMissing -> PType.unknown() + is LiteralString -> PType.string() + is LiteralBool -> PType.bool() + is LiteralDecimal -> PType.decimal(this.value.precision(), this.value.scale()) + is LiteralInt -> PType.integer() + is LiteralLong -> PType.bigint() + is LiteralDouble -> PType.real() + is LiteralTypedString -> { + val type = this.type + when (type.code()) { + DataType.DATE -> PType.date() + DataType.TIME -> if (type.precision == null) { + PType.time(6) + } else { + PType.time(type.precision) + } + DataType.TIME_WITH_TIME_ZONE -> if (type.precision == null) { + PType.timez(6) + } else { + PType.timez(type.precision) + } + DataType.TIMESTAMP -> if (type.precision == null) { + PType.timestamp(6) + } else { + PType.timestamp(type.precision) + } + DataType.TIMESTAMP_WITH_TIME_ZONE -> if (type.precision == null) { + PType.timestampz(6) + } else { + PType.timestampz(type.precision) + } + else -> error("Unsupported typed literal string: $this") + } + } + else -> error("Unsupported literal: $this") + } + } + + private fun Literal.toPartiQLValue(): PartiQLValue { + return when (this) { + is LiteralNull -> nullValue() + is LiteralMissing -> missingValue() + is LiteralString -> stringValue(value) + is LiteralBool -> boolValue(value) + is LiteralDecimal -> decimalValue(this.value) + is LiteralInt -> int32Value(this.value) + is LiteralLong -> int64Value(this.value) + is LiteralDouble -> float64Value(this.value) + is LiteralTypedString -> { + val type = this.type + val typedString = this.value + when (type.code()) { + DataType.DATE -> { + val value = LocalDate.parse(typedString, DateTimeFormatter.ISO_LOCAL_DATE) + val date = DateTimeValue.date(value.year, value.monthValue, value.dayOfMonth) + dateValue(date) + } + DataType.TIME, DataType.TIME_WITH_TIME_ZONE -> { + val time = DateTimeUtils.parseTimeLiteral(typedString) + val precision = type.precision ?: 6 + timeValue(time.toPrecision(precision)) + } + DataType.TIMESTAMP, DataType.TIMESTAMP_WITH_TIME_ZONE -> { + val timestamp = DateTimeUtils.parseTimestamp(typedString) + val precision = type.precision ?: 6 + val value = timestamp.toPrecision(precision) + timestampValue(value) + } + else -> error("Unsupported typed literal string: $this") + } + } + else -> error("Unsupported literal: $this") + } + } + /** * TODO PartiQLValue will be replaced by Datum (i.e. IonDatum) is a subsequent PR. */ @@ -386,8 +470,8 @@ internal object RexConverter { is PathStep.Element -> { val key = visitExprCoerce(curStep.element, context) val op = when (val astKey = curStep.element) { - is ExprLit -> when (astKey.value) { - is StringValue -> rexOpPathKey(curPathNavi, key) + is ExprLit -> when (astKey.lit) { + is LiteralString -> rexOpPathKey(curPathNavi, key) else -> rexOpPathIndex(curPathNavi, key) } is ExprCast -> when (astKey.asType.code() == DataType.STRING) { diff --git a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/util/DateTimeUtils.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/utils/DateTimeUtils.kt similarity index 98% rename from partiql-parser/src/main/kotlin/org/partiql/parser/internal/util/DateTimeUtils.kt rename to partiql-planner/src/main/kotlin/org/partiql/planner/internal/utils/DateTimeUtils.kt index 02fa77c48..1cd4dabc0 100644 --- a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/util/DateTimeUtils.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/utils/DateTimeUtils.kt @@ -1,4 +1,4 @@ -package org.partiql.parser.internal.util +package org.partiql.planner.internal.utils import org.partiql.value.datetime.Date import org.partiql.value.datetime.DateTimeException diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt index 7e9f7fee8..16518cf33 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt @@ -10,6 +10,8 @@ import org.partiql.ast.Ast.from import org.partiql.ast.Ast.fromExpr import org.partiql.ast.Ast.identifier import org.partiql.ast.Ast.identifierChain +import org.partiql.ast.Ast.literalInt +import org.partiql.ast.Ast.literalString import org.partiql.ast.Ast.queryBodySFW import org.partiql.ast.Ast.selectItemExpr import org.partiql.ast.Ast.selectList @@ -18,9 +20,6 @@ import org.partiql.ast.FromType import org.partiql.ast.SelectItem import org.partiql.ast.expr.Expr import org.partiql.ast.expr.Scope -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.int32Value -import org.partiql.value.stringValue import kotlin.test.assertEquals class NormalizeSelectTest { @@ -166,7 +165,6 @@ class NormalizeSelectTest { orderBy = null ) - @OptIn(PartiQLValueExperimental::class) private fun selectValue(vararg items: Pair) = exprQuerySet( body = queryBodySFW( @@ -174,7 +172,7 @@ class NormalizeSelectTest { constructor = exprStruct( items.map { exprStructField( - name = exprLit(stringValue(it.first)), + name = exprLit(literalString(it.first)), value = it.second ) } @@ -221,6 +219,5 @@ class NormalizeSelectTest { asAlias = asAlias?.let { identifier(asAlias, isDelimited = false) } ) - @OptIn(PartiQLValueExperimental::class) - private fun lit(value: Int) = exprLit(int32Value(value)) + private fun lit(value: Int) = exprLit(literalInt(value)) }