1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! M11 #94 — design.md § Portability example, exit-gate integration.
//!
//! Mirrors the verbatim snippet under § Portability ("Copyable at
//! rest"), specifically the `Db::collection::<T>(name)` accessor.
//! design.md reads:
//!
//! ```text
//! db.attach("archive.obj", "archive")?;
//! let archived: Vec<Order> = db
//! .collection::<Order>("archive.orders")
//! .all()?
//! .collect();
//! ```
//!
//! As with `design_md_queries::all_orders_iterates_every_doc`, the
//! M11 surface ships `Collection::all` as an owned `Vec<(Id, T)>`
//! shape (a streaming-iterator follow-up is documented elsewhere);
//! the test adapts the `.collect()` step to thread off the `Id` part
//! exactly as a user would. The collection name and `Db::collection`
//! call match design.md verbatim.
#![forbid(unsafe_code)]
use obj::{Db, Document};
use serde::{Deserialize, Serialize};
use tempfile::TempDir;
/// Design.md's `Order` type — fields trimmed to what the portability
/// example references.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct Order {
customer_id: u64,
total_cents: u64,
}
impl Document for Order {
const COLLECTION: &'static str = "orders";
const VERSION: u32 = 1;
}
/// Exit-gate: the design.md § Portability snippet compiles AND
/// returns the archived documents.
#[test]
fn design_md_attach_collection_reads_archived_orders() {
let dir = TempDir::new().expect("tmp");
let main_path = dir.path().join("main.obj");
let archive_path = dir.path().join("archive.obj");
// Populate the archive database (the file the design.md
// snippet's `.attach` references).
{
let archive_db = Db::open(&archive_path).expect("open archive");
archive_db
.insert(Order {
customer_id: 1,
total_cents: 100,
})
.expect("seed archive 1");
archive_db
.insert(Order {
customer_id: 2,
total_cents: 200,
})
.expect("seed archive 2");
}
// Open the main db and attach the archive — matches the
// design.md snippet line for line.
let mut db = Db::open(&main_path).expect("open main");
db.attach(&archive_path, "archive").expect("attach");
// The design.md snippet:
//
// let archived: Vec<Order> = db
// .collection::<Order>("archive.orders")
// .all()?
// .collect();
//
// M11 #94 ships `Collection::all` as `Result<Vec<(Id, T)>>`;
// the `.collect()` step strips the `Id` pair off, matching what
// a user would write today. The `Db::collection::<T>(name)`
// call shape is verbatim.
let archived: Vec<Order> = db
.collection::<Order>("archive.orders")
.all()
.expect("all on archive.orders")
.into_iter()
.map(|(_id, doc)| doc)
.collect();
assert_eq!(archived.len(), 2);
let totals: Vec<u64> = archived.iter().map(|o| o.total_cents).collect();
assert!(totals.contains(&100));
assert!(totals.contains(&200));
}