11use crate :: oid:: Oid ;
2- use anyhow:: { Result , anyhow} ;
2+ use anyhow:: { Result , anyhow, bail } ;
33use chrono:: { DateTime , Utc } ;
44use native_db:: { Models , ToKey } ;
55use serde:: de:: DeserializeOwned ;
@@ -8,245 +8,76 @@ use sled::transaction::ConflictableTransactionError::Abort;
88use std:: ops:: Range ;
99use std:: path:: Path ;
1010use std:: { marker:: PhantomData , sync:: Arc } ;
11- use tempfile:: { TempDir , tempdir} ;
1211use tracing:: { debug, trace} ;
1312
1413pub mod config;
1514pub mod oid;
1615
17- #[ derive( Clone ) ]
18- pub struct Database ( pub Arc < native_db:: Database < ' static > > ) ;
19-
20- impl Database {
21- /// Initialize a new memory-only database.
22- pub fn new_ephemeral ( models : & ' static Models ) -> Result < Self > {
23- debug ! ( "Initializing ephemeral database" ) ;
24- Ok ( Self ( Arc :: new (
25- native_db:: Builder :: new ( ) . create_in_memory ( models) ?,
26- ) ) )
27- }
28-
29- /// Initialize a new persistent database from the given directory.
30- pub fn new < P > ( models : & ' static Models , path : P ) -> Result < Self >
31- where
32- P : AsRef < Path > ,
33- {
34- let path = path. as_ref ( ) ;
35-
36- debug ! ( path = %path. display( ) , "Initializing persistent database" ) ;
37- Ok ( Self ( Arc :: new (
38- native_db:: Builder :: new ( ) . create ( models, path) ?,
39- ) ) )
40- }
41- }
42-
43- #[ derive( Clone ) ]
44- pub struct Collection < T >
45- where
46- T : Serialize + DeserializeOwned ,
47- {
48- db : sled:: Tree ,
49- oid : Oid ,
50- data : PhantomData < T > ,
51- }
52-
53- impl < T : Serialize + DeserializeOwned + std:: fmt:: Debug > Collection < T > {
54- pub fn get_document ( & self , oid : impl TryInto < Oid > ) -> Result < Option < Document < T > > > {
55- let oid = self . oid . extend ( oid) ?;
56-
57- Ok ( if let Some ( data) = self . db . get ( & oid) ? {
58- Some ( Document {
59- db : self . db . clone ( ) ,
60- data : serde_cbor:: from_slice :: < T > ( & data) ?,
61- oid,
62- } )
63- } else {
64- None
65- } )
66- }
67-
68- pub fn documents ( & self ) -> impl Iterator < Item = Result < Document < T > > > + use < ' _ , T > {
69- trace ! ( oid = %self . oid, "Querying collection" ) ;
70- let mut start = self . oid . 0 . clone ( ) ;
71- start. push ( '/' as u8 ) ;
72- let mut end = start. clone ( ) ;
73- end. push ( 0xff ) ;
74-
75- self . db
76- . range :: < & [ u8 ] , Range < & [ u8 ] > > ( & start..& end)
77- . map ( |r| match r {
78- Ok ( ( key, value) ) => match ( key. try_into ( ) , serde_cbor:: from_slice :: < T > ( & value) ) {
79- ( Ok ( oid) , Ok ( data) ) => {
80- trace ! ( oid = %oid, "Yielding document" ) ;
81- Ok ( Document {
82- db : self . db . clone ( ) ,
83- oid,
84- data,
85- } )
86- }
87- ( Ok ( _) , Err ( _) ) => todo ! ( ) ,
88- ( Err ( _) , Ok ( _) ) => todo ! ( ) ,
89- ( Err ( _) , Err ( _) ) => todo ! ( ) ,
90- } ,
91- Err ( _) => todo ! ( ) ,
92- } )
93- }
94-
95- pub fn collection < U > ( & self , oid : impl TryInto < Oid > ) -> Result < Collection < U > >
96- where
97- U : Serialize + DeserializeOwned ,
98- {
99- Ok ( Collection {
100- db : self . db . clone ( ) ,
101- oid : self . oid . extend ( oid) ?,
102- data : PhantomData { } ,
103- } )
104- }
105-
106- pub fn insert_document ( & self , oid : impl TryInto < Oid > , data : T ) -> Result < Document < T > > {
107- let oid = self . oid . extend ( oid) ?;
108- let d = serde_cbor:: to_vec ( & data) ?;
109-
110- trace ! ( oid = %oid, data = ?data, "Inserting new document" ) ;
111- self . db
112- . transaction ( |tx_db| {
113- if tx_db. get ( & oid) ?. is_some ( ) {
114- return Err ( Abort ( anyhow:: anyhow!( "Already exists" ) ) ) ;
115- }
116-
117- tx_db. insert ( oid. clone ( ) , d. clone ( ) ) ?;
118- Ok ( ( ) )
119- } )
120- . map_err ( |_| anyhow:: anyhow!( "" ) ) ?;
121-
122- Ok ( Document {
123- oid,
124- data,
125- db : self . db . clone ( ) ,
126- } )
127- }
16+ pub struct DatabaseBuilder {
17+ models : & ' static Models ,
18+ groups : Vec < ( String , native_db:: Database < ' static > ) > ,
12819}
12920
130- impl < T : Serialize + DeserializeOwned + Default > Collection < T > {
131- pub fn document ( & self , oid : impl TryInto < Oid > ) -> Result < Document < T > > {
132- let oid = self . oid . extend ( oid) ?;
133-
134- Ok ( Document {
135- db : self . db . clone ( ) ,
136- data : if let Some ( data) = self . db . get ( & oid) ? {
137- serde_cbor:: from_slice :: < T > ( & data) ?
138- } else {
139- // TODO insert
140- T :: default ( )
141- } ,
142- oid,
143- } )
21+ impl DatabaseBuilder {
22+ pub fn new ( models : & ' static Models ) -> Self {
23+ Self {
24+ models,
25+ // Don't bother with a map because groups are few
26+ groups : Vec :: with_capacity ( 1 ) ,
27+ }
14428 }
145- }
14629
147- #[ derive( Clone ) ]
148- pub struct Document < T >
149- where
150- T : Serialize + DeserializeOwned ,
151- {
152- pub db : sled:: Tree ,
153- pub oid : Oid ,
154- pub data : T , // TODO impl AsRef?
155- }
30+ /// Create a new ephemeral database for the given group name.
31+ pub fn add_ephemeral ( mut self , group : impl ToString ) -> Result < Self > {
32+ let name = group. to_string ( ) ;
15633
157- impl < T : Serialize + DeserializeOwned > Document < T > {
158- // pub fn update<U>(&mut self, update: )
159-
160- pub fn get_document < U > ( & self , oid : impl TryInto < Oid > ) -> Result < Option < Document < U > > >
161- where
162- U : Serialize + DeserializeOwned ,
163- {
164- let oid = self . oid . extend ( oid) ?;
165-
166- Ok ( if let Some ( data) = self . db . get ( & oid) ? {
167- Some ( Document {
168- db : self . db . clone ( ) ,
169- data : serde_cbor:: from_slice :: < U > ( & data) ?,
170- oid,
171- } )
172- } else {
173- None
174- } )
175- }
34+ // Check for duplicates
35+ for ( n, _) in self . groups . iter ( ) {
36+ if name == * n {
37+ bail ! ( "Duplicate group" ) ;
38+ }
39+ }
17640
177- pub fn document < U > ( & self , oid : impl TryInto < Oid > ) -> Result < Document < U > >
178- where
179- U : Serialize + DeserializeOwned + Default ,
180- {
181- let oid = self . oid . extend ( oid ) ? ;
41+ debug ! ( group = name , "Initializing ephemeral database" ) ;
42+ self . groups . push ( (
43+ name ,
44+ native_db :: Builder :: new ( ) . create_in_memory ( self . models ) ? ,
45+ ) ) ;
18246
183- Ok ( Document {
184- db : self . db . clone ( ) ,
185- data : if let Some ( data) = self . db . get ( & oid) ? {
186- trace ! ( oid = %oid, "Loading document" ) ;
187- serde_cbor:: from_slice :: < U > ( & data) ?
188- } else {
189- trace ! ( oid = %oid, "Creating new document" ) ;
190- // TODO insert
191- U :: default ( )
192- } ,
193- oid,
194- } )
47+ Ok ( self )
19548 }
19649
197- pub fn insert_document < U > ( & self , oid : impl TryInto < Oid > , data : U ) -> Result < Document < U > >
50+ /// Load or create a new persistent database for the given group name.
51+ pub fn add_persistent < P > ( mut self , group : impl ToString , path : P ) -> Result < Self >
19852 where
199- U : Serialize + DeserializeOwned + std :: fmt :: Debug ,
53+ P : AsRef < Path > ,
20054 {
201- let oid = self . oid . extend ( oid ) ? ;
202- let d = serde_cbor :: to_vec ( & data ) ? ;
55+ let name = group . to_string ( ) ;
56+ let path = path . as_ref ( ) ;
20357
204- trace ! ( oid = %oid , data = ?data , "Inserting new document" ) ;
205- self . db
206- . transaction ( |tx_db| {
207- if tx_db . get ( & oid ) ? . is_some ( ) {
208- return Err ( Abort ( anyhow :: anyhow! ( "Already exists" ) ) ) ;
209- }
58+ // Check for duplicates
59+ for ( n , _ ) in self . groups . iter ( ) {
60+ if name == * n {
61+ bail ! ( "Duplicate group" ) ;
62+ }
63+ }
21064
211- tx_db. insert ( oid. clone ( ) , d. clone ( ) ) ?;
212- Ok ( ( ) )
213- } )
214- . map_err ( |_| anyhow:: anyhow!( "" ) ) ?;
65+ debug ! ( group = name, path = %path. display( ) , "Initializing persistent database" ) ;
66+ self . groups
67+ . push ( ( name, native_db:: Builder :: new ( ) . create ( self . models , path) ?) ) ;
21568
216- Ok ( Document {
217- oid,
218- data,
219- db : self . db . clone ( ) ,
220- } )
69+ Ok ( self )
22170 }
22271
223- pub fn collection < U > ( & self , oid : impl TryInto < Oid > ) -> Result < Collection < U > >
224- where
225- U : Serialize + DeserializeOwned ,
226- {
227- Ok ( Collection {
228- db : self . db . clone ( ) ,
229- oid : self . oid . extend ( oid) ?,
230- data : PhantomData { } ,
231- } )
72+ pub fn build ( self ) -> Database {
73+ Database ( Arc :: new ( self . groups ) )
23274 }
23375}
23476
235- impl < T : Serialize + DeserializeOwned + Clone > Document < T > {
236- pub fn mutate < F > ( & mut self , mutator : F ) -> Result < ( ) >
237- where
238- F : Fn ( & mut T ) -> Result < ( ) > ,
239- {
240- // Create a copy so we can tell what changed
241- let mut object = self . data . clone ( ) ;
242- mutator ( & mut object) ?;
243-
244- // TODO detect changes and update history as part of a transaction
77+ #[ derive( Clone ) ]
78+ pub struct Database ( Arc < Vec < ( String , native_db:: Database < ' static > ) > > ) ;
24579
246- self . db . insert ( & self . oid , serde_cbor:: to_vec ( & object) ?) ?;
247- Ok ( ( ) )
248- }
249- }
80+ impl Database { }
25081
25182// TODO Eq based only on inner?
25283#[ derive( Serialize , Deserialize , Eq , PartialEq , Debug , Clone , Hash ) ]
0 commit comments