From 2676835267930238665e2014458429eeb840b674 Mon Sep 17 00:00:00 2001 From: Arash M <27716912+am357@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:29:47 -0700 Subject: [PATCH] Add metas to PartiQL Commons Adds an implementation for storing metadata for PartiQL objects. Currently, the implementation does not include any traits. It introduces `PartiqlMetadata` and `PartiqlMetaValue` structures: ```rust let foo_val = PartiqlMetaValue::String("foo".to_string()); let i64_val = PartiqlMetaValue::Int64(2); let expected_vec_val = vec![foo_val, i64_val]; let expected_bool_val = true; let expected_int_val = 2; let expected_float_val = 2.5; let expected_str_val = "foo"; let mut expected_map = PartiqlMetadata::new(); expected_map.insert("bool value", expected_bool_val.into()); expected_map.insert("integer value", expected_int_val.into()); let mut metas = PartiqlMetadata::new(); metas.insert("vec value", expected_vec_val.clone().into()); metas.insert("bool value", expected_bool_val.into()); metas.insert("integer value", expected_int_val.into()); metas.insert("float value", expected_float_val.into()); metas.insert("string value", expected_str_val.into()); metas.insert("map value", expected_map.clone().into()); let vec_val = metas.vec_value("vec value").expect("vec meta value"); let bool_val = metas.bool_value("bool value").expect("bool meta value"); let int_val = metas.i32_value("integer value").expect("i32 meta value"); let float_val = metas.f64_value("float value").expect("f64 meta value"); let string_val = metas.string_value("string value").expect("string meta value"); let map_val = metas.map_value("map value").expect("map meta value"); assert_eq!(vec_val, expected_vec_val.clone()); assert_eq!(bool_val, expected_bool_val.clone()); assert_eq!(int_val, expected_int_val.clone()); assert_eq!(float_val, expected_float_val.clone()); assert_eq!(string_val, expected_str_val); assert_eq!(map_val, expected_map.clone()); ``` --- partiql-common/Cargo.toml | 5 +- partiql-common/src/lib.rs | 1 + partiql-common/src/metadata.rs | 366 +++++++++++++++++++++++ partiql-common/src/node.rs | 46 +-- partiql-eval/src/eval/mod.rs | 1 + partiql-parser/Cargo.toml | 1 - partiql-parser/src/parse/partiql.lalrpop | 4 +- partiql-types/src/lib.rs | 3 - 8 files changed, 374 insertions(+), 53 deletions(-) create mode 100644 partiql-common/src/metadata.rs diff --git a/partiql-common/Cargo.toml b/partiql-common/Cargo.toml index 2e487b1b..a20dc02d 100644 --- a/partiql-common/Cargo.toml +++ b/partiql-common/Cargo.toml @@ -23,15 +23,14 @@ bench = false indexmap = "2.2" pretty = "0.12" serde = { version = "1.*", features = ["derive"], optional = true } +rust_decimal = { version = "1.25.0", default-features = false, features = ["std"] } smallvec = { version = "1.*" } thiserror = "1.0" -dashmap = "6.0" [features] default = [] serde = [ "dep:serde", "indexmap/serde", - "smallvec/serde", - "dashmap/serde" + "smallvec/serde" ] diff --git a/partiql-common/src/lib.rs b/partiql-common/src/lib.rs index 3f107b89..ae5c35ae 100644 --- a/partiql-common/src/lib.rs +++ b/partiql-common/src/lib.rs @@ -1,4 +1,5 @@ #![deny(rust_2018_idioms)] #![deny(clippy::all)] +mod metadata; pub mod node; pub mod syntax; diff --git a/partiql-common/src/metadata.rs b/partiql-common/src/metadata.rs new file mode 100644 index 00000000..8568f9e7 --- /dev/null +++ b/partiql-common/src/metadata.rs @@ -0,0 +1,366 @@ +use indexmap::map::Entry; +use indexmap::IndexMap; +use rust_decimal::Decimal; +use std::borrow::Borrow; +use std::fmt::Result; +use std::fmt::{Display, Formatter}; +use std::hash::Hash; + +#[derive(Debug, Clone, PartialEq)] +pub struct PartiqlMetadata +where + T: Eq + Clone + Hash + Borrow, +{ + inner: IndexMap>, +} + +impl PartiqlMetadata +where + T: Eq + Clone + Hash + Borrow, +{ + pub fn new() -> Self { + Self { + inner: IndexMap::new(), + } + } + + pub fn insert(&mut self, key: T, value: PartiqlMetaValue) { + self.inner.insert(key, value); + } + + pub fn get(&self, key: &T) -> Option<&PartiqlMetaValue> { + self.inner.get(key) + } + + pub fn get_mut(&mut self, key: &T) -> Option<&mut PartiqlMetaValue> { + self.inner.get_mut(key) + } + + pub fn contains_key(&self, key: &T) -> bool { + self.inner.contains_key(key) + } + + pub fn keys(&self) -> impl Iterator { + self.inner.keys() + } + + pub fn values(&self) -> impl Iterator> { + self.inner.values() + } + + pub fn values_mut(&mut self) -> impl Iterator> { + self.inner.values_mut() + } + + pub fn entry(&mut self, key: T) -> Entry<'_, T, PartiqlMetaValue> { + self.inner.entry(key) + } + + pub fn clear(&mut self) { + self.inner.clear(); + } + + pub fn remove(&mut self, key: &T) -> Option> { + self.inner.swap_remove(key) + } + + pub fn len(&self) -> usize { + self.inner.len() + } + + pub fn iter(&self) -> impl Iterator)> { + self.inner.iter() + } + + pub fn iter_mut(&mut self) -> impl Iterator)> { + self.inner.iter_mut() + } + + pub fn vec_value(&self, key: &str) -> Option>> { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Array(v)) = value { + Some(v.clone()) + } else { + None + } + } + + pub fn bool_value(&self, key: &str) -> Option { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Bool(v)) = value { + Some(*v) + } else { + None + } + } + + pub fn f32_value(&self, key: &str) -> Option { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Float32(v)) = value { + Some(*v) + } else { + None + } + } + + pub fn f64_value(&self, key: &str) -> Option { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Float64(v)) = value { + Some(*v) + } else { + None + } + } + + pub fn decimal_value(&self, key: &str) -> Option { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Decimal(v)) = value { + Some(*v) + } else { + None + } + } + + pub fn i32_value(&self, key: &str) -> Option { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Int32(v)) = value { + Some(*v) + } else { + None + } + } + + pub fn i64_value(&self, key: &str) -> Option { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Int64(v)) = value { + Some(*v) + } else { + None + } + } + + pub fn map_value(&self, key: &str) -> Option> { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::Map(v)) = value { + Some(v.clone()) + } else { + None + } + } + + pub fn string_value(&self, key: &str) -> Option { + let value = self.inner.get(key); + if let Some(PartiqlMetaValue::String(v)) = value { + Some(v.clone()) + } else { + None + } + } +} + +impl Default for PartiqlMetadata +where + T: Eq + Clone + Hash + Borrow, +{ + fn default() -> Self { + Self { + inner: IndexMap::new(), + } + } +} + +impl FromIterator<(T, PartiqlMetaValue)> for PartiqlMetadata +where + T: Eq + Clone + Hash + Borrow, +{ + fn from_iter)>>(iter: I) -> Self { + let inner = iter.into_iter().collect(); + Self { inner } + } +} + +impl IntoIterator for PartiqlMetadata +where + T: Eq + Clone + Hash + Borrow, +{ + type Item = (T, PartiqlMetaValue); + type IntoIter = indexmap::map::IntoIter>; + + fn into_iter(self) -> Self::IntoIter { + self.inner.into_iter() + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + Array(Vec>), + Bool(bool), + Float32(f32), + Float64(f64), + Decimal(Decimal), + Int32(i32), + Int64(i64), + Map(PartiqlMetadata), + String(String), +} + +impl From for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: bool) -> Self { + PartiqlMetaValue::Bool(value) + } +} + +impl From for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: i32) -> Self { + PartiqlMetaValue::Int32(value) + } +} +impl From for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: i64) -> Self { + PartiqlMetaValue::Int64(value) + } +} + +impl From for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: f64) -> Self { + PartiqlMetaValue::Float64(value) + } +} + +impl From for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: String) -> Self { + PartiqlMetaValue::String(value) + } +} +impl From<&'static str> for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: &'static str) -> Self { + PartiqlMetaValue::String(value.to_owned()) + } +} + +impl From>> for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: Vec>) -> Self { + PartiqlMetaValue::Array(value) + } +} + +impl From<&[PartiqlMetaValue]> for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(slice: &[PartiqlMetaValue]) -> Self { + PartiqlMetaValue::Array(slice.to_vec()) + } +} + +impl From> for PartiqlMetaValue +where + T: Eq + Clone + Hash + Borrow, +{ + fn from(value: PartiqlMetadata) -> Self { + PartiqlMetaValue::Map(value) + } +} + +impl Display for PartiqlMetaValue +where + T: Eq + Hash + Display + Clone + Borrow, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match self { + PartiqlMetaValue::Array(arr) => { + write!(f, "[")?; + for (idx, item) in arr.iter().enumerate() { + if idx > 0 { + write!(f, ", ")?; + } + write!(f, "{}", item)?; + } + write!(f, "]") + } + PartiqlMetaValue::Bool(v) => write!(f, "{}", v), + PartiqlMetaValue::Decimal(v) => write!(f, "{}", v), + PartiqlMetaValue::Float64(v) => write!(f, "{}", v), + PartiqlMetaValue::Float32(v) => write!(f, "{}", v), + PartiqlMetaValue::Int32(v) => write!(f, "{}", v), + PartiqlMetaValue::Int64(v) => write!(f, "{}", v), + PartiqlMetaValue::Map(map) => { + write!(f, "{{")?; + for (t, v) in map.iter() { + write!(f, "{}: {} , ", t, v)?; + } + write!(f, "}}") + } + PartiqlMetaValue::String(v) => write!(f, "{}", v), + } + } +} + +#[cfg(test)] +mod tests { + use crate::metadata::{PartiqlMetaValue, PartiqlMetadata}; + + #[test] + fn test_metadata() { + let foo_val = PartiqlMetaValue::String("foo".to_string()); + let i64_val = PartiqlMetaValue::Int64(2); + + let expected_vec_val = vec![foo_val, i64_val]; + let expected_bool_val = true; + let expected_int_val = 2; + let expected_float_val = 2.5; + let expected_str_val = "foo"; + + let mut expected_map = PartiqlMetadata::new(); + expected_map.insert("bool value", expected_bool_val.into()); + expected_map.insert("integer value", expected_int_val.into()); + + let mut metas = PartiqlMetadata::new(); + metas.insert("vec value", expected_vec_val.clone().into()); + metas.insert("bool value", expected_bool_val.into()); + metas.insert("integer value", expected_int_val.into()); + metas.insert("float value", expected_float_val.into()); + metas.insert("string value", expected_str_val.into()); + metas.insert("map value", expected_map.clone().into()); + + let vec_val = metas.vec_value("vec value").expect("vec meta value"); + let bool_val = metas.bool_value("bool value").expect("bool meta value"); + let int_val = metas.i32_value("integer value").expect("i32 meta value"); + let float_val = metas.f64_value("float value").expect("f64 meta value"); + let string_val = metas + .string_value("string value") + .expect("string meta value"); + let map_val = metas.map_value("map value").expect("map meta value"); + + assert_eq!(vec_val, expected_vec_val.clone()); + assert_eq!(bool_val, expected_bool_val.clone()); + assert_eq!(int_val, expected_int_val.clone()); + assert_eq!(float_val, expected_float_val.clone()); + assert_eq!(string_val, expected_str_val); + assert_eq!(map_val, expected_map.clone()); + } +} diff --git a/partiql-common/src/node.rs b/partiql-common/src/node.rs index bd736f44..9626d0f0 100644 --- a/partiql-common/src/node.rs +++ b/partiql-common/src/node.rs @@ -1,52 +1,10 @@ -use dashmap::DashMap; +use indexmap::IndexMap; use std::sync::{Arc, RwLock}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct NodeMap { - map: DashMap, - #[cfg_attr(feature = "serde", serde(skip))] - order: Arc>>, -} - -impl Default for NodeMap { - fn default() -> Self { - Self::new() - } -} - -impl NodeMap { - pub fn new() -> Self { - NodeMap { - map: DashMap::new(), - order: Arc::new(RwLock::new(Vec::new())), - } - } - - pub fn with_capacity(capacity: usize) -> Self { - NodeMap { - map: DashMap::with_capacity(capacity), - order: Arc::new(RwLock::new(Vec::with_capacity(capacity))), - } - } - - pub fn insert(&self, node_id: NodeId, value: T) -> Option { - let mut order = self.order.write().expect("NodeMap order write lock"); - if self.map.contains_key(&node_id) { - self.map.insert(node_id, value) - } else { - order.push(node_id); - self.map.insert(node_id, value) - } - } - - pub fn get(&self, node_id: &NodeId) -> Option> { - self.map.get(node_id) - } -} +pub type NodeMap = IndexMap; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/partiql-eval/src/eval/mod.rs b/partiql-eval/src/eval/mod.rs index d693427d..5cfe7dce 100644 --- a/partiql-eval/src/eval/mod.rs +++ b/partiql-eval/src/eval/mod.rs @@ -146,6 +146,7 @@ pub type EvalResult = Result; /// Represents result of evaluation as an evaluated entity. #[non_exhaustive] #[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Evaluated { pub result: Value, } diff --git a/partiql-parser/Cargo.toml b/partiql-parser/Cargo.toml index 74dbce68..fa666915 100644 --- a/partiql-parser/Cargo.toml +++ b/partiql-parser/Cargo.toml @@ -36,7 +36,6 @@ bigdecimal = "~0.2.0" rust_decimal = { version = "1.25.0", default-features = false, features = ["std"] } bitflags = "2" -dashmap = "6.0.1" lalrpop-util = "0.20" logos = "0.12" diff --git a/partiql-parser/src/parse/partiql.lalrpop b/partiql-parser/src/parse/partiql.lalrpop index ef10a99b..d65ca1b0 100644 --- a/partiql-parser/src/parse/partiql.lalrpop +++ b/partiql-parser/src/parse/partiql.lalrpop @@ -287,8 +287,8 @@ FromClause: ast::AstNode = { ast::FromSource::Join(node) => node.id, }; - let start = state.locations.get(&start_id).map_or(total.start.0.clone(), |v| v.start.0.clone()); - let end = state.locations.get(&end_id).map_or(total.end.0.clone(), |v| v.end.0.clone()); + let start = state.locations.get(&start_id).unwrap_or(&total).start.0.clone(); + let end = state.locations.get(&end_id).unwrap_or(&total).end.0.clone(); let range = start..end; let join = state.node(ast::Join { kind: ast::JoinKind::Cross, diff --git a/partiql-types/src/lib.rs b/partiql-types/src/lib.rs index 50e58ce3..8de32be0 100644 --- a/partiql-types/src/lib.rs +++ b/partiql-types/src/lib.rs @@ -6,7 +6,6 @@ use indexmap::IndexSet; use itertools::Itertools; use miette::Diagnostic; use partiql_common::node::{AutoNodeIdGenerator, NodeId, NodeIdGenerator}; -use std::collections::HashMap; use std::fmt::{Debug, Display, Formatter}; use std::hash::{Hash, Hasher}; use std::sync::OnceLock; @@ -622,8 +621,6 @@ impl Display for StaticType { } } -pub type StaticTypeMetas = HashMap; - #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum Static { // Scalar Types