Skip to content

Commit

Permalink
Initializes 'beam' for type and plan serde
Browse files Browse the repository at this point in the history
  • Loading branch information
RCHowell committed Apr 30, 2024
1 parent 607c4c0 commit dda5b69
Show file tree
Hide file tree
Showing 10 changed files with 2,429 additions and 0 deletions.
642 changes: 642 additions & 0 deletions partiql-types/api/partiql-types.api

Large diffs are not rendered by default.

174 changes: 174 additions & 0 deletions partiql-types/src/main/kotlin/org/partiql/beam/BeamStatic.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package org.partiql.beam

import org.partiql.beam.io.Beam
import org.partiql.types.AnyOfType
import org.partiql.types.AnyType
import org.partiql.types.BagType
import org.partiql.types.BlobType
import org.partiql.types.BoolType
import org.partiql.types.ClobType
import org.partiql.types.DateType
import org.partiql.types.DecimalType
import org.partiql.types.FloatType
import org.partiql.types.IntType
import org.partiql.types.ListType
import org.partiql.types.MissingType
import org.partiql.types.NullType
import org.partiql.types.NumberConstraint
import org.partiql.types.SexpType
import org.partiql.types.StaticType
import org.partiql.types.StringType
import org.partiql.types.StructType
import org.partiql.types.SymbolType
import org.partiql.types.TimeType
import org.partiql.types.TimestampType
import org.partiql.types.TupleConstraint
import org.partiql.value.PartiQLTimestampExperimental

/**
* Convert a static type to a Beam Shape for serde purposes.
*/
public fun StaticType.beam(): Beam.Shape = when (this) {
is AnyOfType -> beam()
is AnyType -> Beam.Shape.TDynamic
is BlobType -> Beam.Shape.TBlob
is BoolType -> Beam.Shape.TBool
is ClobType -> Beam.Shape.TClob
is BagType -> beam()
is ListType -> beam()
is SexpType -> beam()
is DateType -> Beam.Shape.TDate
is DecimalType -> beam()
is FloatType -> beam()
is IntType -> beam()
MissingType -> Beam.Shape.TMissing
is NullType -> Beam.Shape.TNull
is StringType -> beam()
is StructType -> beam()
is SymbolType -> Beam.Shape.TSymbol
is TimeType -> beam()
is TimestampType -> beam()
else -> error("unsupported type $this") // graph
}

private fun AnyOfType.beam(): Beam.Shape.TUnion {
val shapes = ArrayList<Beam.Shape>()
// create some predictable ordering
val sorted = this.types.sortedWith { t1, t2 -> t1::class.java.simpleName.compareTo(t2::class.java.simpleName) }
for (type in sorted) {
shapes.add(type.beam())
}
return Beam.Shape.TUnion(Beam.Shapes(shapes))
}

private fun BagType.beam(): Beam.Shape.TBag {
return Beam.Shape.TBag(this.elementType.beam())
}

private fun ListType.beam(): Beam.Shape.TList {
return Beam.Shape.TList(this.elementType.beam())
}

private fun SexpType.beam(): Beam.Shape.TSexp {
return Beam.Shape.TSexp(this.elementType.beam())
}

private fun DecimalType.beam(): Beam.Shape {
return when (precisionScaleConstraint) {
is DecimalType.PrecisionScaleConstraint.Unconstrained -> {
Beam.Shape.TDecimal
}
is DecimalType.PrecisionScaleConstraint.Constrained -> {
val p = precisionScaleConstraint.precision.toLong()
val s = precisionScaleConstraint.scale.toLong()
Beam.Shape.TNumeric(p, s)
}
}
}

private fun FloatType.beam(): Beam.Shape {
// StaticType does not have float constraints.
return Beam.Shape.TFloat64
}

private fun IntType.beam(): Beam.Shape {
return when (this.rangeConstraint) {
IntType.IntRangeConstraint.SHORT -> Beam.Shape.TInt16
IntType.IntRangeConstraint.INT4 -> Beam.Shape.TInt32
IntType.IntRangeConstraint.LONG -> Beam.Shape.TInt64
IntType.IntRangeConstraint.UNCONSTRAINED -> Beam.Shape.TInteger
}
}

