Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+161
View File
@@ -0,0 +1,161 @@
use super::package::packages;
use dever::{compiler::model::Program, syntax::diagnostic::Diagnostic};
mod defaults;
mod native;
mod privacy;
mod query;
mod relation;
mod scalar;
mod schema;
pub(super) const ERROR: &str = "public type Error { error Pool(message: Text)\nerror PoolExhausted(message: Text)\nerror Connection(message: Text)\nerror Timeout(message: Text)\nerror Cancelled(message: Text)\nerror Database(message: Text)\nerror Constraint(message: Text)\nerror NotFound(message: Text)\nerror InvalidData(message: Text)\nerror Migration(message: Text) }";
fn checked(app: &str, api: &str) -> Result<Program, Diagnostic> {
packages(&[
("dever.database", ERROR),
(
"demo.account.model",
"type Account { name: Text(1, 64) unique\nnote: Text? }",
),
("demo.account.app", app),
("demo.account.api", api),
])
}
#[test]
fn model_ids_queries_and_failures_keep_static_identity() {
let program = checked(
"get(id: model.id) (account: model.Account) { account = model.get(id) }",
"cmd get = app.get",
)
.unwrap();
let function = &program.functions[0].signature;
assert!(function.effects.database);
assert!(!function.effects.database_write);
assert_eq!(function.failures.len(), 10);
assert_eq!(program.models.len(), 1);
assert!(program.models[0].columns[2].unique);
assert_eq!(program.models[0].columns[2].limits, Some((1, 64)));
assert_eq!(
checked(
"get(id: Int) (account: model.Account) { account = model.get(id) }",
"cmd get = app.get"
)
.unwrap_err()
.code,
"C005"
);
let app = "read(value: model.Account) (id: model.id) { value.id = value.id\nid = value.id }";
assert_eq!(
checked(app, "cmd read = app.read").unwrap_err().code,
"C014"
);
assert_eq!(checked("create(name: Text) (account: model.Account) { account = model.create({ name = name }) }", "public get create = app.create").unwrap_err().code, "C014");
}
#[test]
fn transactions_reject_unrelated_work_and_role_bypasses() {
let crypto = "public type HashResult { Ready(value: Text)\nerror Failed(message: Text) }\npublic passwordHash(secret: Secret) (hash: Text) { hash = hashValue(dever.system.cryptoPasswordHash(secret)) }\nhashValue(result: HashResult.Ready(value)) (hash: Text) { hash = value }\nhashValue(result: HashResult.Failed(message)) (hash: Text) { fail(result) }";
let blocked = packages(&[
("dever.database", ERROR),
("dever.crypto", crypto),
("demo.account.model", "type Account { name: Text }"),
(
"demo.account.app",
"transaction create(password: Secret) (account: model.Account) { hash = blocking(dever.crypto.passwordHash(password))\naccount = model.create({ name = hash }) }",
),
("demo.account.api", "cmd create = app.create"),
]);
assert_eq!(blocked.unwrap_err().code, "C014");
let staged = packages(&[
("dever.database", ERROR),
("dever.crypto", crypto),
("demo.account.model", "type Account { name: Text }"),
("demo.account.app", "transaction persist(name: Text) (account: model.Account) { account = model.create({ name = name }) }\ncreate(password: Secret) (account: model.Account) { hash = blocking(dever.crypto.passwordHash(password))\naccount = persist(hash) }"),
]).unwrap();
let staged = &staged
.functions
.iter()
.find(|function| function.signature.name == "create")
.unwrap()
.signature
.effects;
assert!(staged.password);
assert!(!staged.unscoped_write);
let app = "transaction create(name: Text) (account: model.Account) { account = model.create({ name = name }) }";
assert!(checked(app, "long cmd create = app.create").is_ok());
assert!(checked(app, "public long post create = app.create").is_ok());
assert_eq!(checked("create(name: Text) (account: model.Account) { account = model.create({ name = name }) }", "long cmd create = app.create").unwrap_err().code, "C014");
assert_eq!(checked("create(name: Text) (account: model.Account) { account = model.create({ name = name }) }", "public long post create = app.create").unwrap_err().code, "C014");
assert!(
checked(
"read(value: model.Page) (page: model.Page) { value.page = 2\npage = value }",
"cmd read = app.read"
)
.is_ok()
);
assert_eq!(
checked(
"transaction empty(value: Int) (answer: Int) { answer = value }",
"cmd empty = app.empty"
)
.unwrap_err()
.code,
"C014"
);
assert_eq!(checked("read() (total: Int) { total = model.count() }\ntransaction spawn() (total: Int) { work = run(read())\ntotal = wait(work) }", "cmd spawn = app.spawn").unwrap_err().code, "C014");
assert_eq!(
packages(&[
("dever.database", ERROR),
("demo.account.model", "type Account { name: Text }"),
(
"demo.account.domain",
"read() (total: Int) { total = model.count() }"
)
])
.unwrap_err()
.code,
"C006"
);
assert_eq!(
packages(&[("main", "type Value { name: Text(64) }")])
.unwrap_err()
.code,
"C014"
);
assert_eq!(
packages(&[("main", "type Value { name: Text unique }")])
.unwrap_err()
.code,
"C014"
);
}
#[test]
fn model_query_blocks_reject_dynamic_fields_and_invalid_options() {
for query in [
"{ where = missing == name }",
"{ where = name }",
"{ order = [missing.asc] }",
"{ size = 1, size = 2 }",
"{ size = name }",
] {
let app = format!("search(name: Text) (page: model.Page) {{ page = model.list({query}) }}");
assert!(checked(&app, "cmd search = app.search").is_err(), "{query}");
}
assert_eq!(
packages(&[(
"demo.account.model",
"database one\ndatabase two\ntype Account { name: Text }"
)])
.unwrap_err()
.code,
"C002"
);
assert_eq!(
packages(&[("demo.account.model", "type Account { name: Text(65, 64) }")])
.unwrap_err()
.code,
"C014"
);
}