diff --git a/CHANGELOG.md b/CHANGELOG.md index dddddd2c41..1172bba0a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ Thank you to all who have contributed! ## [Unreleased] ### Added +- Adds `org.partiql.value` (experimental) package for reading/writing PartiQL + values ### Changed @@ -42,6 +44,7 @@ Thank you to all who have contributed! ### Contributors Thank you to all who have contributed! +- @howero - @ ## [0.12.0] - 2023-06-14 diff --git a/buildSrc/src/main/kotlin/partiql.versions.kt b/buildSrc/src/main/kotlin/partiql.versions.kt index 611e86e260..19a37c4ece 100644 --- a/buildSrc/src/main/kotlin/partiql.versions.kt +++ b/buildSrc/src/main/kotlin/partiql.versions.kt @@ -38,6 +38,7 @@ object Versions { const val jmh = "0.5.3" const val joda = "2.12.1" const val kotlinPoet = "1.11.0" + const val kotlinxCollections = "0.3.5" const val picoCli = "4.7.0" const val kasechange = "1.3.0" const val ktlint = "10.2.1" @@ -76,6 +77,7 @@ object Deps { const val joda = "joda-time:joda-time:${Versions.joda}" const val kasechange = "net.pearx.kasechange:kasechange:${Versions.kasechange}" const val kotlinPoet = "com.squareup:kotlinpoet:${Versions.kotlinPoet}" + const val kotlinxCollections = "org.jetbrains.kotlinx:kotlinx-collections-immutable:${Versions.kotlinxCollections}" const val picoCli = "info.picocli:picocli:${Versions.picoCli}" const val pig = "org.partiql:partiql-ir-generator:${Versions.pig}" const val pigRuntime = "org.partiql:partiql-ir-generator-runtime:${Versions.pig}" diff --git a/partiql-types/build.gradle.kts b/partiql-types/build.gradle.kts index 4bc426ec27..b7559baacf 100644 --- a/partiql-types/build.gradle.kts +++ b/partiql-types/build.gradle.kts @@ -20,6 +20,7 @@ plugins { dependencies { implementation(Deps.ionElement) + implementation(Deps.kotlinxCollections) } publish { diff --git a/partiql-types/src/main/kotlin/org/partiql/types/PartiQLValueType.kt b/partiql-types/src/main/kotlin/org/partiql/types/PartiQLValueType.kt new file mode 100644 index 0000000000..d5da2aea0a --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/types/PartiQLValueType.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.types + +/** + * PartiQL Type Names + */ +public enum class PartiQLValueType { + BOOL, + INT8, + INT16, + INT32, + INT64, + INT, + DECIMAL, + FLOAT32, + FLOAT64, + CHAR, + STRING, + SYMBOL, + BINARY, + BYTE, + BLOB, + CLOB, + DATE, + TIME, + TIMESTAMP, + INTERVAL, + BAG, + LIST, + SEXP, + STRUCT, + NULL, // null.null + MISSING, // missing + NULLABLE_BOOL, // null.bool + NULLABLE_INT8, // null.int8 + NULLABLE_INT16, // null.int16 + NULLABLE_INT32, // null.int32 + NULLABLE_INT64, // null.int64 + NULLABLE_INT, // null.int + NULLABLE_DECIMAL, // null.decimal + NULLABLE_FLOAT32, // null.float32 + NULLABLE_FLOAT64, // null.float64 + NULLABLE_CHAR, // null.char + NULLABLE_STRING, // null.string + NULLABLE_SYMBOL, // null.symbol + NULLABLE_BINARY, // null.binary + NULLABLE_BYTE, // null.byte + NULLABLE_BLOB, // null.blob + NULLABLE_CLOB, // null.clob + NULLABLE_DATE, // null.date + NULLABLE_TIME, // null.time + NULLABLE_TIMESTAMP, // null.timestamp + NULLABLE_INTERVAL, // null.interval + NULLABLE_BAG, // null.bag + NULLABLE_LIST, // null.list + NULLABLE_SEXP, // null.sexp + NULLABLE_STRUCT, // null.struct +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/PartiQL.kt b/partiql-types/src/main/kotlin/org/partiql/value/PartiQL.kt new file mode 100644 index 0000000000..a04e94f226 --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/PartiQL.kt @@ -0,0 +1,819 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +// Not strictly necessary, but is explicit +@file: JvmName("PartiQL") + +package org.partiql.value + +import kotlinx.collections.immutable.toPersistentList +import org.partiql.value.impl.BagValueImpl +import org.partiql.value.impl.BinaryValueImpl +import org.partiql.value.impl.BlobValueImpl +import org.partiql.value.impl.BoolValueImpl +import org.partiql.value.impl.ByteValueImpl +import org.partiql.value.impl.CharValueImpl +import org.partiql.value.impl.ClobValueImpl +import org.partiql.value.impl.DateValueImpl +import org.partiql.value.impl.DecimalValueImpl +import org.partiql.value.impl.Float32ValueImpl +import org.partiql.value.impl.Float64ValueImpl +import org.partiql.value.impl.Int16ValueImpl +import org.partiql.value.impl.Int32ValueImpl +import org.partiql.value.impl.Int64ValueImpl +import org.partiql.value.impl.Int8ValueImpl +import org.partiql.value.impl.IntValueImpl +import org.partiql.value.impl.IntervalValueImpl +import org.partiql.value.impl.ListValueImpl +import org.partiql.value.impl.MissingValueImpl +import org.partiql.value.impl.NullValueImpl +import org.partiql.value.impl.NullableBagValueImpl +import org.partiql.value.impl.NullableBinaryValueImpl +import org.partiql.value.impl.NullableBlobValueImpl +import org.partiql.value.impl.NullableBoolValueImpl +import org.partiql.value.impl.NullableByteValueImpl +import org.partiql.value.impl.NullableCharValueImpl +import org.partiql.value.impl.NullableClobValueImpl +import org.partiql.value.impl.NullableDateValueImpl +import org.partiql.value.impl.NullableDecimalValueImpl +import org.partiql.value.impl.NullableFloat32ValueImpl +import org.partiql.value.impl.NullableFloat64ValueImpl +import org.partiql.value.impl.NullableInt16ValueImpl +import org.partiql.value.impl.NullableInt32ValueImpl +import org.partiql.value.impl.NullableInt64ValueImpl +import org.partiql.value.impl.NullableInt8ValueImpl +import org.partiql.value.impl.NullableIntValueImpl +import org.partiql.value.impl.NullableIntervalValueImpl +import org.partiql.value.impl.NullableListValueImpl +import org.partiql.value.impl.NullableSexpValueImpl +import org.partiql.value.impl.NullableStringValueImpl +import org.partiql.value.impl.NullableStructValueImpl +import org.partiql.value.impl.NullableSymbolValueImpl +import org.partiql.value.impl.NullableTimeValueImpl +import org.partiql.value.impl.NullableTimestampValueImpl +import org.partiql.value.impl.SexpValueImpl +import org.partiql.value.impl.StringValueImpl +import org.partiql.value.impl.StructValueImpl +import org.partiql.value.impl.SymbolValueImpl +import org.partiql.value.impl.TimeValueImpl +import org.partiql.value.impl.TimestampValueImpl +import java.math.BigDecimal +import java.math.BigInteger +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.ZoneOffset +import java.util.BitSet + +/** + * BOOL type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun boolValue( + value: Boolean, + annotations: Annotations = emptyList(), +): BoolValue = BoolValueImpl(value, annotations.toPersistentList()) + +/** + * INT8 type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun int8Value( + value: Byte, + annotations: Annotations = emptyList(), +): Int8Value = Int8ValueImpl(value, annotations.toPersistentList()) + +/** + * INT16 type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun int16Value( + value: Short, + annotations: Annotations = emptyList(), +): Int16Value = Int16ValueImpl(value, annotations.toPersistentList()) + +/** + * INT32 type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun int32Value( + value: Int, + annotations: Annotations = emptyList(), +): Int32Value = Int32ValueImpl(value, annotations.toPersistentList()) + +/** + * INT64 type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun int64Value( + value: Long, + annotations: Annotations = emptyList(), +): Int64Value = Int64ValueImpl(value, annotations.toPersistentList()) + +/** + * INT type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun intValue( + value: BigInteger, + annotations: Annotations = emptyList(), +): IntValue = IntValueImpl(value, annotations.toPersistentList()) + +/** + * DECIMAL type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun decimalValue( + value: BigDecimal, + annotations: Annotations = emptyList(), +): DecimalValue = DecimalValueImpl(value, annotations.toPersistentList()) + +/** + * FLOAT32 type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun float32Value( + value: Float, + annotations: Annotations = emptyList(), +): Float32Value = Float32ValueImpl(value, annotations.toPersistentList()) + +/** + * FLOAT64 type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun float64Value( + value: Double, + annotations: Annotations = emptyList(), +): Float64Value = Float64ValueImpl(value, annotations.toPersistentList()) + +/** + * CHAR type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun charValue( + value: Char, + annotations: Annotations = emptyList(), +): CharValue = CharValueImpl(value, annotations.toPersistentList()) + +/** + * STRING type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun stringValue( + value: String, + annotations: Annotations = emptyList(), +): StringValue = StringValueImpl(value, annotations.toPersistentList()) + +/** + * SYMBOL type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun symbolValue( + value: String, + annotations: Annotations = emptyList(), +): SymbolValue = SymbolValueImpl(value, annotations.toPersistentList()) + +/** + * CLOB type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun clobValue( + value: ByteArray, + annotations: Annotations = emptyList(), +): ClobValue = ClobValueImpl(value, annotations.toPersistentList()) + +/** + * BINARY type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun binaryValue( + value: BitSet, + annotations: Annotations = emptyList(), +): BinaryValue = BinaryValueImpl(value, annotations.toPersistentList()) + +/** + * BYTE type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun byteValue( + value: Byte, + annotations: Annotations = emptyList(), +): ByteValue = ByteValueImpl(value, annotations.toPersistentList()) + +/** + * BLOB type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun blobValue( + value: ByteArray, + annotations: Annotations = emptyList(), +): BlobValue = BlobValueImpl(value, annotations.toPersistentList()) + +/** + * DATE type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun dateValue( + value: LocalDate, + annotations: Annotations = emptyList(), +): DateValue = DateValueImpl(value, annotations.toPersistentList()) + +/** + * TIME type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun timeValue( + value: LocalTime, + precision: Int = 0, + offset: ZoneOffset? = null, + withZone: Boolean = false, + annotations: Annotations = emptyList(), +): TimeValue = TimeValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + +/** + * TIMESTAMP type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun timestampValue( + value: LocalDateTime, + precision: Int = 0, + offset: ZoneOffset? = null, + withZone: Boolean = false, + annotations: Annotations = emptyList(), +): TimestampValue = TimestampValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + +/** + * INTERVAL type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun intervalValue( + value: Long, + annotations: Annotations = emptyList(), +): IntervalValue = IntervalValueImpl(value, annotations.toPersistentList()) + +/** + * BAG type value. + * + * @param T + * @param elements + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun bagValue( + elements: List, + annotations: Annotations = emptyList(), +): BagValue = BagValueImpl(elements.toPersistentList(), annotations.toPersistentList()) + +/** + * LIST type value. + * + * @param T + * @param elements + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun listValue( + elements: List, + annotations: Annotations = emptyList(), +): ListValue = ListValueImpl(elements.toPersistentList(), annotations.toPersistentList()) + +/** + * SEXP type value. + * + * @param T + * @param elements + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun sexpValue( + elements: List, + annotations: Annotations = emptyList(), +): SexpValue = SexpValueImpl(elements.toPersistentList(), annotations.toPersistentList()) + +/** + * STRUCT type value. + * + * @param T + * @param fields + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun structValue( + fields: List>, + annotations: Annotations = emptyList(), +): StructValue = StructValueImpl(fields.toPersistentList(), annotations.toPersistentList()) + +/** + * NULL type value. + * + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullValue( + annotations: Annotations = emptyList(), +): NullValue = NullValueImpl(annotations.toPersistentList()) + +/** + * MISSING type value. + * + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun missingValue( + annotations: Annotations = emptyList(), +): MissingValue = MissingValueImpl(annotations.toPersistentList()) + +/** + * UNION(NULL, BOOL) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableBoolValue( + value: Boolean? = null, + annotations: Annotations = emptyList(), +): NullableBoolValue = NullableBoolValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, INT8) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableInt8Value( + value: Byte? = null, + annotations: Annotations = emptyList(), +): NullableInt8Value = NullableInt8ValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, INT8) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableInt16Value( + value: Short? = null, + annotations: Annotations = emptyList(), +): NullableInt16Value = NullableInt16ValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, INT16) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableInt32Value( + value: Int? = null, + annotations: Annotations = emptyList(), +): NullableInt32Value = NullableInt32ValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, INT64) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableInt64Value( + value: Long? = null, + annotations: Annotations = emptyList(), +): NullableInt64Value = NullableInt64ValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, INT) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableIntValue( + value: BigInteger? = null, + annotations: Annotations = emptyList(), +): NullableIntValue = NullableIntValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, DECIMAL) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableDecimalValue( + value: BigDecimal? = null, + annotations: Annotations = emptyList(), +): NullableDecimalValue = NullableDecimalValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, FLOAT32) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableFloat32Value( + value: Float? = null, + annotations: Annotations = emptyList(), +): NullableFloat32Value = NullableFloat32ValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, FLOAT64) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableFloat64Value( + value: Double? = null, + annotations: Annotations = emptyList(), +): NullableFloat64Value = NullableFloat64ValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, CHAR) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableCharValue( + value: Char? = null, + annotations: Annotations = emptyList(), +): NullableCharValue = NullableCharValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, STRING) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableStringValue( + value: String? = null, + annotations: Annotations = emptyList(), +): NullableStringValue = NullableStringValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, SYMBOL) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableSymbolValue( + value: String? = null, + annotations: Annotations = emptyList(), +): NullableSymbolValue = NullableSymbolValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, CLOB) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableClobValue( + value: ByteArray? = null, + annotations: Annotations = emptyList(), +): NullableClobValue = NullableClobValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, BINARY) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableBinaryValue( + value: BitSet? = null, + annotations: Annotations = emptyList(), +): NullableBinaryValue = NullableBinaryValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, BYTE) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableByteValue( + value: Byte? = null, + annotations: Annotations = emptyList(), +): NullableByteValue = NullableByteValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, BLOB) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableBlobValue( + value: ByteArray? = null, + annotations: Annotations = emptyList(), +): NullableBlobValue = NullableBlobValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, DATE) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableDateValue( + value: LocalDate? = null, + annotations: Annotations = emptyList(), +): NullableDateValue = NullableDateValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, TIME) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableTimeValue( + annotations: Annotations = emptyList(), +): NullableTimeValue = NullableTimeValueImpl(null, 0, null, false, annotations.toPersistentList()) + +/** + * UNION(NULL, TIME) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableTimeValue( + value: LocalTime, + precision: Int = 0, + offset: ZoneOffset? = null, + withZone: Boolean = false, + annotations: Annotations = emptyList(), +): NullableTimeValue = NullableTimeValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + +/** + * UNION(NULL, TIMESTAMP) type value. + * + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableTimestampValue( + annotations: Annotations = emptyList(), +): NullableTimestampValue = NullableTimestampValueImpl(null, 0, null, false, annotations.toPersistentList()) + +/** + * UNION(NULL, TIMESTAMP) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableTimestampValue( + value: LocalDateTime, + precision: Int = 0, + offset: ZoneOffset? = null, + withZone: Boolean = false, + annotations: Annotations = emptyList(), +): NullableTimestampValue = + NullableTimestampValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + +/** + * UNION(NULL, TIMESTAMP) type value. + * + * @param value + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableIntervalValue( + value: Long? = null, + annotations: Annotations = emptyList(), +): NullableIntervalValue = NullableIntervalValueImpl(value, annotations.toPersistentList()) + +/** + * UNION(NULL, BAG) type value. + * + * @param T + * @param elements + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableBagValue( + elements: List? = null, + annotations: Annotations = emptyList(), +): NullableBagValue = NullableBagValueImpl(elements?.toPersistentList(), annotations.toPersistentList()) + +/** + * UNION(NULL, LIST) type value. + * + * @param T + * @param elements + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableListValue( + elements: List? = null, + annotations: Annotations = emptyList(), +): NullableListValue = NullableListValueImpl(elements?.toPersistentList(), annotations.toPersistentList()) + +/** + * UNION(NULL, SEXP) type value. + * + * @param T + * @param elements + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableSexpValue( + elements: List? = null, + annotations: Annotations = emptyList(), +): NullableSexpValue = NullableSexpValueImpl(elements?.toPersistentList(), annotations.toPersistentList()) + +/** + * UNION(NULL, STRUCT) type value. + * + * @param T + * @param fields + * @param annotations + * @return + */ +@JvmOverloads +@PartiQLValueExperimental +public fun nullableStructValue( + fields: List>? = null, + annotations: Annotations = emptyList(), +): NullableStructValue = NullableStructValueImpl(fields?.toPersistentList(), annotations.toPersistentList()) diff --git a/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValue.kt b/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValue.kt new file mode 100644 index 0000000000..81383915c6 --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValue.kt @@ -0,0 +1,833 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value + +import org.partiql.types.PartiQLValueType +import org.partiql.value.util.PartiQLValueVisitor +import java.math.BigDecimal +import java.math.BigInteger +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.ZoneOffset +import java.util.BitSet + +internal typealias Annotations = List + +/** + * TODO + * - Implement value equality for comparisons of nullable and non-nullable value classes + * - Relate types T and UNION(NULL, T) with an abstract base + * - Implement comparators + */ +@PartiQLValueExperimental +public sealed interface PartiQLValue { + + public val type: PartiQLValueType + + public val annotations: Annotations + + public fun copy(annotations: Annotations = this.annotations): PartiQLValue + + public fun withAnnotations(annotations: Annotations): PartiQLValue + + public fun withoutAnnotations(): PartiQLValue + + public fun accept(visitor: PartiQLValueVisitor, ctx: C): R +} + +@PartiQLValueExperimental +public abstract class MissingValue : PartiQLValue { + + override val type: PartiQLValueType = PartiQLValueType.MISSING + + abstract override fun copy(annotations: Annotations): MissingValue + + abstract override fun withAnnotations(annotations: Annotations): MissingValue + + abstract override fun withoutAnnotations(): MissingValue +} + +@PartiQLValueExperimental +public sealed interface ScalarValue : PartiQLValue { + + public val value: T + + override fun copy(annotations: Annotations): ScalarValue + + override fun withAnnotations(annotations: Annotations): ScalarValue + + override fun withoutAnnotations(): ScalarValue +} + +@PartiQLValueExperimental +public sealed interface CollectionValue : PartiQLValue, Collection { + + public override val size: Int + + public val elements: Collection + + override fun copy(annotations: Annotations): CollectionValue + + override fun withAnnotations(annotations: Annotations): CollectionValue + + override fun withoutAnnotations(): CollectionValue +} + +@PartiQLValueExperimental +public abstract class BoolValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.BOOL + + abstract override fun copy(annotations: Annotations): BoolValue + + abstract override fun withAnnotations(annotations: Annotations): BoolValue + + abstract override fun withoutAnnotations(): BoolValue +} + +@PartiQLValueExperimental +public sealed class NumericValue : ScalarValue { + + public val int: Int + get() = value.toInt() + + public val long: Long + get() = value.toLong() + + public val float: Float + get() = value.toFloat() + + public val double: Double + get() = value.toDouble() + + abstract override fun copy(annotations: Annotations): NumericValue + + abstract override fun withAnnotations(annotations: Annotations): NumericValue + + abstract override fun withoutAnnotations(): NumericValue +} + +@PartiQLValueExperimental +public abstract class Int8Value : NumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.INT8 + + abstract override fun copy(annotations: Annotations): Int8Value + + abstract override fun withAnnotations(annotations: Annotations): Int8Value + + abstract override fun withoutAnnotations(): Int8Value +} + +@PartiQLValueExperimental +public abstract class Int16Value : NumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.INT16 + + abstract override fun copy(annotations: Annotations): Int16Value + + abstract override fun withAnnotations(annotations: Annotations): Int16Value + + abstract override fun withoutAnnotations(): Int16Value +} + +@PartiQLValueExperimental +public abstract class Int32Value : NumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.INT32 + + abstract override fun copy(annotations: Annotations): Int32Value + + abstract override fun withAnnotations(annotations: Annotations): Int32Value + + abstract override fun withoutAnnotations(): Int32Value +} + +@PartiQLValueExperimental +public abstract class Int64Value : NumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.INT64 + + abstract override fun copy(annotations: Annotations): Int64Value + + abstract override fun withAnnotations(annotations: Annotations): Int64Value + + abstract override fun withoutAnnotations(): Int64Value +} + +@PartiQLValueExperimental +public abstract class IntValue : NumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.INT + + abstract override fun copy(annotations: Annotations): IntValue + + abstract override fun withAnnotations(annotations: Annotations): IntValue + + abstract override fun withoutAnnotations(): IntValue +} + +@PartiQLValueExperimental +public abstract class DecimalValue : NumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.DECIMAL + + abstract override fun copy(annotations: Annotations): DecimalValue + + abstract override fun withAnnotations(annotations: Annotations): DecimalValue + + abstract override fun withoutAnnotations(): DecimalValue +} + +@PartiQLValueExperimental +public abstract class Float32Value : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.FLOAT32 + + abstract override fun copy(annotations: Annotations): Float32Value + + abstract override fun withAnnotations(annotations: Annotations): Float32Value + + abstract override fun withoutAnnotations(): Float32Value +} + +@PartiQLValueExperimental +public abstract class Float64Value : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.FLOAT64 + + abstract override fun copy(annotations: Annotations): Float64Value + + abstract override fun withAnnotations(annotations: Annotations): Float64Value + + abstract override fun withoutAnnotations(): Float64Value +} + +@PartiQLValueExperimental +public sealed class TextValue : ScalarValue { + + public abstract val string: String + + abstract override fun copy(annotations: Annotations): TextValue + + abstract override fun withAnnotations(annotations: Annotations): TextValue + + abstract override fun withoutAnnotations(): TextValue +} + +@PartiQLValueExperimental +public abstract class CharValue : TextValue() { + + override val type: PartiQLValueType = PartiQLValueType.CHAR + + override val string: String + get() = value.toString() + + abstract override fun copy(annotations: Annotations): CharValue + + abstract override fun withAnnotations(annotations: Annotations): CharValue + + abstract override fun withoutAnnotations(): CharValue +} + +@PartiQLValueExperimental +public abstract class StringValue : TextValue() { + + override val type: PartiQLValueType = PartiQLValueType.STRING + + override val string: String + get() = value + + abstract override fun copy(annotations: Annotations): StringValue + + abstract override fun withAnnotations(annotations: Annotations): StringValue + + abstract override fun withoutAnnotations(): StringValue +} + +@PartiQLValueExperimental +public abstract class SymbolValue : TextValue() { + + override val type: PartiQLValueType = PartiQLValueType.SYMBOL + + override val string: String + get() = value + + abstract override fun copy(annotations: Annotations): SymbolValue + + abstract override fun withAnnotations(annotations: Annotations): SymbolValue + + abstract override fun withoutAnnotations(): SymbolValue +} + +@PartiQLValueExperimental +public abstract class ClobValue : TextValue() { + + override val type: PartiQLValueType = PartiQLValueType.CLOB + + override val string: String + get() = value.toString(Charsets.UTF_8) + + abstract override fun copy(annotations: Annotations): ClobValue + + abstract override fun withAnnotations(annotations: Annotations): ClobValue + + abstract override fun withoutAnnotations(): ClobValue +} + +@PartiQLValueExperimental +public abstract class BinaryValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.BINARY + + abstract override fun copy(annotations: Annotations): BinaryValue + + abstract override fun withAnnotations(annotations: Annotations): BinaryValue + + abstract override fun withoutAnnotations(): BinaryValue +} + +@PartiQLValueExperimental +public abstract class ByteValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.BYTE + + abstract override fun copy(annotations: Annotations): ByteValue + + abstract override fun withAnnotations(annotations: Annotations): ByteValue + + abstract override fun withoutAnnotations(): ByteValue +} + +@PartiQLValueExperimental +public abstract class BlobValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.BLOB + + abstract override fun copy(annotations: Annotations): BlobValue + + abstract override fun withAnnotations(annotations: Annotations): BlobValue + + abstract override fun withoutAnnotations(): BlobValue +} + +@PartiQLValueExperimental +public abstract class DateValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.DATE + + abstract override fun copy(annotations: Annotations): DateValue + + abstract override fun withAnnotations(annotations: Annotations): DateValue + + abstract override fun withoutAnnotations(): DateValue +} + +@PartiQLValueExperimental +public abstract class TimeValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.TIME + + // TEMPORARY + public abstract val precision: Int + + // TEMPORARY + public abstract val offset: ZoneOffset? + + // TEMPORARY + public abstract val withZone: Boolean + + abstract override fun copy(annotations: Annotations): TimeValue + + abstract override fun withAnnotations(annotations: Annotations): TimeValue + + abstract override fun withoutAnnotations(): TimeValue +} + +@PartiQLValueExperimental +public abstract class TimestampValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.TIMESTAMP + + // TEMPORARY + public abstract val precision: Int + + // TEMPORARY + public abstract val offset: ZoneOffset? + + // TEMPORARY + public abstract val withZone: Boolean + + abstract override fun copy(annotations: Annotations): TimestampValue + + abstract override fun withAnnotations(annotations: Annotations): TimestampValue + + abstract override fun withoutAnnotations(): TimestampValue +} + +@PartiQLValueExperimental +public abstract class IntervalValue : ScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.INTERVAL + + abstract override fun copy(annotations: Annotations): IntervalValue + + abstract override fun withAnnotations(annotations: Annotations): IntervalValue + + abstract override fun withoutAnnotations(): IntervalValue +} + +@PartiQLValueExperimental +public abstract class BagValue : CollectionValue { + + override val type: PartiQLValueType = PartiQLValueType.BAG + + abstract override fun copy(annotations: Annotations): BagValue + + abstract override fun withAnnotations(annotations: Annotations): BagValue + + abstract override fun withoutAnnotations(): BagValue +} + +@PartiQLValueExperimental +public abstract class ListValue : CollectionValue { + + override val type: PartiQLValueType = PartiQLValueType.LIST + + abstract override fun copy(annotations: Annotations): ListValue + + abstract override fun withAnnotations(annotations: Annotations): ListValue + + abstract override fun withoutAnnotations(): ListValue +} + +@PartiQLValueExperimental +public abstract class SexpValue : CollectionValue { + + override val type: PartiQLValueType = PartiQLValueType.SEXP + + abstract override fun copy(annotations: Annotations): SexpValue + + abstract override fun withAnnotations(annotations: Annotations): SexpValue + + abstract override fun withoutAnnotations(): SexpValue +} + +@PartiQLValueExperimental +public abstract class StructValue : PartiQLValue, Collection> { + + public abstract val fields: List> + + override val type: PartiQLValueType = PartiQLValueType.STRUCT + + abstract override fun copy(annotations: Annotations): StructValue + + abstract override fun withAnnotations(annotations: Annotations): StructValue + + abstract override fun withoutAnnotations(): StructValue +} + +@PartiQLValueExperimental +public abstract class NullValue : PartiQLValue { + + override val type: PartiQLValueType = PartiQLValueType.NULL + + abstract override fun copy(annotations: Annotations): NullValue + + abstract override fun withAnnotations(annotations: Annotations): NullValue + + abstract override fun withoutAnnotations(): NullValue +} + +@PartiQLValueExperimental +public sealed interface NullableScalarValue : PartiQLValue { + + public val value: T? + + override fun copy(annotations: Annotations): NullableScalarValue + + override fun withAnnotations(annotations: Annotations): NullableScalarValue + + override fun withoutAnnotations(): NullableScalarValue +} + +@PartiQLValueExperimental +public sealed interface NullableCollectionValue : PartiQLValue, Collection { + + public override val size: Int + + public val elements: Collection? + + override fun copy(annotations: Annotations): NullableCollectionValue + + override fun withAnnotations(annotations: Annotations): NullableCollectionValue + + override fun withoutAnnotations(): NullableCollectionValue +} + +@PartiQLValueExperimental +public abstract class NullableBoolValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_BOOL + + abstract override fun copy(annotations: Annotations): NullableBoolValue + + abstract override fun withAnnotations(annotations: Annotations): NullableBoolValue + + abstract override fun withoutAnnotations(): NullableBoolValue +} + +@PartiQLValueExperimental +public sealed class NullableNumericValue : NullableScalarValue { + + public val int: Int? + get() = value?.toInt() + + public val long: Long? + get() = value?.toLong() + + public val float: Float? + get() = value?.toFloat() + + public val double: Double? + get() = value?.toDouble() + + abstract override fun copy(annotations: Annotations): NullableNumericValue + + abstract override fun withAnnotations(annotations: Annotations): NullableNumericValue + + abstract override fun withoutAnnotations(): NullableNumericValue +} + +@PartiQLValueExperimental +public abstract class NullableInt8Value : NullableNumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_INT8 + + abstract override fun copy(annotations: Annotations): NullableInt8Value + + abstract override fun withAnnotations(annotations: Annotations): NullableInt8Value + + abstract override fun withoutAnnotations(): NullableInt8Value +} + +@PartiQLValueExperimental +public abstract class NullableInt16Value : NullableNumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_INT16 + + abstract override fun copy(annotations: Annotations): NullableInt16Value + + abstract override fun withAnnotations(annotations: Annotations): NullableInt16Value + + abstract override fun withoutAnnotations(): NullableInt16Value +} + +@PartiQLValueExperimental +public abstract class NullableInt32Value : NullableNumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_INT32 + + abstract override fun copy(annotations: Annotations): NullableInt32Value + + abstract override fun withAnnotations(annotations: Annotations): NullableInt32Value + + abstract override fun withoutAnnotations(): NullableInt32Value +} + +@PartiQLValueExperimental +public abstract class NullableInt64Value : NullableNumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_INT64 + + abstract override fun copy(annotations: Annotations): NullableInt64Value + + abstract override fun withAnnotations(annotations: Annotations): NullableInt64Value + + abstract override fun withoutAnnotations(): NullableInt64Value +} + +@PartiQLValueExperimental +public abstract class NullableIntValue : NullableNumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_INT + + abstract override fun copy(annotations: Annotations): NullableIntValue + + abstract override fun withAnnotations(annotations: Annotations): NullableIntValue + + abstract override fun withoutAnnotations(): NullableIntValue +} + +@PartiQLValueExperimental +public abstract class NullableDecimalValue : NullableNumericValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_DECIMAL + + abstract override fun copy(annotations: Annotations): NullableDecimalValue + + abstract override fun withAnnotations(annotations: Annotations): NullableDecimalValue + + abstract override fun withoutAnnotations(): NullableDecimalValue +} + +@PartiQLValueExperimental +public abstract class NullableFloat32Value : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_FLOAT32 + + abstract override fun copy(annotations: Annotations): NullableFloat32Value + + abstract override fun withAnnotations(annotations: Annotations): NullableFloat32Value + + abstract override fun withoutAnnotations(): NullableFloat32Value +} + +@PartiQLValueExperimental +public abstract class NullableFloat64Value : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_FLOAT64 + + abstract override fun copy(annotations: Annotations): NullableFloat64Value + + abstract override fun withAnnotations(annotations: Annotations): NullableFloat64Value + + abstract override fun withoutAnnotations(): NullableFloat64Value +} + +@PartiQLValueExperimental +public sealed class NullableTextValue : NullableScalarValue { + + public abstract val string: String? + + abstract override fun copy(annotations: Annotations): NullableTextValue + + abstract override fun withAnnotations(annotations: Annotations): NullableTextValue + + abstract override fun withoutAnnotations(): NullableTextValue +} + +@PartiQLValueExperimental +public abstract class NullableCharValue : NullableTextValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_CHAR + + override val string: String? + get() = value?.toString() + + abstract override fun copy(annotations: Annotations): NullableCharValue + + abstract override fun withAnnotations(annotations: Annotations): NullableCharValue + + abstract override fun withoutAnnotations(): NullableCharValue +} + +@PartiQLValueExperimental +public abstract class NullableStringValue : NullableTextValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_STRING + + override val string: String? + get() = value + + abstract override fun copy(annotations: Annotations): NullableStringValue + + abstract override fun withAnnotations(annotations: Annotations): NullableStringValue + + abstract override fun withoutAnnotations(): NullableStringValue +} + +@PartiQLValueExperimental +public abstract class NullableSymbolValue : NullableTextValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_SYMBOL + + override val string: String? + get() = value + + abstract override fun copy(annotations: Annotations): NullableSymbolValue + + abstract override fun withAnnotations(annotations: Annotations): NullableSymbolValue + + abstract override fun withoutAnnotations(): NullableSymbolValue +} + +@PartiQLValueExperimental +public abstract class NullableClobValue : NullableTextValue() { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_CLOB + + override val string: String? + get() = value?.toString(Charsets.UTF_8) + + abstract override fun copy(annotations: Annotations): NullableClobValue + + abstract override fun withAnnotations(annotations: Annotations): NullableClobValue + + abstract override fun withoutAnnotations(): NullableClobValue +} + +@PartiQLValueExperimental +public abstract class NullableBinaryValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_BINARY + + abstract override fun copy(annotations: Annotations): NullableBinaryValue + + abstract override fun withAnnotations(annotations: Annotations): NullableBinaryValue + + abstract override fun withoutAnnotations(): NullableBinaryValue +} + +@PartiQLValueExperimental +public abstract class NullableByteValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_BYTE + + abstract override fun copy(annotations: Annotations): NullableByteValue + + abstract override fun withAnnotations(annotations: Annotations): NullableByteValue + + abstract override fun withoutAnnotations(): NullableByteValue +} + +@PartiQLValueExperimental +public abstract class NullableBlobValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_BLOB + + abstract override fun copy(annotations: Annotations): NullableBlobValue + + abstract override fun withAnnotations(annotations: Annotations): NullableBlobValue + + abstract override fun withoutAnnotations(): NullableBlobValue +} + +@PartiQLValueExperimental +public abstract class NullableDateValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_DATE + + abstract override fun copy(annotations: Annotations): NullableDateValue + + abstract override fun withAnnotations(annotations: Annotations): NullableDateValue + + abstract override fun withoutAnnotations(): NullableDateValue +} + +@PartiQLValueExperimental +public abstract class NullableTimeValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_TIME + + // TEMPORARY + public abstract val precision: Int + + // TEMPORARY + public abstract val offset: ZoneOffset? + + // TEMPORARY + public abstract val withZone: Boolean + + abstract override fun copy(annotations: Annotations): NullableTimeValue + + abstract override fun withAnnotations(annotations: Annotations): NullableTimeValue + + abstract override fun withoutAnnotations(): NullableTimeValue +} + +@PartiQLValueExperimental +public abstract class NullableTimestampValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_TIMESTAMP + + // TEMPORARY + public abstract val precision: Int + + // TEMPORARY + public abstract val offset: ZoneOffset? + + // TEMPORARY + public abstract val withZone: Boolean + + abstract override fun copy(annotations: Annotations): NullableTimestampValue + + abstract override fun withAnnotations(annotations: Annotations): NullableTimestampValue + + abstract override fun withoutAnnotations(): NullableTimestampValue +} + +@PartiQLValueExperimental +public abstract class NullableIntervalValue : NullableScalarValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_INTERVAL + + abstract override fun copy(annotations: Annotations): NullableIntervalValue + + abstract override fun withAnnotations(annotations: Annotations): NullableIntervalValue + + abstract override fun withoutAnnotations(): NullableIntervalValue +} + +@PartiQLValueExperimental +public abstract class NullableBagValue : NullableCollectionValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_BAG + + abstract override fun copy(annotations: Annotations): NullableBagValue + + abstract override fun withAnnotations(annotations: Annotations): NullableBagValue + + abstract override fun withoutAnnotations(): NullableBagValue +} + +@PartiQLValueExperimental +public abstract class NullableListValue : NullableCollectionValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_LIST + + abstract override fun copy(annotations: Annotations): NullableListValue + + abstract override fun withAnnotations(annotations: Annotations): NullableListValue + + abstract override fun withoutAnnotations(): NullableListValue +} + +@PartiQLValueExperimental +public abstract class NullableSexpValue : NullableCollectionValue { + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_SEXP + + abstract override fun copy(annotations: Annotations): NullableSexpValue + + abstract override fun withAnnotations(annotations: Annotations): NullableSexpValue + + abstract override fun withoutAnnotations(): NullableSexpValue +} + +@PartiQLValueExperimental +public abstract class NullableStructValue : PartiQLValue, Collection> { + + public abstract val fields: List>? + + override val type: PartiQLValueType = PartiQLValueType.NULLABLE_STRUCT + + abstract override fun copy(annotations: Annotations): NullableStructValue + + abstract override fun withAnnotations(annotations: Annotations): NullableStructValue + + abstract override fun withoutAnnotations(): NullableStructValue +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValueExperimental.kt b/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValueExperimental.kt new file mode 100644 index 0000000000..87c389ef59 --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValueExperimental.kt @@ -0,0 +1,7 @@ +package org.partiql.value + +@RequiresOptIn( + message = "PartiQL Value requires explicit opt-in", + level = RequiresOptIn.Level.ERROR, +) +public annotation class PartiQLValueExperimental diff --git a/partiql-types/src/main/kotlin/org/partiql/value/impl/PartiQLValueImpl.kt b/partiql-types/src/main/kotlin/org/partiql/value/impl/PartiQLValueImpl.kt new file mode 100644 index 0000000000..c9493970ed --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/impl/PartiQLValueImpl.kt @@ -0,0 +1,456 @@ +@file:OptIn(PartiQLValueExperimental::class) + +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.impl + +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toPersistentList +import org.partiql.value.Annotations +import org.partiql.value.BagValue +import org.partiql.value.BinaryValue +import org.partiql.value.BlobValue +import org.partiql.value.BoolValue +import org.partiql.value.ByteValue +import org.partiql.value.CharValue +import org.partiql.value.ClobValue +import org.partiql.value.DateValue +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.IntervalValue +import org.partiql.value.ListValue +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.SexpValue +import org.partiql.value.StringValue +import org.partiql.value.StructValue +import org.partiql.value.SymbolValue +import org.partiql.value.TimeValue +import org.partiql.value.TimestampValue +import org.partiql.value.util.PartiQLValueVisitor +import java.math.BigDecimal +import java.math.BigInteger +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.ZoneOffset +import java.util.BitSet + +@Suppress("FunctionName") +internal inline fun T._withAnnotations(annotations: Annotations): T = + when { + annotations.isEmpty() -> this + else -> copy(annotations = this.annotations + annotations) as T + } + +@Suppress("FunctionName") +internal inline fun T._withoutAnnotations(): T = + when { + this.annotations.isNotEmpty() -> copy(annotations = emptyList()) as T + else -> this + } + +internal data class BoolValueImpl( + override val value: Boolean, + override val annotations: PersistentList, +) : BoolValue() { + + override fun copy(annotations: Annotations) = BoolValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): BoolValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): BoolValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitBool(this, ctx) +} + +internal data class Int8ValueImpl( + override val value: Byte, + override val annotations: PersistentList, +) : Int8Value() { + + override fun copy(annotations: Annotations) = Int8ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): Int8Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): Int8Value = _withoutAnnotations() + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitInt8(this, ctx) +} + +internal data class Int16ValueImpl( + override val value: Short, + override val annotations: PersistentList, +) : Int16Value() { + + override fun copy(annotations: Annotations) = Int16ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): Int16Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): Int16Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitInt16(this, ctx) +} + +internal data class Int32ValueImpl( + override val value: Int, + override val annotations: PersistentList, +) : Int32Value() { + + override fun copy(annotations: Annotations) = Int32ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): Int32Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): Int32Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitInt32(this, ctx) +} + +internal data class Int64ValueImpl( + override val value: Long, + override val annotations: PersistentList, +) : Int64Value() { + override fun copy(annotations: Annotations) = Int64ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): Int64Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): Int64Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitInt64(this, ctx) +} + +internal data class IntValueImpl( + override val value: BigInteger, + override val annotations: PersistentList, +) : IntValue() { + + override fun copy(annotations: Annotations) = IntValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): IntValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): IntValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitInt(this, ctx) +} + +internal data class DecimalValueImpl( + override val value: BigDecimal, + override val annotations: PersistentList, +) : DecimalValue() { + + override fun copy(annotations: Annotations) = DecimalValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): DecimalValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): DecimalValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitDecimal(this, ctx) +} + +internal data class Float32ValueImpl( + override val value: Float, + override val annotations: PersistentList, +) : Float32Value() { + + override fun copy(annotations: Annotations) = Float32ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): Float32Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): Float32Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitFloat32(this, ctx) +} + +internal data class Float64ValueImpl( + override val value: Double, + override val annotations: PersistentList, +) : Float64Value() { + override fun copy(annotations: Annotations) = Float64ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): Float64Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): Float64Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitFloat64(this, ctx) +} + +internal data class CharValueImpl( + override val value: Char, + override val annotations: PersistentList, +) : CharValue() { + + override fun copy(annotations: Annotations) = CharValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): CharValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): CharValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitChar(this, ctx) +} + +internal data class StringValueImpl( + override val value: String, + override val annotations: PersistentList, +) : StringValue() { + override fun copy(annotations: Annotations) = StringValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): StringValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): StringValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitString(this, ctx) +} + +internal data class SymbolValueImpl( + override val value: String, + override val annotations: PersistentList, +) : SymbolValue() { + override fun copy(annotations: Annotations) = SymbolValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): SymbolValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): SymbolValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitSymbol(this, ctx) +} + +internal data class ClobValueImpl( + override val value: ByteArray, + override val annotations: PersistentList, +) : ClobValue() { + override fun copy(annotations: Annotations) = ClobValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): ClobValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): ClobValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitClob(this, ctx) +} + +internal data class BinaryValueImpl( + override val value: BitSet, + override val annotations: PersistentList, +) : BinaryValue() { + override fun copy(annotations: Annotations) = BinaryValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): BinaryValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): BinaryValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitBinary(this, ctx) +} + +internal data class ByteValueImpl( + override val value: Byte, + override val annotations: PersistentList, +) : ByteValue() { + override fun copy(annotations: Annotations) = ByteValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): ByteValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): ByteValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitByte(this, ctx) +} + +internal data class BlobValueImpl( + override val value: ByteArray, + override val annotations: PersistentList, +) : BlobValue() { + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as BlobValueImpl + return value.contentEquals(other.value) + } + + override fun hashCode() = value.contentHashCode() + override fun copy(annotations: Annotations) = BlobValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): BlobValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): BlobValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitBlob(this, ctx) +} + +internal data class DateValueImpl( + override val value: LocalDate, + override val annotations: PersistentList, +) : DateValue() { + override fun copy(annotations: Annotations) = DateValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): DateValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): DateValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitDate(this, ctx) +} + +internal data class TimeValueImpl( + override val value: LocalTime, + override val precision: Int, + override val offset: ZoneOffset?, + override val withZone: Boolean, + override val annotations: PersistentList, +) : TimeValue() { + override fun copy(annotations: Annotations) = TimeValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): TimeValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): TimeValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitTime(this, ctx) +} + +internal data class TimestampValueImpl( + override val value: LocalDateTime, + override val precision: Int, + override val offset: ZoneOffset?, + override val withZone: Boolean, + override val annotations: PersistentList, +) : TimestampValue() { + override fun copy(annotations: Annotations) = TimestampValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): TimestampValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): TimestampValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitTimestamp(this, ctx) +} + +internal data class IntervalValueImpl( + override val value: Long, + override val annotations: PersistentList, +) : IntervalValue() { + override fun copy(annotations: Annotations) = IntervalValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): IntervalValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): IntervalValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitInterval(this, ctx) +} + +internal data class BagValueImpl( + private val delegate: PersistentList, + override val annotations: PersistentList, +) : BagValue() { + + override fun contains(element: T) = delegate.contains(element) + + override fun containsAll(elements: Collection) = delegate.containsAll(elements) + + override fun isEmpty() = delegate.isEmpty() + + override fun iterator() = delegate.iterator() + + override val size = delegate.size + + override val elements = delegate.toImmutableList() + + override fun copy(annotations: Annotations) = BagValueImpl(delegate, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): BagValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): BagValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitBag(this, ctx) +} + +internal data class ListValueImpl( + private val delegate: PersistentList, + override val annotations: PersistentList, +) : ListValue() { + + override fun contains(element: T) = delegate.contains(element) + + override fun containsAll(elements: Collection) = delegate.containsAll(elements) + + override fun isEmpty() = delegate.isEmpty() + + override fun iterator() = delegate.iterator() + + override val size = delegate.size + + override val elements = delegate.toImmutableList() + + override fun copy(annotations: Annotations) = ListValueImpl(delegate, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): ListValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): ListValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitList(this, ctx) +} + +internal data class SexpValueImpl( + private val delegate: PersistentList, + override val annotations: PersistentList, +) : SexpValue() { + + override fun contains(element: T) = delegate.contains(element) + + override fun containsAll(elements: Collection) = delegate.containsAll(elements) + + override fun isEmpty() = delegate.isEmpty() + + override fun iterator() = delegate.iterator() + + override val size = delegate.size + + override val elements = delegate.toImmutableList() + + override fun copy(annotations: Annotations) = SexpValueImpl(delegate, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): SexpValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): SexpValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitSexp(this, ctx) +} + +internal data class StructValueImpl( + private val values: PersistentList>, + override val annotations: PersistentList, +) : StructValue() { + + override val fields = values.toImmutableList() + + override val size = values.size + + override fun isEmpty() = values.isEmpty() + + override fun iterator(): Iterator> = values.iterator() + + override fun containsAll(elements: Collection>) = values.containsAll(elements) + + override fun contains(element: Pair) = values.contains(element) + + override fun copy(annotations: Annotations) = StructValueImpl(values, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): StructValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): StructValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitStruct(this, ctx) +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/impl/PartiQLValueNullableImpl.kt b/partiql-types/src/main/kotlin/org/partiql/value/impl/PartiQLValueNullableImpl.kt new file mode 100644 index 0000000000..d905af3514 --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/impl/PartiQLValueNullableImpl.kt @@ -0,0 +1,499 @@ +@file:OptIn(PartiQLValueExperimental::class) + +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.impl + +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toPersistentList +import org.partiql.value.Annotations +import org.partiql.value.MissingValue +import org.partiql.value.NullValue +import org.partiql.value.NullableBagValue +import org.partiql.value.NullableBinaryValue +import org.partiql.value.NullableBlobValue +import org.partiql.value.NullableBoolValue +import org.partiql.value.NullableByteValue +import org.partiql.value.NullableCharValue +import org.partiql.value.NullableClobValue +import org.partiql.value.NullableDateValue +import org.partiql.value.NullableDecimalValue +import org.partiql.value.NullableFloat32Value +import org.partiql.value.NullableFloat64Value +import org.partiql.value.NullableInt16Value +import org.partiql.value.NullableInt32Value +import org.partiql.value.NullableInt64Value +import org.partiql.value.NullableInt8Value +import org.partiql.value.NullableIntValue +import org.partiql.value.NullableIntervalValue +import org.partiql.value.NullableListValue +import org.partiql.value.NullableSexpValue +import org.partiql.value.NullableStringValue +import org.partiql.value.NullableStructValue +import org.partiql.value.NullableSymbolValue +import org.partiql.value.NullableTimeValue +import org.partiql.value.NullableTimestampValue +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.util.PartiQLValueVisitor +import java.math.BigDecimal +import java.math.BigInteger +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.ZoneOffset +import java.util.BitSet + +internal data class NullValueImpl( + override val annotations: PersistentList, +) : NullValue() { + + override fun copy(annotations: Annotations) = NullValueImpl(annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNull(this, ctx) +} + +internal data class MissingValueImpl( + override val annotations: PersistentList, +) : MissingValue() { + + override fun copy(annotations: Annotations) = MissingValueImpl(annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): MissingValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): MissingValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitMissing(this, ctx) +} + +internal data class NullableBoolValueImpl( + override val value: Boolean?, + override val annotations: PersistentList, +) : NullableBoolValue() { + + override fun copy(annotations: Annotations) = NullableBoolValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableBoolValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableBoolValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableBool(this, ctx) +} + +internal data class NullableInt8ValueImpl( + override val value: Byte?, + override val annotations: PersistentList, +) : NullableInt8Value() { + + override fun copy(annotations: Annotations) = NullableInt8ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableInt8Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableInt8Value = _withoutAnnotations() + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableInt8(this, ctx) +} + +internal data class NullableInt16ValueImpl( + override val value: Short?, + override val annotations: PersistentList, +) : NullableInt16Value() { + + override fun copy(annotations: Annotations) = NullableInt16ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableInt16Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableInt16Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableInt16(this, ctx) +} + +internal data class NullableInt32ValueImpl( + override val value: Int?, + override val annotations: PersistentList, +) : NullableInt32Value() { + + override fun copy(annotations: Annotations) = NullableInt32ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableInt32Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableInt32Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableInt32(this, ctx) +} + +internal data class NullableInt64ValueImpl( + override val value: Long?, + override val annotations: PersistentList, +) : NullableInt64Value() { + override fun copy(annotations: Annotations) = NullableInt64ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableInt64Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableInt64Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableInt64(this, ctx) +} + +internal data class NullableIntValueImpl( + override val value: BigInteger?, + override val annotations: PersistentList, +) : NullableIntValue() { + + override fun copy(annotations: Annotations) = NullableIntValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableIntValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableIntValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableInt(this, ctx) +} + +internal data class NullableDecimalValueImpl( + override val value: BigDecimal?, + override val annotations: PersistentList, +) : NullableDecimalValue() { + + override fun copy(annotations: Annotations) = NullableDecimalValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableDecimalValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableDecimalValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableDecimal(this, ctx) +} + +internal data class NullableFloat32ValueImpl( + override val value: Float?, + override val annotations: PersistentList, +) : NullableFloat32Value() { + + override fun copy(annotations: Annotations) = NullableFloat32ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableFloat32Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableFloat32Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableFloat32(this, ctx) +} + +internal data class NullableFloat64ValueImpl( + override val value: Double?, + override val annotations: PersistentList, +) : NullableFloat64Value() { + override fun copy(annotations: Annotations) = NullableFloat64ValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableFloat64Value = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableFloat64Value = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableFloat64(this, ctx) +} + +internal data class NullableCharValueImpl( + override val value: Char?, + override val annotations: PersistentList, +) : NullableCharValue() { + + override fun copy(annotations: Annotations) = NullableCharValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableCharValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableCharValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableChar(this, ctx) +} + +internal data class NullableStringValueImpl( + override val value: String?, + override val annotations: PersistentList, +) : NullableStringValue() { + override fun copy(annotations: Annotations) = NullableStringValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableStringValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableStringValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableString(this, ctx) +} + +internal data class NullableSymbolValueImpl( + override val value: String?, + override val annotations: PersistentList, +) : NullableSymbolValue() { + override fun copy(annotations: Annotations) = NullableSymbolValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableSymbolValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableSymbolValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableSymbol(this, ctx) +} + +internal data class NullableClobValueImpl( + override val value: ByteArray?, + override val annotations: PersistentList, +) : NullableClobValue() { + override fun copy(annotations: Annotations) = NullableClobValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableClobValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableClobValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableClob(this, ctx) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as NullableClobValueImpl + if (value != null) { + if (other.value == null) return false + if (!value.contentEquals(other.value)) return false + } else if (other.value != null) return false + return annotations == other.annotations + } + + override fun hashCode(): Int { + var result = value?.contentHashCode() ?: 0 + result = 31 * result + annotations.hashCode() + return result + } +} + +internal data class NullableBinaryValueImpl( + override val value: BitSet?, + override val annotations: PersistentList, +) : NullableBinaryValue() { + override fun copy(annotations: Annotations) = NullableBinaryValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableBinaryValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableBinaryValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableBinary(this, ctx) +} + +internal data class NullableByteValueImpl( + override val value: Byte?, + override val annotations: PersistentList, +) : NullableByteValue() { + override fun copy(annotations: Annotations) = NullableByteValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableByteValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableByteValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableByte(this, ctx) +} + +internal data class NullableBlobValueImpl( + override val value: ByteArray?, + override val annotations: PersistentList, +) : NullableBlobValue() { + + override fun copy(annotations: Annotations) = NullableBlobValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableBlobValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableBlobValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableBlob(this, ctx) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as NullableClobValueImpl + if (value != null) { + if (other.value == null) return false + if (!value.contentEquals(other.value)) return false + } else if (other.value != null) return false + return annotations == other.annotations + } + + override fun hashCode(): Int { + var result = value?.contentHashCode() ?: 0 + result = 31 * result + annotations.hashCode() + return result + } +} + +internal data class NullableDateValueImpl( + override val value: LocalDate?, + override val annotations: PersistentList, +) : NullableDateValue() { + override fun copy(annotations: Annotations) = NullableDateValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableDateValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableDateValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableDate(this, ctx) +} + +internal data class NullableTimeValueImpl( + override val value: LocalTime?, + override val precision: Int, + override val offset: ZoneOffset?, + override val withZone: Boolean, + override val annotations: PersistentList, +) : NullableTimeValue() { + override fun copy(annotations: Annotations) = + NullableTimeValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableTimeValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableTimeValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableTime(this, ctx) +} + +internal data class NullableTimestampValueImpl( + override val value: LocalDateTime?, + override val precision: Int, + override val offset: ZoneOffset?, + override val withZone: Boolean, + override val annotations: PersistentList, +) : NullableTimestampValue() { + override fun copy(annotations: Annotations) = + NullableTimestampValueImpl(value, precision, offset, withZone, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableTimestampValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableTimestampValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = + visitor.visitNullableTimestamp(this, ctx) +} + +internal data class NullableIntervalValueImpl( + override val value: Long?, + override val annotations: PersistentList, +) : NullableIntervalValue() { + override fun copy(annotations: Annotations) = NullableIntervalValueImpl(value, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableIntervalValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableIntervalValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableInterval(this, ctx) +} + +internal data class NullableBagValueImpl( + private val delegate: PersistentList?, + override val annotations: PersistentList, +) : NullableBagValue() { + + override fun contains(element: T) = delegate!!.contains(element) + + override fun containsAll(elements: Collection) = delegate!!.containsAll(elements) + + override fun isEmpty() = delegate!!.isEmpty() + + override fun iterator() = delegate!!.iterator() + + override val size = delegate!!.size + + override val elements = delegate!!.toImmutableList() + + override fun copy(annotations: Annotations) = NullableBagValueImpl(delegate, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableBagValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableBagValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableBag(this, ctx) +} + +internal data class NullableListValueImpl( + private val delegate: PersistentList?, + override val annotations: PersistentList, +) : NullableListValue() { + + override fun contains(element: T) = delegate!!.contains(element) + + override fun containsAll(elements: Collection) = delegate!!.containsAll(elements) + + override fun isEmpty() = delegate!!.isEmpty() + + override fun iterator() = delegate!!.iterator() + + override val size = delegate!!.size + + override val elements = delegate!!.toImmutableList() + + override fun copy(annotations: Annotations) = NullableListValueImpl(delegate, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableListValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableListValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableList(this, ctx) +} + +internal data class NullableSexpValueImpl( + private val delegate: PersistentList?, + override val annotations: PersistentList, +) : NullableSexpValue() { + + override fun contains(element: T) = delegate!!.contains(element) + + override fun containsAll(elements: Collection) = delegate!!.containsAll(elements) + + override fun isEmpty() = delegate!!.isEmpty() + + override fun iterator() = delegate!!.iterator() + + override val size = delegate!!.size + + override val elements = delegate!!.toImmutableList() + + override fun copy(annotations: Annotations) = NullableSexpValueImpl(delegate, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableSexpValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableSexpValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableSexp(this, ctx) +} + +internal data class NullableStructValueImpl( + private val values: PersistentList>?, + override val annotations: PersistentList, +) : NullableStructValue() { + + override val fields = values!!.toImmutableList() + + override val size = values!!.size + + override fun isEmpty() = values!!.isEmpty() + + override fun iterator(): Iterator> = values!!.iterator() + + override fun containsAll(elements: Collection>) = values!!.containsAll(elements) + + override fun contains(element: Pair) = values!!.contains(element) + + override fun copy(annotations: Annotations) = NullableStructValueImpl(values, annotations.toPersistentList()) + + override fun withAnnotations(annotations: Annotations): NullableStructValue = _withAnnotations(annotations) + + override fun withoutAnnotations(): NullableStructValue = _withoutAnnotations() + + override fun accept(visitor: PartiQLValueVisitor, ctx: C): R = visitor.visitNullableStruct(this, ctx) +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueReader.kt b/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueReader.kt new file mode 100644 index 0000000000..50eae0757f --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueReader.kt @@ -0,0 +1,30 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.io + +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental + +/** + * Basic PartiQLValueReader akin to java.io.Reader. + */ +@PartiQLValueExperimental +public interface PartiQLValueReader : AutoCloseable { + + /** + * Reads a single value. + */ + public fun read(): PartiQLValue +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueTextWriter.kt b/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueTextWriter.kt new file mode 100644 index 0000000000..802bf9a6ea --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueTextWriter.kt @@ -0,0 +1,318 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.io + +import org.partiql.value.BagValue +import org.partiql.value.BoolValue +import org.partiql.value.CharValue +import org.partiql.value.CollectionValue +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.ListValue +import org.partiql.value.MissingValue +import org.partiql.value.NullValue +import org.partiql.value.NullableBagValue +import org.partiql.value.NullableBoolValue +import org.partiql.value.NullableCharValue +import org.partiql.value.NullableDecimalValue +import org.partiql.value.NullableFloat32Value +import org.partiql.value.NullableFloat64Value +import org.partiql.value.NullableInt16Value +import org.partiql.value.NullableInt32Value +import org.partiql.value.NullableInt64Value +import org.partiql.value.NullableInt8Value +import org.partiql.value.NullableIntValue +import org.partiql.value.NullableListValue +import org.partiql.value.NullableSexpValue +import org.partiql.value.NullableStringValue +import org.partiql.value.NullableStructValue +import org.partiql.value.NullableSymbolValue +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.SexpValue +import org.partiql.value.StringValue +import org.partiql.value.StructValue +import org.partiql.value.SymbolValue +import org.partiql.value.bagValue +import org.partiql.value.boolValue +import org.partiql.value.charValue +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.listValue +import org.partiql.value.sexpValue +import org.partiql.value.stringValue +import org.partiql.value.structValue +import org.partiql.value.symbolValue +import org.partiql.value.util.PartiQLValueBaseVisitor +import java.io.PrintStream + +/** + * [PartiQLValueWriter] which outputs PartiQL text. + * + * @property out PrintStream + * @property formatted Print with newlines and indents + * @property indent Indent prefix, default is 2-spaces + */ +@PartiQLValueExperimental +internal class PartiQLValueTextWriter( + private val out: PrintStream, + private val formatted: Boolean = true, + private val indent: String = " ", +) : PartiQLValueWriter { + + override fun append(value: PartiQLValue): PartiQLValueWriter { + val format = if (formatted) Format(indent) else null + val v = value.accept(ToString, format) // value.toString(format) + out.append(v) + return this + } + + override fun close() { + out.close() + } + + /** + * Text format + * + * @param indent Index prefix + */ + private data class Format( + val indent: String = " ", + val prefix: String = "", + ) { + fun nest() = copy(prefix = prefix + indent) + } + + /** + * Not implemented on the value classes as the textual format is not inherent to the values. + */ + @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") + private object ToString : PartiQLValueBaseVisitor() { + + override fun defaultVisit(v: PartiQLValue, format: Format?) = defaultReturn(v, format) + + override fun defaultReturn(v: PartiQLValue, format: Format?): Nothing = + throw IllegalArgumentException("Cannot write value of type ${v.type}") + + private inline fun PartiQLValue.toString(format: Format?, block: PartiQLValue.() -> String) = buildString { + if (format != null) append(format.prefix) + annotate(this@toString, this) + append(block()) + } + + private fun annotate(v: PartiQLValue, sb: StringBuilder) { + val annotations = v.annotations + if (annotations.isNotEmpty()) { + // handle escaping + sb.append(annotations.joinToString("::", postfix = "::")) + } + } + + private fun visit( + v: CollectionValue<*>, + format: Format?, + terminals: Pair, + separator: CharSequence = ",", + ) = buildString { + // skip empty + if (v.isEmpty() || format == null) { + format?.let { append(it.prefix) } + annotate(v, this) + append(terminals.first) + val items = v.elements.map { + it.accept(ToString, null) // it.toString() + } + append(items.joinToString(separator)) + append(terminals.second) + return@buildString + } + // print formatted + append(format.prefix) + annotate(v, this) + appendLine(terminals.first) + v.elements.forEachIndexed { i, e -> + val content = e.accept(ToString, format.nest()) // e.toString(format) + val suffix = if (i == v.size - 1) "" else "," + append(content) + appendLine(suffix) + } + append(format.prefix) + append(terminals.second) + } + + override fun visitNull(v: NullValue, format: Format?) = v.toString(format) { "null" } + + override fun visitMissing(v: MissingValue, format: Format?) = v.toString(format) { "missing" } + + override fun visitBool(v: BoolValue, format: Format?) = v.toString(format) { + when (v.value) { + true -> "true" + else -> "false" + } + } + + override fun visitInt8(v: Int8Value, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitInt16(v: Int16Value, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitInt32(v: Int32Value, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitInt64(v: Int64Value, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitInt(v: IntValue, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitDecimal(v: DecimalValue, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitFloat32(v: Float32Value, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitFloat64(v: Float64Value, format: Format?) = v.toString(format) { v.value.toString() } + + override fun visitChar(v: CharValue, format: Format?) = v.toString(format) { "'${v.value}'" } + + // TODO escapes + override fun visitString(v: StringValue, format: Format?) = v.toString(format) { "'${v.value}'" } + + // TODO escapes + override fun visitSymbol(v: SymbolValue, format: Format?) = v.toString(format) { v.value } + + override fun visitBag(v: BagValue<*>, format: Format?) = visit(v, format, "<<" to ">>") + + override fun visitList(v: ListValue<*>, format: Format?) = visit(v, format, "[" to "]") + + override fun visitSexp(v: SexpValue<*>, format: Format?) = visit(v, format, "(" to ")", " ") + + override fun visitStruct(v: StructValue<*>, format: Format?): String = buildString { + if (v.isEmpty() || format == null) { + format?.let { append(it.prefix) } + annotate(v, this) + append("{") + val items = v.fields.map { + val fk = it.first + val fv = it.second.accept(ToString, null) // it.toString() + "$fk:$fv" + } + append(items.joinToString(",")) + append("}") + return@buildString + } + // print formatted + append(format.prefix) + annotate(v, this) + appendLine("{") + v.fields.forEachIndexed { i, e -> + val fk = e.first + val fv = e.second.accept(ToString, format.nest()).trimStart() // e.toString(format) + val suffix = if (i == v.size - 1) "" else "," + append(format.prefix + format.indent) + append("$fk: $fv") + appendLine(suffix) + } + append(format.prefix) + append("}") + } + + override fun visitNullableBool(v: NullableBoolValue, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitBool(boolValue(v.value!!, v.annotations), ctx) + } + + override fun visitNullableInt8(v: NullableInt8Value, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitInt8(int8Value(v.value!!, v.annotations), ctx) + } + + override fun visitNullableInt16(v: NullableInt16Value, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitInt16(int16Value(v.value!!, v.annotations), ctx) + } + + override fun visitNullableInt32(v: NullableInt32Value, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitInt32(int32Value(v.value!!, v.annotations), ctx) + } + + override fun visitNullableInt64(v: NullableInt64Value, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitInt64(int64Value(v.value!!, v.annotations), ctx) + } + + override fun visitNullableInt(v: NullableIntValue, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitInt(intValue(v.value!!, v.annotations), ctx) + } + + override fun visitNullableDecimal(v: NullableDecimalValue, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitDecimal(decimalValue(v.value!!, v.annotations), ctx) + } + + override fun visitNullableFloat32(v: NullableFloat32Value, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitFloat32(float32Value(v.value!!, v.annotations), ctx) + } + + override fun visitNullableFloat64(v: NullableFloat64Value, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitFloat64(float64Value(v.value!!, v.annotations), ctx) + } + + override fun visitNullableChar(v: NullableCharValue, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitChar(charValue(v.value!!, v.annotations), ctx) + } + + override fun visitNullableString(v: NullableStringValue, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitString(stringValue(v.value!!, v.annotations), ctx) + } + + override fun visitNullableSymbol(v: NullableSymbolValue, ctx: Format?) = when (v.value) { + null -> "null" + else -> visitSymbol(symbolValue(v.value!!, v.annotations), ctx) + } + + override fun visitNullableBag(v: NullableBagValue<*>, ctx: Format?) = when (v.elements) { + null -> "null" + else -> visitBag(bagValue(v.elements!!.toList(), v.annotations), ctx) + } + + override fun visitNullableList(v: NullableListValue<*>, ctx: Format?) = when (v.elements) { + null -> "null" + else -> visitList(listValue(v.elements!!.toList(), v.annotations), ctx) + } + + override fun visitNullableSexp(v: NullableSexpValue<*>, ctx: Format?) = when (v.elements) { + null -> "null" + else -> visitSexp(sexpValue(v.elements!!.toList(), v.annotations), ctx) + } + + override fun visitNullableStruct(v: NullableStructValue<*>, ctx: Format?) = when (v.fields) { + null -> "null" + else -> visitStruct(structValue(v.fields!!.toList(), v.annotations), ctx) + } + } +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueWriter.kt b/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueWriter.kt new file mode 100644 index 0000000000..9d14e4d1f7 --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/io/PartiQLValueWriter.kt @@ -0,0 +1,30 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.io + +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental + +/** + * Basic PartiQLValue Writer akin to java.io.Writer. + */ +@PartiQLValueExperimental +public interface PartiQLValueWriter : AutoCloseable { + + /** + * Appends the specified value to this writer. + */ + public fun append(value: PartiQLValue): PartiQLValueWriter +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/util/PartiQLValueBaseVisitor.kt b/partiql-types/src/main/kotlin/org/partiql/value/util/PartiQLValueBaseVisitor.kt new file mode 100644 index 0000000000..b3459c0737 --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/util/PartiQLValueBaseVisitor.kt @@ -0,0 +1,293 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.util + +import org.partiql.value.BagValue +import org.partiql.value.BinaryValue +import org.partiql.value.BlobValue +import org.partiql.value.BoolValue +import org.partiql.value.ByteValue +import org.partiql.value.CharValue +import org.partiql.value.ClobValue +import org.partiql.value.CollectionValue +import org.partiql.value.DateValue +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.IntervalValue +import org.partiql.value.ListValue +import org.partiql.value.MissingValue +import org.partiql.value.NullValue +import org.partiql.value.NullableBagValue +import org.partiql.value.NullableBinaryValue +import org.partiql.value.NullableBlobValue +import org.partiql.value.NullableBoolValue +import org.partiql.value.NullableByteValue +import org.partiql.value.NullableCharValue +import org.partiql.value.NullableClobValue +import org.partiql.value.NullableCollectionValue +import org.partiql.value.NullableDateValue +import org.partiql.value.NullableDecimalValue +import org.partiql.value.NullableFloat32Value +import org.partiql.value.NullableFloat64Value +import org.partiql.value.NullableInt16Value +import org.partiql.value.NullableInt32Value +import org.partiql.value.NullableInt64Value +import org.partiql.value.NullableInt8Value +import org.partiql.value.NullableIntValue +import org.partiql.value.NullableIntervalValue +import org.partiql.value.NullableListValue +import org.partiql.value.NullableNumericValue +import org.partiql.value.NullableScalarValue +import org.partiql.value.NullableSexpValue +import org.partiql.value.NullableStringValue +import org.partiql.value.NullableStructValue +import org.partiql.value.NullableSymbolValue +import org.partiql.value.NullableTextValue +import org.partiql.value.NullableTimeValue +import org.partiql.value.NullableTimestampValue +import org.partiql.value.NumericValue +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.ScalarValue +import org.partiql.value.SexpValue +import org.partiql.value.StringValue +import org.partiql.value.StructValue +import org.partiql.value.SymbolValue +import org.partiql.value.TextValue +import org.partiql.value.TimeValue +import org.partiql.value.TimestampValue + +@PartiQLValueExperimental +public abstract class PartiQLValueBaseVisitor : PartiQLValueVisitor { + + public open fun defaultVisit(v: PartiQLValue, ctx: C): R { + when (v) { + is CollectionValue<*> -> { + v.elements.forEach { it.accept(this, ctx) } + } + is StructValue<*> -> { + v.fields.forEach { it.second.accept(this, ctx) } + } + is NullableCollectionValue<*> -> { + v.elements?.forEach { it.accept(this, ctx) } + } + is NullableStructValue<*> -> { + v.fields?.forEach { it.second.accept(this, ctx) } + } + else -> {} + } + return defaultReturn(v, ctx) + } + + public abstract fun defaultReturn(v: PartiQLValue, ctx: C): R + + override fun visit(v: PartiQLValue, ctx: C): R = v.accept(this, ctx) + + override fun visitScalar(v: ScalarValue<*>, ctx: C): R = when (v) { + is BinaryValue -> visitBinary(v, ctx) + is BlobValue -> visitBlob(v, ctx) + is BoolValue -> visitBool(v, ctx) + is ByteValue -> visitByte(v, ctx) + is DateValue -> visitDate(v, ctx) + is Float32Value -> visitFloat32(v, ctx) + is Float64Value -> visitFloat64(v, ctx) + is IntervalValue -> visitInterval(v, ctx) + is DecimalValue -> visitDecimal(v, ctx) + is Int16Value -> visitInt16(v, ctx) + is Int32Value -> visitInt32(v, ctx) + is Int64Value -> visitInt64(v, ctx) + is Int8Value -> visitInt8(v, ctx) + is IntValue -> visitInt(v, ctx) + is CharValue -> visitChar(v, ctx) + is ClobValue -> visitClob(v, ctx) + is StringValue -> visitString(v, ctx) + is SymbolValue -> visitSymbol(v, ctx) + is TimeValue -> visitTime(v, ctx) + is TimestampValue -> visitTimestamp(v, ctx) + } + + override fun visitCollection(v: CollectionValue<*>, ctx: C): R = when (v) { + is BagValue -> visitBag(v, ctx) + is ListValue -> visitList(v, ctx) + is SexpValue -> visitSexp(v, ctx) + } + + override fun visitBool(v: BoolValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNumeric(v: NumericValue<*>, ctx: C): R = when (v) { + is DecimalValue -> visitDecimal(v, ctx) + is Int16Value -> visitInt16(v, ctx) + is Int32Value -> visitInt32(v, ctx) + is Int64Value -> visitInt64(v, ctx) + is Int8Value -> visitInt8(v, ctx) + is IntValue -> visitInt(v, ctx) + } + + override fun visitInt8(v: Int8Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitInt16(v: Int16Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitInt32(v: Int32Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitInt64(v: Int64Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitInt(v: IntValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitDecimal(v: DecimalValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitFloat32(v: Float32Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitFloat64(v: Float64Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitText(v: TextValue<*>, ctx: C): R = when (v) { + is CharValue -> visitChar(v, ctx) + is ClobValue -> visitClob(v, ctx) + is StringValue -> visitString(v, ctx) + is SymbolValue -> visitSymbol(v, ctx) + } + + override fun visitChar(v: CharValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitString(v: StringValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitSymbol(v: SymbolValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitClob(v: ClobValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitBinary(v: BinaryValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitByte(v: ByteValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitBlob(v: BlobValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitDate(v: DateValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitTime(v: TimeValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitTimestamp(v: TimestampValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitInterval(v: IntervalValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitBag(v: BagValue<*>, ctx: C): R = defaultVisit(v, ctx) + + override fun visitList(v: ListValue<*>, ctx: C): R = defaultVisit(v, ctx) + + override fun visitSexp(v: SexpValue<*>, ctx: C): R = defaultVisit(v, ctx) + + override fun visitStruct(v: StructValue<*>, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNull(v: NullValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitMissing(v: MissingValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableScalar(v: NullableScalarValue<*>, ctx: C): R = when (v) { + is NullableBinaryValue -> visitNullableBinary(v, ctx) + is NullableBlobValue -> visitNullableBlob(v, ctx) + is NullableBoolValue -> visitNullableBool(v, ctx) + is NullableByteValue -> visitNullableByte(v, ctx) + is NullableDateValue -> visitNullableDate(v, ctx) + is NullableFloat32Value -> visitNullableFloat32(v, ctx) + is NullableFloat64Value -> visitNullableFloat64(v, ctx) + is NullableIntervalValue -> visitNullableInterval(v, ctx) + is NullableDecimalValue -> visitNullableDecimal(v, ctx) + is NullableInt16Value -> visitNullableInt16(v, ctx) + is NullableInt32Value -> visitNullableInt32(v, ctx) + is NullableInt64Value -> visitNullableInt64(v, ctx) + is NullableInt8Value -> visitNullableInt8(v, ctx) + is NullableIntValue -> visitNullableInt(v, ctx) + is NullableCharValue -> visitNullableChar(v, ctx) + is NullableClobValue -> visitNullableClob(v, ctx) + is NullableStringValue -> visitNullableString(v, ctx) + is NullableSymbolValue -> visitNullableSymbol(v, ctx) + is NullableTimeValue -> visitNullableTime(v, ctx) + is NullableTimestampValue -> visitNullableTimestamp(v, ctx) + } + + override fun visitNullableCollection(v: NullableCollectionValue<*>, ctx: C): R = when (v) { + is NullableBagValue -> visitNullableBag(v, ctx) + is NullableListValue -> visitNullableList(v, ctx) + is NullableSexpValue -> visitNullableSexp(v, ctx) + } + + override fun visitNullableBool(v: NullableBoolValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableNumeric(v: NullableNumericValue<*>, ctx: C): R = when (v) { + is NullableDecimalValue -> visitNullableDecimal(v, ctx) + is NullableInt16Value -> visitNullableInt16(v, ctx) + is NullableInt32Value -> visitNullableInt32(v, ctx) + is NullableInt64Value -> visitNullableInt64(v, ctx) + is NullableInt8Value -> visitNullableInt8(v, ctx) + is NullableIntValue -> visitNullableInt(v, ctx) + } + + override fun visitNullableInt8(v: NullableInt8Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableInt16(v: NullableInt16Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableInt32(v: NullableInt32Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableInt64(v: NullableInt64Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableInt(v: NullableIntValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableDecimal(v: NullableDecimalValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableFloat32(v: NullableFloat32Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableFloat64(v: NullableFloat64Value, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableText(v: NullableTextValue<*>, ctx: C): R = when (v) { + is NullableCharValue -> visitNullableChar(v, ctx) + is NullableClobValue -> visitNullableClob(v, ctx) + is NullableStringValue -> visitNullableString(v, ctx) + is NullableSymbolValue -> visitNullableSymbol(v, ctx) + } + + override fun visitNullableChar(v: NullableCharValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableString(v: NullableStringValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableSymbol(v: NullableSymbolValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableClob(v: NullableClobValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableBinary(v: NullableBinaryValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableByte(v: NullableByteValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableBlob(v: NullableBlobValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableDate(v: NullableDateValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableTime(v: NullableTimeValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableTimestamp(v: NullableTimestampValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableInterval(v: NullableIntervalValue, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableBag(v: NullableBagValue<*>, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableList(v: NullableListValue<*>, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableSexp(v: NullableSexpValue<*>, ctx: C): R = defaultVisit(v, ctx) + + override fun visitNullableStruct(v: NullableStructValue<*>, ctx: C): R = defaultVisit(v, ctx) +} diff --git a/partiql-types/src/main/kotlin/org/partiql/value/util/PartiQLValueVisitor.kt b/partiql-types/src/main/kotlin/org/partiql/value/util/PartiQLValueVisitor.kt new file mode 100644 index 0000000000..6ad69ab3ef --- /dev/null +++ b/partiql-types/src/main/kotlin/org/partiql/value/util/PartiQLValueVisitor.kt @@ -0,0 +1,198 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.util + +import org.partiql.value.BagValue +import org.partiql.value.BinaryValue +import org.partiql.value.BlobValue +import org.partiql.value.BoolValue +import org.partiql.value.ByteValue +import org.partiql.value.CharValue +import org.partiql.value.ClobValue +import org.partiql.value.CollectionValue +import org.partiql.value.DateValue +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.IntervalValue +import org.partiql.value.ListValue +import org.partiql.value.MissingValue +import org.partiql.value.NullValue +import org.partiql.value.NullableBagValue +import org.partiql.value.NullableBinaryValue +import org.partiql.value.NullableBlobValue +import org.partiql.value.NullableBoolValue +import org.partiql.value.NullableByteValue +import org.partiql.value.NullableCharValue +import org.partiql.value.NullableClobValue +import org.partiql.value.NullableCollectionValue +import org.partiql.value.NullableDateValue +import org.partiql.value.NullableDecimalValue +import org.partiql.value.NullableFloat32Value +import org.partiql.value.NullableFloat64Value +import org.partiql.value.NullableInt16Value +import org.partiql.value.NullableInt32Value +import org.partiql.value.NullableInt64Value +import org.partiql.value.NullableInt8Value +import org.partiql.value.NullableIntValue +import org.partiql.value.NullableIntervalValue +import org.partiql.value.NullableListValue +import org.partiql.value.NullableNumericValue +import org.partiql.value.NullableScalarValue +import org.partiql.value.NullableSexpValue +import org.partiql.value.NullableStringValue +import org.partiql.value.NullableStructValue +import org.partiql.value.NullableSymbolValue +import org.partiql.value.NullableTextValue +import org.partiql.value.NullableTimeValue +import org.partiql.value.NullableTimestampValue +import org.partiql.value.NumericValue +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.ScalarValue +import org.partiql.value.SexpValue +import org.partiql.value.StringValue +import org.partiql.value.StructValue +import org.partiql.value.SymbolValue +import org.partiql.value.TextValue +import org.partiql.value.TimeValue +import org.partiql.value.TimestampValue + +@PartiQLValueExperimental +public interface PartiQLValueVisitor { + + public fun visit(v: PartiQLValue, ctx: C): R + + public fun visitScalar(v: ScalarValue<*>, ctx: C): R + + public fun visitCollection(v: CollectionValue<*>, ctx: C): R + + public fun visitBool(v: BoolValue, ctx: C): R + + public fun visitNumeric(v: NumericValue<*>, ctx: C): R + + public fun visitInt8(v: Int8Value, ctx: C): R + + public fun visitInt16(v: Int16Value, ctx: C): R + + public fun visitInt32(v: Int32Value, ctx: C): R + + public fun visitInt64(v: Int64Value, ctx: C): R + + public fun visitInt(v: IntValue, ctx: C): R + + public fun visitDecimal(v: DecimalValue, ctx: C): R + + public fun visitFloat32(v: Float32Value, ctx: C): R + + public fun visitFloat64(v: Float64Value, ctx: C): R + + public fun visitText(v: TextValue<*>, ctx: C): R + + public fun visitChar(v: CharValue, ctx: C): R + + public fun visitString(v: StringValue, ctx: C): R + + public fun visitSymbol(v: SymbolValue, ctx: C): R + + public fun visitClob(v: ClobValue, ctx: C): R + + public fun visitBinary(v: BinaryValue, ctx: C): R + + public fun visitByte(v: ByteValue, ctx: C): R + + public fun visitBlob(v: BlobValue, ctx: C): R + + public fun visitDate(v: DateValue, ctx: C): R + + public fun visitTime(v: TimeValue, ctx: C): R + + public fun visitTimestamp(v: TimestampValue, ctx: C): R + + public fun visitInterval(v: IntervalValue, ctx: C): R + + public fun visitBag(v: BagValue<*>, ctx: C): R + + public fun visitList(v: ListValue<*>, ctx: C): R + + public fun visitSexp(v: SexpValue<*>, ctx: C): R + + public fun visitStruct(v: StructValue<*>, ctx: C): R + + public fun visitNull(v: NullValue, ctx: C): R + + public fun visitMissing(v: MissingValue, ctx: C): R + + public fun visitNullableScalar(v: NullableScalarValue<*>, ctx: C): R + + public fun visitNullableCollection(v: NullableCollectionValue<*>, ctx: C): R + + public fun visitNullableBool(v: NullableBoolValue, ctx: C): R + + public fun visitNullableNumeric(v: NullableNumericValue<*>, ctx: C): R + + public fun visitNullableInt8(v: NullableInt8Value, ctx: C): R + + public fun visitNullableInt16(v: NullableInt16Value, ctx: C): R + + public fun visitNullableInt32(v: NullableInt32Value, ctx: C): R + + public fun visitNullableInt64(v: NullableInt64Value, ctx: C): R + + public fun visitNullableInt(v: NullableIntValue, ctx: C): R + + public fun visitNullableDecimal(v: NullableDecimalValue, ctx: C): R + + public fun visitNullableFloat32(v: NullableFloat32Value, ctx: C): R + + public fun visitNullableFloat64(v: NullableFloat64Value, ctx: C): R + + public fun visitNullableText(v: NullableTextValue<*>, ctx: C): R + + public fun visitNullableChar(v: NullableCharValue, ctx: C): R + + public fun visitNullableString(v: NullableStringValue, ctx: C): R + + public fun visitNullableSymbol(v: NullableSymbolValue, ctx: C): R + + public fun visitNullableClob(v: NullableClobValue, ctx: C): R + + public fun visitNullableBinary(v: NullableBinaryValue, ctx: C): R + + public fun visitNullableByte(v: NullableByteValue, ctx: C): R + + public fun visitNullableBlob(v: NullableBlobValue, ctx: C): R + + public fun visitNullableDate(v: NullableDateValue, ctx: C): R + + public fun visitNullableTime(v: NullableTimeValue, ctx: C): R + + public fun visitNullableTimestamp(v: NullableTimestampValue, ctx: C): R + + public fun visitNullableInterval(v: NullableIntervalValue, ctx: C): R + + public fun visitNullableBag(v: NullableBagValue<*>, ctx: C): R + + public fun visitNullableList(v: NullableListValue<*>, ctx: C): R + + public fun visitNullableSexp(v: NullableSexpValue<*>, ctx: C): R + + public fun visitNullableStruct(v: NullableStructValue<*>, ctx: C): R +} diff --git a/partiql-types/src/test/kotlin/org/partiql/value/io/PartiQLValueTextWriterTest.kt b/partiql-types/src/test/kotlin/org/partiql/value/io/PartiQLValueTextWriterTest.kt new file mode 100644 index 0000000000..13404fd72d --- /dev/null +++ b/partiql-types/src/test/kotlin/org/partiql/value/io/PartiQLValueTextWriterTest.kt @@ -0,0 +1,756 @@ +@file:OptIn(PartiQLValueExperimental::class) + +package org.partiql.value.io + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.partiql.value.Annotations +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.bagValue +import org.partiql.value.boolValue +import org.partiql.value.charValue +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.listValue +import org.partiql.value.missingValue +import org.partiql.value.nullValue +import org.partiql.value.nullableBoolValue +import org.partiql.value.nullableCharValue +import org.partiql.value.nullableDecimalValue +import org.partiql.value.nullableFloat32Value +import org.partiql.value.nullableFloat64Value +import org.partiql.value.nullableInt16Value +import org.partiql.value.nullableInt32Value +import org.partiql.value.nullableInt64Value +import org.partiql.value.nullableInt8Value +import org.partiql.value.nullableIntValue +import org.partiql.value.nullableStringValue +import org.partiql.value.nullableSymbolValue +import org.partiql.value.sexpValue +import org.partiql.value.stringValue +import org.partiql.value.structValue +import org.partiql.value.symbolValue +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.math.BigDecimal +import java.math.BigInteger + +/** + * Basic text writing test. + * + * TODOs + * - Dates and times + * - String/Symbol escapes + */ +class PartiQLValueTextWriterTest { + + @ParameterizedTest + @MethodSource("scalars") + @Execution(ExecutionMode.CONCURRENT) + fun testScalars(case: Case) = case.assert() + + @ParameterizedTest + @MethodSource("nulls") + @Execution(ExecutionMode.CONCURRENT) + fun testNulls(case: Case) = case.assert() + + @ParameterizedTest + @MethodSource("collections") + @Execution(ExecutionMode.CONCURRENT) + fun testCollections(case: Case) = case.assert() + + @ParameterizedTest + @MethodSource("struct") + @Execution(ExecutionMode.CONCURRENT) + fun testStruct(case: Case) = case.assert() + + @ParameterizedTest + @MethodSource("collectionsFormatted") + @Execution(ExecutionMode.CONCURRENT) + fun testCollectionsFormatted(case: Case) = case.assert() + + @ParameterizedTest + @MethodSource("structFormatted") + @Execution(ExecutionMode.CONCURRENT) + fun testStructFormatted(case: Case) = case.assert() + + @ParameterizedTest + @MethodSource("nestedCollectionsFormatted") + @Execution(ExecutionMode.CONCURRENT) + fun testNestedCollectionsFormatted(case: Case) = case.assert() + + @ParameterizedTest + @MethodSource("annotations") + @Execution(ExecutionMode.CONCURRENT) + fun testAnnotations(case: Case) = case.assert() + + @OptIn(PartiQLValueExperimental::class) + companion object { + + private val annotations: Annotations = listOf("x", "y") + + private fun case(value: PartiQLValue, expected: String) = Case(value, expected, false) + + private fun formatted(value: PartiQLValue, expected: String) = Case(value, expected, true) + + @JvmStatic + fun scalars() = listOf( + case( + value = nullValue(), + expected = "null", + ), + case( + value = missingValue(), + expected = "missing", + ), + case( + value = boolValue(true), + expected = "true", + ), + case( + value = boolValue(false), + expected = "false", + ), + case( + value = int8Value(1), + expected = "1", + ), + case( + value = int16Value(1), + expected = "1", + ), + case( + value = int32Value(1), + expected = "1", + ), + case( + value = int64Value(1), + expected = "1", + ), + case( + value = intValue(BigInteger.valueOf(1)), + expected = "1", + ), + case( + value = decimalValue(BigDecimal("123.456")), + expected = "123.456", + ), + case( + value = decimalValue(BigDecimal("0.456")), + expected = "0.456", + ), + case( + value = float32Value(123.0f), + expected = "123.0", + ), + case( + value = float32Value(123f), + expected = "123.0", + ), + case( + value = float64Value(123.0), + expected = "123.0", + ), + case( + value = float64Value(123.toDouble()), + expected = "123.0", + ), + case( + value = charValue('C'), + expected = "'C'", + ), + case( + value = stringValue("word"), + expected = "'word'", + ), + case( + value = stringValue("word\nword"), + expected = "'word\nword'", + ), + case( + value = symbolValue("x"), + expected = "x", + ), + case( + value = symbolValue("f.x"), + expected = "f.x", + ), + // TODO CLOB + // TODO BINARY + // TODO BYTE + // TODO BLOB + // TODO DATE + // TODO TIME + // TODO TIMESTAMP + // TODO INTERVAL + ) + + @JvmStatic + fun nulls() = listOf( + case( + value = nullValue(), + expected = "null", + ), + case( + value = missingValue(), + expected = "missing", + ), + case( + value = nullableBoolValue(true), + expected = "true", + ), + case( + value = nullableBoolValue(false), + expected = "false", + ), + case( + value = nullableBoolValue(null), + expected = "null", + ), + case( + value = nullableInt8Value(1), + expected = "1", + ), + case( + value = nullableInt8Value(null), + expected = "null", + ), + case( + value = nullableInt16Value(1), + expected = "1", + ), + case( + value = nullableInt16Value(null), + expected = "null", + ), + case( + value = nullableInt32Value(1), + expected = "1", + ), + case( + value = nullableInt32Value(null), + expected = "null", + ), + case( + value = nullableInt64Value(1), + expected = "1", + ), + case( + value = nullableInt64Value(null), + expected = "null", + ), + case( + value = nullableIntValue(BigInteger.valueOf(1)), + expected = "1", + ), + case( + value = nullableIntValue(null), + expected = "null", + ), + case( + value = nullableDecimalValue(BigDecimal("123.456")), + expected = "123.456", + ), + case( + value = nullableDecimalValue(null), + expected = "null", + ), + case( + value = nullableFloat32Value(123.0f), + expected = "123.0", + ), + case( + value = nullableFloat32Value(null), + expected = "null", + ), + case( + value = nullableFloat64Value(123.0), + expected = "123.0", + ), + case( + value = nullableFloat64Value(null), + expected = "null", + ), + case( + value = nullableCharValue('C'), + expected = "'C'", + ), + case( + value = nullableCharValue(null), + expected = "null", + ), + case( + value = nullableStringValue("word"), + expected = "'word'", + ), + case( + value = nullableStringValue(null), + expected = "null", + ), + case( + value = nullableStringValue("word\nword"), + expected = "'word\nword'", + ), + case( + value = nullableStringValue(null), + expected = "null", + ), + case( + value = nullableSymbolValue("x"), + expected = "x", + ), + case( + value = nullableSymbolValue(null), + expected = "null", + ), + case( + value = nullableSymbolValue("f.x"), + expected = "f.x", + ), + case( + value = nullableSymbolValue(null), + expected = "null", + ), + // TODO CLOB + // TODO BINARY + // TODO BYTE + // TODO BLOB + // TODO DATE + // TODO TIME + // TODO TIMESTAMP + // TODO INTERVAL + ) + + @JvmStatic + fun collections() = listOf( + case( + value = bagValue(emptyList()), + expected = "<<>>", + ), + case( + value = listValue(emptyList()), + expected = "[]", + ), + case( + value = sexpValue(emptyList()), + expected = "()", + ), + case( + value = bagValue( + listOf( + int32Value(1), + int32Value(2), + int32Value(3), + ) + ), + expected = "<<1,2,3>>", + ), + case( + value = listValue( + listOf( + stringValue("a"), + stringValue("b"), + stringValue("c"), + ) + ), + expected = "['a','b','c']", + ), + case( + value = sexpValue( + listOf( + int32Value(1), + int32Value(2), + int32Value(3), + ) + ), + expected = "(1 2 3)", + ), + ) + + @JvmStatic + fun struct() = listOf( + case( + value = structValue(emptyList()), + expected = "{}", + ), + case( + value = structValue( + listOf( + "a" to int32Value(1), + "b" to stringValue("x"), + ) + ), + expected = "{a:1,b:'x'}", + ), + ) + + @JvmStatic + fun collectionsFormatted() = listOf( + formatted( + value = bagValue( + listOf( + int32Value(1), + int32Value(2), + int32Value(3), + ) + ), + expected = """ + |<< + | 1, + | 2, + | 3 + |>> + """.trimMargin("|"), + ), + formatted( + value = listValue( + listOf( + stringValue("a"), + stringValue("b"), + stringValue("c"), + ) + ), + expected = """ + |[ + | 'a', + | 'b', + | 'c' + |] + """.trimMargin("|"), + ), + formatted( + value = sexpValue( + listOf( + int32Value(1), + int32Value(2), + int32Value(3), + ) + ), + expected = """ + |( + | 1, + | 2, + | 3 + |) + """.trimMargin("|"), + ), + ) + + @JvmStatic + fun structFormatted() = listOf( + formatted( + value = structValue(emptyList()), + expected = "{}", + ), + formatted( + value = structValue( + listOf( + "a" to int32Value(1), + "b" to stringValue("x"), + ) + ), + expected = """ + |{ + | a: 1, + | b: 'x' + |} + """.trimMargin("|"), + ), + ) + + @JvmStatic + fun nestedCollectionsFormatted() = listOf( + formatted( + value = structValue( + listOf( + "bag" to bagValue( + listOf( + int32Value(1), + int32Value(2), + int32Value(3), + ) + ), + "list" to listValue( + listOf( + stringValue("a"), + stringValue("b"), + stringValue("c"), + ) + ), + "sexp" to sexpValue( + listOf( + int32Value(1), + int32Value(2), + int32Value(3), + ) + ), + ) + ), + expected = """ + |{ + | bag: << + | 1, + | 2, + | 3 + | >>, + | list: [ + | 'a', + | 'b', + | 'c' + | ], + | sexp: ( + | 1, + | 2, + | 3 + | ) + |} + """.trimMargin("|"), + ), + formatted( + value = bagValue( + listOf( + listValue( + listOf( + stringValue("a"), + stringValue("b"), + stringValue("c"), + ) + ), + sexpValue( + listOf( + int32Value(1), + int32Value(2), + int32Value(3), + ) + ), + structValue( + listOf( + "a" to int32Value(1), + "b" to stringValue("x"), + ) + ), + ) + ), + expected = """ + |<< + | [ + | 'a', + | 'b', + | 'c' + | ], + | ( + | 1, + | 2, + | 3 + | ), + | { + | a: 1, + | b: 'x' + | } + |>> + """.trimMargin("|"), + ), + formatted( + value = structValue( + listOf( + "bag" to bagValue(emptyList()), + "list" to listValue(emptyList()), + "sexp" to sexpValue(emptyList()), + ) + ), + expected = """ + |{ + | bag: <<>>, + | list: [], + | sexp: () + |} + """.trimMargin("|"), + ), + formatted( + value = bagValue( + listOf( + listValue(emptyList()), + sexpValue(emptyList()), + structValue(emptyList()), + ) + ), + expected = """ + |<< + | [], + | (), + | {} + |>> + """.trimMargin("|"), + ), + ) + + @JvmStatic + fun annotations() = listOf( + case( + value = nullValue(annotations), + expected = "x::y::null", + ), + case( + value = missingValue(annotations), + expected = "x::y::missing", + ), + case( + value = boolValue(true, annotations), + expected = "x::y::true", + ), + case( + value = boolValue(false, annotations), + expected = "x::y::false", + ), + case( + value = int8Value(1, annotations), + expected = "x::y::1", + ), + case( + value = int16Value(1, annotations), + expected = "x::y::1", + ), + case( + value = int32Value(1, annotations), + expected = "x::y::1", + ), + case( + value = int64Value(1, annotations), + expected = "x::y::1", + ), + case( + value = intValue(BigInteger.valueOf(1), annotations), + expected = "x::y::1", + ), + case( + value = decimalValue(BigDecimal("123.456"), annotations), + expected = "x::y::123.456", + ), + case( + value = decimalValue(BigDecimal("0.456"), annotations), + expected = "x::y::0.456", + ), + case( + value = float32Value(123.0f, annotations), + expected = "x::y::123.0", + ), + case( + value = float32Value(123f, annotations), + expected = "x::y::123.0", + ), + case( + value = float64Value(123.0, annotations), + expected = "x::y::123.0", + ), + case( + value = float64Value(123.toDouble(), annotations), + expected = "x::y::123.0", + ), + case( + value = charValue('C', annotations), + expected = "x::y::'C'", + ), + case( + value = stringValue("word", annotations), + expected = "x::y::'word'", + ), + case( + value = stringValue("word\nword", annotations), + expected = "x::y::'word\nword'", + ), + case( + value = symbolValue("x", annotations), + expected = "x::y::x", + ), + case( + value = symbolValue("f.x", annotations), + expected = "x::y::f.x", + ), + // TODO CLOB + // TODO BINARY + // TODO BYTE + // TODO BLOB + // TODO DATE + // TODO TIME + // TODO TIMESTAMP + // TODO INTERVAL + case( + value = bagValue(emptyList(), annotations), + expected = "x::y::<<>>", + ), + case( + value = listValue(emptyList(), annotations), + expected = "x::y::[]", + ), + case( + value = sexpValue(emptyList(), annotations), + expected = "x::y::()", + ), + formatted( + value = bagValue( + listOf( + listValue( + listOf( + stringValue("a", listOf("x")), + ), + listOf("list") + ), + sexpValue( + listOf( + int32Value(1, listOf("y")), + ), + listOf("sexp") + ), + structValue( + listOf( + "a" to int32Value(1, listOf("z")), + ), + listOf("struct") + ), + ) + ), + expected = """ + |<< + | list::[ + | x::'a' + | ], + | sexp::( + | y::1 + | ), + | struct::{ + | a: z::1 + | } + |>> + """.trimMargin("|"), + ), + ) + } + + @OptIn(PartiQLValueExperimental::class) + class Case( + private val value: PartiQLValue, + private val expected: String, + private val formatted: Boolean, + ) { + + fun assert() { + val buffer = ByteArrayOutputStream() + val out = PrintStream(buffer) + val writer = PartiQLValueTextWriter(out, formatted) + writer.append(value) + val actual = buffer.toString() + // string equality + Assertions.assertEquals(expected, actual) + } + } +}