Skip to content

Commit 7782bb2

Browse files
authored
Add SimpleGraph; minimal graph needed to read experimental tests (#546)
1 parent e47058e commit 7782bb2

File tree

18 files changed

+731
-25
lines changed

18 files changed

+731
-25
lines changed

extension/partiql-extension-ion/src/boxed_ion.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ pub struct BoxedIon {
169169

170170
#[cfg(feature = "serde")]
171171
impl Serialize for BoxedIon {
172-
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
172+
fn serialize<S>(&self, _serializer: S) -> std::result::Result<S::Ok, S::Error>
173173
where
174174
S: Serializer,
175175
{
@@ -179,7 +179,7 @@ impl Serialize for BoxedIon {
179179

180180
#[cfg(feature = "serde")]
181181
impl<'de> Deserialize<'de> for BoxedIon {
182-
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
182+
fn deserialize<D>(_deserializer: D) -> std::result::Result<Self, D::Error>
183183
where
184184
D: Deserializer<'de>,
185185
{

extension/partiql-extension-ion/src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) const BAG_ANNOT: &str = "$bag";
1616
pub(crate) const TIME_ANNOT: &str = "$time";
1717
pub(crate) const DATE_ANNOT: &str = "$date";
1818
pub(crate) const MISSING_ANNOT: &str = "$missing";
19-
19+
pub(crate) const GRAPH_ANNOT: &str = "$graph";
2020
pub(crate) const TIME_PART_HOUR_KEY: &str = "hour";
2121
pub(crate) const TIME_PART_MINUTE_KEY: &str = "minute";
2222
pub(crate) const TIME_PART_SECOND_KEY: &str = "second";

extension/partiql-extension-ion/src/decode.rs

Lines changed: 230 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use delegate::delegate;
22
use ion_rs_old::{Decimal, Int, IonError, IonReader, IonType, StreamItem, Symbol};
33
use once_cell::sync::Lazy;
4-
use partiql_value::{Bag, DateTime, List, Tuple, Value, Variant};
4+
use partiql_value::{Bag, DateTime, EdgeSpec, Graph, List, SimpleGraph, Tuple, Value, Variant};
55
use regex::RegexSet;
66
use rust_decimal::prelude::ToPrimitive;
7+
use std::collections::HashSet;
78

89
use crate::boxed_ion::BoxedIonType;
910
use crate::common::{
10-
Encoding, BAG_ANNOT, BOXED_ION_ANNOT, DATE_ANNOT, MISSING_ANNOT, RE_SET_TIME_PARTS, TIME_ANNOT,
11-
TIME_PARTS_HOUR, TIME_PARTS_MINUTE, TIME_PARTS_SECOND, TIME_PARTS_TZ_HOUR,
12-
TIME_PARTS_TZ_MINUTE,
11+
Encoding, BAG_ANNOT, BOXED_ION_ANNOT, DATE_ANNOT, GRAPH_ANNOT, MISSING_ANNOT,
12+
RE_SET_TIME_PARTS, TIME_ANNOT, TIME_PARTS_HOUR, TIME_PARTS_MINUTE, TIME_PARTS_SECOND,
13+
TIME_PARTS_TZ_HOUR, TIME_PARTS_TZ_MINUTE,
1314
};
1415
use std::num::NonZeroU8;
16+
use std::rc::Rc;
1517
use std::str::FromStr;
1618
use thiserror::Error;
1719
use time::Duration;
@@ -368,6 +370,23 @@ fn has_annotation(
368370
static TIME_PARTS_PATTERN_SET: Lazy<RegexSet> =
369371
Lazy::new(|| RegexSet::new(RE_SET_TIME_PARTS).unwrap());
370372

373+
type GNode = (String, HashSet<String>, Option<Value>);
374+
type GNodes = (Vec<String>, Vec<HashSet<String>>, Vec<Option<Value>>);
375+
#[allow(clippy::type_complexity)]
376+
type GEdge = (
377+
String,
378+
HashSet<String>,
379+
(String, String, String),
380+
Option<Value>,
381+
);
382+
#[allow(clippy::type_complexity)]
383+
type GEdges = (
384+
Vec<String>,
385+
Vec<HashSet<String>>,
386+
Vec<(String, String, String)>,
387+
Vec<Option<Value>>,
388+
);
389+
371390
impl PartiqlEncodedIonValueDecoder {
372391
fn decode_date<R>(&self, reader: &mut R) -> IonDecodeResult
373392
where
@@ -527,6 +546,211 @@ impl PartiqlEncodedIonValueDecoder {
527546
.map_err(|e| IonDecodeError::StreamError(e.to_string()))?,
528547
))
529548
}
549+
550+
fn decode_graph<R>(&self, reader: &mut R) -> IonDecodeResult
551+
where
552+
R: IonReader<Item = StreamItem, Symbol = Symbol>,
553+
{
554+
let err = || IonDecodeError::ConversionError("Invalid graph specified".into());
555+
let mut nodes = None;
556+
let mut edges = None;
557+
reader.step_in()?;
558+
'kv: loop {
559+
match reader.next()? {
560+
StreamItem::Value(typ) => match typ {
561+
IonType::List => match reader.field_name()?.text_or_error()? {
562+
"nodes" => nodes = Some(self.decode_nodes(reader)?),
563+
"edges" => edges = Some(self.decode_edges(reader)?),
564+
_ => return Err(err()),
565+
},
566+
_ => return Err(err()),
567+
},
568+
StreamItem::Null(_) => return Err(err()),
569+
StreamItem::Nothing => break 'kv,
570+
}
571+
}
572+
reader.step_out()?;
573+
574+
let nodes = nodes.ok_or_else(err)?;
575+
let (ids, labels, ends, payloads) = edges.ok_or_else(err)?;
576+
let edge_specs = ends
577+
.into_iter()
578+
.map(|(l, dir, r)| match dir.as_str() {
579+
"->" => Ok(EdgeSpec::Directed(l, r)),
580+
"<-" => Ok(EdgeSpec::Directed(r, l)),
581+
"--" => Ok(EdgeSpec::Undirected(l, r)),
582+
_ => Err(err()),
583+
})
584+
.collect::<Result<Vec<EdgeSpec>, _>>()?;
585+
Ok(Value::Graph(Box::new(Graph::Simple(Rc::new(
586+
SimpleGraph::from_spec(nodes, (ids, labels, edge_specs, payloads)),
587+
)))))
588+
}
589+
590+
fn decode_nodes<R>(&self, reader: &mut R) -> Result<GNodes, IonDecodeError>
591+
where
592+
R: IonReader<Item = StreamItem, Symbol = Symbol>,
593+
{
594+
let err = || IonDecodeError::ConversionError("Invalid graph specified".into());
595+
reader.step_in()?;
596+
let mut ids = vec![];
597+
let mut labels = vec![];
598+
let mut payloads = vec![];
599+
'values: loop {
600+
let item = reader.next()?;
601+
match item {
602+
StreamItem::Nothing => break 'values,
603+
StreamItem::Value(IonType::Struct) => {
604+
let (id, labelset, payload) = self.decode_node(reader)?;
605+
ids.push(id);
606+
labels.push(labelset);
607+
payloads.push(payload);
608+
}
609+
_ => return Err(err()),
610+
}
611+
}
612+
reader.step_out()?;
613+
Ok((ids, labels, payloads))
614+
}
615+
616+
fn decode_node<R>(&self, reader: &mut R) -> Result<GNode, IonDecodeError>
617+
where
618+
R: IonReader<Item = StreamItem, Symbol = Symbol>,
619+
{
620+
let err = || IonDecodeError::ConversionError("Invalid graph specified".into());
621+
let mut id = None;
622+
let mut labels = None;
623+
let mut payload = None;
624+
reader.step_in()?;
625+
'kv: loop {
626+
let item = reader.next()?;
627+
if item == StreamItem::Nothing {
628+
break 'kv;
629+
}
630+
let fname = reader.field_name()?;
631+
let fname = fname.text_or_error()?;
632+
match (fname, item) {
633+
("id", StreamItem::Value(IonType::Symbol)) => {
634+
id = Some(reader.read_symbol()?.text_or_error()?.to_string());
635+
}
636+
("labels", StreamItem::Value(IonType::List)) => {
637+
let mut labelset = HashSet::new();
638+
reader.step_in()?;
639+
#[allow(irrefutable_let_patterns)]
640+
while let item = reader.next()? {
641+
match item {
642+
StreamItem::Value(IonType::String) => {
643+
labelset.insert(reader.read_string()?.text().to_string());
644+
}
645+
StreamItem::Nothing => break,
646+
_ => return Err(err()),
647+
}
648+
}
649+
reader.step_out()?;
650+
labels = Some(labelset);
651+
}
652+
("payload", StreamItem::Value(typ)) => {
653+
payload = Some(self.decode_value(reader, typ)?);
654+
}
655+
_ => return Err(err()),
656+
}
657+
}
658+
reader.step_out()?;
659+
660+
let id = id.ok_or_else(err)?;
661+
let labels = labels.unwrap_or_else(Default::default);
662+
Ok((id, labels, payload))
663+
}
664+
665+
fn decode_edges<R>(&self, reader: &mut R) -> Result<GEdges, IonDecodeError>
666+
where
667+
R: IonReader<Item = StreamItem, Symbol = Symbol>,
668+
{
669+
let err = || IonDecodeError::ConversionError("Invalid graph specified".into());
670+
reader.step_in()?;
671+
let mut ids = vec![];
672+
let mut labels = vec![];
673+
let mut ends = vec![];
674+
let mut payloads = vec![];
675+
'values: loop {
676+
let item = reader.next()?;
677+
match item {
678+
StreamItem::Nothing => break 'values,
679+
StreamItem::Value(IonType::Struct) => {
680+
let (id, labelset, end, payload) = self.decode_edge(reader)?;
681+
ids.push(id);
682+
labels.push(labelset);
683+
ends.push(end);
684+
payloads.push(payload);
685+
}
686+
_ => return Err(err()),
687+
}
688+
}
689+
reader.step_out()?;
690+
Ok((ids, labels, ends, payloads))
691+
}
692+
693+
fn decode_edge<R>(&self, reader: &mut R) -> Result<GEdge, IonDecodeError>
694+
where
695+
R: IonReader<Item = StreamItem, Symbol = Symbol>,
696+
{
697+
let err = || IonDecodeError::ConversionError("Invalid graph specified".into());
698+
let mut id = None;
699+
let mut labels = None;
700+
let mut ends = None;
701+
let mut payload = None;
702+
reader.step_in()?;
703+
'kv: loop {
704+
let item = reader.next()?;
705+
if item == StreamItem::Nothing {
706+
break 'kv;
707+
}
708+
let fname = reader.field_name()?;
709+
let fname = fname.text_or_error()?;
710+
match (fname, item) {
711+
("id", StreamItem::Value(IonType::Symbol)) => {
712+
id = Some(reader.read_symbol()?.text_or_error()?.to_string());
713+
}
714+
("labels", StreamItem::Value(IonType::List)) => {
715+
let mut labelset = HashSet::new();
716+
reader.step_in()?;
717+
#[allow(irrefutable_let_patterns)]
718+
while let item = reader.next()? {
719+
match item {
720+
StreamItem::Value(IonType::String) => {
721+
labelset.insert(reader.read_string()?.text().to_string());
722+
}
723+
StreamItem::Nothing => break,
724+
_ => return Err(err()),
725+
}
726+
}
727+
reader.step_out()?;
728+
labels = Some(labelset);
729+
}
730+
("ends", StreamItem::Value(IonType::SExp)) => {
731+
reader.step_in()?;
732+
reader.next()?;
733+
let l = reader.read_symbol()?.text_or_error()?.to_string();
734+
reader.next()?;
735+
let dir = reader.read_symbol()?.text_or_error()?.to_string();
736+
reader.next()?;
737+
let r = reader.read_symbol()?.text_or_error()?.to_string();
738+
reader.step_out()?;
739+
ends = Some((l, dir, r));
740+
}
741+
("payload", StreamItem::Value(typ)) => {
742+
payload = Some(self.decode_value(reader, typ)?);
743+
}
744+
_ => return Err(err()),
745+
}
746+
}
747+
reader.step_out()?;
748+
749+
let id = id.ok_or_else(err)?;
750+
let labels = labels.unwrap_or_else(Default::default);
751+
let ends = ends.ok_or_else(err)?;
752+
Ok((id, labels, ends, payload))
753+
}
530754
}
531755

