feat: release Dever 0.1.5 with direct workers and long transactions

This commit is contained in:
Codex committed 2026-10-11 11:17:33 +00:00
1 parent 89629c2197
commit a900d7e8db
153 files changed
+3676 -3708

No files matched your search

+84 -3
View File
@@ -6,6 +6,9 @@ use dever_runtime::http::{Header, Request};
use std::fs;
use std::process::Command;
#[path = "support/process.rs"]
#[allow(dead_code)]
mod process;
#[path = "support/temp.rs"]
mod temp;
@@ -17,6 +20,81 @@ fn source(files: &[(&str, &str)]) -> SourceMap {
sources
}
#[cfg(feature = "sqlite")]
#[test]
fn command_releases_short_transactions_before_waiting_and_preserves_committed_stages() {
let sources = source(&[
(
"content/item/model.dever",
"global type Item { name: Text unique }",
),
(
"content/item/app.dever",
"transaction store(name: Text) (value: Text) { saved = model.create({ name = name })\nvalue = saved.name }\ncount() (total: Int) { total = model.count() }\nperform() (total: Int) { saved = store(\"first\")\ntask = run(count())\ntotal = wait(task) }\nfail_later() (value: Text) { committed = store(\"second\")\nvalue = store(committed) }",
),
(
"content/item/api.dever",
"long cmd perform = app.perform\nlong cmd fail_later = app.fail_later\ncmd fail_atomic = app.fail_later\ncmd count = app.count",
),
]);
let program = dever_core::check(&sources).unwrap_or_else(|errors| panic!("{errors:?}"));
let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let native = dever_core::native::compile_project(
&program,
&sources,
&rustc,
RuntimeProfile {
sqlite: true,
postgres: false,
},
)
.unwrap();
let root = native.executable().parent().unwrap();
fs::create_dir_all(root.join("config")).unwrap();
fs::write(
root.join("config/setting.json"),
r#"{"database":{"default":{"type":"sqlite","path":"data/db/app.db","max_connections":1}}}"#,
)
.unwrap();
let invoke = |operation: &str| {
let mut child = Command::new(native.executable())
.current_dir(root)
.args([operation, "{}"])
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap();
process::wait(&mut child, std::time::Duration::from_secs(10)).unwrap();
child.wait_with_output().unwrap()
};
let first = invoke("content.item.perform");
assert!(
first.status.success(),
"{}",
String::from_utf8_lossy(&first.stderr)
);
let first: serde_json::Value = serde_json::from_slice(&first.stdout).unwrap();
assert_eq!(first["data"], 1);
let atomic = invoke("content.item.fail_atomic");
assert!(!atomic.status.success());
assert!(String::from_utf8_lossy(&atomic.stderr).contains("UNIQUE"));
let retained = invoke("content.item.count");
assert!(retained.status.success());
let retained: serde_json::Value = serde_json::from_slice(&retained.stdout).unwrap();
assert_eq!(retained["data"], 1);
let failed = invoke("content.item.fail_later");
assert!(!failed.status.success());
assert!(String::from_utf8_lossy(&failed.stderr).contains("UNIQUE"));
let count = invoke("content.item.count");
assert!(
count.status.success(),
"{}",
String::from_utf8_lossy(&count.stderr)
);
let count: serde_json::Value = serde_json::from_slice(&count.stdout).unwrap();
assert_eq!(count["data"], 2);
}
#[test]
fn project_entry_collects_api_and_command_without_main() {
let sources = source(&[
@@ -175,13 +253,13 @@ fn generated_write_entry_rejects_detached_concurrency() {
.map(|error| error.render(&sources))
.collect::<String>();
assert!(
rendered.contains("transaction cannot start concurrent work"),
rendered.contains("automatic entry transactions cannot contain"),
"{rendered}"
);
}
#[test]
fn generated_write_entry_allows_structured_blocking_work() {
fn generated_long_entry_keeps_password_work_outside_its_write_transaction() {
let sources = source(&[
(
"user/account/model.dever",
@@ -201,7 +279,10 @@ transaction persist(hash: Text) (id: model.id) {
id = stored.id
}"#,
),
("user/account/api.dever", "post register = app.register"),
(
"user/account/api.dever",
"long post register = app.register",
),
]);
let program = dever_core::check(&sources).unwrap_or_else(|errors| {
panic!(