rustlavel_model_cache/
keys.rs1use rustlavel_core::Json;
11use rustlavel_db::Value;
12use std::hash::{Hash, Hasher};
13
14pub const PREFIX: &str = "rl:mc";
15
16pub fn entity(table: &str, key: &str) -> String {
17 format!("{PREFIX}:e:{table}:{key}")
18}
19
20pub fn query(table: &str, fingerprint: u64) -> String {
21 format!("{PREFIX}:q:{table}:{fingerprint:016x}")
22}
23
24pub fn generation(table: &str) -> String {
25 format!("{PREFIX}:g:{table}")
26}
27
28pub fn fingerprint(sql: &str, bindings: &[Value]) -> u64 {
41 let mut hasher = std::collections::hash_map::DefaultHasher::new();
42 sql.hash(&mut hasher);
43 for value in bindings {
44 Json::from(value.clone()).to_string().hash(&mut hasher);
47 }
48 hasher.finish()
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn the_three_shapes_do_not_collide_with_each_other() {
57 assert_eq!(entity("users", "7"), "rl:mc:e:users:7");
58 assert_eq!(generation("users"), "rl:mc:g:users");
59 assert!(query("users", 1).starts_with("rl:mc:q:users:"));
60
61 assert_ne!(entity("users", "7"), query("users", 7));
64 }
65
66 #[test]
67 fn the_bindings_are_part_of_the_fingerprint() {
68 let sql = "select * from users where role = ?";
69
70 let admin = fingerprint(sql, &[Value::from("admin")]);
71 let support = fingerprint(sql, &[Value::from("support")]);
72
73 assert_ne!(admin, support, "two different filters shared a cache key");
74 assert_eq!(admin, fingerprint(sql, &[Value::from("admin")]), "not stable");
75
76 assert_ne!(admin, fingerprint("select 1", &[Value::from("admin")]));
78 }
79
80 #[test]
83 fn a_number_and_its_text_are_different_bindings() {
84 let sql = "select * from users where id = ?";
85
86 assert_ne!(
87 fingerprint(sql, &[Value::from(7i64)]),
88 fingerprint(sql, &[Value::from("7")]),
89 );
90 }
91
92 #[test]
93 fn the_order_of_the_bindings_matters() {
94 let sql = "select * from users where a = ? and b = ?";
95
96 assert_ne!(
97 fingerprint(sql, &[Value::from("x"), Value::from("y")]),
98 fingerprint(sql, &[Value::from("y"), Value::from("x")]),
99 );
100 }
101}