Implement parsing for ML models. (#2691)
Co-authored-by: Tobie Morgan Hitchcock <tobie@surrealdb.com>
This commit is contained in:
parent
538ad50c65
commit
178e2a0d4a
12 changed files with 365 additions and 161 deletions
|
@ -394,7 +394,7 @@ fn into_json(value: Value, simplify: bool) -> JsonValue {
|
|||
Value::Param(param) => json!(param),
|
||||
Value::Idiom(idiom) => json!(idiom),
|
||||
Value::Table(table) => json!(table),
|
||||
Value::Model(model) => json!(model),
|
||||
Value::Mock(mock) => json!(mock),
|
||||
Value::Regex(regex) => json!(regex),
|
||||
Value::Block(block) => json!(block),
|
||||
Value::Range(range) => json!(range),
|
||||
|
@ -409,6 +409,7 @@ fn into_json(value: Value, simplify: bool) -> JsonValue {
|
|||
},
|
||||
Value::Cast(cast) => json!(cast),
|
||||
Value::Function(function) => json!(function),
|
||||
Value::MlModel(model) => json!(model),
|
||||
Value::Query(query) => json!(query),
|
||||
Value::Subquery(subquery) => json!(subquery),
|
||||
Value::Expression(expression) => json!(expression),
|
||||
|
|
|
@ -142,7 +142,7 @@ impl Iterator {
|
|||
// Add the record to the iterator
|
||||
self.ingest(Iterable::Thing(v));
|
||||
}
|
||||
Value::Model(v) => {
|
||||
Value::Mock(v) => {
|
||||
// Check if there is a data clause
|
||||
if let Some(data) = stm.data() {
|
||||
// Check if there is an id field specified
|
||||
|
|
130
lib/src/sql/mock.rs
Normal file
130
lib/src/sql/mock.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
use crate::sql::common::take_u64;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::escape_ident;
|
||||
use crate::sql::id::Id;
|
||||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::thing::Thing;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::map;
|
||||
use nom::{branch::alt, combinator::value};
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Mock";
|
||||
|
||||
pub struct IntoIter {
|
||||
model: Mock,
|
||||
index: u64,
|
||||
}
|
||||
|
||||
impl Iterator for IntoIter {
|
||||
type Item = Thing;
|
||||
fn next(&mut self) -> Option<Thing> {
|
||||
match &self.model {
|
||||
Mock::Count(tb, c) => {
|
||||
if self.index < *c {
|
||||
self.index += 1;
|
||||
Some(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: Id::rand(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Mock::Range(tb, b, e) => {
|
||||
if self.index == 0 {
|
||||
self.index = *b - 1;
|
||||
}
|
||||
if self.index < *e {
|
||||
self.index += 1;
|
||||
Some(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: Id::from(self.index),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
#[serde(rename = "$surrealdb::private::sql::Mock")]
|
||||
#[revisioned(revision = 1)]
|
||||
pub enum Mock {
|
||||
Count(String, u64),
|
||||
Range(String, u64, u64),
|
||||
// Add new variants here
|
||||
}
|
||||
|
||||
impl IntoIterator for Mock {
|
||||
type Item = Thing;
|
||||
type IntoIter = IntoIter;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter {
|
||||
model: self,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Mock {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Mock::Count(tb, c) => {
|
||||
write!(f, "|{}:{}|", escape_ident(tb), c)
|
||||
}
|
||||
Mock::Range(tb, b, e) => {
|
||||
write!(f, "|{}:{}..{}|", escape_ident(tb), b, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mock(i: &str) -> IResult<&str, Mock> {
|
||||
let (i, _) = char('|')(i)?;
|
||||
let (i, t) = ident_raw(i)?;
|
||||
let (i, _) = char(':')(i)?;
|
||||
let (i, c) = take_u64(i)?;
|
||||
let (i, e) = alt((value(None, char('|')), map(mock_range, Some)))(i)?;
|
||||
if let Some(e) = e {
|
||||
Ok((i, Mock::Range(t, c, e)))
|
||||
} else {
|
||||
Ok((i, Mock::Count(t, c)))
|
||||
}
|
||||
}
|
||||
|
||||
fn mock_range(i: &str) -> IResult<&str, u64> {
|
||||
let (i, _) = char('.')(i)?;
|
||||
let (i, _) = char('.')(i)?;
|
||||
let (i, e) = take_u64(i)?;
|
||||
let (i, _) = char('|')(i)?;
|
||||
Ok((i, e))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn mock_count() {
|
||||
let sql = "|test:1000|";
|
||||
let res = mock(sql);
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("|test:1000|", format!("{}", out));
|
||||
assert_eq!(out, Mock::Count(String::from("test"), 1000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mock_range() {
|
||||
let sql = "|test:1..1000|";
|
||||
let res = mock(sql);
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("|test:1..1000|", format!("{}", out));
|
||||
assert_eq!(out, Mock::Range(String::from("test"), 1, 1000));
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ pub(crate) mod index;
|
|||
pub(crate) mod kind;
|
||||
pub(crate) mod language;
|
||||
pub(crate) mod limit;
|
||||
pub(crate) mod mock;
|
||||
pub(crate) mod model;
|
||||
pub(crate) mod number;
|
||||
pub(crate) mod object;
|
||||
|
@ -114,7 +115,7 @@ pub use self::idiom::Idioms;
|
|||
pub use self::index::Index;
|
||||
pub use self::kind::Kind;
|
||||
pub use self::limit::Limit;
|
||||
pub use self::model::Model;
|
||||
pub use self::mock::Mock;
|
||||
pub use self::number::Number;
|
||||
pub use self::object::Object;
|
||||
pub use self::operation::Operation;
|
||||
|
|
|
@ -1,131 +1,133 @@
|
|||
use crate::sql::common::take_u64;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::escape_ident;
|
||||
use crate::sql::id::Id;
|
||||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::thing::Thing;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::map;
|
||||
use nom::{branch::alt, combinator::value};
|
||||
use async_recursion::async_recursion;
|
||||
use derive::Store;
|
||||
use nom::{
|
||||
bytes::complete::{tag, take_while1},
|
||||
character::complete::i64,
|
||||
combinator::{cut, recognize},
|
||||
multi::separated_list1,
|
||||
};
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Model";
|
||||
use crate::{
|
||||
ctx::Context,
|
||||
dbs::{Options, Transaction},
|
||||
doc::CursorDoc,
|
||||
err::Error,
|
||||
sql::{error::IResult, value::Value},
|
||||
};
|
||||
|
||||
pub struct IntoIter {
|
||||
model: Model,
|
||||
index: u64,
|
||||
}
|
||||
use super::{
|
||||
common::{closechevron, closeparentheses, openchevron, openparentheses, val_char},
|
||||
error::{expect_tag_no_case, expected},
|
||||
util::expect_delimited,
|
||||
value::value,
|
||||
};
|
||||
|
||||
impl Iterator for IntoIter {
|
||||
type Item = Thing;
|
||||
fn next(&mut self) -> Option<Thing> {
|
||||
match &self.model {
|
||||
Model::Count(tb, c) => {
|
||||
if self.index < *c {
|
||||
self.index += 1;
|
||||
Some(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: Id::rand(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Model::Range(tb, b, e) => {
|
||||
if self.index == 0 {
|
||||
self.index = *b - 1;
|
||||
}
|
||||
if self.index < *e {
|
||||
self.index += 1;
|
||||
Some(Thing {
|
||||
tb: tb.to_string(),
|
||||
id: Id::from(self.index),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
#[serde(rename = "$surrealdb::private::sql::Model")]
|
||||
#[derive(Clone, Debug, Default, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub enum Model {
|
||||
Count(String, u64),
|
||||
Range(String, u64, u64),
|
||||
// Add new variants here
|
||||
}
|
||||
|
||||
impl IntoIterator for Model {
|
||||
type Item = Thing;
|
||||
type IntoIter = IntoIter;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter {
|
||||
model: self,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
pub struct Model {
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub parameters: Value,
|
||||
}
|
||||
|
||||
impl fmt::Display for Model {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Model::Count(tb, c) => {
|
||||
write!(f, "|{}:{}|", escape_ident(tb), c)
|
||||
}
|
||||
Model::Range(tb, b, e) => {
|
||||
write!(f, "|{}:{}..{}|", escape_ident(tb), b, e)
|
||||
}
|
||||
}
|
||||
write!(f, "ml::{}<{}>({})", self.name, self.version, self.parameters)
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
Err(Error::Unimplemented("ML model evaluation not yet implemented".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn model(i: &str) -> IResult<&str, Model> {
|
||||
let (i, _) = char('|')(i)?;
|
||||
let (i, t) = ident_raw(i)?;
|
||||
let (i, _) = char(':')(i)?;
|
||||
let (i, c) = take_u64(i)?;
|
||||
let (i, e) = alt((value(None, char('|')), map(model_range, Some)))(i)?;
|
||||
if let Some(e) = e {
|
||||
Ok((i, Model::Range(t, c, e)))
|
||||
} else {
|
||||
Ok((i, Model::Count(t, c)))
|
||||
}
|
||||
let (i, _) = tag("ml::")(i)?;
|
||||
|
||||
cut(|i| {
|
||||
let (i, name) = recognize(separated_list1(tag("::"), take_while1(val_char)))(i)?;
|
||||
|
||||
let (i, version) =
|
||||
expected("a version", expect_delimited(openchevron, version, closechevron))(i)?;
|
||||
|
||||
let (i, parameters) = expected(
|
||||
"model parameters",
|
||||
expect_delimited(openparentheses, value, closeparentheses),
|
||||
)(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
Model {
|
||||
name: name.to_owned(),
|
||||
version,
|
||||
parameters,
|
||||
},
|
||||
))
|
||||
})(i)
|
||||
}
|
||||
|
||||
fn model_range(i: &str) -> IResult<&str, u64> {
|
||||
let (i, _) = char('.')(i)?;
|
||||
let (i, _) = char('.')(i)?;
|
||||
let (i, e) = take_u64(i)?;
|
||||
let (i, _) = char('|')(i)?;
|
||||
//Ok((i, Model::Range(t, b, e)))
|
||||
Ok((i, e))
|
||||
pub fn version(i: &str) -> IResult<&str, String> {
|
||||
use std::fmt::Write;
|
||||
|
||||
let (i, major) = expected("a version number", i64)(i)?;
|
||||
let (i, _) = expect_tag_no_case(".")(i)?;
|
||||
let (i, minor) = expected("a version number", i64)(i)?;
|
||||
let (i, _) = expect_tag_no_case(".")(i)?;
|
||||
let (i, patch) = expected("a version number", i64)(i)?;
|
||||
|
||||
let mut res = String::new();
|
||||
// Writing into a string can never error.
|
||||
write!(&mut res, "{major}.{minor}.{patch}").unwrap();
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::sql::query;
|
||||
|
||||
#[test]
|
||||
fn model_count() {
|
||||
let sql = "|test:1000|";
|
||||
fn ml_model_example() {
|
||||
let sql = r#"ml::insurance::prediction<1.0.0>({
|
||||
age: 18,
|
||||
disposable_income: "yes",
|
||||
purchased_before: true
|
||||
})
|
||||
"#;
|
||||
let res = model(sql);
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("|test:1000|", format!("{}", out));
|
||||
assert_eq!(out, Model::Count(String::from("test"), 1000));
|
||||
let out = res.unwrap().1.to_string();
|
||||
assert_eq!("ml::insurance::prediction<1.0.0>({ age: 18, disposable_income: 'yes', purchased_before: true })",out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_range() {
|
||||
let sql = "|test:1..1000|";
|
||||
let res = model(sql);
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("|test:1..1000|", format!("{}", out));
|
||||
assert_eq!(out, Model::Range(String::from("test"), 1, 1000));
|
||||
fn ml_model_example_in_select() {
|
||||
let sql = r"
|
||||
SELECT
|
||||
name,
|
||||
age,
|
||||
ml::insurance::prediction<1.0.0>({
|
||||
age: age,
|
||||
disposable_income: math::round(income),
|
||||
purchased_before: array::len(->purchased->property) > 0,
|
||||
}) AS likely_to_buy FROM person:tobie;
|
||||
";
|
||||
let res = query::query(sql);
|
||||
let out = res.unwrap().1.to_string();
|
||||
assert_eq!(
|
||||
"SELECT name, age, ml::insurance::prediction<1.0.0>({ age: age, disposable_income: math::round(income), purchased_before: array::len(->purchased->property) > 0 }) AS likely_to_buy FROM person:tobie;",
|
||||
out,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ mod event;
|
|||
mod field;
|
||||
mod function;
|
||||
mod index;
|
||||
mod model;
|
||||
mod namespace;
|
||||
mod param;
|
||||
mod scope;
|
||||
|
@ -17,6 +18,7 @@ pub use event::{event, DefineEventStatement};
|
|||
pub use field::{field, DefineFieldStatement};
|
||||
pub use function::{function, DefineFunctionStatement};
|
||||
pub use index::{index, DefineIndexStatement};
|
||||
pub use model::DefineModelStatement;
|
||||
pub use namespace::{namespace, DefineNamespaceStatement};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
pub use param::{param, DefineParamStatement};
|
||||
|
@ -55,6 +57,7 @@ pub enum DefineStatement {
|
|||
Field(DefineFieldStatement),
|
||||
Index(DefineIndexStatement),
|
||||
User(DefineUserStatement),
|
||||
MlModel(DefineModelStatement),
|
||||
}
|
||||
|
||||
impl DefineStatement {
|
||||
|
@ -83,6 +86,7 @@ impl DefineStatement {
|
|||
Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::User(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::MlModel(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +106,7 @@ impl Display for DefineStatement {
|
|||
Self::Field(v) => Display::fmt(v, f),
|
||||
Self::Index(v) => Display::fmt(v, f),
|
||||
Self::Analyzer(v) => Display::fmt(v, f),
|
||||
Self::MlModel(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
59
lib/src/sql/statements/define/model.rs
Normal file
59
lib/src/sql/statements/define/model.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use crate::sql::fmt::is_pretty;
|
||||
use crate::sql::fmt::pretty_indent;
|
||||
use crate::sql::permission::Permission;
|
||||
use async_recursion::async_recursion;
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::{
|
||||
ctx::Context,
|
||||
dbs::{Options, Transaction},
|
||||
doc::CursorDoc,
|
||||
err::Error,
|
||||
sql::{Ident, Strand, Value},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineModelStatement {
|
||||
pub name: Ident,
|
||||
pub version: String,
|
||||
pub comment: Option<Strand>,
|
||||
pub permissions: Permission,
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineModelStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "DEFINE MODEL ml::{}<{}>", self.name, self.version)?;
|
||||
if let Some(comment) = self.comment.as_ref() {
|
||||
write!(f, "COMMENT {}", comment)?;
|
||||
}
|
||||
if !self.permissions.is_full() {
|
||||
let _indent = if is_pretty() {
|
||||
Some(pretty_indent())
|
||||
} else {
|
||||
f.write_char(' ')?;
|
||||
None
|
||||
};
|
||||
write!(f, "PERMISSIONS {}", self.permissions)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DefineModelStatement {
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
Err(Error::Unimplemented("Ml model definition not yet implemented".to_string()))
|
||||
}
|
||||
}
|
|
@ -105,7 +105,7 @@ impl SelectStatement {
|
|||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||
Value::Range(v) => i.ingest(Iterable::Range(*v)),
|
||||
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
||||
Value::Model(v) => {
|
||||
Value::Mock(v) => {
|
||||
for v in v {
|
||||
i.ingest(Iterable::Thing(v));
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ impl SelectStatement {
|
|||
}
|
||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
||||
Value::Model(v) => {
|
||||
Value::Mock(v) => {
|
||||
for v in v {
|
||||
i.ingest(Iterable::Thing(v));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::value::serde::ser;
|
||||
use crate::sql::Model;
|
||||
use crate::sql::Mock;
|
||||
use ser::Serializer as _;
|
||||
use serde::ser::Error as _;
|
||||
use serde::ser::Impossible;
|
||||
|
@ -9,18 +9,18 @@ use serde::ser::Serialize;
|
|||
pub(super) struct Serializer;
|
||||
|
||||
impl ser::Serializer for Serializer {
|
||||
type Ok = Model;
|
||||
type Ok = Mock;
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = Impossible<Model, Error>;
|
||||
type SerializeTuple = Impossible<Model, Error>;
|
||||
type SerializeTupleStruct = Impossible<Model, Error>;
|
||||
type SerializeTupleVariant = SerializeModel;
|
||||
type SerializeMap = Impossible<Model, Error>;
|
||||
type SerializeStruct = Impossible<Model, Error>;
|
||||
type SerializeStructVariant = Impossible<Model, Error>;
|
||||
type SerializeSeq = Impossible<Mock, Error>;
|
||||
type SerializeTuple = Impossible<Mock, Error>;
|
||||
type SerializeTupleStruct = Impossible<Mock, Error>;
|
||||
type SerializeTupleVariant = SerializeMock;
|
||||
type SerializeMap = Impossible<Mock, Error>;
|
||||
type SerializeStruct = Impossible<Mock, Error>;
|
||||
type SerializeStructVariant = Impossible<Mock, Error>;
|
||||
|
||||
const EXPECTED: &'static str = "an enum `Model`";
|
||||
const EXPECTED: &'static str = "an enum `Mock`";
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
|
@ -36,14 +36,14 @@ impl ser::Serializer for Serializer {
|
|||
return Err(Error::custom(format!("unexpected tuple variant `{name}::{variant}`")));
|
||||
}
|
||||
};
|
||||
Ok(SerializeModel {
|
||||
Ok(SerializeMock {
|
||||
inner,
|
||||
index: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct SerializeModel {
|
||||
pub(super) struct SerializeMock {
|
||||
index: usize,
|
||||
inner: Inner,
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ enum Inner {
|
|||
Range(Option<String>, Option<u64>, Option<u64>),
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeTupleVariant for SerializeModel {
|
||||
type Ok = Model;
|
||||
impl serde::ser::SerializeTupleVariant for SerializeMock {
|
||||
type Ok = Mock;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
|
@ -76,9 +76,7 @@ impl serde::ser::SerializeTupleVariant for SerializeModel {
|
|||
Inner::Count(..) => "Count",
|
||||
Inner::Range(..) => "Range",
|
||||
};
|
||||
return Err(Error::custom(format!(
|
||||
"unexpected `Model::{variant}` index `{index}`"
|
||||
)));
|
||||
return Err(Error::custom(format!("unexpected `Mock::{variant}` index `{index}`")));
|
||||
}
|
||||
}
|
||||
self.index += 1;
|
||||
|
@ -87,9 +85,9 @@ impl serde::ser::SerializeTupleVariant for SerializeModel {
|
|||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
match self.inner {
|
||||
Inner::Count(Some(one), Some(two)) => Ok(Model::Count(one, two)),
|
||||
Inner::Range(Some(one), Some(two), Some(three)) => Ok(Model::Range(one, two, three)),
|
||||
_ => Err(Error::custom("`Model` missing required value(s)")),
|
||||
Inner::Count(Some(one), Some(two)) => Ok(Mock::Count(one, two)),
|
||||
Inner::Range(Some(one), Some(two), Some(three)) => Ok(Mock::Range(one, two, three)),
|
||||
_ => Err(Error::custom("`Mock` missing required value(s)")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,14 +99,14 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn count() {
|
||||
let model = Model::Count(Default::default(), Default::default());
|
||||
let model = Mock::Count(Default::default(), Default::default());
|
||||
let serialized = model.serialize(Serializer.wrap()).unwrap();
|
||||
assert_eq!(model, serialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range() {
|
||||
let model = Model::Range(Default::default(), 1, 2);
|
||||
let model = Mock::Range(Default::default(), 1, 2);
|
||||
let serialized = model.serialize(Serializer.wrap()).unwrap();
|
||||
assert_eq!(model, serialized);
|
||||
}
|
|
@ -30,7 +30,7 @@ mod index;
|
|||
mod kind;
|
||||
mod language;
|
||||
mod limit;
|
||||
mod model;
|
||||
mod mock;
|
||||
mod number;
|
||||
mod operator;
|
||||
mod order;
|
||||
|
|
|
@ -27,7 +27,7 @@ use ser::cast::SerializeCast;
|
|||
use ser::edges::SerializeEdges;
|
||||
use ser::expression::SerializeExpression;
|
||||
use ser::function::SerializeFunction;
|
||||
use ser::model::SerializeModel;
|
||||
use ser::mock::SerializeMock;
|
||||
use ser::range::SerializeRange;
|
||||
use ser::thing::SerializeThing;
|
||||
use ser::Serializer as _;
|
||||
|
@ -323,14 +323,9 @@ impl ser::Serializer for Serializer {
|
|||
len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Error> {
|
||||
Ok(match name {
|
||||
sql::model::TOKEN => {
|
||||
SerializeTupleVariant::Model(ser::model::Serializer.serialize_tuple_variant(
|
||||
name,
|
||||
variant_index,
|
||||
variant,
|
||||
len,
|
||||
)?)
|
||||
}
|
||||
sql::mock::TOKEN => SerializeTupleVariant::Model(
|
||||
ser::mock::Serializer.serialize_tuple_variant(name, variant_index, variant, len)?,
|
||||
),
|
||||
sql::function::TOKEN => {
|
||||
SerializeTupleVariant::Function(ser::function::Serializer.serialize_tuple_variant(
|
||||
name,
|
||||
|
@ -462,7 +457,7 @@ impl serde::ser::SerializeMap for SerializeMap {
|
|||
}
|
||||
|
||||
pub(super) enum SerializeTupleVariant {
|
||||
Model(SerializeModel),
|
||||
Model(SerializeMock),
|
||||
Function(SerializeFunction),
|
||||
Unknown {
|
||||
variant: &'static str,
|
||||
|
@ -517,7 +512,7 @@ impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
|||
|
||||
fn end(self) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Model(model) => Ok(Value::Model(model.end()?)),
|
||||
Self::Model(model) => Ok(Value::Mock(model.end()?)),
|
||||
Self::Function(function) => Ok(Value::Function(Box::new(function.end()?))),
|
||||
Self::Unknown {
|
||||
variant,
|
||||
|
@ -789,9 +784,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn model() {
|
||||
let model = Model::Count("foo".to_owned(), Default::default());
|
||||
let model = Mock::Count("foo".to_owned(), Default::default());
|
||||
let value = to_value(&model).unwrap();
|
||||
let expected = Value::Model(model);
|
||||
let expected = Value::Mock(model);
|
||||
assert_eq!(value, expected);
|
||||
assert_eq!(expected, to_value(&expected).unwrap());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ use crate::sql::geometry::{geometry, Geometry};
|
|||
use crate::sql::id::{Gen, Id};
|
||||
use crate::sql::idiom::{self, reparse_idiom_start, Idiom};
|
||||
use crate::sql::kind::Kind;
|
||||
use crate::sql::mock::{mock, Mock};
|
||||
use crate::sql::model::{model, Model};
|
||||
use crate::sql::number::{number, Number};
|
||||
use crate::sql::object::{key, object, Object};
|
||||
|
@ -140,7 +141,7 @@ pub enum Value {
|
|||
Param(Param),
|
||||
Idiom(Idiom),
|
||||
Table(Table),
|
||||
Model(Model),
|
||||
Mock(Mock),
|
||||
Regex(Regex),
|
||||
Cast(Box<Cast>),
|
||||
Block(Box<Block>),
|
||||
|
@ -153,6 +154,7 @@ pub enum Value {
|
|||
Subquery(Box<Subquery>),
|
||||
Expression(Box<Expression>),
|
||||
Query(Query),
|
||||
MlModel(Box<Model>),
|
||||
// Add new variants here
|
||||
}
|
||||
|
||||
|
@ -189,9 +191,9 @@ impl From<Idiom> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Model> for Value {
|
||||
fn from(v: Model) -> Self {
|
||||
Value::Model(v)
|
||||
impl From<Mock> for Value {
|
||||
fn from(v: Mock) -> Self {
|
||||
Value::Mock(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,6 +305,12 @@ impl From<Function> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Model> for Value {
|
||||
fn from(v: Model) -> Self {
|
||||
Value::MlModel(Box::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Subquery> for Value {
|
||||
fn from(v: Subquery) -> Self {
|
||||
Value::Subquery(Box::new(v))
|
||||
|
@ -854,9 +862,9 @@ impl Value {
|
|||
matches!(self, Value::Thing(_))
|
||||
}
|
||||
|
||||
/// Check if this Value is a Model
|
||||
pub fn is_model(&self) -> bool {
|
||||
matches!(self, Value::Model(_))
|
||||
/// Check if this Value is a Mock
|
||||
pub fn is_mock(&self) -> bool {
|
||||
matches!(self, Value::Mock(_))
|
||||
}
|
||||
|
||||
/// Check if this Value is a Range
|
||||
|
@ -1055,7 +1063,8 @@ impl Value {
|
|||
pub fn can_start_idiom(&self) -> bool {
|
||||
match self {
|
||||
Value::Function(x) => !x.is_script(),
|
||||
Value::Subquery(_)
|
||||
Value::MlModel(_)
|
||||
| Value::Subquery(_)
|
||||
| Value::Constant(_)
|
||||
| Value::Datetime(_)
|
||||
| Value::Duration(_)
|
||||
|
@ -2526,10 +2535,11 @@ impl fmt::Display for Value {
|
|||
Value::Edges(v) => write!(f, "{v}"),
|
||||
Value::Expression(v) => write!(f, "{v}"),
|
||||
Value::Function(v) => write!(f, "{v}"),
|
||||
Value::MlModel(v) => write!(f, "{v}"),
|
||||
Value::Future(v) => write!(f, "{v}"),
|
||||
Value::Geometry(v) => write!(f, "{v}"),
|
||||
Value::Idiom(v) => write!(f, "{v}"),
|
||||
Value::Model(v) => write!(f, "{v}"),
|
||||
Value::Mock(v) => write!(f, "{v}"),
|
||||
Value::Number(v) => write!(f, "{v}"),
|
||||
Value::Object(v) => write!(f, "{v}"),
|
||||
Value::Param(v) => write!(f, "{v}"),
|
||||
|
@ -2556,6 +2566,7 @@ impl Value {
|
|||
Value::Function(v) => {
|
||||
v.is_custom() || v.is_script() || v.args().iter().any(Value::writeable)
|
||||
}
|
||||
Value::MlModel(m) => m.parameters.writeable(),
|
||||
Value::Subquery(v) => v.writeable(),
|
||||
Value::Expression(v) => v.writeable(),
|
||||
_ => false,
|
||||
|
@ -2586,6 +2597,7 @@ impl Value {
|
|||
Value::Future(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Constant(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Function(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::MlModel(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Subquery(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Expression(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
_ => Ok(self.to_owned()),
|
||||
|
@ -2741,7 +2753,7 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
|||
alt((
|
||||
into(future),
|
||||
into(cast),
|
||||
function_or_const,
|
||||
path_like,
|
||||
into(geometry),
|
||||
into(subquery),
|
||||
into(datetime),
|
||||
|
@ -2756,7 +2768,7 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
|||
into(block),
|
||||
into(param),
|
||||
into(regex),
|
||||
into(model),
|
||||
into(mock),
|
||||
into(edges),
|
||||
into(range),
|
||||
into(thing),
|
||||
|
@ -2780,7 +2792,7 @@ pub fn select_start(i: &str) -> IResult<&str, Value> {
|
|||
alt((
|
||||
into(future),
|
||||
into(cast),
|
||||
function_or_const,
|
||||
path_like,
|
||||
into(geometry),
|
||||
into(subquery),
|
||||
into(datetime),
|
||||
|
@ -2792,7 +2804,7 @@ pub fn select_start(i: &str) -> IResult<&str, Value> {
|
|||
into(block),
|
||||
into(param),
|
||||
into(regex),
|
||||
into(model),
|
||||
into(mock),
|
||||
into(edges),
|
||||
into(range),
|
||||
into(thing),
|
||||
|
@ -2803,8 +2815,9 @@ pub fn select_start(i: &str) -> IResult<&str, Value> {
|
|||
reparse_idiom_start(v, i)
|
||||
}
|
||||
|
||||
pub fn function_or_const(i: &str) -> IResult<&str, Value> {
|
||||
alt((into(defined_function), |i| {
|
||||
/// A path like production: Constants, predefined functions, user defined functions and ml models.
|
||||
pub fn path_like(i: &str) -> IResult<&str, Value> {
|
||||
alt((into(defined_function), into(model), |i| {
|
||||
let (i, v) = builtin_name(i)?;
|
||||
match v {
|
||||
builtin::BuiltinName::Constant(x) => Ok((i, x.into())),
|
||||
|
@ -2841,14 +2854,14 @@ pub fn what(i: &str) -> IResult<&str, Value> {
|
|||
let _diving = crate::sql::parser::depth::dive(i)?;
|
||||
let (i, v) = alt((
|
||||
into(idiom::multi_without_start),
|
||||
function_or_const,
|
||||
path_like,
|
||||
into(subquery),
|
||||
into(datetime),
|
||||
into(duration),
|
||||
into(future),
|
||||
into(block),
|
||||
into(param),
|
||||
into(model),
|
||||
into(mock),
|
||||
into(edges),
|
||||
into(range),
|
||||
into(thing),
|
||||
|
@ -2995,7 +3008,7 @@ mod tests {
|
|||
assert_eq!(24, std::mem::size_of::<crate::sql::idiom::Idiom>());
|
||||
assert_eq!(24, std::mem::size_of::<crate::sql::table::Table>());
|
||||
assert_eq!(56, std::mem::size_of::<crate::sql::thing::Thing>());
|
||||
assert_eq!(40, std::mem::size_of::<crate::sql::model::Model>());
|
||||
assert_eq!(40, std::mem::size_of::<crate::sql::mock::Mock>());
|
||||
assert_eq!(32, std::mem::size_of::<crate::sql::regex::Regex>());
|
||||
assert_eq!(8, std::mem::size_of::<Box<crate::sql::range::Range>>());
|
||||
assert_eq!(8, std::mem::size_of::<Box<crate::sql::edges::Edges>>());
|
||||
|
|
Loading…
Reference in a new issue