winbrew_database\catalog/
mod.rs1use anyhow::{Context, Result, anyhow};
2use rusqlite::{Connection, OptionalExtension};
3
4use super::CatalogSchemaVersionMismatchError;
5use crate::models::catalog::metadata::CATALOG_DB_SCHEMA_VERSION as CATALOG_SCHEMA_VERSION;
6
7mod installers;
8mod row;
9mod search;
10
11pub(crate) use installers::get_installers;
12pub(crate) use search::{get_package_by_id, search};
13
14pub(crate) fn ensure_schema_version(conn: &Connection) -> Result<()> {
15 let version_text: Option<String> = conn
16 .query_row(
17 "SELECT value FROM schema_meta WHERE name = 'schema_version'",
18 [],
19 |row| row.get(0),
20 )
21 .optional()
22 .context("failed to read package catalog schema version metadata")?;
23
24 let version_text = version_text
25 .ok_or_else(|| anyhow!("package catalog schema version metadata is missing"))?;
26
27 let actual_version: i64 = version_text.parse().with_context(|| {
28 format!("failed to parse schema_meta schema_version value: {version_text}")
29 })?;
30 let expected_version = i64::from(CATALOG_SCHEMA_VERSION);
31
32 if actual_version != expected_version {
33 return Err(CatalogSchemaVersionMismatchError {
34 expected: CATALOG_SCHEMA_VERSION,
35 actual: actual_version,
36 }
37 .into());
38 }
39
40 Ok(())
41}
42
43#[cfg(test)]
44mod tests {
45 use super::{CATALOG_SCHEMA_VERSION, ensure_schema_version};
46 use rusqlite::Connection;
47
48 #[test]
49 fn ensure_schema_version_accepts_expected_version() {
50 let conn = Connection::open_in_memory().expect("open in-memory database");
51 conn.execute_batch(&format!(
52 "
53 CREATE TABLE schema_meta (
54 name TEXT PRIMARY KEY,
55 value TEXT NOT NULL
56 );
57
58 INSERT INTO schema_meta (name, value)
59 VALUES ('schema_version', '{}');
60 ",
61 CATALOG_SCHEMA_VERSION
62 ))
63 .expect("set schema version");
64
65 ensure_schema_version(&conn).expect("schema version should match");
66 }
67
68 #[test]
69 fn ensure_schema_version_rejects_mismatch() {
70 let conn = Connection::open_in_memory().expect("open in-memory database");
71 conn.execute_batch(
72 "
73 CREATE TABLE schema_meta (
74 name TEXT PRIMARY KEY,
75 value TEXT NOT NULL
76 );
77
78 INSERT INTO schema_meta (name, value)
79 VALUES ('schema_version', '99');
80 ",
81 )
82 .expect("set mismatched schema version");
83
84 let err = ensure_schema_version(&conn).expect_err("schema mismatch should fail");
85
86 assert!(
87 err.to_string()
88 .contains("Package catalog schema version mismatch")
89 );
90 }
91
92 #[test]
93 fn ensure_schema_version_rejects_missing_schema_version_row() {
94 let conn = Connection::open_in_memory().expect("open in-memory database");
95
96 conn.execute_batch(
97 "
98 CREATE TABLE schema_meta (
99 name TEXT PRIMARY KEY,
100 value TEXT NOT NULL
101 );
102 ",
103 )
104 .expect("create schema_meta table");
105
106 let err = ensure_schema_version(&conn).expect_err("missing schema version row should fail");
107
108 assert!(
109 err.to_string()
110 .contains("package catalog schema version metadata is missing")
111 );
112 }
113
114 #[test]
115 fn ensure_schema_version_rejects_missing_schema_meta_table() {
116 let conn = Connection::open_in_memory().expect("open in-memory database");
117
118 let err = ensure_schema_version(&conn).expect_err("missing schema_meta table should fail");
119
120 assert!(
121 err.to_string()
122 .contains("failed to read package catalog schema version metadata")
123 );
124 }
125}