use spg_engine::{Engine, QueryResult};
fn text(e: &mut Engine, sql: &str) -> String {
match e.execute(sql).unwrap_or_else(|x| panic!("{sql}: {x:?}")) {
QueryResult::Rows { rows, .. } => match &rows[0].values[0] {
spg_storage::Value::Null => "NULL".to_string(),
v => spg_engine::eval::value_to_text(v),
},
other => panic!("{sql}: {other:?}"),
}
}
fn err(e: &mut Engine, sql: &str) -> String {
match e.execute(sql) {
Err(x) => format!("{x}"),
Ok(ok) => panic!("{sql}: expected an error, got {ok:?}"),
}
}
#[test]
fn empty_path_is_a_no_op() {
let mut e = Engine::new();
assert_eq!(
text(&mut e, "SELECT jsonb_set('{\"a\":1}','{}','9')"),
"{\"a\": 1}"
);
assert_eq!(text(&mut e, "SELECT jsonb_set('[1,2]','{}','9')"), "[1, 2]");
assert_eq!(
text(&mut e, "SELECT jsonb_set('{\"a\":1}','{}','9',true)"),
"{\"a\": 1}"
);
assert_eq!(
text(&mut e, "SELECT jsonb_insert('{\"a\":1}','{}','9')"),
"{\"a\": 1}"
);
assert_eq!(
text(&mut e, "SELECT jsonb_insert('[1,2]','{}','9')"),
"[1, 2]"
);
assert_eq!(text(&mut e, "SELECT '[1,2]'::jsonb #- '{}'"), "[1, 2]");
assert_eq!(
text(&mut e, "SELECT jsonb_set('{\"a\":1}','{a}','9')"),
"{\"a\": 9}"
);
}
#[test]
fn scalar_documents_reject_path_modification() {
let mut e = Engine::new();
for (sql, want) in [
("SELECT '\"str\"'::jsonb - 'a'", "cannot delete from scalar"),
("SELECT '1'::jsonb - 'a'", "cannot delete from scalar"),
("SELECT 'true'::jsonb - 'a'", "cannot delete from scalar"),
("SELECT 'null'::jsonb - 'a'", "cannot delete from scalar"),
("SELECT '\"str\"'::jsonb - 0", "cannot delete from scalar"),
(
"SELECT '\"str\"'::jsonb #- '{a}'",
"cannot delete path in scalar",
),
(
"SELECT jsonb_set('\"str\"','{a}','9')",
"cannot set path in scalar",
),
(
"SELECT jsonb_insert('\"str\"','{a}','9')",
"cannot set path in scalar",
),
] {
let got = err(&mut e, sql);
assert!(got.contains(want), "{sql}\n want {want:?}\n got {got:?}");
}
}
#[test]
fn integer_index_is_meaningless_on_an_object() {
let mut e = Engine::new();
let got = err(&mut e, "SELECT '{\"a\":1}'::jsonb - 0");
assert!(
got.contains("cannot delete from object using integer index"),
"{got}"
);
assert_eq!(
text(&mut e, "SELECT '{\"a\":1,\"b\":2}'::jsonb - 'a'"),
"{\"b\": 2}"
);
assert_eq!(text(&mut e, "SELECT '[1,2,3]'::jsonb - 1"), "[1, 3]");
assert_eq!(
text(&mut e, "SELECT '{\"a\":1}'::jsonb - 'zz'"),
"{\"a\": 1}"
);
assert_eq!(text(&mut e, "SELECT '[1,2]'::jsonb - 'a'"), "[1, 2]");
}
#[test]
fn the_rest_of_the_modification_family_is_unchanged() {
let mut e = Engine::new();
for (sql, want) in [
(
"SELECT jsonb_set('{\"a\":{\"b\":1}}','{a,b}','9')",
"{\"a\": {\"b\": 9}}",
),
(
"SELECT jsonb_set('{\"a\":{\"b\":1}}','{a,c}','9',true)",
"{\"a\": {\"b\": 1, \"c\": 9}}",
),
(
"SELECT jsonb_set('{\"a\":{\"b\":1}}','{a,c}','9',false)",
"{\"a\": {\"b\": 1}}",
),
(
"SELECT jsonb_insert('{\"a\":[1,2]}','{a,1}','9')",
"{\"a\": [1, 9, 2]}",
),
(
"SELECT jsonb_insert('{\"a\":[1,2]}','{a,1}','9',true)",
"{\"a\": [1, 2, 9]}",
),
(
"SELECT '{\"a\":{\"b\":1}}'::jsonb #- '{a,b}'",
"{\"a\": {}}",
),
(
"SELECT jsonb_strip_nulls('{\"a\":null,\"b\":1}')",
"{\"b\": 1}",
),
(
"SELECT '{\"a\":1}'::jsonb || '{\"b\":2}'::jsonb",
"{\"a\": 1, \"b\": 2}",
),
] {
assert_eq!(text(&mut e, sql), want, "{sql}");
}
}