Implement SQL Object as a newtype tuple struct
This commit is contained in:
parent
5182359813
commit
3ee1ddb5b1
12 changed files with 88 additions and 91 deletions
|
@ -15,37 +15,31 @@ use nom::combinator::opt;
|
|||
use nom::multi::separated_list0;
|
||||
use nom::sequence::delimited;
|
||||
use serde::ser::SerializeMap;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Object {
|
||||
pub value: BTreeMap<String, Value>,
|
||||
}
|
||||
pub struct Object(pub BTreeMap<String, Value>);
|
||||
|
||||
impl From<BTreeMap<String, Value>> for Object {
|
||||
fn from(v: BTreeMap<String, Value>) -> Self {
|
||||
Object {
|
||||
value: v,
|
||||
}
|
||||
Object(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HashMap<String, Value>> for Object {
|
||||
fn from(v: HashMap<String, Value>) -> Self {
|
||||
Object {
|
||||
value: v.into_iter().collect(),
|
||||
}
|
||||
Object(v.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Operation> for Object {
|
||||
fn from(v: Operation) -> Self {
|
||||
Object {
|
||||
value: map! {
|
||||
Object(map! {
|
||||
String::from("op") => match v.op {
|
||||
Op::None => Value::from("none"),
|
||||
Op::Add => Value::from("add"),
|
||||
|
@ -55,25 +49,39 @@ impl From<Operation> for Object {
|
|||
},
|
||||
String::from("path") => v.path.to_path().into(),
|
||||
String::from("value") => v.value,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Object {
|
||||
type Target = BTreeMap<String, Value>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Object {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Object {
|
||||
type Item = (String, Value);
|
||||
type IntoIter = std::collections::btree_map::IntoIter<String, Value>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn remove(&mut self, key: &str) {
|
||||
self.value.remove(key);
|
||||
}
|
||||
pub fn insert(&mut self, key: &str, val: Value) {
|
||||
self.value.insert(key.to_owned(), val);
|
||||
}
|
||||
pub fn to_operation(&self) -> Result<Operation, Error> {
|
||||
match self.value.get("op") {
|
||||
Some(o) => match self.value.get("path") {
|
||||
match self.get("op") {
|
||||
Some(o) => match self.get("path") {
|
||||
Some(p) => Ok(Operation {
|
||||
op: o.into(),
|
||||
path: p.to_idiom(),
|
||||
value: match self.value.get("value") {
|
||||
value: match self.get("value") {
|
||||
Some(v) => v.clone(),
|
||||
None => Value::Null,
|
||||
},
|
||||
|
@ -98,15 +106,13 @@ impl Object {
|
|||
doc: Option<&Value>,
|
||||
) -> Result<Value, Error> {
|
||||
let mut x = BTreeMap::new();
|
||||
for (k, v) in &self.value {
|
||||
for (k, v) in self.iter() {
|
||||
match v.compute(ctx, opt, txn, doc).await {
|
||||
Ok(v) => x.insert(k.clone(), v),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
}
|
||||
Ok(Value::Object(Object {
|
||||
value: x,
|
||||
}))
|
||||
Ok(Value::Object(Object(x)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,8 +121,7 @@ impl fmt::Display for Object {
|
|||
write!(
|
||||
f,
|
||||
"{{ {} }}",
|
||||
self.value
|
||||
.iter()
|
||||
self.iter()
|
||||
.map(|(k, v)| format!("{}: {}", escape(k, &val_char, "\""), v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
|
@ -130,16 +135,14 @@ impl Serialize for Object {
|
|||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
let mut map = serializer.serialize_map(Some(self.value.len()))?;
|
||||
for (ref k, ref v) in &self.value {
|
||||
let mut map = serializer.serialize_map(Some(self.len()))?;
|
||||
for (ref k, ref v) in &self.0 {
|
||||
map.serialize_key(k)?;
|
||||
map.serialize_value(v)?;
|
||||
}
|
||||
map.end()
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct("Object", 1)?;
|
||||
val.serialize_field("value", &self.value)?;
|
||||
val.end()
|
||||
serializer.serialize_newtype_struct("Object", &self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,12 +155,7 @@ pub fn object(i: &str) -> IResult<&str, Object> {
|
|||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('}')(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Object {
|
||||
value: v.into_iter().collect(),
|
||||
},
|
||||
))
|
||||
Ok((i, Object(v.into_iter().collect())))
|
||||
}
|
||||
|
||||
fn item(i: &str) -> IResult<&str, (String, Value)> {
|
||||
|
@ -197,7 +195,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("{ one: 1, tre: 3, two: 2 }", format!("{}", out));
|
||||
assert_eq!(out.value.len(), 3);
|
||||
assert_eq!(out.0.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -207,7 +205,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("{ one: 1, tre: 3, two: 2 }", format!("{}", out));
|
||||
assert_eq!(out.value.len(), 3);
|
||||
assert_eq!(out.0.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -217,6 +215,6 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("{ one: 1, tre: 3 + 1, two: 2 }", format!("{}", out));
|
||||
assert_eq!(out.value.len(), 3);
|
||||
assert_eq!(out.0.len(), 3);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,9 +45,9 @@ impl InfoStatement {
|
|||
// Process the statement
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_ns().await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("ns", tmp.into());
|
||||
res.insert("ns".to_owned(), tmp.into());
|
||||
// Ok all good
|
||||
Value::from(res).ok()
|
||||
}
|
||||
|
@ -63,21 +63,21 @@ impl InfoStatement {
|
|||
// Process the databases
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_db(opt.ns()).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("db", tmp.into());
|
||||
res.insert("db".to_owned(), tmp.into());
|
||||
// Process the tokens
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_nt(opt.ns()).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("nt", tmp.into());
|
||||
res.insert("nt".to_owned(), tmp.into());
|
||||
// Process the logins
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_nl(opt.ns()).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("nl", tmp.into());
|
||||
res.insert("nl".to_owned(), tmp.into());
|
||||
// Ok all good
|
||||
Value::from(res).ok()
|
||||
}
|
||||
|
@ -93,27 +93,27 @@ impl InfoStatement {
|
|||
// Process the tables
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_tb(opt.ns(), opt.db()).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("tb", tmp.into());
|
||||
res.insert("tb".to_owned(), tmp.into());
|
||||
// Process the scopes
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_sc(opt.ns(), opt.db()).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("sc", tmp.into());
|
||||
res.insert("sc".to_owned(), tmp.into());
|
||||
// Process the tokens
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_nt(opt.ns()).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("nt", tmp.into());
|
||||
res.insert("nt".to_owned(), tmp.into());
|
||||
// Process the logins
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_nl(opt.ns()).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("nl", tmp.into());
|
||||
res.insert("nl".to_owned(), tmp.into());
|
||||
// Ok all good
|
||||
Value::from(res).ok()
|
||||
}
|
||||
|
@ -129,9 +129,9 @@ impl InfoStatement {
|
|||
// Process the tokens
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_st(opt.ns(), opt.db(), sc).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("st", tmp.into());
|
||||
res.insert("st".to_owned(), tmp.into());
|
||||
// Ok all good
|
||||
Value::from(res).ok()
|
||||
}
|
||||
|
@ -147,27 +147,27 @@ impl InfoStatement {
|
|||
// Process the events
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_ev(opt.ns(), opt.db(), tb).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("ev", tmp.into());
|
||||
res.insert("ev".to_owned(), tmp.into());
|
||||
// Process the fields
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_fd(opt.ns(), opt.db(), tb).await? {
|
||||
tmp.insert(&v.name.to_string(), v.to_string().into());
|
||||
tmp.insert(v.name.to_string(), v.to_string().into());
|
||||
}
|
||||
res.insert("fd", tmp.into());
|
||||
res.insert("fd".to_owned(), tmp.into());
|
||||
// Process the indexs
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_ix(opt.ns(), opt.db(), tb).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("ix", tmp.into());
|
||||
res.insert("ix".to_owned(), tmp.into());
|
||||
// Process the tables
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_ft(opt.ns(), opt.db(), tb).await? {
|
||||
tmp.insert(&v.name, v.to_string().into());
|
||||
tmp.insert(v.name.to_owned(), v.to_string().into());
|
||||
}
|
||||
res.insert("ft", tmp.into());
|
||||
res.insert("ft".to_owned(), tmp.into());
|
||||
// Ok all good
|
||||
Value::from(res).ok()
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ impl Value {
|
|||
Some(p) => match (self, other) {
|
||||
// Current path part is an object
|
||||
(Value::Object(a), Value::Object(b)) => match p {
|
||||
Part::Field(f) => match (a.value.get(&f.name), b.value.get(&f.name)) {
|
||||
Part::Field(f) => match (a.get(&f.name), b.get(&f.name)) {
|
||||
(Some(a), Some(b)) => a.compare(b, path.next(), collate, numeric),
|
||||
(Some(_), None) => Some(Ordering::Greater),
|
||||
(None, Some(_)) => Some(Ordering::Less),
|
||||
|
|
|
@ -30,7 +30,7 @@ impl Value {
|
|||
v.remove(&f.name);
|
||||
Ok(())
|
||||
}
|
||||
_ => match v.value.get_mut(&f.name) {
|
||||
_ => match v.get_mut(&f.name) {
|
||||
Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await,
|
||||
_ => Ok(()),
|
||||
},
|
||||
|
|
|
@ -9,8 +9,8 @@ impl Value {
|
|||
match (self, val) {
|
||||
(Value::Object(a), Value::Object(b)) if a != b => {
|
||||
// Loop over old keys
|
||||
for (key, _) in a.value.iter() {
|
||||
if !b.value.contains_key(key) {
|
||||
for (key, _) in a.iter() {
|
||||
if !b.contains_key(key) {
|
||||
ops.push(Operation {
|
||||
op: Op::Remove,
|
||||
path: path.clone().push(key.clone().into()),
|
||||
|
@ -19,8 +19,8 @@ impl Value {
|
|||
}
|
||||
}
|
||||
// Loop over new keys
|
||||
for (key, val) in b.value.iter() {
|
||||
match a.value.get(key) {
|
||||
for (key, val) in b.iter() {
|
||||
match a.get(key) {
|
||||
None => ops.push(Operation {
|
||||
op: Op::Add,
|
||||
path: path.clone().push(key.clone().into()),
|
||||
|
|
|
@ -13,7 +13,7 @@ impl Value {
|
|||
Some(p) => match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Field(f) => match v.value.get(&f.name) {
|
||||
Part::Field(f) => match v.get(&f.name) {
|
||||
Some(v) => v._each(path.next(), prev.push(p.clone())),
|
||||
None => vec![],
|
||||
},
|
||||
|
|
|
@ -10,7 +10,6 @@ impl Value {
|
|||
match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => v
|
||||
.value
|
||||
.iter()
|
||||
.flat_map(|(k, v)| v._every(prev.clone().push(Part::from(k))))
|
||||
.collect::<Vec<_>>(),
|
||||
|
|
|
@ -26,7 +26,7 @@ impl Value {
|
|||
Some(p) => match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Field(f) => match v.value.get(&f.name) {
|
||||
Part::Field(f) => match v.get(&f.name) {
|
||||
Some(v) => v.get(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
|
|
|
@ -15,7 +15,7 @@ impl Value {
|
|||
) -> Result<(), Error> {
|
||||
match val.compute(ctx, opt, txn, Some(self)).await? {
|
||||
Value::Object(v) => {
|
||||
for (k, v) in v.value.into_iter() {
|
||||
for (k, v) in v {
|
||||
self.set(ctx, opt, txn, &[Part::from(k)], v).await?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -9,7 +9,7 @@ impl Value {
|
|||
Some(p) => match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Field(f) => match v.value.get(&f.name) {
|
||||
Part::Field(f) => match v.get(&f.name) {
|
||||
Some(v) => v.pick(path.next()),
|
||||
None => Value::None,
|
||||
},
|
||||
|
|
|
@ -24,12 +24,12 @@ impl Value {
|
|||
Some(p) => match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Field(f) => match v.value.get_mut(&f.name) {
|
||||
Part::Field(f) => match v.get_mut(&f.name) {
|
||||
Some(v) if v.is_some() => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
_ => {
|
||||
let mut obj = Value::base();
|
||||
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||
v.insert(&f.name, obj);
|
||||
v.insert(f.name.to_owned(), obj);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
|
|
|
@ -499,7 +499,7 @@ impl Value {
|
|||
Value::Thing(_) => true,
|
||||
Value::Geometry(_) => true,
|
||||
Value::Array(v) => !v.value.is_empty(),
|
||||
Value::Object(v) => !v.value.is_empty(),
|
||||
Value::Object(v) => !v.is_empty(),
|
||||
Value::Strand(v) => !v.value.is_empty() && v.value.to_ascii_lowercase() != "false",
|
||||
Value::Number(v) => v.is_truthy(),
|
||||
Value::Duration(v) => v.value.as_nanos() > 0,
|
||||
|
|
Loading…
Reference in a new issue