diff --git a/core/src/err/mod.rs b/core/src/err/mod.rs index c178fb76..5cd9a928 100644 --- a/core/src/err/mod.rs +++ b/core/src/err/mod.rs @@ -527,7 +527,7 @@ pub enum Error { }, /// The specified table is not configured for the type of record being added - #[error("Found record: `{thing}` which is {}a relation, but expected a `target_type`", if *relation { "not " } else { "" })] + #[error("Found record: `{thing}` which is {}a relation, but expected a {target_type}", if *relation { "not " } else { "" })] TableCheck { thing: String, relation: bool, diff --git a/lib/tests/define.rs b/lib/tests/define.rs index 0115bd23..55f60c7a 100644 --- a/lib/tests/define.rs +++ b/lib/tests/define.rs @@ -2692,3 +2692,251 @@ async fn define_statement_index_empty_array() -> Result<(), Error> { // Ok(()) } + +#[tokio::test] +async fn define_table_relation_in_out() -> Result<(), Error> { + let sql = r" + DEFINE TABLE likes TYPE RELATION FROM person TO person | thing SCHEMAFUL; + LET $first_p = CREATE person SET name = 'first person'; + LET $second_p = CREATE person SET name = 'second person'; + LET $thing = CREATE thing SET name = 'rust'; + LET $other = CREATE other; + RELATE $first_p->likes->$thing; + RELATE $first_p->likes->$second_p; + CREATE likes; + RELATE $first_p->likes->$other; + RELATE $thing->likes->$first_p; + "; + let dbs = new_ds().await?; + let ses = Session::owner().with_ns("test").with_db("test"); + let res = &mut dbs.execute(sql, &ses, None).await?; + assert_eq!(res.len(), 10); + // + for _ in 0..7 { + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + } + // + let tmp = res.remove(0).result; + assert!(matches!( + tmp, + Err(crate::Error::TableCheck { + thing: _, + relation: _, + target_type: _ + }) + )); + // + let tmp = res.remove(0).result; + assert!(tmp.is_err()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_err()); + // + + Ok(()) +} + +#[tokio::test] +async fn define_table_relation_redefinition() -> Result<(), Error> { + let sql = " + DEFINE TABLE likes TYPE RELATION IN person OUT person; + LET $person = CREATE person; + LET $thing = CREATE thing; + LET $other = CREATE other; + RELATE $person->likes->$thing; + DEFINE TABLE likes TYPE RELATION IN person OUT person | thing; + RELATE $person->likes->$thing; + RELATE $person->likes->$other; + DEFINE FIELD out ON TABLE likes TYPE record; + RELATE $person->likes->$other; + "; + let dbs = new_ds().await?; + let ses = Session::owner().with_ns("test").with_db("test"); + let res = &mut dbs.execute(sql, &ses, None).await?; + assert_eq!(res.len(), 10); + // + for _ in 0..4 { + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + } + // + let tmp = res.remove(0).result; + assert!(tmp.is_err()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_err()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + Ok(()) +} + +#[tokio::test] +async fn define_table_relation_redefinition_info() -> Result<(), Error> { + let sql = " + DEFINE TABLE likes TYPE RELATION IN person OUT person; + INFO FOR TABLE likes; + INFO FOR DB; + DEFINE TABLE likes TYPE RELATION IN person OUT person | thing; + INFO FOR TABLE likes; + INFO FOR DB; + DEFINE FIELD out ON TABLE likes TYPE record; + INFO FOR TABLE likes; + INFO FOR DB; + "; + let dbs = new_ds().await?; + let ses = Session::owner().with_ns("test").with_db("test"); + let res = &mut dbs.execute(sql, &ses, None).await?; + assert_eq!(res.len(), 9); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + "{ + events: {}, + fields: { in: 'DEFINE FIELD in ON likes TYPE record PERMISSIONS FULL', out: 'DEFINE FIELD out ON likes TYPE record PERMISSIONS FULL' }, + tables: {}, + indexes: {}, + lives: {}, + }", + ); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + "{ + analyzers: {}, + tokens: {}, + functions: {}, + models: {}, + params: {}, + scopes: {}, + tables: { likes: 'DEFINE TABLE likes TYPE RELATION IN person OUT person SCHEMALESS PERMISSIONS NONE' }, + users: {}, + }", + ); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + "{ + events: {}, + fields: { in: 'DEFINE FIELD in ON likes TYPE record PERMISSIONS FULL', out: 'DEFINE FIELD out ON likes TYPE record PERMISSIONS FULL' }, + tables: {}, + indexes: {}, + lives: {}, + }", + ); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + "{ + analyzers: {}, + tokens: {}, + functions: {}, + models: {}, + params: {}, + scopes: {}, + tables: { likes: 'DEFINE TABLE likes TYPE RELATION IN person OUT person | thing SCHEMALESS PERMISSIONS NONE' }, + users: {}, + }", + ); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + "{ + events: {}, + fields: { in: 'DEFINE FIELD in ON likes TYPE record PERMISSIONS FULL', out: 'DEFINE FIELD out ON likes TYPE record PERMISSIONS FULL' }, + tables: {}, + indexes: {}, + lives: {}, + }", + ); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + "{ + analyzers: {}, + tokens: {}, + functions: {}, + models: {}, + params: {}, + scopes: {}, + tables: { likes: 'DEFINE TABLE likes TYPE RELATION IN person OUT person | thing | other SCHEMALESS PERMISSIONS NONE' }, + users: {}, + }", + ); + assert_eq!(tmp, val); + // + Ok(()) +} + +#[tokio::test] +async fn define_table_type_normal() -> Result<(), Error> { + let sql = " + DEFINE TABLE thing TYPE NORMAL; + CREATE thing; + RELATE foo:one->thing->foo:two; + "; + let dbs = new_ds().await?; + let ses = Session::owner().with_ns("test").with_db("test"); + let res = &mut dbs.execute(sql, &ses, None).await?; + assert_eq!(res.len(), 3); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_err()); + // + Ok(()) +} + +#[tokio::test] +async fn define_table_type_any() -> Result<(), Error> { + let sql = " + DEFINE TABLE thing TYPE ANY; + CREATE thing; + RELATE foo:one->thing->foo:two; + "; + let dbs = new_ds().await?; + let ses = Session::owner().with_ns("test").with_db("test"); + let res = &mut dbs.execute(sql, &ses, None).await?; + assert_eq!(res.len(), 3); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + Ok(()) +}