use super::checked; #[test] fn conditional_writes_require_static_predicates_and_write_entries() { let update = "change(name: Text) (count: Int) { count = model.update({ where = name == name }, { note = name }) }"; assert!(checked(update, "cmd change = app.change").is_ok()); assert_eq!( checked(update, "public get change = app.change") .unwrap_err() .code, "C014" ); for expression in [ "model.update({}, { note = name })", "model.update({ where = name == name, order = [id.asc] }, { note = name })", "model.update({ where = name == name }, {})", "model.update({ where = name == name }, { note = name, note = name })", "model.delete({})", "model.delete({ where = name == name, size = 1 })", ] { let source = format!("change(name: Text) (count: Int) {{ count = {expression} }}"); assert!( checked(&source, "cmd change = app.change").is_err(), "{expression}" ); } } #[test] fn cursor_checks_snapshot_type_order_and_options() { for query in ["", "{ after = null, size = 2, order = [name.asc] }"] { let app = format!("search() (page: model.Cursor) {{ page = model.cursor({query}) }}"); assert!(checked(&app, "cmd search = app.search").is_ok(), "{query}"); } for query in [ "{ after = 1 }", "{ size = \"two\" }", "{ order = [note.asc] }", "{ order = [name.asc, name.desc] }", "{ page = 1 }", ] { let app = format!("search() (page: model.Cursor) {{ page = model.cursor({query}) }}"); assert!(checked(&app, "cmd search = app.search").is_err(), "{query}"); } } #[test] fn query_predicates_require_static_fields_and_typed_bounded_values() { let api = "cmd search = app.search"; for condition in [ "not contains(name, value) and in(name, [value, \"other\"])", "between(name, value, \"雪\") or startsWith(note, value)", "endsWith(name, value) and note == null", ] { let app = format!( "search(value: Text) (total: Int) {{ total = model.count({{ where = {condition} }}) }}" ); assert!(checked(&app, api).is_ok(), "{condition}"); } for condition in [ "in(name, [])", "in(name, value)", "in(name, [1])", "contains(name)", "contains(id, value)", "contains(\"field\", value)", "contains(missing, value)", "between(name, value)", "startsWith(name, 1)", "unknown(name, value)", ] { let app = format!( "search(value: Text) (total: Int) {{ total = model.count({{ where = {condition} }}) }}" ); assert!(checked(&app, api).is_err(), "accepted {condition}"); } let items = vec!["value"; 101].join(","); let app = format!( "search(value: Text) (total: Int) {{ total = model.count({{ where = in(name, [{items}]) }}) }}" ); assert!(checked(&app, api).is_err()); assert!( checked( "search(value: Text) (answer: Bool) { answer = contains(value, value) }", api ) .is_err() ); } #[test] fn bulk_and_upsert_keep_field_contracts_and_unique_keys() { for body in [ "total = model.createMany([])", "total = model.createMany([{ name = \"one\" }, { name = \"two\", note = null }])", "row = model.upsert({ name = \"one\" }, {}, { note = \"updated\" })\ntotal = length(row.name)", ] { let app = format!("write() (total: Int) {{ {body} }}"); assert!(checked(&app, "cmd write = app.write").is_ok(), "{body}"); assert!(checked(&app, "public get write = app.write").is_err()); } for body in [ "total = model.createMany([{}])", "total = model.createMany([{ name = \"one\", name = \"two\" }])", "total = model.createMany([{ id = 1, name = \"one\" }])", "total = model.createMany([{ name = 7 }])", "row = model.upsert({}, { name = \"one\" }, {})\ntotal = length(row.name)", "row = model.upsert({ note = \"key\" }, { name = \"one\" }, {})\ntotal = length(row.name)", "row = model.upsert({ name = \"key\" }, { name = \"one\" }, {})\ntotal = length(row.name)", "row = model.upsert({ name = \"key\" }, {}, { id = 2 })\ntotal = length(row.name)", ] { let app = format!("write() (total: Int) {{ {body} }}"); assert!( checked(&app, "cmd write = app.write").is_err(), "accepted {body}" ); } }