Enable support for numbers and strings in record ids

This commit is contained in:
Tobie Morgan Hitchcock 2022-03-18 07:24:36 +00:00
parent 364412b437
commit 24752a75d9
10 changed files with 158 additions and 28 deletions

View file

@ -1,16 +1,15 @@
use crate::cnf::ID_CHARS;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Runtime; use crate::dbs::Runtime;
use crate::dbs::Transaction; use crate::dbs::Transaction;
use crate::err::Error; use crate::err::Error;
use crate::key::thing; use crate::key::thing;
use crate::sql::array::Array; use crate::sql::array::Array;
use crate::sql::id::Id;
use crate::sql::model::Model; use crate::sql::model::Model;
use crate::sql::table::Table; use crate::sql::table::Table;
use crate::sql::thing::Thing; use crate::sql::thing::Thing;
use crate::sql::value::Value; use crate::sql::value::Value;
use async_recursion::async_recursion; use async_recursion::async_recursion;
use nanoid::nanoid;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
impl Value { impl Value {
@ -71,7 +70,7 @@ impl Model {
for _ in 0..c { for _ in 0..c {
Thing { Thing {
tb: self.table.to_string(), tb: self.table.to_string(),
id: nanoid!(20, &ID_CHARS), id: Id::rand(),
} }
.process(ctx, opt, txn, chn) .process(ctx, opt, txn, chn)
.await?; .await?;
@ -81,7 +80,7 @@ impl Model {
for x in r.0..=r.1 { for x in r.0..=r.1 {
Thing { Thing {
tb: self.table.to_string(), tb: self.table.to_string(),
id: x.to_string(), id: Id::from(x),
} }
.process(ctx, opt, txn, chn) .process(ctx, opt, txn, chn)
.await?; .await?;

View file

@ -1,4 +1,3 @@
use crate::cnf::ID_CHARS;
use crate::dbs::Iterator; use crate::dbs::Iterator;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Runtime; use crate::dbs::Runtime;
@ -6,12 +5,12 @@ use crate::dbs::Transaction;
use crate::err::Error; use crate::err::Error;
use crate::key::thing; use crate::key::thing;
use crate::sql::array::Array; use crate::sql::array::Array;
use crate::sql::id::Id;
use crate::sql::model::Model; use crate::sql::model::Model;
use crate::sql::table::Table; use crate::sql::table::Table;
use crate::sql::thing::Thing; use crate::sql::thing::Thing;
use crate::sql::value::Value; use crate::sql::value::Value;
use async_recursion::async_recursion; use async_recursion::async_recursion;
use nanoid::nanoid;
impl Value { impl Value {
#[cfg_attr(feature = "parallel", async_recursion)] #[cfg_attr(feature = "parallel", async_recursion)]
@ -74,7 +73,7 @@ impl Model {
for _ in 0..c { for _ in 0..c {
Thing { Thing {
tb: self.table.to_string(), tb: self.table.to_string(),
id: nanoid!(20, &ID_CHARS), id: Id::rand(),
} }
.iterate(ctx, opt, txn, ite) .iterate(ctx, opt, txn, ite)
.await?; .await?;
@ -84,7 +83,7 @@ impl Model {
for x in r.0..=r.1 { for x in r.0..=r.1 {
Thing { Thing {
tb: self.table.to_string(), tb: self.table.to_string(),
id: x.to_string(), id: Id::from(x),
} }
.iterate(ctx, opt, txn, ite) .iterate(ctx, opt, txn, ite)
.await?; .await?;

View file

@ -1,4 +1,3 @@
use crate::cnf::ID_CHARS;
use crate::cnf::MAX_CONCURRENT_TASKS; use crate::cnf::MAX_CONCURRENT_TASKS;
use crate::ctx::Canceller; use crate::ctx::Canceller;
use crate::ctx::Context; use crate::ctx::Context;
@ -8,6 +7,7 @@ use crate::dbs::Statement;
use crate::dbs::Transaction; use crate::dbs::Transaction;
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::id::Id;
use crate::sql::statements::create::CreateStatement; use crate::sql::statements::create::CreateStatement;
use crate::sql::statements::delete::DeleteStatement; use crate::sql::statements::delete::DeleteStatement;
use crate::sql::statements::insert::InsertStatement; use crate::sql::statements::insert::InsertStatement;
@ -17,7 +17,6 @@ use crate::sql::statements::update::UpdateStatement;
use crate::sql::table::Table; use crate::sql::table::Table;
use crate::sql::thing::Thing; use crate::sql::thing::Thing;
use crate::sql::value::Value; use crate::sql::value::Value;
use nanoid::nanoid;
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
@ -107,7 +106,7 @@ impl Iterator {
pub fn produce(&mut self, val: Table) { pub fn produce(&mut self, val: Table) {
self.prepare(Value::Thing(Thing { self.prepare(Value::Thing(Thing {
tb: val.name, tb: val.name,
id: nanoid!(20, &ID_CHARS), id: Id::rand(),
})) }))
} }

View file

@ -107,7 +107,7 @@ pub fn thing(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
})), })),
id => Ok(Value::Thing(Thing { id => Ok(Value::Thing(Thing {
tb: tb.as_strand().value, tb: tb.as_strand().value,
id: id.as_strand().value, id: id.as_strand().into(),
})), })),
} }
} }

View file

@ -1,4 +1,5 @@
use crate::err::Error; use crate::err::Error;
use crate::sql::id::Id;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use storekey::{deserialize, serialize}; use storekey::{deserialize, serialize};
@ -12,7 +13,7 @@ pub struct Thing {
_c: u8, _c: u8,
pub tb: String, pub tb: String,
_d: u8, _d: u8,
pub id: String, pub id: Id,
} }
impl From<Thing> for Vec<u8> { impl From<Thing> for Vec<u8> {
@ -33,8 +34,8 @@ impl From<&Vec<u8>> for Thing {
} }
} }
pub fn new(ns: &str, db: &str, tb: &str, id: &str) -> Thing { pub fn new(ns: &str, db: &str, tb: &str, id: &Id) -> Thing {
Thing::new(ns.to_string(), db.to_string(), tb.to_string(), id.to_string()) Thing::new(ns.to_string(), db.to_string(), tb.to_string(), id.to_owned())
} }
pub fn prefix(ns: &str, db: &str, tb: &str) -> Vec<u8> { pub fn prefix(ns: &str, db: &str, tb: &str) -> Vec<u8> {
@ -50,7 +51,7 @@ pub fn suffix(ns: &str, db: &str, tb: &str) -> Vec<u8> {
} }
impl Thing { impl Thing {
pub fn new(ns: String, db: String, tb: String, id: String) -> Thing { pub fn new(ns: String, db: String, tb: String, id: Id) -> Thing {
Thing { Thing {
__: 0x2f, // / __: 0x2f, // /
_a: 0x2a, // * _a: 0x2a, // *

100
lib/src/sql/id.rs Normal file
View file

@ -0,0 +1,100 @@
use crate::cnf::ID_CHARS;
use crate::sql::common::escape;
use crate::sql::common::val_char;
use crate::sql::error::IResult;
use crate::sql::ident::ident_raw;
use crate::sql::number::{number, Number};
use crate::sql::strand::Strand;
use nanoid::nanoid;
use nom::branch::alt;
use nom::combinator::map;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum Id {
Number(Number),
String(String),
}
impl From<Number> for Id {
fn from(v: Number) -> Self {
Id::Number(v)
}
}
impl From<String> for Id {
fn from(v: String) -> Self {
Id::String(v)
}
}
impl From<Strand> for Id {
fn from(v: Strand) -> Self {
Id::String(v.value)
}
}
impl From<&str> for Id {
fn from(v: &str) -> Self {
Id::String(v.to_owned())
}
}
impl From<u64> for Id {
fn from(v: u64) -> Self {
Id::Number(Number::from(v))
}
}
impl Id {
pub fn rand() -> Id {
Id::String(nanoid!(20, &ID_CHARS))
}
}
impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Id::Number(v) => write!(f, "{}", v),
Id::String(v) => write!(f, "{}", escape(&v, &val_char, "`")),
}
}
}
pub fn id(i: &str) -> IResult<&str, Id> {
alt((map(number, Id::Number), map(ident_raw, Id::String)))(i)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn id_number() {
let sql = "100";
let res = id(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!(Id::from(100), out);
}
#[test]
fn id_string() {
let sql = "test";
let res = id(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!(Id::from("test"), out);
}
#[test]
fn id_either() {
let sql = "100test";
let res = id(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!(Id::from("100test"), out);
}
}

View file

@ -15,6 +15,7 @@ pub(crate) mod function;
pub(crate) mod geometry; pub(crate) mod geometry;
pub(crate) mod graph; pub(crate) mod graph;
pub(crate) mod group; pub(crate) mod group;
pub(crate) mod id;
pub(crate) mod ident; pub(crate) mod ident;
pub(crate) mod idiom; pub(crate) mod idiom;
pub(crate) mod kind; pub(crate) mod kind;
@ -70,6 +71,7 @@ pub use self::geometry::Geometry;
pub use self::graph::Graph; pub use self::graph::Graph;
pub use self::group::Group; pub use self::group::Group;
pub use self::group::Groups; pub use self::group::Groups;
pub use self::id::Id;
pub use self::ident::Ident; pub use self::ident::Ident;
pub use self::idiom::Idiom; pub use self::idiom::Idiom;
pub use self::idiom::Idioms; pub use self::idiom::Idioms;

View file

@ -1,20 +1,22 @@
use crate::sql::common::escape; use crate::sql::common::escape;
use crate::sql::common::val_char; use crate::sql::common::val_char;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::id::{id, Id};
use crate::sql::ident::ident_raw; use crate::sql::ident::ident_raw;
use crate::sql::number::Number;
use nom::character::complete::char; use nom::character::complete::char;
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Deserialize)]
pub struct Thing { pub struct Thing {
pub tb: String, pub tb: String,
pub id: String, pub id: Id,
} }
impl From<(String, String)> for Thing { impl From<(String, Id)> for Thing {
fn from(v: (String, String)) -> Self { fn from(v: (String, Id)) -> Self {
Thing { Thing {
tb: v.0, tb: v.0,
id: v.1, id: v.1,
@ -22,11 +24,28 @@ impl From<(String, String)> for Thing {
} }
} }
impl From<(String, String)> for Thing {
fn from(v: (String, String)) -> Self {
Thing {
tb: v.0,
id: Id::from(v.1),
}
}
}
impl From<(String, Number)> for Thing {
fn from(v: (String, Number)) -> Self {
Thing {
tb: v.0,
id: Id::from(v.1),
}
}
}
impl fmt::Display for Thing { impl fmt::Display for Thing {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let t = escape(&self.tb, &val_char, "`"); let t = escape(&self.tb, &val_char, "`");
let i = escape(&self.id, &val_char, "`"); write!(f, "{}:{}", t, self.id)
write!(f, "{}:{}", t, i)
} }
} }
@ -50,7 +69,7 @@ impl Serialize for Thing {
pub fn thing(i: &str) -> IResult<&str, Thing> { pub fn thing(i: &str) -> IResult<&str, Thing> {
let (i, t) = ident_raw(i)?; let (i, t) = ident_raw(i)?;
let (i, _) = char(':')(i)?; let (i, _) = char(':')(i)?;
let (i, v) = ident_raw(i)?; let (i, v) = id(i)?;
Ok(( Ok((
i, i,
Thing { Thing {
@ -76,7 +95,7 @@ mod tests {
out, out,
Thing { Thing {
tb: String::from("test"), tb: String::from("test"),
id: String::from("id"), id: Id::from("id"),
} }
); );
} }
@ -92,7 +111,7 @@ mod tests {
out, out,
Thing { Thing {
tb: String::from("test"), tb: String::from("test"),
id: String::from("id"), id: Id::from("id"),
} }
); );
} }
@ -108,7 +127,7 @@ mod tests {
out, out,
Thing { Thing {
tb: String::from("test"), tb: String::from("test"),
id: String::from("id"), id: Id::from("id"),
} }
); );
} }

View file

@ -100,6 +100,7 @@ mod tests {
use super::*; use super::*;
use crate::dbs::test::mock; use crate::dbs::test::mock;
use crate::sql::id::Id;
use crate::sql::idiom::Idiom; use crate::sql::idiom::Idiom;
use crate::sql::test::Parse; use crate::sql::test::Parse;
use crate::sql::thing::Thing; use crate::sql::thing::Thing;
@ -132,7 +133,7 @@ mod tests {
res, res,
Value::from(Thing { Value::from(Thing {
tb: String::from("test"), tb: String::from("test"),
id: String::from("tobie") id: Id::from("tobie")
}) })
); );
} }
@ -156,7 +157,7 @@ mod tests {
res, res,
Value::from(Thing { Value::from(Thing {
tb: String::from("test"), tb: String::from("test"),
id: String::from("jaime") id: Id::from("jaime")
}) })
); );
} }

View file

@ -10,6 +10,7 @@ use crate::sql::error::IResult;
use crate::sql::expression::{expression, Expression}; use crate::sql::expression::{expression, Expression};
use crate::sql::function::{function, Function}; use crate::sql::function::{function, Function};
use crate::sql::geometry::{geometry, Geometry}; use crate::sql::geometry::{geometry, Geometry};
use crate::sql::id::Id;
use crate::sql::idiom::{idiom, Idiom}; use crate::sql::idiom::{idiom, Idiom};
use crate::sql::model::{model, Model}; use crate::sql::model::{model, Model};
use crate::sql::number::{number, Number}; use crate::sql::number::{number, Number};
@ -387,6 +388,15 @@ impl From<Option<String>> for Value {
} }
} }
impl From<Id> for Value {
fn from(v: Id) -> Self {
match v {
Id::String(v) => Strand::from(v).into(),
Id::Number(v) => Number::from(v).into(),
}
}
}
impl Value { impl Value {
// ----------------------------------- // -----------------------------------
// Initial record value // Initial record value