valence_backend_sqlite/
backend.rs1use sqlx::sqlite::{SqliteConnectOptions, SqlitePool};
4use std::str::FromStr;
5
6use valence_backend_sql::{
7 create_record_sqlite, define_unique_index_sqlite, delete_record_sqlite, ensure_table_sqlite,
8 execute_select_sqlite, get_edge_targets_sqlite, get_record_sqlite, merge_record_sqlite,
9 relate_edge_sqlite, sql_capabilities, ttl_deferred, unrelate_edge_sqlite, update_record_sqlite,
10};
11use valence_core::backend::DatabaseBackend;
12use valence_core::compiled_query::CompiledQuery;
13use valence_core::error::{Error, Result};
14use valence_core::record_id::RecordId;
15use valence_core::ttl::SchemaTtlPolicy;
16use valence_core::{Database, DatabaseFromEngine, KnownEngines};
17
18pub const ENGINE_ID: &str = KnownEngines::SQLITE;
20
21pub const PRIMARY: DatabaseFromEngine = Database::from_engine("primary", ENGINE_ID);
23
24#[derive(Debug, Clone)]
61pub struct SqliteBackend {
62 pool: SqlitePool,
63}
64
65impl SqliteBackend {
66 pub async fn connect_memory() -> Result<Self> {
68 Self::connect(":memory:").await
69 }
70
71 pub async fn connect(path: &str) -> Result<Self> {
73 let options = SqliteConnectOptions::from_str(path)
74 .or_else(|_| SqliteConnectOptions::from_str(&format!("sqlite:{path}")))
75 .map_err(|e| Error::Database(e.to_string()))?
76 .create_if_missing(true);
77 let pool = SqlitePool::connect_with(options)
78 .await
79 .map_err(|e| Error::Database(e.to_string()))?;
80 valence_backend_sql::ensure_edges_sqlite(&pool).await?;
81 Ok(Self { pool })
82 }
83
84 pub fn pool(&self) -> &SqlitePool {
86 &self.pool
87 }
88}
89
90#[async_trait::async_trait]
91impl DatabaseBackend for SqliteBackend {
92 fn engine_id(&self) -> &'static str {
93 ENGINE_ID
94 }
95
96 fn capabilities(&self) -> valence_core::BackendCapabilities {
97 sql_capabilities("sqlite")
98 }
99
100 async fn execute_compiled_query(
101 &self,
102 compiled: &CompiledQuery,
103 ) -> Result<Vec<serde_json::Value>> {
104 execute_select_sqlite(&self.pool, compiled, "").await
105 }
106
107 async fn ensure_schemaless_table(&self, table: &str) -> Result<()> {
108 ensure_table_sqlite(&self.pool, table).await
109 }
110
111 async fn get_record(&self, table: &str, id: &str) -> Result<Option<serde_json::Value>> {
112 get_record_sqlite(&self.pool, table, id).await
113 }
114
115 async fn create_record(
116 &self,
117 table: &str,
118 content: serde_json::Value,
119 ) -> Result<serde_json::Value> {
120 create_record_sqlite(&self.pool, table, content).await
121 }
122
123 async fn update_record(
124 &self,
125 table: &str,
126 id: &str,
127 content: serde_json::Value,
128 ) -> Result<serde_json::Value> {
129 update_record_sqlite(&self.pool, table, id, content).await
130 }
131
132 async fn merge_record(
133 &self,
134 table: &str,
135 id: &str,
136 patch: serde_json::Value,
137 ) -> Result<serde_json::Value> {
138 merge_record_sqlite(&self.pool, table, id, patch).await
139 }
140
141 async fn upsert_record(
142 &self,
143 table: &str,
144 id: &str,
145 content: serde_json::Value,
146 ) -> Result<serde_json::Value> {
147 if self.get_record(table, id).await?.is_some() {
148 self.update_record(table, id, content).await
149 } else {
150 let mut c = content;
151 if let Some(obj) = c.as_object_mut() {
152 obj.insert("id".into(), serde_json::json!({"table": table, "id": id}));
153 }
154 self.create_record(table, c).await
155 }
156 }
157
158 async fn delete_record(&self, table: &str, id: &str) -> Result<()> {
159 delete_record_sqlite(&self.pool, table, id).await
160 }
161
162 async fn relate_edge(&self, from: &RecordId, edge_table: &str, to: &RecordId) -> Result<()> {
163 relate_edge_sqlite(&self.pool, from, edge_table, to).await
164 }
165
166 async fn unrelate_edge(&self, from: &RecordId, edge_table: &str, to: &RecordId) -> Result<()> {
167 unrelate_edge_sqlite(&self.pool, from, edge_table, to).await
168 }
169
170 async fn get_edge_targets(&self, from: &RecordId, edge_table: &str) -> Result<Vec<RecordId>> {
171 get_edge_targets_sqlite(&self.pool, from, edge_table).await
172 }
173
174 async fn define_unique_index(&self, table: &str, field: &str) -> Result<()> {
175 define_unique_index_sqlite(&self.pool, table, field).await
176 }
177
178 fn ttl_capability(&self) -> valence_core::ttl::BackendTtlCapability {
179 ttl_deferred()
180 }
181
182 async fn apply_ttl_policy(&self, _table: &str, _policy: &SchemaTtlPolicy) -> Result<()> {
183 Ok(())
184 }
185}