1mod adapter;
8mod contract;
9mod rows;
10mod schema;
11
12pub mod error;
13
14pub use crate::contract::{
15 AccessMode, AtomicResult, GeneratedKey, OpenOptions, Operation, OperationKind, OperationResult,
16 StorageContext, WriteResult, STORAGE_CONTEXT_VERSION,
17};
18pub use crate::error::{AdapterErrorKind, DactylError};
19pub use crate::rows::{Parameter, Row, Rows};
20pub use crate::schema::{
21 ColumnSchema, ForeignKeyAction, ForeignKeySchema, IndexSchema, StoreSchema, TableSchema,
22};
23
24use crate::adapter::Adapter;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum Datastore {
29 Sqlite,
30 Neon,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct DatastoreRoute {
36 datastore: Datastore,
37 route: String,
38 token: Option<String>,
39}
40
41impl DatastoreRoute {
42 pub fn sqlite(path: impl Into<String>) -> Self {
43 Self {
44 datastore: Datastore::Sqlite,
45 route: path.into(),
46 token: None,
47 }
48 }
49
50 pub fn neon(endpoint: impl Into<String>, token: Option<String>) -> Self {
51 Self {
52 datastore: Datastore::Neon,
53 route: endpoint.into(),
54 token,
55 }
56 }
57
58 pub fn datastore(&self) -> Datastore {
59 self.datastore
60 }
61
62 pub fn route(&self) -> &str {
63 &self.route
64 }
65
66 pub fn token(&self) -> Option<&str> {
67 self.token.as_deref()
68 }
69
70 pub fn from_env() -> Result<Self, DactylError> {
72 let datastore = std::env::var("DATASTORE")
73 .map_err(|_| DactylError::Config("DATASTORE is not set: use sqlite or neon".into()))?;
74 let route = std::env::var("DATASTORE_ROUTE")
75 .map_err(|_| DactylError::Config("DATASTORE_ROUTE is not set".into()))?;
76 match datastore.as_str() {
77 "sqlite" => Ok(Self::sqlite(route)),
78 "neon" => Ok(Self::neon(route, std::env::var("DATASTORE_TOKEN").ok())),
79 other => Err(DactylError::Config(format!(
80 "invalid DATASTORE value {other:?}: use sqlite or neon"
81 ))),
82 }
83 }
84}
85
86pub struct Connection {
88 adapter: Box<dyn Adapter>,
89 route: DatastoreRoute,
90 context: Option<StorageContext>,
91}
92
93impl Connection {
94 pub fn open(route: DatastoreRoute) -> Result<Self, DactylError> {
95 Self::open_with_options_and_context(route, OpenOptions::default(), None)
96 }
97
98 pub fn open_with_options(
99 route: DatastoreRoute,
100 options: OpenOptions,
101 ) -> Result<Self, DactylError> {
102 Self::open_with_options_and_context(route, options, None)
103 }
104
105 pub fn open_with_context(
110 route: DatastoreRoute,
111 context: Option<StorageContext>,
112 ) -> Result<Self, DactylError> {
113 Self::open_with_options_and_context(route, OpenOptions::default(), context)
114 }
115
116 pub fn open_with_options_and_context(
117 route: DatastoreRoute,
118 options: OpenOptions,
119 context: Option<StorageContext>,
120 ) -> Result<Self, DactylError> {
121 if let Some(context) = &context {
122 context.validate()?;
123 }
124 let adapter = build_adapter(&route, options, context.clone())?;
125 Ok(Self {
126 adapter,
127 route,
128 context,
129 })
130 }
131
132 pub fn from_env() -> Result<Self, DactylError> {
133 Self::open(DatastoreRoute::from_env()?)
134 }
135
136 pub fn datastore(&self) -> Datastore {
137 self.route.datastore
138 }
139
140 pub fn route(&self) -> &DatastoreRoute {
141 &self.route
142 }
143
144 pub fn context(&self) -> Option<&StorageContext> {
145 self.context.as_ref()
146 }
147
148 pub fn read(&self, sql: &str, params: &[Parameter]) -> Result<Rows, DactylError> {
150 self.adapter.read(sql, params)
151 }
152
153 pub fn write_result(
155 &self,
156 sql: &str,
157 params: &[Parameter],
158 ) -> Result<WriteResult, DactylError> {
159 self.adapter.write(sql, params)
160 }
161
162 pub fn write(&self, sql: &str, params: &[Parameter]) -> Result<u64, DactylError> {
164 Ok(self.write_result(sql, params)?.affected_rows)
165 }
166
167 pub fn atomic(&self, operations: &[Operation]) -> Result<AtomicResult, DactylError> {
168 self.adapter.atomic(operations)
169 }
170
171 pub fn access_mode(&self) -> AccessMode {
172 self.adapter.access_mode()
173 }
174
175 pub fn inspect_schema(&self) -> Result<StoreSchema, DactylError> {
177 self.adapter.inspect_schema()
178 }
179}
180
181pub type Driver = Connection;
183
184pub fn read(sql: &str, params: &[Parameter]) -> Result<Rows, DactylError> {
185 Connection::from_env()?.read(sql, params)
186}
187
188pub fn read_with_context(
189 context: Option<StorageContext>,
190 sql: &str,
191 params: &[Parameter],
192) -> Result<Rows, DactylError> {
193 Connection::open_with_context(DatastoreRoute::from_env()?, context)?.read(sql, params)
194}
195
196pub fn write(sql: &str, params: &[Parameter]) -> Result<u64, DactylError> {
197 Connection::from_env()?.write(sql, params)
198}
199
200pub fn write_with_context(
201 context: Option<StorageContext>,
202 sql: &str,
203 params: &[Parameter],
204) -> Result<u64, DactylError> {
205 Connection::open_with_context(DatastoreRoute::from_env()?, context)?.write(sql, params)
206}
207
208#[deprecated(note = "use dactyl_db::read")]
209pub fn query(sql: &str, params: &[Parameter]) -> Result<Rows, DactylError> {
210 read(sql, params)
211}
212
213#[deprecated(note = "use dactyl_db::write")]
214pub fn execute(sql: &str, params: &[Parameter]) -> Result<u64, DactylError> {
215 write(sql, params)
216}
217
218fn build_adapter(
219 route: &DatastoreRoute,
220 _options: OpenOptions,
221 _context: Option<StorageContext>,
222) -> Result<Box<dyn Adapter>, DactylError> {
223 match route.datastore {
224 Datastore::Sqlite => {
225 #[cfg(feature = "sqlite")]
226 {
227 Ok(Box::new(
228 crate::adapter::sqlite::SqliteAdapter::open_with_options(
229 &route.route,
230 _options,
231 )?,
232 ))
233 }
234 #[cfg(not(feature = "sqlite"))]
235 {
236 Err(DactylError::Config(
237 "sqlite support is disabled; enable the `sqlite` feature".into(),
238 ))
239 }
240 }
241 Datastore::Neon => {
242 #[cfg(feature = "neon")]
243 {
244 Ok(Box::new(
245 crate::adapter::neon::NeonAdapter::new_with_options(
246 &route.route,
247 route.token.clone(),
248 _options,
249 _context,
250 ),
251 ))
252 }
253 #[cfg(not(feature = "neon"))]
254 {
255 Err(DactylError::Config(
256 "neon support is disabled; enable the `neon` feature".into(),
257 ))
258 }
259 }
260 }
261}