bindizr_db/repository/sqlite/
zone_snapshot_repository_impl.rs1use async_trait::async_trait;
2use sqlx::{Pool, Sqlite};
3
4use crate::{
5 error::DatabaseError,
6 model::zone_snapshot::ZoneSnapshot,
7 repository::{RepositoryTx, RepositoryTxKind, ZoneSnapshotRepository},
8};
9
10pub struct SqliteZoneSnapshotRepository {
11 pool: Pool<Sqlite>,
12}
13
14impl SqliteZoneSnapshotRepository {
15 pub fn new(pool: Pool<Sqlite>) -> Self {
16 Self { pool }
17 }
18}
19
20#[async_trait]
21impl ZoneSnapshotRepository for SqliteZoneSnapshotRepository {
22 async fn upsert(&self, snapshot: ZoneSnapshot) -> Result<ZoneSnapshot, DatabaseError> {
23 sqlx::query(
24 r#"
25 INSERT INTO zone_soa_history (zone_id, serial, primary_ns, admin_email, ttl, refresh, retry, expire, minimum_ttl)
26 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
27 ON CONFLICT(zone_id, serial)
28 DO UPDATE SET
29 primary_ns = excluded.primary_ns,
30 admin_email = excluded.admin_email,
31 ttl = excluded.ttl,
32 refresh = excluded.refresh,
33 retry = excluded.retry,
34 expire = excluded.expire,
35 minimum_ttl = excluded.minimum_ttl
36 "#,
37 )
38 .bind(snapshot.zone_id)
39 .bind(snapshot.serial)
40 .bind(&snapshot.primary_ns)
41 .bind(&snapshot.admin_email)
42 .bind(snapshot.ttl)
43 .bind(snapshot.refresh)
44 .bind(snapshot.retry)
45 .bind(snapshot.expire)
46 .bind(snapshot.minimum_ttl)
47 .execute(&self.pool)
48 .await
49 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))?;
50
51 sqlx::query_as::<_, ZoneSnapshot>(
52 r#"
53 SELECT id, zone_id, serial, primary_ns, admin_email, ttl, refresh, retry, expire, minimum_ttl, created_at
54 FROM zone_soa_history
55 WHERE zone_id = ? AND serial = ?
56 "#,
57 )
58 .bind(snapshot.zone_id)
59 .bind(snapshot.serial)
60 .fetch_one(&self.pool)
61 .await
62 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))
63 }
64
65 async fn upsert_tx(
66 &self,
67 tx: &mut RepositoryTx<'_>,
68 snapshot: ZoneSnapshot,
69 ) -> Result<ZoneSnapshot, DatabaseError> {
70 let sqlite_tx = match &mut tx.0 {
71 RepositoryTxKind::SQLite(tx) => tx,
72 _ => {
73 return Err(DatabaseError::TransactionFailed(
74 "transaction kind mismatch (expected SQLite)".to_string(),
75 ));
76 }
77 };
78
79 sqlx::query(
80 r#"
81 INSERT INTO zone_soa_history (zone_id, serial, primary_ns, admin_email, ttl, refresh, retry, expire, minimum_ttl)
82 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
83 ON CONFLICT(zone_id, serial)
84 DO UPDATE SET
85 primary_ns = excluded.primary_ns,
86 admin_email = excluded.admin_email,
87 ttl = excluded.ttl,
88 refresh = excluded.refresh,
89 retry = excluded.retry,
90 expire = excluded.expire,
91 minimum_ttl = excluded.minimum_ttl
92 "#,
93 )
94 .bind(snapshot.zone_id)
95 .bind(snapshot.serial)
96 .bind(&snapshot.primary_ns)
97 .bind(&snapshot.admin_email)
98 .bind(snapshot.ttl)
99 .bind(snapshot.refresh)
100 .bind(snapshot.retry)
101 .bind(snapshot.expire)
102 .bind(snapshot.minimum_ttl)
103 .execute(&mut **sqlite_tx)
104 .await
105 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))?;
106
107 sqlx::query_as::<_, ZoneSnapshot>(
108 r#"
109 SELECT id, zone_id, serial, primary_ns, admin_email, ttl, refresh, retry, expire, minimum_ttl, created_at
110 FROM zone_soa_history
111 WHERE zone_id = ? AND serial = ?
112 "#,
113 )
114 .bind(snapshot.zone_id)
115 .bind(snapshot.serial)
116 .fetch_one(&mut **sqlite_tx)
117 .await
118 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))
119 }
120
121 async fn get_by_zone_id_and_serial(
122 &self,
123 zone_id: i32,
124 serial: i32,
125 ) -> Result<Option<ZoneSnapshot>, DatabaseError> {
126 sqlx::query_as::<_, ZoneSnapshot>(
127 r#"
128 SELECT id, zone_id, serial, primary_ns, admin_email, ttl, refresh, retry, expire, minimum_ttl, created_at
129 FROM zone_soa_history
130 WHERE zone_id = ? AND serial = ?
131 "#,
132 )
133 .bind(zone_id)
134 .bind(serial)
135 .fetch_optional(&self.pool)
136 .await
137 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))
138 }
139}