Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,246 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conditional_writes_compare_and_modify_in_one_statement() {
|
||||
let directory = Directory::new();
|
||||
let project = Project::load(&fixture().with_file_name("database")).unwrap();
|
||||
let program = project.check().unwrap();
|
||||
let binary = build::build(
|
||||
&program,
|
||||
&project.sources,
|
||||
"main",
|
||||
&directory.0.join("conditional"),
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::create_dir(directory.0.join("config")).unwrap();
|
||||
std::fs::write(
|
||||
directory.0.join("config/setting.json"),
|
||||
r#"{"database":{"default":{"type":"sqlite","path":"conditional.db"}}}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let run = |name: &str, input: serde_json::Value| {
|
||||
let output = execute(&binary, &format!("demo.account.{name}"), &input.to_string());
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"{name}: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
serde_json::from_slice::<serde_json::Value>(&output.stdout).unwrap()["data"].clone()
|
||||
};
|
||||
let first = run("create", serde_json::json!({"name":"original"}));
|
||||
run("create", serde_json::json!({"name":"other"}));
|
||||
let input =
|
||||
serde_json::json!({"id":first["id"],"expected":"original","note":null,"next":"updated"});
|
||||
assert_eq!(run("compare_name", input.clone()), 1);
|
||||
assert_eq!(run("compare_name", input), 0);
|
||||
let updated = run("get", serde_json::json!({"id":first["id"]}));
|
||||
assert_eq!(updated["name"], "updated");
|
||||
assert_eq!(updated["note"], "changed");
|
||||
let invalid = serde_json::json!({"id":first["id"],"expected":"updated","note":"changed","next":"x".repeat(65)});
|
||||
assert!(
|
||||
!execute(&binary, "demo.account.compare_name", &invalid.to_string())
|
||||
.status
|
||||
.success()
|
||||
);
|
||||
assert_eq!(run("get", serde_json::json!({"id":first["id"]})), updated);
|
||||
assert_eq!(
|
||||
run("remove_matching", serde_json::json!({"rank":7,"note":null})),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
run("remove_matching", serde_json::json!({"rank":7,"note":null})),
|
||||
0
|
||||
);
|
||||
assert_eq!(run("get", serde_json::json!({"id":first["id"]})), updated);
|
||||
assert_eq!(
|
||||
run(
|
||||
"remove_matching",
|
||||
serde_json::json!({"rank":7,"note":"changed"})
|
||||
),
|
||||
1
|
||||
);
|
||||
assert_eq!(run("count", serde_json::json!({})), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn static_query_predicates_match_literal_text_and_inclusive_ranges() {
|
||||
let directory = Directory::new();
|
||||
let project = Project::load(&fixture().with_file_name("database")).unwrap();
|
||||
let program = project.check().unwrap();
|
||||
let binary = build::build(
|
||||
&program,
|
||||
&project.sources,
|
||||
"main",
|
||||
&directory.0.join("queries"),
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::create_dir(directory.0.join("config")).unwrap();
|
||||
std::fs::write(
|
||||
directory.0.join("config/setting.json"),
|
||||
r#"{"database":{"default":{"type":"sqlite","path":"query.db"}}}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let run = |name: &str, input: serde_json::Value| {
|
||||
let output = execute(&binary, &format!("demo.account.{name}"), &input.to_string());
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"{name}: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
serde_json::from_slice::<serde_json::Value>(&output.stdout).unwrap()["data"].clone()
|
||||
};
|
||||
let names = [
|
||||
"ab",
|
||||
"Ab",
|
||||
"a\0b",
|
||||
"ab\0",
|
||||
"前雪尾",
|
||||
"雪_%' OR 1=1 --",
|
||||
"excluded",
|
||||
];
|
||||
let created: Vec<_> = names
|
||||
.into_iter()
|
||||
.map(|name| run("create", serde_json::json!({"name":name})))
|
||||
.collect();
|
||||
let recent = run("recent", serde_json::json!({}));
|
||||
assert_eq!(
|
||||
recent["items"],
|
||||
serde_json::json!(created.iter().rev().collect::<Vec<_>>())
|
||||
);
|
||||
assert_eq!(recent["has_more"], false);
|
||||
assert!(recent["next"].is_null());
|
||||
let mut ordered: Vec<_> = created
|
||||
.iter()
|
||||
.filter(|row| row["name"] != "excluded")
|
||||
.cloned()
|
||||
.collect();
|
||||
ordered.sort_by(|left, right| {
|
||||
left["created_at"]
|
||||
.as_str()
|
||||
.cmp(&right["created_at"].as_str())
|
||||
.then_with(|| right["name"].as_str().cmp(&left["name"].as_str()))
|
||||
.then_with(|| right["id"].as_i64().cmp(&left["id"].as_i64()))
|
||||
});
|
||||
for size in [1, 2, 4, 20] {
|
||||
let mut after = serde_json::Value::Null;
|
||||
let mut seen = Vec::new();
|
||||
loop {
|
||||
let page = run("scan", serde_json::json!({"after":after,"size":size}));
|
||||
let items = page["items"].as_array().unwrap();
|
||||
assert!(items.len() <= size);
|
||||
seen.extend(items.iter().cloned());
|
||||
assert!(seen.len() <= ordered.len(), "cursor must advance");
|
||||
if page["has_more"] == false {
|
||||
assert!(page["next"].is_null());
|
||||
break;
|
||||
}
|
||||
assert_eq!(page["next"], *items.last().unwrap());
|
||||
after = page["next"].clone();
|
||||
}
|
||||
assert_eq!(seen, ordered);
|
||||
}
|
||||
for size in [0, -1, 101] {
|
||||
assert!(
|
||||
!execute(
|
||||
&binary,
|
||||
"demo.account.scan",
|
||||
&serde_json::json!({"after":null,"size":size}).to_string()
|
||||
)
|
||||
.status
|
||||
.success()
|
||||
);
|
||||
}
|
||||
for needle in [
|
||||
"",
|
||||
"a",
|
||||
"A",
|
||||
"ab",
|
||||
"\0",
|
||||
"a\0",
|
||||
"b\0",
|
||||
"雪",
|
||||
"%",
|
||||
"_",
|
||||
"' OR 1=1 --",
|
||||
"missing",
|
||||
] {
|
||||
let actual = run("probe", serde_json::json!({"needle":needle}));
|
||||
assert_eq!(
|
||||
actual,
|
||||
serde_json::json!({
|
||||
"contained":names.iter().filter(|name|name.contains(needle)).count(),
|
||||
"prefixed":names.iter().filter(|name|name.starts_with(needle)).count(),
|
||||
"suffixed":names.iter().filter(|name|name.ends_with(needle)).count(),
|
||||
"notes":0
|
||||
}),
|
||||
"needle {needle:?}"
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
run("select", serde_json::json!({"first":"ab","second":"Ab"})),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
run("select", serde_json::json!({"first":"ab","second":"ab"})),
|
||||
1
|
||||
);
|
||||
for (lower, upper) in [("Ab", "ab"), ("ab", "ab"), ("ab", "Ab"), ("", "雪")] {
|
||||
let expected = names
|
||||
.iter()
|
||||
.filter(|name| **name >= lower && **name <= upper && **name != "excluded")
|
||||
.count();
|
||||
assert_eq!(
|
||||
run("range", serde_json::json!({"lower":lower,"upper":upper})),
|
||||
expected
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
run(
|
||||
"bulk",
|
||||
serde_json::json!({"first":"bulk one","second":"bulk two"})
|
||||
),
|
||||
2
|
||||
);
|
||||
let bulk = run("recent", serde_json::json!({}));
|
||||
assert_eq!(bulk["items"][0]["rank"], 9);
|
||||
assert_eq!(bulk["items"][1]["rank"], 7);
|
||||
let mut unique = std::collections::HashSet::new();
|
||||
for row in bulk["items"].as_array().unwrap() {
|
||||
let uid = row["uid"].as_str().unwrap();
|
||||
assert_eq!(&uid[14..15], "7");
|
||||
assert!(unique.insert(uid));
|
||||
}
|
||||
let before = run("count", serde_json::json!({}));
|
||||
for (command, input) in [
|
||||
(
|
||||
"bulk",
|
||||
serde_json::json!({"first":"must rollback","second":"ab"}),
|
||||
),
|
||||
(
|
||||
"failed_bulk",
|
||||
serde_json::json!({"first":"rollback one","second":"rollback two","value":i64::MAX}),
|
||||
),
|
||||
] {
|
||||
let output = execute(
|
||||
&binary,
|
||||
&format!("demo.account.{command}"),
|
||||
&input.to_string(),
|
||||
);
|
||||
assert!(!output.status.success(), "{command}");
|
||||
assert_eq!(run("count", serde_json::json!({})), before);
|
||||
}
|
||||
let created = run(
|
||||
"save",
|
||||
serde_json::json!({"name":"upsert","initial":"first","replacement":"unused"}),
|
||||
);
|
||||
assert_eq!(created["note"], "first");
|
||||
let updated = run(
|
||||
"save",
|
||||
serde_json::json!({"name":"upsert","initial":"ignored","replacement":"changed"}),
|
||||
);
|
||||
assert_eq!(updated["id"], created["id"]);
|
||||
assert_eq!(updated["created_at"], created["created_at"]);
|
||||
assert_eq!(updated["uid"], created["uid"]);
|
||||
assert_eq!(updated["note"], "changed");
|
||||
assert_eq!(run("retain", serde_json::json!({"name":"upsert"})), updated);
|
||||
}
|
||||
Reference in new issue
Block a user