Skip to content

Commit

Permalink
partial work towards embedded value
Browse files Browse the repository at this point in the history
  • Loading branch information
jpschorr committed Oct 22, 2024
1 parent bfb5e87 commit eeab642
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 2 deletions.
11 changes: 11 additions & 0 deletions extension/partiql-extension-ion/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ bench = false

[dependencies]
partiql-value = { path = "../../partiql-value", version = "0.11.*" }
partiql-common = { path = "../../partiql-common", version = "0.11.*" }

serde = { version = "1", features = ["derive"], optional = true }

ordered-float = "4"
itertools = "0.13"
unicase = "2.7"
Expand All @@ -35,7 +39,14 @@ regex = "1.10"
thiserror = "1.0"
delegate = "0.13"

typetag = "0.2"

[dev-dependencies]

[features]
default = []
serde = [
"dep:serde",
"partiql-value/serde",
"partiql-common/serde"
]
3 changes: 3 additions & 0 deletions extension/partiql-extension-ion/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ where
Value::List(l) => self.encode_list(l.as_ref()),
Value::Bag(b) => self.encode_bag(b.as_ref()),
Value::Tuple(t) => self.encode_tuple(t.as_ref()),
Value::EmbeddedDoc(_) => {
todo!("ion encode embedded doc")
}
}
}

Expand Down
37 changes: 37 additions & 0 deletions extension/partiql-extension-ion/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,49 @@
#![deny(rust_2018_idioms)]
#![deny(clippy::all)]

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

Check warning on line 5 in extension/partiql-extension-ion/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

unused imports: `Deserialize` and `Serialize`

warning: unused imports: `Deserialize` and `Serialize` --> extension/partiql-extension-ion/src/lib.rs:5:13 | 5 | use serde::{Deserialize, Serialize}; | ^^^^^^^^^^^ ^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default

mod common;
pub mod decode;
pub mod encode;

pub use common::Encoding;

pub mod embedded {
use partiql_common::embedded_document::{EmbeddedDocument, EmbeddedDocumentType};
use std::fmt::{Debug, Formatter};
use std::hash::Hasher;

Check warning on line 16 in extension/partiql-extension-ion/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `std::hash::Hasher`

warning: unused import: `std::hash::Hasher` --> extension/partiql-extension-ion/src/lib.rs:16:9 | 16 | use std::hash::Hasher; | ^^^^^^^^^^^^^^^^^

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

#[derive(Default, Copy, Clone)]
pub struct EmbeddedIonType {}
impl EmbeddedDocumentType for EmbeddedIonType {
type Doc = EmbeddedIon;

fn construct(&self, bytes: &[u8]) -> Self::Doc {
EmbeddedIon::Unparsed(bytes.into())
}
}

#[derive(Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum EmbeddedIon {
Unparsed(Vec<u8>),
}

impl Debug for EmbeddedIon {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {

Check warning on line 38 in extension/partiql-extension-ion/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `f`

warning: unused variable: `f` --> extension/partiql-extension-ion/src/lib.rs:38:23 | 38 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ^ help: if this is intentional, prefix it with an underscore: `_f` | = note: `#[warn(unused_variables)]` on by default
todo!()
}
}

