headless_lms_server/programs/seed/builder/
id.rs

1use headless_lms_models::PKeyPolicy;
2use uuid::Uuid;
3
4/// Strategy for generating primary keys or deterministic UUIDs.
5///
6/// Use V5 with a stable namespace to keep seeds idempotent.
7#[derive(Clone, Copy, Debug)]
8pub enum IdStrategy<'a> {
9    /// Let database generate random IDs (use sparingly in seeds)
10    Generate,
11    /// Use a specific UUID
12    Fixed(Uuid),
13    /// Generate deterministic UUIDv5 from namespace + name
14    V5 { ns: &'a Uuid, name: &'a [u8] },
15}
16
17impl<'a> IdStrategy<'a> {
18    /// Converts to a concrete UUID value.
19    pub fn to_uuid(self) -> Uuid {
20        match self {
21            IdStrategy::Generate => Uuid::new_v4(),
22            IdStrategy::Fixed(u) => u,
23            IdStrategy::V5 { ns, name } => Uuid::new_v5(ns, name),
24        }
25    }
26
27    /// Converts to a PKeyPolicy for database insert helpers.
28    pub fn to_pkey(self) -> PKeyPolicy<Uuid> {
29        match self {
30            IdStrategy::Generate => PKeyPolicy::Generate,
31            IdStrategy::Fixed(u) => PKeyPolicy::Fixed(u),
32            IdStrategy::V5 { ns, name } => PKeyPolicy::Fixed(Uuid::new_v5(ns, name)),
33        }
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn v5_is_deterministic() {
43        let ns = Uuid::nil();
44        let a1 = IdStrategy::V5 {
45            ns: &ns,
46            name: b"hello",
47        }
48        .to_uuid();
49        let a2 = IdStrategy::V5 {
50            ns: &ns,
51            name: b"hello",
52        }
53        .to_uuid();
54        assert_eq!(a1, a2);
55    }
56
57    #[test]
58    fn fixed_roundtrips() {
59        let u = Uuid::new_v4();
60        if let PKeyPolicy::Fixed(got) = IdStrategy::Fixed(u).to_pkey() {
61            assert_eq!(got, u);
62        } else {
63            panic!("expected fixed");
64        }
65    }
66
67    #[test]
68    fn v5_deterministic() {
69        let ns = Uuid::new_v4();
70        let a = IdStrategy::V5 {
71            ns: &ns,
72            name: b"page-1",
73        }
74        .to_uuid();
75        let b = IdStrategy::V5 {
76            ns: &ns,
77            name: b"page-1",
78        }
79        .to_uuid();
80        assert_eq!(a, b);
81        assert_ne!(a, Uuid::new_v4());
82    }
83}