532756
impl<R> IonValueDecoder<R> for PartiqlEncodedIonValueDecoder
@@ -576,6 +800,8 @@ where
576800
fn decode_struct(&self, reader: &mut R) -> IonDecodeResult {
577801
if has_annotation(reader, TIME_ANNOT) {
578802
self.decode_time(reader)
803+
} else if has_annotation(reader, GRAPH_ANNOT) {
804+
self.decode_graph(reader)
579805
} else {
580806
decode_struct(self, reader)
581807
}

extension/partiql-extension-ion/src/encode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ where
135135
Value::List(l) => self.encode_list(l.as_ref()),
136136
Value::Bag(b) => self.encode_bag(b.as_ref()),
137137
Value::Tuple(t) => self.encode_tuple(t.as_ref()),
138+
Value::Graph(_) => todo!("Graph: encode_value"),
138139
Value::Variant(v) => self.encode_variant(v),
139140
}
140141
}

extension/partiql-extension-ion/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
#![deny(rust_2018_idioms)]
22
#![deny(clippy::all)]
33

4-
#[cfg(feature = "serde")]
5-
use serde::{Deserialize, Serialize};
6-
74
pub mod boxed_ion;
85
mod common;
96
pub mod decode;

extension/partiql-extension-ion/tests/test.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ use partiql_extension_ion::boxed_ion::BoxedIonType;
77
use partiql_extension_ion::decode::{IonDecodeResult, IonDecoderBuilder, IonDecoderConfig};
88
use partiql_extension_ion::encode::{IonEncodeError, IonEncoderBuilder, IonEncoderConfig};
99
use partiql_extension_ion::Encoding;
10-
use partiql_value::boxed_variant::BoxedVariantType;
1110
use partiql_value::datum::{
1211
Datum, DatumCategory, DatumCategoryOwned, DatumCategoryRef, DatumLower, OwnedFieldView,
1312
OwnedSequenceView, OwnedTupleView, RefSequenceView, RefTupleView, SequenceDatum, TupleDatum,
1413
};
15-
use partiql_value::Value::Variant;
1614
use partiql_value::{Bag, BindingsName, EqualityValue, NullableEq, Value};
1715
use std::collections::HashMap;
1816
use std::fs::File;

