Allow CREATE statement to accept an id field in the content
This commit is contained in:
parent
fba743ef0b
commit
5580f288fd
7 changed files with 120 additions and 49 deletions
lib/src/sql
|
@ -1,9 +1,12 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::idiom::{idiom, Idiom};
|
||||
use crate::sql::operator::{assigner, Operator};
|
||||
use crate::sql::table::Table;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::{value, Value};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
|
@ -30,6 +33,22 @@ impl Default for Data {
|
|||
}
|
||||
}
|
||||
|
||||
impl Data {
|
||||
// Fetch
|
||||
pub(crate) fn rid(&self, tb: &Table) -> Result<Thing, Error> {
|
||||
match self {
|
||||
Data::MergeExpression(v) => v.generate(tb, false),
|
||||
Data::ReplaceExpression(v) => v.generate(tb, false),
|
||||
Data::ContentExpression(v) => v.generate(tb, false),
|
||||
Data::SetExpression(v) => match v.iter().find(|f| f.0.is_id()) {
|
||||
Some((_, _, v)) => v.generate(tb, false),
|
||||
_ => Ok(tb.generate()),
|
||||
},
|
||||
_ => Ok(tb.generate()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Data {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
|
|
@ -5,6 +5,8 @@ use crate::sql::escape::escape_id;
|
|||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::number::integer;
|
||||
use crate::sql::object::{object, Object};
|
||||
use crate::sql::strand::Strand;
|
||||
use crate::sql::uuid::Uuid;
|
||||
use nanoid::nanoid;
|
||||
use nom::branch::alt;
|
||||
use nom::combinator::map;
|
||||
|
@ -37,6 +39,12 @@ impl From<u64> for Id {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<String> for Id {
|
||||
fn from(v: String) -> Self {
|
||||
Id::String(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Array> for Id {
|
||||
fn from(v: Array) -> Self {
|
||||
Id::Array(v)
|
||||
|
@ -49,9 +57,15 @@ impl From<Object> for Id {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<String> for Id {
|
||||
fn from(v: String) -> Self {
|
||||
Id::String(v)
|
||||
impl From<Uuid> for Id {
|
||||
fn from(v: Uuid) -> Self {
|
||||
Id::String(v.to_raw())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Strand> for Id {
|
||||
fn from(v: Strand) -> Self {
|
||||
Id::String(v.as_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,17 @@ impl CreateStatement {
|
|||
for w in self.what.0.iter() {
|
||||
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||
match v {
|
||||
Value::Table(v) => i.ingest(Iterable::Thing(v.generate())),
|
||||
Value::Table(v) => match &self.data {
|
||||
// There is a data clause so check for a record id
|
||||
Some(data) => match data.rid(&v) {
|
||||
// There was a problem creating the record id
|
||||
Err(e) => return Err(e),
|
||||
// There is an id field so use the record id
|
||||
Ok(v) => i.ingest(Iterable::Thing(v)),
|
||||
},
|
||||
// There is no data clause so create a record id
|
||||
None => i.ingest(Iterable::Thing(v.generate())),
|
||||
},
|
||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||
Value::Model(v) => {
|
||||
for v in v {
|
||||
|
|
|
@ -65,7 +65,7 @@ impl InsertStatement {
|
|||
o.set(ctx, opt, txn, k, v).await?;
|
||||
}
|
||||
// Specify the new table record id
|
||||
let id = o.retable(&self.into)?;
|
||||
let id = o.generate(&self.into, true)?;
|
||||
// Pass the mergeable to the iterator
|
||||
i.ingest(Iterable::Mergeable(id, o));
|
||||
}
|
||||
|
@ -77,14 +77,14 @@ impl InsertStatement {
|
|||
Value::Array(v) => {
|
||||
for v in v {
|
||||
// Specify the new table record id
|
||||
let id = v.retable(&self.into)?;
|
||||
let id = v.generate(&self.into, true)?;
|
||||
// Pass the mergeable to the iterator
|
||||
i.ingest(Iterable::Mergeable(id, v));
|
||||
}
|
||||
}
|
||||
Value::Object(_) => {
|
||||
// Specify the new table record id
|
||||
let id = v.retable(&self.into)?;
|
||||
let id = v.generate(&self.into, true)?;
|
||||
// Pass the mergeable to the iterator
|
||||
i.ingest(Iterable::Mergeable(id, v));
|
||||
}
|
||||
|
|
69
lib/src/sql/value/generate.rs
Normal file
69
lib/src/sql/value/generate.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::id::Id;
|
||||
use crate::sql::paths::ID;
|
||||
use crate::sql::table::Table;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
pub fn generate(&self, tb: &Table, retable: bool) -> Result<Thing, Error> {
|
||||
match self.pick(&*ID) {
|
||||
// There is a floating point number for the id field
|
||||
Value::Number(id) if id.is_float() => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: id.as_int().into(),
|
||||
}),
|
||||
// There is an integer number for the id field
|
||||
Value::Number(id) if id.is_int() => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: id.as_int().into(),
|
||||
}),
|
||||
// There is a string for the id field
|
||||
Value::Strand(id) => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: id.into(),
|
||||
}),
|
||||
// There is an object for the id field
|
||||
Value::Object(id) => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: id.into(),
|
||||
}),
|
||||
// There is an array for the id field
|
||||
Value::Array(id) => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: id.into(),
|
||||
}),
|
||||
// There is a UUID for the id field
|
||||
Value::Uuid(id) => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: id.into(),
|
||||
}),
|
||||
// There is no record id field
|
||||
Value::None => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: Id::rand(),
|
||||
}),
|
||||
// There is a record id defined
|
||||
Value::Thing(id) => match retable {
|
||||
// Let's re-table this record id
|
||||
true => Ok(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: id.id,
|
||||
}),
|
||||
// Let's use the specified record id
|
||||
false => match tb.0 == id.tb {
|
||||
// The record is from the same table
|
||||
true => Ok(id),
|
||||
// The record id is from another table
|
||||
false => Err(Error::IdInvalid {
|
||||
value: id.to_string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
// Any other value is wrong
|
||||
id => Err(Error::IdInvalid {
|
||||
value: id.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ mod each;
|
|||
mod every;
|
||||
mod first;
|
||||
mod flatten;
|
||||
mod generate;
|
||||
mod get;
|
||||
mod increment;
|
||||
mod last;
|
||||
|
@ -24,7 +25,6 @@ mod patch;
|
|||
mod pick;
|
||||
mod put;
|
||||
mod replace;
|
||||
mod retable;
|
||||
mod set;
|
||||
mod single;
|
||||
mod walk;
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::id::Id;
|
||||
use crate::sql::paths::ID;
|
||||
use crate::sql::table::Table;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
pub fn retable(&self, val: &Table) -> Result<Thing, Error> {
|
||||
// Fetch the id from the document
|
||||
let id = match self.pick(&*ID) {
|
||||
Value::Number(id) if id.is_float() => Thing {
|
||||
tb: val.to_string(),
|
||||
id: Id::Number(id.as_int()),
|
||||
},
|
||||
Value::Number(id) if id.is_int() => Thing {
|
||||
tb: val.to_string(),
|
||||
id: Id::Number(id.as_int()),
|
||||
},
|
||||
Value::Strand(id) => Thing {
|
||||
tb: val.to_string(),
|
||||
id: Id::String(id.0),
|
||||
},
|
||||
Value::Thing(id) => Thing {
|
||||
tb: val.to_string(),
|
||||
id: id.id,
|
||||
},
|
||||
Value::None => Thing {
|
||||
tb: val.to_string(),
|
||||
id: Id::rand(),
|
||||
},
|
||||
id => {
|
||||
return Err(Error::IdInvalid {
|
||||
value: id.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
// Return the record id
|
||||
Ok(id)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue