Skip to content

Commit

Permalink
Refactor ShapeBuilder away from a single shared global value
Browse files Browse the repository at this point in the history
  • Loading branch information
jpschorr committed Aug 28, 2024
1 parent d6c1484 commit 0607b05
Show file tree
Hide file tree
Showing 12 changed files with 562 additions and 429 deletions.
37 changes: 18 additions & 19 deletions extension/partiql-extension-ddl/src/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,38 +231,37 @@ mod tests {
use indexmap::IndexSet;
use partiql_types::{
struct_fields, type_array, type_bag, type_float64, type_int8, type_string, type_struct,
PartiqlShapeBuilder, StructConstraint,
PartiqlShapeBuilder, ShapeBuilderExtensions, StructConstraint,
};

#[test]
fn ddl_test() {
let mut bld = PartiqlShapeBuilder::default();
let nested_attrs = struct_fields![
(
"a",
PartiqlShapeBuilder::init_or_get().any_of(vec![
PartiqlShapeBuilder::init_or_get().new_static(Static::DecimalP(5, 4)),
PartiqlShapeBuilder::init_or_get().new_static(Static::Int8),
])
[
bld.new_static(Static::DecimalP(5, 4)),
bld.new_static(Static::Int8),
]
.into_any_of(&mut bld)
),
("b", type_array![type_string![]]),
("c", type_float64!()),
("b", type_string![bld].into_array(&mut bld)),
("c", type_float64!(bld)),
];
let details = type_struct![IndexSet::from([nested_attrs])];
let details = type_struct![bld, IndexSet::from([nested_attrs])];

let fields = struct_fields![
("employee_id", type_int8![]),
("full_name", type_string![]),
(
"salary",
PartiqlShapeBuilder::init_or_get().new_static(Static::DecimalP(8, 2))
),
("employee_id", type_int8![bld]),
("full_name", type_string![bld]),
("salary", bld.new_static(Static::DecimalP(8, 2))),
("details", details),
("dependents", type_array![type_string![]])
("dependents", type_array![bld, type_string![bld]])
];
let ty = type_bag![
bld,
type_struct![bld, IndexSet::from([fields, StructConstraint::Open(false)])]
];
let ty = type_bag![type_struct![IndexSet::from([
fields,
StructConstraint::Open(false)
])]];

let expected_compact = r#""employee_id" TINYINT,"full_name" VARCHAR,"salary" DECIMAL(8, 2),"details" STRUCT<"a": UNION<DECIMAL(5, 4),TINYINT>,"b": type_array<VARCHAR>,"c": DOUBLE>,"dependents" type_array<VARCHAR>"#;
let expected_pretty = r#""employee_id" TINYINT,
Expand Down
28 changes: 16 additions & 12 deletions extension/partiql-extension-ddl/tests/ddl-tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@ use partiql_types::{BagType, Static, StructType};

#[test]
fn basic_ddl_test() {
let details_fields = struct_fields![("age", type_int!())];
let details = type_struct![IndexSet::from([details_fields])];
let mut bld = PartiqlShapeBuilder::default();
let details_fields = struct_fields![("age", type_int!(bld))];
let details = type_struct![bld, IndexSet::from([details_fields])];
let fields = [
StructField::new("id", type_int!()),
StructField::new("name", type_string!()),
StructField::new(
"address",
PartiqlShapeBuilder::init_or_get().new_non_nullable_static(Static::String),
),
StructField::new("id", type_int!(bld)),
StructField::new("name", type_string!(bld)),
StructField::new("address", bld.new_non_nullable_static(Static::String)),
StructField::new_optional("details", details.clone()),
]
.into();
let shape = type_bag![type_struct![IndexSet::from([
StructConstraint::Fields(fields),
StructConstraint::Open(false)
])]];
let shape = type_bag![
bld,
type_struct![
bld,
IndexSet::from([
StructConstraint::Fields(fields),
StructConstraint::Open(false)
])
]
];

let ddl_compact = PartiqlBasicDdlEncoder::new(DdlFormat::Compact);
let actual = ddl_compact.ddl(&shape).expect("ddl_output");
Expand Down
5 changes: 5 additions & 0 deletions partiql-common/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use indexmap::IndexMap;
use std::hash::Hash;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

pub type NodeMap<T> = IndexMap<NodeId, T>;

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct NodeId(pub u32);

#[derive(Debug)]
/// Auto-incrementing [`NodeIdGenerator`]
pub struct AutoNodeIdGenerator {
next_id: NodeId,
Expand Down
2 changes: 1 addition & 1 deletion partiql-eval/src/eval/eval_expr_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ impl UnaryValueExpr {
where
F: 'static + Fn(&Value) -> Value,
{
Self::create_typed::<STRICT, F>([type_dynamic!(); 1], args, f)
Self::create_typed::<STRICT, F>([PartiqlShape::Dynamic; 1], args, f)
}

#[allow(dead_code)]
Expand Down
52 changes: 26 additions & 26 deletions partiql-eval/src/eval/expr/coll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::eval::expr::{BindError, BindEvalExpr, EvalExpr};
use itertools::{Itertools, Unique};

use partiql_types::{
type_bool, type_numeric, ArrayType, BagType, PartiqlShape, PartiqlShapeBuilder, Static,
type_bool, type_numeric, ArrayType, BagType, DummyShapeBuilder, PartiqlShape,
PartiqlShapeBuilder, ShapeBuilder, ShapeBuilderExtensions, Static,
};
use partiql_value::Value::{Missing, Null};
use partiql_value::{BinaryAnd, BinaryOr, Value, ValueIter};
Expand Down Expand Up @@ -51,46 +52,45 @@ impl BindEvalExpr for EvalCollFn {
value.sequence_iter().map_or(Missing, &f)
})
}
let boolean_elems = [PartiqlShapeBuilder::init_or_get().any_of([
PartiqlShapeBuilder::init_or_get()
.new_static(Static::Array(ArrayType::new(Box::new(type_bool!())))),
PartiqlShapeBuilder::init_or_get()
.new_static(Static::Bag(BagType::new(Box::new(type_bool!())))),
])];
let numeric_elems = [PartiqlShapeBuilder::init_or_get().any_of([
PartiqlShapeBuilder::init_or_get().new_static(Static::Array(ArrayType::new(Box::new(
PartiqlShapeBuilder::init_or_get().any_of(type_numeric!()),
)))),
PartiqlShapeBuilder::init_or_get().new_static(Static::Bag(BagType::new(Box::new(
PartiqlShapeBuilder::init_or_get().any_of(type_numeric!()),
)))),
])];
let any_elems = [PartiqlShapeBuilder::init_or_get().any_of([
PartiqlShapeBuilder::init_or_get().new_static(Static::Array(ArrayType::new_any())),
PartiqlShapeBuilder::init_or_get().new_static(Static::Bag(BagType::new_any())),
])];

// use DummyShapeBuilder, as we don't care about shape Ids for evaluation dispatch
let mut bld = DummyShapeBuilder::default();

let boolean_elems = [
bld.new_array_of_static(Static::Bool),
bld.new_bag_of_static(Static::Bool),
]
.into_any_of(&mut bld);

let numeric_elems = [
type_numeric!(&mut bld).into_array(&mut bld),
type_numeric!(&mut bld).into_bag(&mut bld),
]
.into_any_of(&mut bld);

let any_elems = [bld.new_array_of_dyn(), bld.new_bag_of_dyn()].into_any_of(&mut bld);

match *self {
EvalCollFn::Count(setq) => {
create::<{ STRICT }, _>(any_elems, args, move |it| it.coll_count(setq))
create::<{ STRICT }, _>([any_elems], args, move |it| it.coll_count(setq))
}
EvalCollFn::Avg(setq) => {
create::<{ STRICT }, _>(numeric_elems, args, move |it| it.coll_avg(setq))
create::<{ STRICT }, _>([numeric_elems], args, move |it| it.coll_avg(setq))
}
EvalCollFn::Max(setq) => {
create::<{ STRICT }, _>(any_elems, args, move |it| it.coll_max(setq))
create::<{ STRICT }, _>([any_elems], args, move |it| it.coll_max(setq))
}
EvalCollFn::Min(setq) => {
create::<{ STRICT }, _>(any_elems, args, move |it| it.coll_min(setq))
create::<{ STRICT }, _>([any_elems], args, move |it| it.coll_min(setq))
}
EvalCollFn::Sum(setq) => {
create::<{ STRICT }, _>(numeric_elems, args, move |it| it.coll_sum(setq))
create::<{ STRICT }, _>([numeric_elems], args, move |it| it.coll_sum(setq))
}
EvalCollFn::Any(setq) => {
create::<{ STRICT }, _>(boolean_elems, args, move |it| it.coll_any(setq))
create::<{ STRICT }, _>([boolean_elems], args, move |it| it.coll_any(setq))
}
EvalCollFn::Every(setq) => {
create::<{ STRICT }, _>(boolean_elems, args, move |it| it.coll_every(setq))
create::<{ STRICT }, _>([boolean_elems], args, move |it| it.coll_every(setq))
}
}
}
Expand Down
14 changes: 9 additions & 5 deletions partiql-eval/src/eval/expr/datetime.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::eval::expr::{BindError, BindEvalExpr, EvalExpr};

use partiql_types::type_datetime;
use partiql_types::{type_datetime, DummyShapeBuilder, PartiqlShapeBuilder};
use partiql_value::Value::Missing;
use partiql_value::{DateTime, Value};

Expand Down Expand Up @@ -41,14 +41,18 @@ impl BindEvalExpr for EvalExtractFn {
let total = Duration::new(u64::from(second), nanosecond).as_nanos() as i128;
Decimal::from_i128_with_scale(total, NANOSECOND_SCALE).into()
}
// use DummyShapeBuilder, as we don't care about shape Ids for evaluation dispatch
let mut bld = DummyShapeBuilder::default();

let create = |f: fn(&DateTime) -> Value| {
UnaryValueExpr::create_typed::<{ STRICT }, _>([type_datetime!()], args, move |value| {
match value {
UnaryValueExpr::create_typed::<{ STRICT }, _>(
[type_datetime!(bld)],
args,
move |value| match value {
Value::DateTime(dt) => f(dt.as_ref()),
_ => Missing,
}
})
},
)
};

match self {
Expand Down
60 changes: 36 additions & 24 deletions partiql-eval/src/eval/expr/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::eval::expr::{BindError, BindEvalExpr, EvalExpr};
use crate::eval::EvalContext;

use partiql_types::{
type_bool, type_dynamic, type_numeric, ArrayType, BagType, PartiqlShape, PartiqlShapeBuilder,
Static, StructType,
type_bool, type_dynamic, type_numeric, ArrayType, BagType, DummyShapeBuilder, PartiqlShape,
PartiqlShapeBuilder, ShapeBuilder, ShapeBuilderExtensions, Static, StructType,
};
use partiql_value::Value::{Boolean, Missing, Null};
use partiql_value::{BinaryAnd, EqualityValue, NullableEq, NullableOrd, Tuple, Value};
Expand Down Expand Up @@ -80,7 +80,9 @@ impl BindEvalExpr for EvalOpUnary {
&self,
args: Vec<Box<dyn EvalExpr>>,
) -> Result<Box<dyn EvalExpr>, BindError> {
let any_num = PartiqlShapeBuilder::init_or_get().any_of(type_numeric!());
// use DummyShapeBuilder, as we don't care about shape Ids for evaluation dispatch
let mut bld = DummyShapeBuilder::default();
let any_num = type_numeric!(&mut bld);

let unop = |types, f: fn(&Value) -> Value| {
UnaryValueExpr::create_typed::<{ STRICT }, _>(types, args, f)
Expand All @@ -89,7 +91,7 @@ impl BindEvalExpr for EvalOpUnary {
match self {
EvalOpUnary::Pos => unop([any_num], std::clone::Clone::clone),
EvalOpUnary::Neg => unop([any_num], |operand| -operand),
EvalOpUnary::Not => unop([type_bool!()], |operand| !operand),
EvalOpUnary::Not => unop([type_bool!(bld)], |operand| !operand),
}
}
}
Expand Down Expand Up @@ -131,7 +133,7 @@ struct BoolShortCircuitArgChecker<const TARGET: bool, OnMissing: ArgShortCircuit
}

impl<const TARGET: bool, OnMissing: ArgShortCircuit> ArgChecker
for BoolShortCircuitArgChecker<TARGET, OnMissing>
for BoolShortCircuitArgChecker<TARGET, OnMissing>
{
fn arg_check<'a>(
_typ: &PartiqlShape,
Expand Down Expand Up @@ -159,6 +161,9 @@ impl BindEvalExpr for EvalOpBinary {
type EqCheck<const STRICT: bool> = DefaultArgChecker<STRICT, PropagateMissing<false>>;
type MathCheck<const STRICT: bool> = DefaultArgChecker<STRICT, PropagateMissing<true>>;

// use DummyShapeBuilder, as we don't care about shape Ids for evaluation dispatch
let mut bld = DummyShapeBuilder::default();

macro_rules! create {
($check: ty, $types: expr, $f:expr) => {
BinaryValueExpr::create_checked::<{ STRICT }, $check, _>($types, args, $f)
Expand All @@ -167,19 +172,23 @@ impl BindEvalExpr for EvalOpBinary {

macro_rules! logical {
($check: ty, $f:expr) => {
create!($check, [type_bool!(), type_bool!()], $f)
create!($check, [type_bool!(bld), type_bool!(bld)], $f)
};
}

macro_rules! equality {
($f:expr) => {
create!(EqCheck<STRICT>, [type_dynamic!(), type_dynamic!()], $f)
create!(
EqCheck<STRICT>,
[PartiqlShape::Dynamic, PartiqlShape::Dynamic],
$f
)
};
}

macro_rules! math {
($f:expr) => {{
let nums = PartiqlShapeBuilder::init_or_get().any_of(type_numeric!());
let nums = type_numeric!(&mut bld);
create!(MathCheck<STRICT>, [nums.clone(), nums], $f)
}};
}
Expand Down Expand Up @@ -209,13 +218,8 @@ impl BindEvalExpr for EvalOpBinary {
create!(
InCheck<STRICT>,
[
type_dynamic!(),
PartiqlShapeBuilder::init_or_get().any_of([
PartiqlShapeBuilder::init_or_get()
.new_static(Static::Array(ArrayType::new_any())),
PartiqlShapeBuilder::init_or_get()
.new_static(Static::Bag(BagType::new_any())),
])
type_dynamic!(bld),
[bld.new_array_of_dyn(), bld.new_bag_of_dyn()].into_any_of(&mut bld)
],
|lhs, rhs| {
match rhs.sequence_iter() {
Expand Down Expand Up @@ -254,7 +258,7 @@ impl BindEvalExpr for EvalOpBinary {
EvalOpBinary::Concat => {
create!(
Check<STRICT>,
[type_dynamic!(), type_dynamic!()],
[PartiqlShape::Dynamic, PartiqlShape::Dynamic],
|lhs, rhs| {
// TODO non-naive concat (i.e., don't just use debug print for non-strings).
let lhs = if let Value::String(s) = lhs {
Expand Down Expand Up @@ -284,7 +288,11 @@ impl BindEvalExpr for EvalBetweenExpr {
&self,
args: Vec<Box<dyn EvalExpr>>,
) -> Result<Box<dyn EvalExpr>, BindError> {
let types = [type_dynamic!(), type_dynamic!(), type_dynamic!()];
let types = [
PartiqlShape::Dynamic,
PartiqlShape::Dynamic,
PartiqlShape::Dynamic,
];
TernaryValueExpr::create_checked::<{ STRICT }, NullArgChecker, _>(
types,
args,
Expand Down Expand Up @@ -322,7 +330,9 @@ impl BindEvalExpr for EvalFnAbs {
&self,
args: Vec<Box<dyn EvalExpr>>,
) -> Result<Box<dyn EvalExpr>, BindError> {
let nums = PartiqlShapeBuilder::init_or_get().any_of(type_numeric!());
// use DummyShapeBuilder, as we don't care about shape Ids for evaluation dispatch
let mut bld = DummyShapeBuilder::default();
let nums = type_numeric!(&mut bld);
UnaryValueExpr::create_typed::<{ STRICT }, _>([nums], args, |v| {
match NullableOrd::lt(v, &Value::from(0)) {
Null => Null,
Expand All @@ -343,12 +353,14 @@ impl BindEvalExpr for EvalFnCardinality {
&self,
args: Vec<Box<dyn EvalExpr>>,
) -> Result<Box<dyn EvalExpr>, BindError> {
let shape_builder = PartiqlShapeBuilder::init_or_get();
let collections = PartiqlShapeBuilder::init_or_get().any_of([
shape_builder.new_static(Static::Array(ArrayType::new_any())),
shape_builder.new_static(Static::Bag(BagType::new_any())),
shape_builder.new_static(Static::Struct(StructType::new_any())),
]);
// use DummyShapeBuilder, as we don't care about shape Ids for evaluation dispatch
let mut bld = DummyShapeBuilder::default();
let collections = [
bld.new_array_of_dyn(),
bld.new_bag_of_dyn(),
bld.new_struct_of_dyn(),
]
.into_any_of(&mut bld);

UnaryValueExpr::create_typed::<{ STRICT }, _>([collections], args, |v| match v {
Value::List(l) => Value::from(l.len()),
Expand Down
Loading

0 comments on commit 0607b05

Please sign in to comment.