partiql-eval/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ partiql-value = { path = "../partiql-value", version = "0.11.*" }
2727
partiql-catalog = { path = "../partiql-catalog", version = "0.11.*" }
2828
partiql-types = { path = "../partiql-types", version = "0.11.*" }
2929
partiql-extension-ion = { path = "../extension/partiql-extension-ion", version = "0.11.*" }
30-
petgraph = "0.6"
30+
petgraph = "0.7"
3131
ordered-float = "4"
3232
itertools = "0.13"
3333
unicase = "2"

partiql-logical-planner/src/functions.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ impl Function for FunctionEntry<'_> {
1212
fn resolve(&self, name: &str, args: &[CallArgument]) -> Result<ValueExpr, CallLookupError> {
1313
let oid = self.id();
1414
match self.entry() {
15-
FunctionEntryFunction::Table(tbl) => {
16-
tbl.call_def().lookup(args, name).map_err(Into::into)
17-
}
15+
FunctionEntryFunction::Table(tbl) => tbl.call_def().lookup(args, name),
1816
FunctionEntryFunction::Scalar(scfn) => {
1917
ScalarFnResolver { oid, scfn }.resolve(name, args)
2018
}

partiql-logical/src/util.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ impl From<Value> for Lit {
2121
Value::List(list) => (*list).into(),
2222
Value::Bag(bag) => (*bag).into(),
2323
Value::Tuple(tuple) => (*tuple).into(),
24+
Value::Graph(_) => todo!("Value to Lit: Graph"),
2425
Value::Variant(_) => {
25-
todo!("Value to Lit: EmbeddedDoc")
26+
todo!("Value to Lit: Variant")
2627
}
2728
}
2829
}

partiql-value/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ bench = false
2323
[dependencies]
2424
partiql-common = { path = "../partiql-common", version = "0.11.*" }
2525
partiql-types = { path = "../partiql-types", version = "0.11.*" }
26+
petgraph = "0.7"
27+
lasso = "0.7"
2628
delegate = "0.13"
2729
ordered-float = "4"
2830
itertools = "0.13"

0 commit comments

Comments
 (0)