bindizr_db/repository/sqlite/
zone_change_repository_impl.rs1use async_trait::async_trait;
2use sqlx::{Pool, Sqlite};
3
4use crate::{
5 error::DatabaseError,
6 model::zone_change::ZoneChange,
7 repository::{RepositoryTx, RepositoryTxKind, ZoneChangeRepository},
8};
9
10pub struct SqliteZoneChangeRepository {
11 pool: Pool<Sqlite>,
12}
13
14impl SqliteZoneChangeRepository {
15 pub fn new(pool: Pool<Sqlite>) -> Self {
16 Self { pool }
17 }
18}
19
20#[async_trait]
21impl ZoneChangeRepository for SqliteZoneChangeRepository {
22 async fn create(&self, zone_change: ZoneChange) -> Result<ZoneChange, DatabaseError> {
23 let result = sqlx::query(
24 r#"
25 INSERT INTO zone_changes (zone_id, serial, operation, record_name, record_type, record_value, record_ttl, record_priority)
26 VALUES (?, ?, ?, ?, ?, ?, ?, ?)
27 "#
28 )
29 .bind(zone_change.zone_id)
30 .bind(zone_change.serial)
31 .bind(&zone_change.operation)
32 .bind(&zone_change.record_name)
33 .bind(&zone_change.record_type)
34 .bind(&zone_change.record_value)
35 .bind(zone_change.record_ttl)
36 .bind(zone_change.record_priority)
37 .execute(&self.pool)
38 .await
39 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))?;
40
41 let id = result.last_insert_rowid() as i32;
42
43 sqlx::query_as::<_, ZoneChange>(
44 r#"
45 SELECT id, zone_id, serial, operation, record_name, record_type, record_value, record_ttl, record_priority
46 FROM zone_changes
47 WHERE id = ?
48 "#
49 )
50 .bind(id)
51 .fetch_one(&self.pool)
52 .await
53 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))
54 }
55
56 async fn create_tx(
57 &self,
58 tx: &mut RepositoryTx<'_>,
59 zone_change: ZoneChange,
60 ) -> Result<ZoneChange, DatabaseError> {
61 let sqlite_tx = match &mut tx.0 {
62 RepositoryTxKind::SQLite(tx) => tx,
63 _ => {
64 return Err(DatabaseError::TransactionFailed(
65 "transaction kind mismatch (expected SQLite)".to_string(),
66 ));
67 }
68 };
69
70 let result = sqlx::query(
71 r#"
72 INSERT INTO zone_changes (zone_id, serial, operation, record_name, record_type, record_value, record_ttl, record_priority)
73 VALUES (?, ?, ?, ?, ?, ?, ?, ?)
74 "#,
75 )
76 .bind(zone_change.zone_id)
77 .bind(zone_change.serial)
78 .bind(&zone_change.operation)
79 .bind(&zone_change.record_name)
80 .bind(&zone_change.record_type)
81 .bind(&zone_change.record_value)
82 .bind(zone_change.record_ttl)
83 .bind(zone_change.record_priority)
84 .execute(&mut **sqlite_tx)
85 .await
86 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))?;
87
88 let id = result.last_insert_rowid() as i32;
89
90 sqlx::query_as::<_, ZoneChange>(
91 r#"
92 SELECT id, zone_id, serial, operation, record_name, record_type, record_value, record_ttl, record_priority
93 FROM zone_changes
94 WHERE id = ?
95 "#,
96 )
97 .bind(id)
98 .fetch_one(&mut **sqlite_tx)
99 .await
100 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))
101 }
102
103 async fn get_changes_between_serials(
104 &self,
105 zone_id: i32,
106 from_serial: i32,
107 to_serial: i32,
108 ) -> Result<Vec<ZoneChange>, DatabaseError> {
109 sqlx::query_as::<_, ZoneChange>(
110 r#"
111 SELECT id, zone_id, serial, operation, record_name, record_type, record_value, record_ttl, record_priority
112 FROM zone_changes
113 WHERE zone_id = ? AND serial > ? AND serial <= ?
114 ORDER BY serial, id
115 "#
116 )
117 .bind(zone_id)
118 .bind(from_serial)
119 .bind(to_serial)
120 .fetch_all(&self.pool)
121 .await
122 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))
123 }
124}