Skip to content

Commit 664a9f4

Browse files
committed
Squashed commit of the following:
commit 895692e Author: R. C. Howell <[email protected]> Date: Thu Dec 15 13:32:52 2022 -0800 Prepares 0.9.1-SNAPSHOT (#934) commit 692d442 Author: R. C. Howell <[email protected]> Date: Thu Dec 15 11:09:39 2022 -0800 Prepares 0.9.0 release (#932) Co-authored-by: lziq <[email protected]> commit f7f41fb Author: R. C. Howell <[email protected]> Date: Thu Dec 15 11:09:14 2022 -0800 Revert "Marks GPML and WINDOW AST nodes as Experimental (#923)" (#933) This reverts commit f605f2b. commit f605f2b Author: R. C. Howell <[email protected]> Date: Wed Dec 14 15:30:47 2022 -0800 Marks GPML and WINDOW AST nodes as Experimental (#923) * Marks GPML and WINDOW AST nodes as Experimental * Marks window_expression as experimental commit 94f6435 Author: lziq <[email protected]> Date: Wed Dec 14 10:43:54 2022 -0800 Change `IonValue` & `ExprValue` conversion API (#931) commit 07b3845 Author: R. C. Howell <[email protected]> Date: Tue Dec 13 13:56:21 2022 -0800 Adds 0.9 migration guide (#930)
1 parent 2ab30bc commit 664a9f4

File tree

11 files changed

+199
-113
lines changed

11 files changed

+199
-113
lines changed

CHANGELOG.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323

2424
## [Unreleased]
2525

26+
### Added
27+
28+
### Changed
29+
30+
### Deprecated
31+
32+
### Fixed
33+
34+
### Removed
35+
36+
### Security
37+
38+
## [0.9.0] - 2022-12-13
39+
2640
### Added
2741
- Adds simple auto-completion to the CLI.
2842
- Adds the IsListParenthesizedMeta meta to aid in differentiating between parenthesized and non-parenthesized lists
@@ -35,7 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3549
- Adds continuous performance benchmarking to the CI for existing JMH benchmarks
3650
- Benchmark results can be seen on the project's GitHub Pages site
3751
- Adds the `pipeline` flag to the CLI to provide experimental usage of the PartiQLCompilerPipeline
38-
- Added `ExprValue.toIonValue(ion: IonSystem)` in kotlin, and `ExprValueKt.toIonValue(value: ExprValue, ion: IonSystem)` in Java to transform one `ExprValue` to a corresponding `IonValue`.
52+
- Added `ExprValue.toIonValue(ion: IonSystem)` in kotlin, and `ExprValueExtensionKt.toIonValue(value: ExprValue, ion: IonSystem)` in Java to transform one `ExprValue` to a corresponding `IonValue`.
53+
- Added `ExprValue.of(value: IonValue)` method to construct an `ExprValue` from an `IonValue`.
3954

4055
### Changed
4156
- Now `CompileOption` uses `TypedOpParameter.HONOR_PARAMETERS` as default.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ This project is published to [Maven Central](https://search.maven.org/artifact/o
3131

3232
| Group ID | Artifact ID | Recommended Version |
3333
|---------------|-----------------------|---------------------|
34-
| `org.partiql` | `partiql-lang-kotlin` | `0.8.2` |
34+
| `org.partiql` | `partiql-lang-kotlin` | `0.9.0` |
3535

3636

3737
For Maven builds, add the following to your `pom.xml`:

docs/upgrades/v0.8-to-v0.9-upgrade.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# v0.9.x
2+
3+
## New features
4+
* Adds simple auto-completion to the CLI.
5+
* Adds the IsListParenthesizedMeta meta to aid in differentiating between parenthesized and non*parenthesized lists
6+
* Adds support for HAVING clause in planner
7+
* Adds support for collection aggregation functions in the EvaluatingCompiler and experimental planner
8+
* Adds support for the syntactic sugar of using aggregations functions in place of their collection aggregation function
9+
counterparts (in the experimental planner)
10+
* Experimental implementation for window function `Lag` and `Lead`.
11+
* Adds support for EXPLAIN
12+
* Adds continuous performance benchmarking to the CI for existing JMH benchmarks
13+
* Benchmark results can be seen on the project's GitHub Pages site
14+
* Adds the `pipeline` flag to the CLI to provide experimental usage of the PartiQLCompilerPipeline
15+
* Added `ExprValue.toIonValue(ion: IonSystem)` in kotlin, and `ExprValueKt.toIonValue(value: ExprValue, ion: IonSystem)` in Java to transform one `ExprValue` to a corresponding `IonValue`.
16+
17+
## Deprecated items
18+
* Marks the GroupKeyReferencesVisitorTransform as deprecated. There is no functionally equivalent class.
19+
* Marks `ionValue` property in `ExprValue` interface as deprecated. The functional equivalent method is `ExprValue.toIonValue(ion: IonSystem)` in kotlin, and `ExprValueKt.toIonValue(value: ExprValue, ion: IonSystem)` in Java.
20+
* Marks `Lexer`, `Token`, `TokenType`, `SourcePosition`, and `SourceSpan` as deprecated. These will be removed without
21+
any replacement.
22+
* Marks approximately 60 `ErrorCode`'s as deprecated. These will be removed without any replacement.
23+
* Marks `Property.TOKEN_TYPE` as deprecated. Please use `Property.TOKEN_DESCRIPTION`.
24+
25+
## Misc/bug fixes
26+
* Fixes the ThreadInterruptedTests by modifying the time to interrupt parses. Also adds better exception exposure to
27+
facilitate debugging.
28+
29+
## Breaking changes
30+
31+
### Breaking behavioral changes
32+
33+
N/A
34+
35+
### Breaking API changes
36+
* Removes the deprecated V0 AST in the codebase.
37+
* Removes the deprecated MetaContainer in the codebase, removed interfaces and classes include:
38+
* [MetaContainer] Interface
39+
* [MetaContainerImpl]
40+
* [MetaDeserialize]
41+
* [MemoizedMetaDeserializer]
42+
* Removes the deprecated Rewriter/AstWalker/AstVisitor in the code base, removed interfaces and classes include:
43+
* [AstRewriter] Interface & [AstRewriterBase] class
44+
* [AstVisitor] Interface & [AstVisitorBase] class
45+
* [AstWalker] class
46+
* [MetaStrippingRewriter] class
47+
* Removes the deprecated ExprNode and related files in the code base.
48+
* [Parser] API `parseExprNode(source: String): ExprNode` has been removed.
49+
* [CompilerPipeline] API `compile(query: ExprNode): Expression` has been removed.
50+
* [ExprNode] and [AstNode] have been removed.
51+
* Functions related to conversions between ExprNode and PartiqlAst have been removed.
52+
* Removes the deprecated SqlParser and SqlLexer
53+
* Removes the `CallAgg` node from the Logical, LogicalResolved, and Physical plans.
54+
* Removes the experimental `PlannerPipeline` and replaces it with `PartiQLCompilerPipeline`.

examples/src/main/java/org/partiql/examples/S3JavaExample.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import org.partiql.lang.eval.Bindings;
3232
import org.partiql.lang.eval.EvaluationSession;
3333
import org.partiql.lang.eval.ExprValue;
34-
import org.partiql.lang.eval.ExprValueKt;
34+
import org.partiql.lang.eval.ExprValueExtensionsKt;
3535
import org.partiql.lang.eval.Expression;
3636

3737
import java.io.IOException;
@@ -106,7 +106,7 @@ public void run() {
106106

107107
// Uses ion-java to dump the result as JSON. It's possible to build your own writer and dump the ExprValue
108108
// as any format you want.
109-
ExprValueKt.toIonValue(selectAndFilterResult, ion).writeTo(resultWriter);
109+
ExprValueExtensionsKt.toIonValue(selectAndFilterResult, ion).writeTo(resultWriter);
110110
// result as JSON below
111111
// [{"name":"person_2"},{"name":"person_3","address":{"number":555,"street":"1st street","city":"Seattle"}}]
112112
} catch (IOException e) {

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group=org.partiql
2-
version=0.8.2-SNAPSHOT
2+
version=0.9.1-SNAPSHOT
33

44
ossrhUsername=EMPTY
55
ossrhPassword=EMPTY

lang/src/main/kotlin/org/partiql/lang/eval/ExprValue.kt

Lines changed: 57 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ import com.amazon.ion.IonSexp
2525
import com.amazon.ion.IonString
2626
import com.amazon.ion.IonStruct
2727
import com.amazon.ion.IonSymbol
28-
import com.amazon.ion.IonSystem
2928
import com.amazon.ion.IonTimestamp
30-
import com.amazon.ion.IonType
3129
import com.amazon.ion.IonValue
32-
import com.amazon.ion.Timestamp
3330
import com.amazon.ion.facet.Faceted
3431
import org.partiql.lang.eval.time.NANOS_PER_SECOND
3532
import org.partiql.lang.eval.time.Time
@@ -43,6 +40,15 @@ interface ExprValue : Iterable<ExprValue>, Faceted {
4340
/** The type of value independent of its implementation. */
4441
val type: ExprValueType
4542

43+
/**
44+
* Materializes the expression value as an [IonValue].
45+
*
46+
* The returned value may or may not be tethered to a container, so it is
47+
* the callers responsibility to deal with that accordingly (e.g. via `clone`).
48+
*/
49+
@Deprecated("Please use [ExprValue.toIonValue()] to transform [ExprValue] to [IonValue]")
50+
val ionValue: IonValue
51+
4652
/** Returns the [Scalar] view of this value. */
4753
val scalar: Scalar
4854

@@ -68,111 +74,60 @@ interface ExprValue : Iterable<ExprValue>, Faceted {
6874
* If this value has no children, then it should return the empty iterator.
6975
*/
7076
override operator fun iterator(): Iterator<ExprValue>
71-
}
7277

73-
/**
74-
* This method should only be used in case we want to get result from querying an Ion file or an [IonValue]
75-
*/
76-
fun ExprValue.toIonValue(ion: IonSystem): IonValue =
77-
when (type) {
78-
ExprValueType.NULL -> ion.newNull(asFacet(IonType::class.java))
79-
ExprValueType.MISSING -> ion.newNull().apply { addTypeAnnotation(MISSING_ANNOTATION) }
80-
ExprValueType.BOOL -> ion.newBool(booleanValue())
81-
ExprValueType.INT -> ion.newInt(longValue())
82-
ExprValueType.FLOAT -> ion.newFloat(numberValue().toDouble())
83-
ExprValueType.DECIMAL -> ion.newDecimal(bigDecimalValue())
84-
ExprValueType.DATE -> {
85-
val value = dateValue()
86-
ion.newTimestamp(Timestamp.forDay(value.year, value.monthValue, value.dayOfMonth)).apply {
87-
addTypeAnnotation(DATE_ANNOTATION)
78+
companion object {
79+
@JvmStatic
80+
fun of(value: IonValue): ExprValue {
81+
val valueFactory = ExprValueFactory.standard(value.system)
82+
return when {
83+
value.isNullValue && value.hasTypeAnnotation(MISSING_ANNOTATION) -> valueFactory.missingValue // MISSING
84+
value.isNullValue -> NullExprValue(value.system, value.type) // NULL
85+
value is IonBool -> valueFactory.newBoolean(value.booleanValue()) // BOOL
86+
value is IonInt -> valueFactory.newInt(value.longValue()) // INT
87+
value is IonFloat -> valueFactory.newFloat(value.doubleValue()) // FLOAT
88+
value is IonDecimal -> valueFactory.newDecimal(value.decimalValue()) // DECIMAL
89+
value is IonTimestamp && value.hasTypeAnnotation(DATE_ANNOTATION) -> {
90+
val timestampValue = value.timestampValue()
91+
valueFactory.newDate(timestampValue.year, timestampValue.month, timestampValue.day)
92+
} // DATE
93+
value is IonTimestamp -> valueFactory.newTimestamp(value.timestampValue()) // TIMESTAMP
94+
value is IonStruct && value.hasTypeAnnotation(TIME_ANNOTATION) -> {
95+
val hourValue = (value["hour"] as IonInt).intValue()
96+
val minuteValue = (value["minute"] as IonInt).intValue()
97+
val secondInDecimal = (value["second"] as IonDecimal).decimalValue()
98+
val secondValue = secondInDecimal.toInt()
99+
val nanoValue = secondInDecimal.remainder(BigDecimal.ONE).multiply(NANOS_PER_SECOND.toBigDecimal()).toInt()
100+
val timeZoneHourValue = (value["timezone_hour"] as IonInt).intValue()
101+
val timeZoneMinuteValue = (value["timezone_minute"] as IonInt).intValue()
102+
valueFactory.newTime(Time.of(hourValue, minuteValue, secondValue, nanoValue, secondInDecimal.scale(), timeZoneHourValue * 60 + timeZoneMinuteValue))
103+
} // TIME
104+
value is IonSymbol -> valueFactory.newSymbol(value.stringValue()) // SYMBOL
105+
value is IonString -> valueFactory.newString(value.stringValue()) // STRING
106+
value is IonClob -> valueFactory.newClob(value.bytesValue()) // CLOB
107+
value is IonBlob -> valueFactory.newBlob(value.bytesValue()) // BLOB
108+
value is IonList && value.hasTypeAnnotation(BAG_ANNOTATION) -> valueFactory.newBag(value.map { of(it) }) // BAG
109+
value is IonList -> valueFactory.newList(value.map { of(it) }) // LIST
110+
value is IonSexp -> valueFactory.newSexp(value.map { of(it) }) // SEXP
111+
value is IonStruct -> IonStructExprValue(valueFactory, value) // STRUCT
112+
else -> error("Unrecognized IonValue to transform to ExprValue: $value")
88113
}
89114
}
90-
ExprValueType.TIMESTAMP -> ion.newTimestamp(timestampValue())
91-
ExprValueType.TIME -> timeValue().toIonValue(ion)
92-
ExprValueType.SYMBOL -> ion.newSymbol(stringValue())
93-
ExprValueType.STRING -> ion.newString(stringValue())
94-
ExprValueType.CLOB -> ion.newClob(bytesValue())
95-
ExprValueType.BLOB -> ion.newBlob(bytesValue())
96-
ExprValueType.LIST -> mapTo(ion.newEmptyList()) {
97-
if (it is StructExprValue)
98-
it.toIonStruct(ion)
99-
else
100-
it.toIonValue(ion).clone()
101-
}
102-
ExprValueType.SEXP -> mapTo(ion.newEmptySexp()) {
103-
if (it is StructExprValue)
104-
it.toIonStruct(ion)
105-
else
106-
it.toIonValue(ion).clone()
107-
}
108-
ExprValueType.BAG -> mapTo(
109-
ion.newEmptyList().apply { addTypeAnnotation(BAG_ANNOTATION) }
110-
) {
111-
if (it is StructExprValue)
112-
it.toIonStruct(ion)
113-
else
114-
it.toIonValue(ion).clone()
115-
}
116-
ExprValueType.STRUCT -> toIonStruct(ion)
117115
}
118116

119-
private fun ExprValue.toIonStruct(ion: IonSystem): IonStruct {
120-
return ion.newEmptyStruct().apply {
121-
this@toIonStruct.forEach {
122-
val nameVal = it.name
123-
if (nameVal != null && nameVal.type.isText && it.type != ExprValueType.MISSING) {
124-
val name = nameVal.stringValue()
125-
add(name, it.toIonValue(ion).clone())
126-
}
117+
private class IonStructExprValue(
118+
valueFactory: ExprValueFactory,
119+
private val ionStruct: IonStruct
120+
) : StructExprValue(
121+
valueFactory.ion,
122+
StructOrdering.UNORDERED,
123+
ionStruct.asSequence().map {
124+
of(it).namedValue(valueFactory.newString(it.fieldName))
127125
}
128-
}
129-
}
130-
131-
fun IonValue.toExprValue(): ExprValue {
132-
val valueFactory = ExprValueFactory.standard(system)
133-
return when {
134-
isNullValue && hasTypeAnnotation(MISSING_ANNOTATION) -> valueFactory.missingValue // MISSING
135-
isNullValue -> NullExprValue(type) // NULL
136-
this is IonBool -> valueFactory.newBoolean(booleanValue()) // BOOL
137-
this is IonInt -> valueFactory.newInt(longValue()) // INT
138-
this is IonFloat -> valueFactory.newFloat(doubleValue()) // FLOAT
139-
this is IonDecimal -> valueFactory.newDecimal(decimalValue()) // DECIMAL
140-
this is IonTimestamp && hasTypeAnnotation(DATE_ANNOTATION) -> {
141-
val timestampValue = timestampValue()
142-
valueFactory.newDate(timestampValue.year, timestampValue.month, timestampValue.day)
143-
} // DATE
144-
this is IonTimestamp -> valueFactory.newTimestamp(timestampValue()) // TIMESTAMP
145-
this is IonStruct && hasTypeAnnotation(TIME_ANNOTATION) -> {
146-
val hourValue = (this["hour"] as IonInt).intValue()
147-
val minuteValue = (this["minute"] as IonInt).intValue()
148-
val secondInDecimal = (this["second"] as IonDecimal).decimalValue()
149-
val secondValue = secondInDecimal.toInt()
150-
val nanoValue = secondInDecimal.remainder(BigDecimal.ONE).multiply(NANOS_PER_SECOND.toBigDecimal()).toInt()
151-
val timeZoneHourValue = (this["timezone_hour"] as IonInt).intValue()
152-
val timeZoneMinuteValue = (this["timezone_minute"] as IonInt).intValue()
153-
valueFactory.newTime(Time.of(hourValue, minuteValue, secondValue, nanoValue, secondInDecimal.scale(), timeZoneHourValue * 60 + timeZoneMinuteValue))
154-
} // TIME
155-
this is IonSymbol -> valueFactory.newSymbol(stringValue()) // SYMBOL
156-
this is IonString -> valueFactory.newString(stringValue()) // STRING
157-
this is IonClob -> valueFactory.newClob(bytesValue()) // CLOB
158-
this is IonBlob -> valueFactory.newBlob(bytesValue()) // BLOB
159-
this is IonList && hasTypeAnnotation(BAG_ANNOTATION) -> valueFactory.newBag(map { it.toExprValue() }) // BAG
160-
this is IonList -> valueFactory.newList(map { it.toExprValue() }) // LIST
161-
this is IonSexp -> valueFactory.newSexp(map { it.toExprValue() }) // SEXP
162-
this is IonStruct -> IonStructExprValue(valueFactory, this) // STRUCT
163-
else -> error("Unrecognized IonValue to transform to ExprValue: $this")
164-
}
165-
}
126+
) {
127+
override val bindings: Bindings<ExprValue> =
128+
IonStructBindings(valueFactory, ionStruct)
166129

167-
private class IonStructExprValue(
168-
valueFactory: ExprValueFactory,
169-
private val ionStruct: IonStruct
170-
) : StructExprValue(
171-
StructOrdering.UNORDERED,
172-
ionStruct.asSequence().map {
173-
it.toExprValue().namedValue(valueFactory.newString(it.fieldName))
130+
override val ionValue: IonValue
131+
get() = ionStruct
174132
}
175-
) {
176-
override val bindings: Bindings<ExprValue> =
177-
IonStructBindings(valueFactory, ionStruct)
178133
}

lang/src/main/kotlin/org/partiql/lang/eval/ExprValueExtensions.kt

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ package org.partiql.lang.eval
1616

1717
import com.amazon.ion.IntegerSize
1818
import com.amazon.ion.IonInt
19+
import com.amazon.ion.IonStruct
20+
import com.amazon.ion.IonSystem
21+
import com.amazon.ion.IonType
22+
import com.amazon.ion.IonValue
1923
import com.amazon.ion.Timestamp
2024
import org.partiql.lang.ast.SourceLocationMeta
2125
import org.partiql.lang.errors.ErrorCode
@@ -720,3 +724,61 @@ fun Sequence<ExprValue>.multiplicities(): TreeMap<ExprValue, Int> {
720724
}
721725
return multiplicities
722726
}
727+
728+
/**
729+
* This method should only be used in case we want to get result from querying an Ion file or an [IonValue]
730+
*/
731+
fun ExprValue.toIonValue(ion: IonSystem): IonValue =
732+
when (type) {
733+
ExprValueType.NULL -> ion.newNull(asFacet(IonType::class.java))
734+
ExprValueType.MISSING -> ion.newNull().apply { addTypeAnnotation(MISSING_ANNOTATION) }
735+
ExprValueType.BOOL -> ion.newBool(booleanValue())
736+
ExprValueType.INT -> ion.newInt(longValue())
737+
ExprValueType.FLOAT -> ion.newFloat(numberValue().toDouble())
738+
ExprValueType.DECIMAL -> ion.newDecimal(bigDecimalValue())
739+
ExprValueType.DATE -> {
740+
val value = dateValue()
741+
ion.newTimestamp(Timestamp.forDay(value.year, value.monthValue, value.dayOfMonth)).apply {
742+
addTypeAnnotation(DATE_ANNOTATION)
743+
}
744+
}
745+
ExprValueType.TIMESTAMP -> ion.newTimestamp(timestampValue())
746+
ExprValueType.TIME -> timeValue().toIonValue(ion)
747+
ExprValueType.SYMBOL -> ion.newSymbol(stringValue())
748+
ExprValueType.STRING -> ion.newString(stringValue())
749+
ExprValueType.CLOB -> ion.newClob(bytesValue())
750+
ExprValueType.BLOB -> ion.newBlob(bytesValue())
751+
ExprValueType.LIST -> mapTo(ion.newEmptyList()) {
752+
if (it is StructExprValue)
753+
it.toIonStruct(ion)
754+
else
755+
it.toIonValue(ion).clone()
756+
}
757+
ExprValueType.SEXP -> mapTo(ion.newEmptySexp()) {
758+
if (it is StructExprValue)
759+
it.toIonStruct(ion)
760+
else
761+
it.toIonValue(ion).clone()
762+
}
763+
ExprValueType.BAG -> mapTo(
764+
ion.newEmptyList().apply { addTypeAnnotation(BAG_ANNOTATION) }
765+
) {
766+
if (it is StructExprValue)
767+
it.toIonStruct(ion)
768+
else
769+
it.toIonValue(ion).clone()
770+
}
771+
ExprValueType.STRUCT -> toIonStruct(ion)
772+
}
773+
774+
private fun ExprValue.toIonStruct(ion: IonSystem): IonStruct {
775+
return ion.newEmptyStruct().apply {
776+
this@toIonStruct.forEach {
777+
val nameVal = it.name
778+
if (nameVal != null && nameVal.type.isText && it.type != ExprValueType.MISSING) {
779+
val name = nameVal.stringValue()
780+
add(name, it.toIonValue(ion).clone())
781+
}
782+
}
783+
}
784+
}

lang/src/main/kotlin/org/partiql/lang/eval/ExprValueFactory.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ private class ExprValueFactoryImpl(override val ion: IonSystem) : ExprValueFacto
234234
BlobExprValue(value)
235235

236236
override fun newFromIonValue(value: IonValue): ExprValue =
237-
value.toExprValue()
237+
ExprValue.of(value)
238238

239239
override fun newFromIonReader(reader: IonReader): ExprValue =
240240
newFromIonValue(ion.newValue(reader))

lang/src/main/kotlin/org/partiql/lang/eval/IonStructBindings.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@ internal class IonStructBindings(private val valueFactory: ExprValueFactory, pri
6767
BindingCase.SENSITIVE -> caseSensitiveLookup(bindingName.name)
6868
BindingCase.INSENSITIVE -> caseInsensitiveLookup(bindingName.name)
6969
}?.let {
70-
it.toExprValue().namedValue(valueFactory.newString(it.fieldName))
70+
ExprValue.of(it).namedValue(valueFactory.newString(it.fieldName))
7171
}
7272
}

0 commit comments

Comments
 (0)