Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v1] Remove PartiQLValue from AST; refactor AST literals #1650

Merged
merged 7 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions partiql-ast/api/partiql-ast.api
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,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;)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;
Expand Down Expand Up @@ -233,6 +233,8 @@ public abstract class org/partiql/ast/AstRewriter : org/partiql/ast/AstVisitor {
public fun visitLet (Lorg/partiql/ast/Let;Ljava/lang/Object;)Lorg/partiql/ast/AstNode;
public synthetic fun visitLetBinding (Lorg/partiql/ast/Let$Binding;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitLetBinding (Lorg/partiql/ast/Let$Binding;Ljava/lang/Object;)Lorg/partiql/ast/AstNode;
public synthetic fun visitLiteral (Lorg/partiql/ast/Literal;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitLiteral (Lorg/partiql/ast/Literal;Ljava/lang/Object;)Lorg/partiql/ast/AstNode;
public synthetic fun visitPathStepAllElements (Lorg/partiql/ast/expr/PathStep$AllElements;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitPathStepAllElements (Lorg/partiql/ast/expr/PathStep$AllElements;Ljava/lang/Object;)Lorg/partiql/ast/AstNode;
public synthetic fun visitPathStepAllFields (Lorg/partiql/ast/expr/PathStep$AllFields;Ljava/lang/Object;)Ljava/lang/Object;
Expand Down Expand Up @@ -348,6 +350,7 @@ public abstract class org/partiql/ast/AstVisitor {
public fun visitKeyValue (Lorg/partiql/ast/ddl/KeyValue;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitLet (Lorg/partiql/ast/Let;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitLetBinding (Lorg/partiql/ast/Let$Binding;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitLiteral (Lorg/partiql/ast/Literal;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitNullable (Lorg/partiql/ast/ddl/AttributeConstraint$Null;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitOrderBy (Lorg/partiql/ast/OrderBy;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitPartitionBy (Lorg/partiql/ast/ddl/PartitionBy;Ljava/lang/Object;)Ljava/lang/Object;
Expand Down Expand Up @@ -929,6 +932,42 @@ public class org/partiql/ast/Let$Builder {
public fun toString ()Ljava/lang/String;
}

public class org/partiql/ast/Literal : org/partiql/ast/AstEnum {
public static final field APPROX_NUM I
public static final field BOOL I
public static final field EXACT_NUM I
public static final field INT_NUM I
public static final field MISSING I
public static final field NULL I
public static final field STRING I
public static final field TYPED_STRING I
public static final field UNKNOWN I
public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object;
public static fun approxNum (Ljava/lang/String;)Lorg/partiql/ast/Literal;
public fun bigDecimalValue ()Ljava/math/BigDecimal;
public static fun bool (Z)Lorg/partiql/ast/Literal;
public fun booleanValue ()Z
protected fun canEqual (Ljava/lang/Object;)Z
public fun children ()Ljava/util/Collection;
public fun code ()I
public fun dataType ()Lorg/partiql/ast/DataType;
public fun equals (Ljava/lang/Object;)Z
public static fun exactNum (Ljava/lang/String;)Lorg/partiql/ast/Literal;
public static fun exactNum (Ljava/math/BigDecimal;)Lorg/partiql/ast/Literal;
public fun hashCode ()I
public static fun intNum (I)Lorg/partiql/ast/Literal;
public static fun intNum (J)Lorg/partiql/ast/Literal;
public static fun intNum (Ljava/lang/String;)Lorg/partiql/ast/Literal;
public static fun intNum (Ljava/math/BigInteger;)Lorg/partiql/ast/Literal;
public static fun missing ()Lorg/partiql/ast/Literal;
public fun name ()Ljava/lang/String;
public static fun nul ()Lorg/partiql/ast/Literal;
public fun numberValue ()Ljava/lang/String;
public static fun string (Ljava/lang/String;)Lorg/partiql/ast/Literal;
public fun stringValue ()Ljava/lang/String;
public static fun typedString (Lorg/partiql/ast/DataType;Ljava/lang/String;)Lorg/partiql/ast/Literal;
}

public class org/partiql/ast/Nulls : org/partiql/ast/AstEnum {
public static final field FIRST I
public static final field LAST I
Expand Down Expand Up @@ -1657,22 +1696,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 <init> (Lorg/partiql/value/PartiQLValue;)V
public field lit Lorg/partiql/ast/Literal;
public fun <init> (Lorg/partiql/ast/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;
Expand Down
4 changes: 0 additions & 4 deletions partiql-ast/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Comment on lines -23 to -26
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(self-review) partiql-ast now will not depend on other packages. Had to add the spi dependency to partiql-parser following this change

compileOnly(Deps.lombok)
annotationProcessor(Deps.lombok)
}
Expand Down
4 changes: 4 additions & 0 deletions partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ public R visitExprWindowOver(ExprWindow.Over node, C ctx) {
return defaultVisit(node, ctx);
}

public R visitLiteral(Literal node, C ctx) {
return defaultVisit(node, ctx);
}

public R visitQueryBody(QueryBody node, C ctx) {
return node.accept(this, ctx);
}
Expand Down
6 changes: 2 additions & 4 deletions partiql-ast/src/main/java/org/partiql/ast/Explain.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import lombok.Builder;
import lombok.EqualsAndHashCode;
import org.jetbrains.annotations.NotNull;
import org.partiql.value.PartiQLValue;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -16,14 +15,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<String, PartiQLValue> options;
public final Map<String, Literal> options;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(self-review) model the EXPLAIN option map values w/ a Literal directly. Could also opt for ExprLit but wasn't sure

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Literal makes sense


@NotNull
public final Statement statement;

public Explain(@NotNull Map<String, PartiQLValue> options, @NotNull Statement statement) {
public Explain(@NotNull Map<String, Literal> options, @NotNull Statement statement) {
this.options = options;
this.statement = statement;
}
Expand Down
254 changes: 254 additions & 0 deletions partiql-ast/src/main/java/org/partiql/ast/Literal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
package org.partiql.ast;

import lombok.EqualsAndHashCode;
import org.jetbrains.annotations.NotNull;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Collections;

import static java.util.Objects.requireNonNull;

/**
* TODO docs
*/
@EqualsAndHashCode(callSuper = false)
public class Literal extends AstEnum {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modeling looks good to me; very concise union and easy to extend if needed.

public static final int UNKNOWN = 0;
// absent literals
public static final int NULL = 1;
public static final int MISSING = 2;
// boolean literal
public static final int BOOL = 3;
// numeric literals
public static final int APPROX_NUM = 4;
public static final int EXACT_NUM = 5;
public static final int INT_NUM = 6;
// string literal
public static final int STRING = 7;
// typed string literal
public static final int TYPED_STRING = 8;

// Literal fields
private final int code;
private final Boolean boolValue;
private final String stringValue;
private final DataType dataType;

/////// Constructors
private Literal(int code, Boolean value, String stringValue, DataType dataType) {
this.code = code;
this.boolValue = value;
this.stringValue = stringValue;
this.dataType = dataType;
}

// Private constructor for absent literals
private Literal(int code) {
this.code = code;
// Rest set to null
this.boolValue = null;
this.stringValue = null;
this.dataType = null;
}

// Private constructor for boolean literal
private Literal(boolean value) {
this.code = BOOL;
this.boolValue = value;
// Rest set to null
this.stringValue = null;
this.dataType = null;
}

// Private constructor for literals stored w/ just a string (e.g. numerics, single-quoted strings)
private Literal(int code, String value) {
this.code = code;
this.stringValue = value;
// Rest set to null
this.boolValue = null;
this.dataType = null;
}

// Private constructor for typed string literal
private Literal(DataType dataType, String value) {
this.code = TYPED_STRING;
this.stringValue = value;
this.dataType = dataType;
// Rest set to null
this.boolValue = null;
}

@Override
public int code() {
return code;
}

@NotNull
@Override
public String name() {
switch (code) {
case NULL: return "NULL";
case MISSING: return "MISSING";
case BOOL: return "BOOL";
case APPROX_NUM: return "APPROX_NUM";
case EXACT_NUM: return "EXACT_NUM";
case INT_NUM: return "INT_NUM";
case STRING: return "STRING";
case TYPED_STRING: return "TYPED_STRING";
default: return "UNKNOWN";
}
}

@Override
@NotNull
public Collection<AstNode> children() {
return Collections.emptyList();
}

@Override
public <R, C> R accept(@NotNull AstVisitor<R, C> visitor, C ctx) {
return visitor.visitLiteral(this, ctx);
}

// Factory methods
@NotNull
public static Literal approxNum(@NotNull String value) {
return new Literal(APPROX_NUM, value);
}

@NotNull
public static Literal bool(boolean value) {
return new Literal(value);
}

@NotNull
public static Literal exactNum(@NotNull BigDecimal value) {
if (value.scale() == 0) {
return new Literal(EXACT_NUM, value + ".");
} else {
return new Literal(EXACT_NUM, value.toString());
}
}

@NotNull
public static Literal exactNum(@NotNull String value) {
return new Literal(EXACT_NUM, value);
}

@NotNull
public static Literal intNum(int value) {
return new Literal(INT_NUM, Integer.toString(value));
}

@NotNull
public static Literal intNum(long value) {
return new Literal(INT_NUM, Long.toString(value));
}

@NotNull
public static Literal intNum(@NotNull BigInteger value) {
return new Literal(INT_NUM, value.toString());
}

@NotNull
public static Literal intNum(@NotNull String value) {
return new Literal(INT_NUM, value);
}

@NotNull
public static Literal nul() {
return new Literal(NULL);
}

@NotNull
public static Literal missing() {
return new Literal(MISSING);
}

@NotNull
public static Literal string(@NotNull String value) {
return new Literal(STRING, value);
}

@NotNull
public static Literal typedString(@NotNull DataType type, @NotNull String value) {
return new Literal(type, value);
}

// Value extraction
/**
* TODO docs
* Valid for just BOOL
*/
public boolean booleanValue() {
if (code == BOOL) {
requireNonNull(boolValue, "bool value");
return boolValue;
}
throw new UnsupportedOperationException();
}

/**
* TODO docs
* Valid for just APPROX_NUM, EXACT_NUM, and INT_NUM.
*/
@NotNull
public String numberValue() {
switch (code) {
case APPROX_NUM:
case EXACT_NUM:
case INT_NUM:
requireNonNull(stringValue, "string value for numerics");
return stringValue;
default:
throw new UnsupportedOperationException();
}
}

/**
* TODO docs
* Valid for just EXACT_NUM and INT_NUM
*/
@NotNull
public BigDecimal bigDecimalValue() {
switch (code) {
case EXACT_NUM:
case INT_NUM:
requireNonNull(stringValue, "string value for exact and int numerics");
return new BigDecimal(stringValue);
default:
throw new UnsupportedOperationException();
}
}

/**
* TODO docs
* Valid for just STRING and TYPED_STRING
*/
@NotNull
public String stringValue() {
switch (code) {
case STRING:
case TYPED_STRING:
requireNonNull(stringValue, "string value");
return stringValue;
default:
throw new UnsupportedOperationException();
}
}

/**
* TODO docs
* Valid for just TYPED_STRING
*/
@NotNull
public DataType dataType() {
if (code == TYPED_STRING) {
requireNonNull(dataType, "data type");
return dataType;
}
throw new UnsupportedOperationException();
}
}
Loading
Loading