private fun StringType.beam(): Beam.Shape {
return when (lengthConstraint) {
is StringType.StringLengthConstraint.Constrained -> {
when (lengthConstraint.length) {
is NumberConstraint.Equals -> Beam.Shape.TCharFixed(lengthConstraint.length.value.toLong())
is NumberConstraint.UpTo -> Beam.Shape.TCharVarying(lengthConstraint.length.value.toLong())
}
}
is StringType.StringLengthConstraint.Unconstrained -> Beam.Shape.TString
}
}

private fun StructType.beam(): Beam.Shape.TStruct {
var isClosed = false
var isOrdered = false
var hasUniqueKeys = false
var fields = ArrayList<Beam.Field>()
for (field in this.fields) {
fields.add(
Beam.Field(
name = field.key,
shape = field.value.beam(),
)
)
}
for (constraint in constraints) {
when (constraint) {
is TupleConstraint.Open -> isClosed = true
is TupleConstraint.Ordered -> isOrdered = true
is TupleConstraint.UniqueAttrs -> hasUniqueKeys = true
}
}
return Beam.Shape.TStruct(
isClosed = isClosed,
isOrdered = isOrdered,
hasUniqueFields = hasUniqueKeys,
fields = Beam.Fields(fields),
)
}

private fun TimeType.beam(): Beam.Shape {
if (precision == null) {
error("Time precision is required")
}
return when (withTimeZone) {
true -> Beam.Shape.TTime(
precision = precision.toLong(),
)
else -> Beam.Shape.TTimeTz(
precision = precision.toLong(),
offsetHour = 0L,
offsetMinute = 0L,
)
}
}

@OptIn(PartiQLTimestampExperimental::class)
private fun TimestampType.beam(): Beam.Shape {
if (precision == null) {
error("Time precision is required")
}
return when (withTimeZone) {
true -> Beam.Shape.TTime(
precision = precision.toLong(),
)
else -> Beam.Shape.TTimeTz(
precision = precision.toLong(),
offsetHour = 0L,
offsetMinute = 0L,
)
}
}
25 changes: 25 additions & 0 deletions partiql-types/src/main/kotlin/org/partiql/beam/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
= PartiQL Beam

PartiQL shape and plan encodings.

== Usage

[source,kotlin]
----
// toString
val example = Shape.TNumeric(38, 0)
println(example)
// Output:
// 'shape.numeric'::{
// precision: 38,
// scale: 0
// }
// write
val writer = BeamWriter.text(out)
writer.write(example) // base
writer.writeShapeTNumeric(example) // concrete
// read
// similar to writer, ignore for now
----
113 changes: 113 additions & 0 deletions partiql-types/src/main/kotlin/org/partiql/beam/beam.ridl
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// PartiQL Shapes
type shape union {

// Bool type
t_bool: unit,

// Exact-numeric types
t_int8: unit,
t_int16: unit,
t_int32: unit,
t_int64: unit,
t_integer: unit, // Ion int
t_decimal: unit, // Ion decimal
t_numeric: struct {
precision: int,
scale: int,
},

// Approximate-numeric types
t_float32: unit,
t_float64: unit,
t_float: struct { precision: int },

// Character String Shapes
t_char_fixed: struct {
length: int,
},
t_char_varying: struct {
length: int,
},
t_string: unit,
t_symbol: unit,
t_clob: unit,

// Bit String Shapes
t_bit_fixed: struct {
length: int,
},
t_bit_varying: struct {
length: int,
},

// Byte String Shapes
t_binary: unit,
t_byte_fixed: struct {
length: int,
},
t_byte_varying: struct {
length: int,
},
t_blob: unit,

// Date/Time Shapes
t_date: unit,
t_time: struct {
precision: int,
},
t_time_tz: struct {
precision: int,
offset_hour: int,
offset_minute: int,
},
t_timestamp: struct {
precision: int,
},
t_timestamp_tz: struct {
precision: int,
offset_hour: int,
offset_minute: int,
},

// Collection Shapes
t_bag: struct {
items: shape,
},
t_list: struct {
items: shape,
},
t_sexp: struct {
items: shape,
},

// Struct Shape (currently assuming open/closed/ordered)
t_struct: struct {
fields: fields,
is_closed: bool,
is_ordered: bool,
has_unique_fields: bool,
},

// Absent Shapes
t_null: unit,
t_missing: unit,

// Union Shape
t_union: struct {
shapes: shapes,
},

// Dynamic shape
t_dynamic: unit,
};

type shapes shape[];

type fields field[];

type field struct {
name: string,
shape: shape,
};

// Plans to follow
Loading

0 comments on commit dda5b69

Please sign in to comment.