#[cfg_attr(feature = "serde", typetag::serde)]
impl EmbeddedDocument for EmbeddedIon {}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
4 changes: 4 additions & 0 deletions partiql-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ rust_decimal = { version = "1.36", default-features = false, features = ["std"]
smallvec = { version = "1" }
thiserror = "1"

dyn-clone = "1"
dyn-hash = "0.2"
typetag = "0.2"

[features]
default = []
serde = [
Expand Down
67 changes: 67 additions & 0 deletions partiql-common/src/embedded_document.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use dyn_clone::DynClone;
use dyn_hash::DynHash;
use std::fmt::Debug;
use std::sync::Arc;

#[derive(Clone)]
pub struct LazyEmbeddedDocument {
bytes: Arc<Vec<u8>>,

Check warning on line 8 in partiql-common/src/embedded_document.rs

View workflow job for this annotation

GitHub Actions / clippy

fields `bytes` and `typ` are never read

warning: fields `bytes` and `typ` are never read --> partiql-common/src/embedded_document.rs:8:5 | 7 | pub struct LazyEmbeddedDocument { | -------------------- fields in this struct 8 | bytes: Arc<Vec<u8>>, | ^^^^^ 9 | typ: DynEmbeddedTypeTag, | ^^^ | = note: `LazyEmbeddedDocument` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis = note: `#[warn(dead_code)]` on by default
typ: DynEmbeddedTypeTag,
}

impl LazyEmbeddedDocument {
pub fn new<B: Into<Vec<u8>>, T: Into<DynEmbeddedTypeTag>>(bytes: B, typ: T) -> Self {
let bytes = Arc::new(bytes.into());
let typ = typ.into();
Self { bytes, typ }
}
}

// dyn

pub type DynEmbeddedTypeTag = Box<dyn DynEmbeddedDocumentType>;

pub trait DynEmbeddedDocumentType: DynClone {
fn construct(&self, bytes: &[u8]) -> Box<dyn EmbeddedDocument>;
}

dyn_clone::clone_trait_object!(DynEmbeddedDocumentType);

pub trait DynEmbeddedDocumentTypeFactory {
fn to_dyn_type_tag(self) -> DynEmbeddedTypeTag;
}

// typed

pub type EmbeddedTypeTag<D> = Box<dyn EmbeddedDocumentType<Doc = D>>;

Check warning on line 36 in partiql-common/src/embedded_document.rs

View workflow job for this annotation

GitHub Actions / clippy

unnecessary associated type bound for not object safe associated type

warning: unnecessary associated type bound for not object safe associated type --> partiql-common/src/embedded_document.rs:36:60 | 36 | pub type EmbeddedTypeTag<D> = Box<dyn EmbeddedDocumentType<Doc = D>>; | ^^^^^^^ help: remove this bound | = note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` = note: `#[warn(unused_associated_type_bounds)]` on by default
pub trait EmbeddedDocumentType: Clone {
type Doc: EmbeddedDocument + 'static;

fn construct(&self, bytes: &[u8]) -> Self::Doc;
}

#[cfg_attr(feature = "serde", typetag::serde)]
pub trait EmbeddedDocument: Debug + DynHash + DynClone {}

dyn_hash::hash_trait_object!(EmbeddedDocument);
dyn_clone::clone_trait_object!(EmbeddedDocument);

impl<T, D> DynEmbeddedDocumentType for T
where
T: EmbeddedDocumentType<Doc = D>,
D: EmbeddedDocument + 'static,
{
fn construct(&self, bytes: &[u8]) -> Box<dyn EmbeddedDocument> {
Box::new(EmbeddedDocumentType::construct(self, bytes))
}
}

impl<T, D> DynEmbeddedDocumentTypeFactory for T
where
T: EmbeddedDocumentType<Doc = D> + 'static,
D: EmbeddedDocument + 'static,
{
fn to_dyn_type_tag(self) -> DynEmbeddedTypeTag {
Box::new(self)
}
}
2 changes: 2 additions & 0 deletions partiql-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ pub mod pretty;
pub mod syntax;

pub mod catalog;

pub mod embedded_document;
19 changes: 17 additions & 2 deletions partiql-logical-planner/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use partiql_logical::{
};
use std::borrow::Cow;

use partiql_value::{BindingsName, Value};
use partiql_value::{BindingsName, EmbeddedDoc, Value};

use std::collections::{HashMap, HashSet};

Expand All @@ -35,8 +35,10 @@ use partiql_ast_passes::error::{AstTransformError, AstTransformationError};
use crate::functions::Function;
use partiql_ast_passes::name_resolver::NameRef;
use partiql_catalog::catalog::Catalog;
use partiql_common::embedded_document::{DynEmbeddedDocumentTypeFactory, LazyEmbeddedDocument};
use partiql_common::node::NodeId;
use partiql_extension_ion::decode::{IonDecoderBuilder, IonDecoderConfig};
use partiql_extension_ion::embedded::EmbeddedIonType;
use partiql_extension_ion::Encoding;
use partiql_logical::AggFunc::{AggAny, AggAvg, AggCount, AggEvery, AggMax, AggMin, AggSum};
use partiql_logical::ValueExpr::DynamicLookup;
Expand Down Expand Up @@ -1933,7 +1935,14 @@ fn lit_to_value(lit: &Lit) -> Result<Value, AstTransformError> {
Lit::FloatLit(f) => Value::Real(OrderedFloat::from(f64::from(*f))),
Lit::DoubleLit(f) => Value::Real(OrderedFloat::from(*f)),
Lit::BoolLit(b) => Value::Boolean(*b),
Lit::EmbeddedDocLit(s, _typ) => parse_embedded_ion_str(s)?,
Lit::EmbeddedDocLit(s, _typ) => {
let new_stuff = true;
if !new_stuff {
parse_embedded_ion_str(s)?
} else {
lazy_doc(s)?
}
}
Lit::CharStringLit(s) => Value::String(Box::new(s.clone())),
Lit::NationalCharStringLit(s) => Value::String(Box::new(s.clone())),
Lit::BitStringLit(_) => {
Expand Down Expand Up @@ -2002,6 +2011,12 @@ fn parse_embedded_ion_str(contents: &str) -> Result<Value, AstTransformError> {
.map_err(|e| lit_err(contents, e))
}

fn lazy_doc(contents: &str) -> Result<Value, AstTransformError> {
let ion_typ = EmbeddedIonType::default().to_dyn_type_tag();
let ion_doc = LazyEmbeddedDocument::new(contents, ion_typ);
Ok(Value::EmbeddedDoc(Box::new(EmbeddedDoc::Lazy(ion_doc))))
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
76 changes: 76 additions & 0 deletions partiql-value/src/embedded_doc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use partiql_common::embedded_document::{EmbeddedDocument, LazyEmbeddedDocument};

Check warning on line 1 in partiql-value/src/embedded_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `EmbeddedDocument`

warning: unused import: `EmbeddedDocument` --> partiql-value/src/embedded_doc.rs:1:41 | 1 | use partiql_common::embedded_document::{EmbeddedDocument, LazyEmbeddedDocument}; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
use partiql_common::pretty::{pretty_surrounded, pretty_surrounded_doc, PrettyDoc};

Check warning on line 2 in partiql-value/src/embedded_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

unused imports: `pretty_surrounded_doc` and `pretty_surrounded`

warning: unused imports: `pretty_surrounded_doc` and `pretty_surrounded` --> partiql-value/src/embedded_doc.rs:2:30 | 2 | use partiql_common::pretty::{pretty_surrounded, pretty_surrounded_doc, PrettyDoc}; | ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
use pretty::{DocAllocator, DocBuilder};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};

pub enum EmbeddedDoc {
Lazy(LazyEmbeddedDocument),
}

impl Debug for EmbeddedDoc {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("<<TODO: Debug for EmbeddedDoc>>")
}
}

impl Hash for EmbeddedDoc {
fn hash<H: Hasher>(&self, state: &mut H) {

Check warning on line 20 in partiql-value/src/embedded_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `state`

warning: unused variable: `state` --> partiql-value/src/embedded_doc.rs:20:31 | 20 | fn hash<H: Hasher>(&self, state: &mut H) { | ^^^^^ help: if this is intentional, prefix it with an underscore: `_state` | = note: `#[warn(unused_variables)]` on by default
todo!()
}
}

impl Clone for EmbeddedDoc {
fn clone(&self) -> Self {
match self {
EmbeddedDoc::Lazy(doc) => Self::Lazy(doc.clone()),
}
}
}

impl PartialEq<Self> for EmbeddedDoc {
fn eq(&self, other: &Self) -> bool {

Check warning on line 34 in partiql-value/src/embedded_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `other`

warning: unused variable: `other` --> partiql-value/src/embedded_doc.rs:34:18 | 34 | fn eq(&self, other: &Self) -> bool { | ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
todo!()
}
}

impl Eq for EmbeddedDoc {}

#[cfg(feature = "serde")]
impl Serialize for EmbeddedDoc {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

Check warning on line 43 in partiql-value/src/embedded_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `serializer`

warning: unused variable: `serializer` --> partiql-value/src/embedded_doc.rs:43:28 | 43 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_serializer`
where
S: Serializer,
{
todo!()
}
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for EmbeddedDoc {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>

Check warning on line 53 in partiql-value/src/embedded_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `deserializer`

warning: unused variable: `deserializer` --> partiql-value/src/embedded_doc.rs:53:23 | 53 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_deserializer`
where
D: Deserializer<'de>,
{
todo!()
}
}

impl PrettyDoc for EmbeddedDoc {
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>

Check warning on line 62 in partiql-value/src/embedded_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `arena`

warning: unused variable: `arena` --> partiql-value/src/embedded_doc.rs:62:39 | 62 | fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> | ^^^^^ help: if this is intentional, prefix it with an underscore: `_arena`
where
D: DocAllocator<'b, A>,
D::Doc: Clone,
A: Clone,
{
todo!()
/*
//// TODO handle backticks better
let doc = self.data.pretty_doc(arena);
pretty_surrounded_doc(doc, "`````", "`````", arena)
*/
}
}
2 changes: 2 additions & 0 deletions partiql-value/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod bag;
mod bindings;
pub mod comparison;
mod datetime;
mod embedded_doc;
mod list;
mod pretty;
mod sort;
Expand All @@ -16,6 +17,7 @@ pub use bag::*;
pub use bindings::*;
pub use comparison::*;
pub use datetime::*;
pub use embedded_doc::*;
pub use list::*;
pub use pretty::*;
pub use sort::*;
Expand Down
1 change: 1 addition & 0 deletions partiql-value/src/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ impl PrettyDoc for Value {
Value::List(inner) => inner.pretty_doc(arena),
Value::Bag(inner) => inner.pretty_doc(arena),
Value::Tuple(inner) => inner.pretty_doc(arena),
Value::EmbeddedDoc(inner) => inner.pretty_doc(arena),
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions partiql-value/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::hash::Hash;

use rust_decimal::Decimal as RustDecimal;

use crate::embedded_doc::EmbeddedDoc;
use crate::{Bag, BindingIntoIter, BindingIter, DateTime, List, Tuple};
use rust_decimal::prelude::FromPrimitive;
#[cfg(feature = "serde")]
Expand Down Expand Up @@ -36,6 +37,7 @@ pub enum Value {
List(Box<List>),
Bag(Box<Bag>),
Tuple(Box<Tuple>),
EmbeddedDoc(Box<EmbeddedDoc>),
// TODO: add other supported PartiQL values -- sexp
}

Expand Down Expand Up @@ -232,6 +234,7 @@ impl Debug for Value {
Value::List(l) => l.fmt(f),
Value::Bag(b) => b.fmt(f),
Value::Tuple(t) => t.fmt(f),
Value::EmbeddedDoc(doc) => doc.fmt(f),
}
}
}
Expand All @@ -247,6 +250,9 @@ impl PartialOrd for Value {
impl Ord for Value {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Value::EmbeddedDoc(_), _) => todo!("EmbeddedDoc Ord"),
(_, Value::EmbeddedDoc(_)) => todo!("EmbeddedDoc Ord"),

(Value::Null, Value::Null) => Ordering::Equal,
(Value::Missing, Value::Null) => Ordering::Equal,

Expand Down

0 comments on commit eeab642

Please sign in to comment.