Skip to content

Commit

Permalink
Add category for PartiqlShape
Browse files Browse the repository at this point in the history
  • Loading branch information
jpschorr committed Jan 14, 2025
1 parent a409335 commit d9dee1f
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 39 deletions.
93 changes: 57 additions & 36 deletions partiql-eval/src/eval/eval_expr_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::eval::expr::{BindError, EvalExpr};
use crate::eval::EvalContext;
use itertools::Itertools;

use partiql_types::{PartiqlShape, Static, TYPE_DYNAMIC};
use partiql_types::{PartiqlShape, Static, StaticCategory, TYPE_DYNAMIC};
use partiql_value::Value::{Missing, Null};
use partiql_value::{Tuple, Value};

Expand All @@ -14,44 +14,66 @@ use std::hash::Hash;

use std::marker::PhantomData;

use partiql_value::datum::{DatumCategory, DatumCategoryRef, DatumValueRef};
use std::ops::ControlFlow;

// TODO replace with type system's subsumption once it is in place
#[inline]
pub(crate) fn subsumes(typ: &PartiqlShape, value: &Value) -> bool {
match (typ, value) {
(_, Value::Null) => true,
(_, Value::Missing) => true,
(PartiqlShape::Dynamic, _) => true,
(PartiqlShape::AnyOf(anyof), val) => anyof.types().any(|typ| subsumes(typ, val)),
(PartiqlShape::Static(s), val) => match (s.ty(), val) {
(
Static::Int | Static::Int8 | Static::Int16 | Static::Int32 | Static::Int64,
Value::Integer(_),
) => true,
(Static::Bool, Value::Boolean(_)) => true,
(Static::Decimal | Static::DecimalP(_, _), Value::Decimal(_)) => true,
(Static::Float32 | Static::Float64, Value::Real(_)) => true,
(
Static::String | Static::StringFixed(_) | Static::StringVarying(_),
Value::String(_),
) => true,
(Static::Struct(_), Value::Tuple(_)) => true,
(Static::Bag(b_type), Value::Bag(b_values)) => {
let bag_element_type = b_type.element_type();
let mut b_values = b_values.iter();
b_values.all(|b_value| subsumes(bag_element_type, b_value))
}
(Static::DateTime, Value::DateTime(_)) => true,
/// A Trait that represents the ability to match an expected 'type' judgement against a provided value.
trait TypeSatisfier {
/// Returns true if the provided [`Value`] satisfies this type expectation.
fn satisfies(&self, value: &Value) -> bool;
}

(Static::Array(a_type), Value::List(l_values)) => {
let array_element_type = a_type.element_type();
let mut l_values = l_values.iter();
l_values.all(|l_value| subsumes(array_element_type, l_value))
/// Type subsumbtion for [`Static`]
impl TypeSatisfier for Static {
fn satisfies(&self, value: &Value) -> bool {
match (self.category(), value.category()) {
(_, DatumCategoryRef::Null) => true,
(_, DatumCategoryRef::Missing) => true,
(StaticCategory::Scalar(ty), DatumCategoryRef::Scalar(scalar)) => match scalar {
DatumValueRef::Value(scalar) => {
matches!(
(ty, scalar),
(
Static::Int
| Static::Int8
| Static::Int16
| Static::Int32
| Static::Int64,
Value::Integer(_),
) | (Static::Bool, Value::Boolean(_))
| (Static::Decimal | Static::DecimalP(_, _), Value::Decimal(_))
| (Static::Float32 | Static::Float64, Value::Real(_))
| (
Static::String | Static::StringFixed(_) | Static::StringVarying(_),
Value::String(_),
)
| (Static::DateTime, Value::DateTime(_))
)
}
},
(StaticCategory::Sequence(shape), DatumCategoryRef::Sequence(seq)) => match shape {
PartiqlShape::Dynamic | PartiqlShape::Undefined => true,
shape => seq.into_iter().all(|v| shape.satisfies(v)),
},
(StaticCategory::Tuple(), DatumCategoryRef::Tuple(_)) => {
true // TODO when Static typing knows how to type a tuple
}
_ => false,
},
_ => false,
}
}
}

/// Type subsumbtion for [`PartiqlShape`]
impl TypeSatisfier for PartiqlShape {
fn satisfies(&self, value: &Value) -> bool {
match (self, value) {
(_, Value::Null) => true,
(_, Value::Missing) => true,
(PartiqlShape::Dynamic, _) => true,
(PartiqlShape::AnyOf(anyof), val) => anyof.types().any(|typ| typ.satisfies(val)),
(PartiqlShape::Static(s), val) => s.ty().satisfies(val),
_ => false,
}
}
}

Expand Down Expand Up @@ -187,7 +209,7 @@ impl<const STRICT: bool, OnMissing: ArgShortCircuit> ArgChecker
Missing => ArgCheckControlFlow::Propagate(OnMissing::propagate()),
Null => ArgCheckControlFlow::Propagate(Null),
val => {
if subsumes(typ, val) {
if typ.satisfies(val) {
ArgCheckControlFlow::Continue(arg)
} else {
err()
Expand Down Expand Up @@ -322,7 +344,6 @@ where
for (idx, arg) in args.iter().enumerate() {
let typ = types(idx);
let arg = arg.evaluate(bindings, ctx);

match ArgC::arg_check(typ, arg) {
ArgCheckControlFlow::Continue(v) => {
if propagate.is_none() {
Expand Down
15 changes: 15 additions & 0 deletions partiql-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,12 @@ pub enum Static {
// TODO Add BitString, ByteString, Blob, Clob, and Graph types
}

pub enum StaticCategory<'a> {
Tuple(),
Sequence(&'a PartiqlShape),
Scalar(&'a Static),
}

impl Static {
pub fn is_scalar(&self) -> bool {
!matches!(self, Static::Struct(_) | Static::Bag(_) | Static::Array(_))
Expand All @@ -754,6 +760,15 @@ impl Static {
pub fn is_struct(&self) -> bool {
matches!(self, Static::Struct(_))
}

pub fn category(&self) -> StaticCategory<'_> {
match self {
Static::Struct(_) => StaticCategory::Tuple(),
Static::Bag(b) => StaticCategory::Sequence(b.element_type()),
Static::Array(b) => StaticCategory::Sequence(b.element_type()),
_ => StaticCategory::Scalar(self),
}
}
}

// TODO, this should probably be via a prettyprint...
Expand Down
66 changes: 63 additions & 3 deletions partiql-value/src/datum.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{Bag, BindingsName, List, Tuple, Value};
use crate::{
Bag, BagIntoIterator, BagIter, BindingsName, List, ListIntoIterator, ListIter, Tuple, Value,
};
use std::borrow::Cow;
use std::error::Error;

Expand Down Expand Up @@ -194,11 +196,13 @@ pub trait SequenceDatum {
}
}

pub trait RefSequenceView<'a, DV: DatumValue<DV>>: SequenceDatum {
pub trait RefSequenceView<'a, DV: DatumValue<DV> + 'a>:
SequenceDatum + IntoIterator<Item = &'a DV>
{
fn get_val(&self, k: i64) -> Option<Cow<'a, DV>>;
}

pub trait OwnedSequenceView<D: Datum<D>>: SequenceDatum {
pub trait OwnedSequenceView<D: Datum<D>>: SequenceDatum + IntoIterator<Item = D> {
fn take_val(self, k: i64) -> Option<D>;
fn take_val_boxed(self: Box<Self>, k: i64) -> Option<D>;
}
Expand Down Expand Up @@ -253,3 +257,59 @@ impl OwnedSequenceView<Value> for DatumSeqOwned {
self.take_val(k)
}
}

impl<'a> IntoIterator for DatumSeqRef<'a> {
type Item = &'a Value;
type IntoIter = DatumSeqRefIterator<'a>;

fn into_iter(self) -> Self::IntoIter {
match self {
DatumSeqRef::List(l) => DatumSeqRefIterator::List(l.into_iter()),
DatumSeqRef::Bag(b) => DatumSeqRefIterator::Bag(b.into_iter()),
}
}
}

pub enum DatumSeqRefIterator<'a> {
List(ListIter<'a>),
Bag(BagIter<'a>),
}

impl<'a> Iterator for DatumSeqRefIterator<'a> {
type Item = &'a Value;

fn next(&mut self) -> Option<Self::Item> {
match self {
DatumSeqRefIterator::List(l) => l.next(),
DatumSeqRefIterator::Bag(b) => b.next(),
}
}
}

impl IntoIterator for DatumSeqOwned {
type Item = Value;
type IntoIter = DatumSeqOwnedIterator;

fn into_iter(self) -> Self::IntoIter {
match self {
DatumSeqOwned::List(l) => DatumSeqOwnedIterator::List(l.into_iter()),
DatumSeqOwned::Bag(b) => DatumSeqOwnedIterator::Bag(b.into_iter()),
}
}
}

pub enum DatumSeqOwnedIterator {
List(ListIntoIterator),
Bag(BagIntoIterator),
}

impl Iterator for DatumSeqOwnedIterator {
type Item = Value;

fn next(&mut self) -> Option<Self::Item> {
match self {
DatumSeqOwnedIterator::List(l) => l.next(),
DatumSeqOwnedIterator::Bag(b) => b.next(),
}
}
}

0 comments on commit d9dee1f

Please sign in to comment.