M12b: category contract v2 on the server (schema 2, fourteen defaults, finer import mapping)
- migrations/0002_categories_v2.sql, byte-identical to contracts/schema/migrations/0002_categories_v2.sql (SPEC §14.1.1), with an identity test; SCHEMA_VERSION = 2 (E-1 reports it, the importer's check follows). - Seed test on a fresh database (the fourteen rows of AC-7.2, server_version 11 to 14) and an upgrade test of a v1 database in use (0001 applied through the migrator, then users, a custom, a renamed and an archived default, an account, a recurring template, expenses): every earlier row unchanged, the four rows above the old sequence, foreign_key_check empty, schema_version 2, a pull from the old cursor returns exactly the four rows. - DefaultCategoryKey with the fourteen keys (wire enum and contracts/openapi.yaml); icons 33 and colours 14 (§9.7) in validation. - The two category examples M12a held back (E-26 response-default, sync/pull-page-categories-v2) and its contracts-check patch for them and the enum. - Importer: splitwise_categories.csv per the §10.8 v0.8 table (D-053), DEFAULT_KEYS of fourteen, synthetic fixtures for the finer mapping (Insurance/Försäkringar to insurance among them), a schema-1 refusal test. - Test harnesses seed users at server_version 15/16 (after the fourteen seeds); pull counts 10 -> 14. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
@@ -89,8 +89,8 @@ async fn the_first_page_has_everything_in_version_order_with_the_epoch_and_serve
|
||||
.iter()
|
||||
.map(|a| page[*a].as_array().unwrap().len())
|
||||
.collect();
|
||||
// 2 users, 10 default categories, 2 accounts, no templates, 1 expense, 1 settlement, 2 audit entries.
|
||||
assert_eq!(counts, [2, 10, 2, 0, 1, 1, 2]);
|
||||
// 2 users, 14 default categories, 2 accounts, no templates, 1 expense, 1 settlement, 2 audit entries.
|
||||
assert_eq!(counts, [2, 14, 2, 0, 1, 1, 2]);
|
||||
for a in ARRAYS {
|
||||
let v: Vec<i64> = page[a]
|
||||
.as_array()
|
||||
@@ -141,7 +141,7 @@ async fn paging_walks_every_row_once_parents_with_children_count_as_one() {
|
||||
for _ in 0..9 {
|
||||
push_one(&app, &admin_token(), exp(expense(&new_id(), T1))).await;
|
||||
}
|
||||
// 2 users + 10 categories + 2 accounts + 9 expenses + 9 audit entries = 32 rows.
|
||||
// 2 users + 14 categories + 2 accounts + 9 expenses + 9 audit entries = 36 rows.
|
||||
let mut since = 0;
|
||||
let mut seen = Vec::new();
|
||||
let mut pages = 0;
|
||||
@@ -160,8 +160,8 @@ async fn paging_walks_every_row_once_parents_with_children_count_as_one() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert_eq!(pages, 7);
|
||||
assert_eq!(seen.len(), 32);
|
||||
assert_eq!(pages, 8);
|
||||
assert_eq!(seen.len(), 36);
|
||||
let mut dedup = seen.clone();
|
||||
dedup.dedup();
|
||||
assert_eq!(dedup, seen);
|
||||
@@ -170,9 +170,9 @@ async fn paging_walks_every_row_once_parents_with_children_count_as_one() {
|
||||
assert_eq!(reply.json["next_since"], since);
|
||||
assert_eq!(reply.json["has_more"], false);
|
||||
// has_more is false when the page ends exactly on the last row.
|
||||
let reply = pull(&app, &admin_token(), 0, Some(32)).await;
|
||||
let reply = pull(&app, &admin_token(), 0, Some(36)).await;
|
||||
assert_eq!(reply.json["has_more"], false);
|
||||
let reply = pull(&app, &admin_token(), 0, Some(31)).await;
|
||||
let reply = pull(&app, &admin_token(), 0, Some(35)).await;
|
||||
assert_eq!(reply.json["has_more"], true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user