feat: publish Dever core with project scaffolding and versioned AI skills
This commit is contained in:
1 parent
70fa73cdc2
commit
ac458ffa7f
960 files changed
+221319
-1163
No files matched your search
@@ -0,0 +1,175 @@
|
||||
#[path = "support/orm_fixture.rs"]
|
||||
mod orm_fixture;
|
||||
mod support;
|
||||
|
||||
use std::fs;
|
||||
|
||||
use dever_runtime::config::RuntimeProfile;
|
||||
use dever_runtime::sqlite::Database;
|
||||
use orm_fixture::DatabaseState;
|
||||
|
||||
#[test]
|
||||
fn shared_orm_fixture_remains_valid_without_opening_a_database() {
|
||||
let sources = orm_fixture::sources();
|
||||
let program = dever_core::check(&sources).unwrap_or_else(|errors| {
|
||||
panic!(
|
||||
"{}",
|
||||
errors
|
||||
.iter()
|
||||
.map(|error| error.render(&sources))
|
||||
.collect::<String>()
|
||||
)
|
||||
});
|
||||
assert!(
|
||||
program
|
||||
.model_snapshot()
|
||||
.contains("model app.user.model name=User")
|
||||
);
|
||||
}
|
||||
|
||||
async fn database_state(database: &Database) -> DatabaseState {
|
||||
let columns = database
|
||||
.query(
|
||||
"SELECT name FROM pragma_table_info('user') ORDER BY cid",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let managed_index_count = database
|
||||
.query(
|
||||
"SELECT COUNT(*) FROM sqlite_schema WHERE type = 'index' AND tbl_name = 'user' AND name LIKE '_dever_idx_%'",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let history = database
|
||||
.query(
|
||||
"SELECT kind, revision FROM _dever_history WHERE model = 'app.user.model' AND kind IN ('schema', 'seed') ORDER BY kind",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let users = database
|
||||
.query(
|
||||
"SELECT email, display_name, status, age, alias FROM user ORDER BY email",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
orm_fixture::database_state(columns, managed_index_count, history, users)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sqlite_executes_the_shared_orm_fixture() {
|
||||
let profile = RuntimeProfile {
|
||||
sqlite: true,
|
||||
postgres: false,
|
||||
};
|
||||
let main = orm_fixture::compile("app.user.main", profile);
|
||||
let rollback = orm_fixture::compile("app.user.rollback", profile);
|
||||
assert_eq!(main.revisions, rollback.revisions);
|
||||
|
||||
let root = main.native.executable().parent().unwrap();
|
||||
let setting = r#"{
|
||||
"database": {
|
||||
"default": {
|
||||
"type": "sqlite",
|
||||
"path": "data/db/app.db",
|
||||
"max_connections": 1,
|
||||
"max_page_size": 10
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
orm_fixture::configure(main.native.executable(), setting);
|
||||
orm_fixture::assert_main_output(orm_fixture::run(main.native.executable()));
|
||||
|
||||
let database = Database::open(root.join("data/db/app.db"), 1, 10).unwrap();
|
||||
let committed = database_state(&database).await;
|
||||
orm_fixture::assert_committed_state(&committed, &main.revisions);
|
||||
drop(database);
|
||||
|
||||
let rollback_executable = root.join("rollback");
|
||||
fs::copy(rollback.native.executable(), &rollback_executable).unwrap();
|
||||
let output = orm_fixture::run(&rollback_executable);
|
||||
assert!(!output.status.success());
|
||||
let stderr = String::from_utf8(output.stderr).unwrap();
|
||||
assert!(stderr.contains("UNIQUE constraint failed"), "{stderr}");
|
||||
|
||||
let database = Database::open(root.join("data/db/app.db"), 1, 10).unwrap();
|
||||
assert_eq!(database_state(&database).await, committed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn database_failures_are_captured_after_transaction_rollback_and_task_wait() {
|
||||
let mut sources = dever_core::source::SourceMap::default();
|
||||
sources.add(
|
||||
"app/item/model.dever",
|
||||
r#"type Item { name: Text unique }
|
||||
"#,
|
||||
);
|
||||
sources.add(
|
||||
"app/item/app.dever",
|
||||
r#"type ReadResult {
|
||||
Found(value: app.item.model.Item)
|
||||
error Failed(error: dever.database.Error)
|
||||
}
|
||||
transaction missing() (value: app.item.model.Item) {
|
||||
saved = model.create({ name = "temporary" })
|
||||
removed = model.delete(saved.id)
|
||||
value = model.get(saved.id)
|
||||
}
|
||||
transaction create_duplicate() (value: app.item.model.Item) {
|
||||
saved = model.create({ name = "duplicate" })
|
||||
value = model.create({ name = "duplicate" })
|
||||
}
|
||||
task_missing() (value: app.item.model.Item) {
|
||||
task = run(missing())
|
||||
value = wait(task)
|
||||
}
|
||||
main() (missing: ReadResult, duplicate: ReadResult, count: Int) {
|
||||
missing = result(task_missing())
|
||||
duplicate = result(create_duplicate())
|
||||
count = model.count()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
let program = support::checked(&sources);
|
||||
let snapshot = program.api_snapshot();
|
||||
assert!(
|
||||
snapshot.contains("dever.database.Error.NotFound"),
|
||||
"{snapshot}"
|
||||
);
|
||||
let native = dever_core::native::compile_application(
|
||||
&program,
|
||||
&sources,
|
||||
"app.item.main",
|
||||
&std::ffi::OsString::from("rustc"),
|
||||
RuntimeProfile {
|
||||
sqlite: true,
|
||||
postgres: false,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
orm_fixture::configure(
|
||||
native.executable(),
|
||||
r#"{
|
||||
"database": { "default": { "type": "sqlite", "path": "data/db/errors.db", "max_connections": 1 } }
|
||||
}"#,
|
||||
);
|
||||
let result = orm_fixture::run(native.executable());
|
||||
assert!(
|
||||
result.status.success(),
|
||||
"{}",
|
||||
String::from_utf8_lossy(&result.stderr)
|
||||
);
|
||||
let output = String::from_utf8(result.stdout).unwrap();
|
||||
assert!(
|
||||
output.contains("app.item.ReadResult.Failed(dever.database.Error.NotFound("),
|
||||
"{output}"
|
||||
);
|
||||
assert!(
|
||||
output.contains("app.item.ReadResult.Failed(dever.database.Error.Constraint("),
|
||||
"{output}"
|
||||
);
|
||||
assert!(output.ends_with("count = 0\n"), "{output}");
|
||||
}
|
||||
Reference in new issue
Block a user