drizzle_migrations/sqlite/
snapshot.rs1use super::ddl::SqliteEntity;
12use crate::snapshot::{Snapshot, SnapshotEntity};
13use crate::version::SQLITE_SNAPSHOT_VERSION;
14use serde::{Deserialize, Serialize};
15
16impl SnapshotEntity for SqliteEntity {
17 const DIALECT: &'static str = "sqlite";
18 const SNAPSHOT_VERSION: &'static str = SQLITE_SNAPSHOT_VERSION;
19}
20
21pub type SQLiteSnapshot = Snapshot<SqliteEntity>;
26
27use super::ddl::{Table, View};
32use std::collections::HashMap;
33
34#[derive(Serialize, Deserialize, Clone, Debug, Default)]
36pub struct Meta {
37 #[serde(default)]
39 pub tables: HashMap<String, String>,
40 #[serde(default)]
42 pub columns: HashMap<String, String>,
43}
44
45#[derive(Serialize, Deserialize, Clone, Debug, Default)]
47pub struct Internal {
48 #[serde(default)]
50 pub indexes: HashMap<String, IndexInternal>,
51}
52
53#[derive(Serialize, Deserialize, Clone, Debug, Default)]
55pub struct IndexInternal {
56 #[serde(default)]
58 pub columns: HashMap<String, ColumnInternal>,
59}
60
61#[derive(Serialize, Deserialize, Clone, Debug, Default)]
63#[serde(rename_all = "camelCase")]
64pub struct ColumnInternal {
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub is_expression: Option<bool>,
68}
69
70#[derive(Serialize, Deserialize, Clone, Debug)]
72#[serde(rename_all = "camelCase")]
73pub struct SnapshotV6 {
74 pub version: String,
76 pub dialect: String,
78 pub id: String,
80 pub prev_id: String,
82 pub tables: HashMap<String, Table>,
84 #[serde(default)]
86 pub views: HashMap<String, View>,
87 #[serde(default)]
90 pub enums: HashMap<String, serde_json::Value>,
91 #[serde(rename = "_meta")]
93 pub meta: Meta,
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub internal: Option<Internal>,
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::sqlite::ddl::{Column, Index, IndexColumn, Table};
103
104 #[test]
105 fn test_new_snapshot() {
106 let snapshot = SQLiteSnapshot::new();
107 assert_eq!(snapshot.version, "7");
108 assert_eq!(snapshot.dialect, "sqlite");
109 assert_eq!(snapshot.prev_ids[0], crate::ORIGIN_UUID);
110 assert!(snapshot.ddl.is_empty());
111 }
112
113 #[test]
114 fn test_add_entity() {
115 let mut snapshot = SQLiteSnapshot::new();
116
117 let table = Table::new("users");
119 snapshot.add_entity(SqliteEntity::Table(table));
120
121 let id_col = Column::new("users", "id", "integer")
123 .not_null()
124 .autoincrement();
125 let name_col = Column::new("users", "name", "text").not_null();
126
127 snapshot.add_entity(SqliteEntity::Column(id_col));
128 snapshot.add_entity(SqliteEntity::Column(name_col));
129
130 assert_eq!(snapshot.ddl.len(), 3);
131 }
132
133 #[test]
134 fn test_snapshot_serialization() {
135 let mut snapshot = SQLiteSnapshot::new();
136
137 let table = Table::new("users");
138 snapshot.add_entity(SqliteEntity::Table(table));
139
140 let col = Column::new("users", "id", "integer").not_null();
141 snapshot.add_entity(SqliteEntity::Column(col));
142
143 let json = snapshot.to_json().unwrap();
144
145 let parsed = SQLiteSnapshot::from_json(&json).unwrap();
147 assert_eq!(parsed.version, "7");
148 assert_eq!(parsed.dialect, "sqlite");
149 assert_eq!(parsed.ddl.len(), 2);
150
151 let value: serde_json::Value = serde_json::from_str(&json).unwrap();
153 assert_eq!(value["version"], "7");
154 assert_eq!(value["dialect"], "sqlite");
155 assert_eq!(value["ddl"][0]["entityType"], "tables");
156 assert_eq!(value["ddl"][1]["entityType"], "columns");
157 }
158
159 #[test]
160 fn partial_index_predicate_round_trips_through_snapshot_json() {
161 let mut snapshot = SQLiteSnapshot::new();
162 let mut index = Index::new("jobs", "idx_jobs_unclaimed", vec![IndexColumn::new("id")]);
163 index.where_clause = Some("builder IS NULL".into());
164 snapshot.add_entity(SqliteEntity::Index(index));
165
166 let json = snapshot.to_json().unwrap();
167 assert_eq!(
168 serde_json::from_str::<serde_json::Value>(&json).unwrap()["ddl"][0]["where"],
169 "builder IS NULL"
170 );
171 let parsed = SQLiteSnapshot::from_json(&json).unwrap();
172 let index = parsed
173 .ddl
174 .iter()
175 .find_map(|entity| match entity {
176 SqliteEntity::Index(index) => Some(index),
177 _ => None,
178 })
179 .expect("partial index");
180 assert_eq!(index.where_clause.as_deref(), Some("builder IS NULL"));
181 }
182
183 #[test]
184 fn test_column_json_format_matches_drizzle_kit() {
185 let col = Column::new("users", "id", "integer")
187 .not_null()
188 .autoincrement();
189
190 let value: serde_json::Value = serde_json::to_value(&col).unwrap();
191
192 assert_eq!(value["autoincrement"], serde_json::json!(true));
197 assert_eq!(value["notNull"], serde_json::json!(true));
198 assert_eq!(value["type"], "integer");
199 assert_eq!(value["table"], "users");
200 assert_eq!(value["name"], "id");
201
202 assert!(
204 value.get("sql_type").is_none(),
205 "Should not contain 'sql_type'"
206 );
207 assert!(
208 value.get("not_null").is_none(),
209 "Should not contain 'not_null'"
210 );
211 }
212}