1use std::path::{Path, PathBuf};
5use std::sync::Arc;
6
7use base::threadpool::ThreadPool;
8use ipc_channel::ipc::IpcSender;
9use log::{error, info};
10use rusqlite::{Connection, Error, OptionalExtension, params};
11use sea_query::{Condition, Expr, ExprTrait, IntoCondition, SqliteQueryBuilder};
12use sea_query_rusqlite::RusqliteBinder;
13use serde::Serialize;
14use storage_traits::indexeddb::{
15 AsyncOperation, AsyncReadOnlyOperation, AsyncReadWriteOperation, BackendError, BackendResult,
16 CreateObjectResult, IndexedDBKeyRange, IndexedDBKeyType, IndexedDBRecord, IndexedDBTxnMode,
17 KeyPath, PutItemResult,
18};
19use tokio::sync::oneshot;
20
21use crate::indexeddb::IndexedDBDescription;
22use crate::indexeddb::engines::{KvsEngine, KvsTransaction};
23use crate::shared::{DB_INIT_PRAGMAS, DB_PRAGMAS};
24
25mod create;
26mod database_model;
27mod object_data_model;
28mod object_store_index_model;
29mod object_store_model;
30
31fn range_to_query(range: IndexedDBKeyRange) -> Condition {
32 if let Some(singleton) = range.as_singleton() {
34 let encoded = bincode::serialize(singleton).unwrap();
35 return Expr::column(object_data_model::Column::Key)
36 .eq(encoded)
37 .into_condition();
38 }
39 let mut parts = vec![];
40 if let Some(upper) = range.upper.as_ref() {
41 let upper_bytes = bincode::serialize(upper).unwrap();
42 let query = if range.upper_open {
43 Expr::column(object_data_model::Column::Key).lt(upper_bytes)
44 } else {
45 Expr::column(object_data_model::Column::Key).lte(upper_bytes)
46 };
47 parts.push(query);
48 }
49 if let Some(lower) = range.lower.as_ref() {
50 let lower_bytes = bincode::serialize(lower).unwrap();
51 let query = if range.lower_open {
52 Expr::column(object_data_model::Column::Key).gt(lower_bytes)
53 } else {
54 Expr::column(object_data_model::Column::Key).gte(lower_bytes)
55 };
56 parts.push(query);
57 }
58 let mut condition = Condition::all();
59 for part in parts {
60 condition = condition.add(part);
61 }
62 condition
63}
64
65pub struct SqliteEngine {
66 db_path: PathBuf,
67 connection: Connection,
68 read_pool: Arc<ThreadPool>,
69 write_pool: Arc<ThreadPool>,
70}
71
72impl SqliteEngine {
73 pub fn new(
75 base_dir: &Path,
76 db_info: &IndexedDBDescription,
77 pool: Arc<ThreadPool>,
78 ) -> Result<Self, Error> {
79 let mut db_path = PathBuf::new();
80 db_path.push(base_dir);
81 db_path.push(db_info.as_path());
82 let db_parent = db_path.clone();
83 db_path.push("db.sqlite");
84
85 if !db_path.exists() {
86 std::fs::create_dir_all(db_parent).unwrap();
87 std::fs::File::create(&db_path).unwrap();
88 }
89 let connection = Self::init_db(&db_path, db_info)?;
90
91 for stmt in DB_PRAGMAS {
92 let _ = connection.execute(stmt, ());
94 }
95
96 Ok(Self {
97 connection,
98 db_path,
99 read_pool: pool.clone(),
100 write_pool: pool,
101 })
102 }
103
104 fn init_db(path: &Path, db_info: &IndexedDBDescription) -> Result<Connection, Error> {
105 let connection = Connection::open(path)?;
106 if connection.table_exists(None, "database")? {
107 return Ok(connection);
109 }
110 info!("Initializing indexeddb database at {:?}", path);
111 for stmt in DB_INIT_PRAGMAS {
112 let _ = connection.execute(stmt, ());
114 }
115 create::create_tables(&connection)?;
116 connection.execute(
119 "INSERT INTO database (name, origin, version) VALUES (?, ?, ?)",
120 params![
121 db_info.name.to_owned(),
122 db_info.origin.to_owned().ascii_serialization(),
123 i64::from_ne_bytes(0_u64.to_ne_bytes())
124 ],
125 )?;
126 Ok(connection)
127 }
128
129 fn get(
130 connection: &Connection,
131 store: object_store_model::Model,
132 key_range: IndexedDBKeyRange,
133 ) -> Result<Option<object_data_model::Model>, Error> {
134 let query = range_to_query(key_range);
135 let (sql, values) = sea_query::Query::select()
136 .from(object_data_model::Column::Table)
137 .columns(vec![
138 object_data_model::Column::ObjectStoreId,
139 object_data_model::Column::Key,
140 object_data_model::Column::Data,
141 ])
142 .and_where(query.and(Expr::col(object_data_model::Column::ObjectStoreId).is(store.id)))
143 .limit(1)
144 .build_rusqlite(SqliteQueryBuilder);
145 connection
146 .prepare(&sql)?
147 .query_one(&*values.as_params(), |row| {
148 object_data_model::Model::try_from(row)
149 })
150 .optional()
151 }
152
153 fn get_key(
154 connection: &Connection,
155 store: object_store_model::Model,
156 key_range: IndexedDBKeyRange,
157 ) -> Result<Option<Vec<u8>>, Error> {
158 Self::get(connection, store, key_range).map(|opt| opt.map(|model| model.key))
159 }
160
161 fn get_item(
162 connection: &Connection,
163 store: object_store_model::Model,
164 key_range: IndexedDBKeyRange,
165 ) -> Result<Option<Vec<u8>>, Error> {
166 Self::get(connection, store, key_range).map(|opt| opt.map(|model| model.data))
167 }
168
169 fn get_all(
170 connection: &Connection,
171 store: object_store_model::Model,
172 key_range: IndexedDBKeyRange,
173 count: Option<u32>,
174 ) -> Result<Vec<object_data_model::Model>, Error> {
175 let query = range_to_query(key_range);
176 let mut sql_query = sea_query::Query::select();
177 sql_query
178 .from(object_data_model::Column::Table)
179 .columns(vec![
180 object_data_model::Column::ObjectStoreId,
181 object_data_model::Column::Key,
182 object_data_model::Column::Data,
183 ])
184 .and_where(query.and(Expr::col(object_data_model::Column::ObjectStoreId).is(store.id)));
185 if let Some(count) = count {
186 sql_query.limit(count as u64);
187 }
188 let (sql, values) = sql_query.build_rusqlite(SqliteQueryBuilder);
189 let mut stmt = connection.prepare(&sql)?;
190 let models = stmt
191 .query_and_then(&*values.as_params(), |row| {
192 object_data_model::Model::try_from(row)
193 })?
194 .collect::<Result<Vec<_>, _>>()?;
195 Ok(models)
196 }
197
198 fn get_all_keys(
199 connection: &Connection,
200 store: object_store_model::Model,
201 key_range: IndexedDBKeyRange,
202 count: Option<u32>,
203 ) -> Result<Vec<Vec<u8>>, Error> {
204 Self::get_all(connection, store, key_range, count)
205 .map(|models| models.into_iter().map(|m| m.key).collect())
206 }
207
208 fn get_all_items(
209 connection: &Connection,
210 store: object_store_model::Model,
211 key_range: IndexedDBKeyRange,
212 count: Option<u32>,
213 ) -> Result<Vec<Vec<u8>>, Error> {
214 Self::get_all(connection, store, key_range, count)
215 .map(|models| models.into_iter().map(|m| m.data).collect())
216 }
217
218 #[allow(clippy::type_complexity)]
219 fn get_all_records(
220 connection: &Connection,
221 store: object_store_model::Model,
222 key_range: IndexedDBKeyRange,
223 ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, Error> {
224 Self::get_all(connection, store, key_range, None)
225 .map(|models| models.into_iter().map(|m| (m.key, m.data)).collect())
226 }
227
228 fn put_item(
229 connection: &Connection,
230 store: object_store_model::Model,
231 serialized_key: Vec<u8>,
232 value: Vec<u8>,
233 should_overwrite: bool,
234 ) -> Result<PutItemResult, Error> {
235 let existing_item = connection
236 .prepare("SELECT * FROM object_data WHERE key = ? AND object_store_id = ?")
237 .and_then(|mut stmt| {
238 stmt.query_row(params![serialized_key, store.id], |row| {
239 object_data_model::Model::try_from(row)
240 })
241 .optional()
242 })?;
243 if should_overwrite || existing_item.is_none() {
244 connection.execute(
245 "INSERT INTO object_data (object_store_id, key, data) VALUES (?, ?, ?)",
246 params![store.id, serialized_key, value],
247 )?;
248 Ok(PutItemResult::Success)
249 } else {
250 Ok(PutItemResult::CannotOverwrite)
251 }
252 }
253
254 fn delete_item(
255 connection: &Connection,
256 store: object_store_model::Model,
257 key_range: IndexedDBKeyRange,
258 ) -> Result<(), Error> {
259 let query = range_to_query(key_range);
260 let (sql, values) = sea_query::Query::delete()
261 .from_table(object_data_model::Column::Table)
262 .and_where(query.and(Expr::col(object_data_model::Column::ObjectStoreId).is(store.id)))
263 .build_rusqlite(SqliteQueryBuilder);
264 connection.prepare(&sql)?.execute(&*values.as_params())?;
265 Ok(())
266 }
267
268 fn clear(connection: &Connection, store: object_store_model::Model) -> Result<(), Error> {
269 connection.execute(
270 "DELETE FROM object_data WHERE object_store_id = ?",
271 params![store.id],
272 )?;
273 Ok(())
274 }
275
276 fn count(
277 connection: &Connection,
278 store: object_store_model::Model,
279 key_range: IndexedDBKeyRange,
280 ) -> Result<usize, Error> {
281 let query = range_to_query(key_range);
282 let (sql, values) = sea_query::Query::select()
283 .expr(Expr::col(object_data_model::Column::Key).count())
284 .from(object_data_model::Column::Table)
285 .and_where(query.and(Expr::col(object_data_model::Column::ObjectStoreId).is(store.id)))
286 .build_rusqlite(SqliteQueryBuilder);
287 connection
288 .prepare(&sql)?
289 .query_row(&*values.as_params(), |row| row.get(0))
290 .map(|count: i64| count as usize)
291 }
292
293 fn generate_key(
294 connection: &Connection,
295 store: &object_store_model::Model,
296 ) -> Result<IndexedDBKeyType, Error> {
297 if store.auto_increment == 0 {
298 unreachable!("Should be caught in the script thread");
299 }
300 let new_key = store.auto_increment + 1;
302 connection.execute(
303 "UPDATE object_store SET auto_increment = ? WHERE id = ?",
304 params![new_key, store.id],
305 )?;
306 Ok(IndexedDBKeyType::Number(new_key as f64))
307 }
308}
309
310impl KvsEngine for SqliteEngine {
311 type Error = Error;
312
313 fn create_store(
314 &self,
315 store_name: &str,
316 key_path: Option<KeyPath>,
317 auto_increment: bool,
318 ) -> Result<CreateObjectResult, Self::Error> {
319 let mut stmt = self
320 .connection
321 .prepare("SELECT * FROM object_store WHERE name = ?")?;
322 if stmt.exists(params![store_name.to_string()])? {
323 return Ok(CreateObjectResult::AlreadyExists);
325 }
326 self.connection.execute(
327 "INSERT INTO object_store (name, key_path, auto_increment) VALUES (?, ?, ?)",
328 params![
329 store_name.to_string(),
330 key_path.map(|v| bincode::serialize(&v).unwrap()),
331 auto_increment as i32
332 ],
333 )?;
334
335 Ok(CreateObjectResult::Created)
336 }
337
338 fn delete_store(&self, store_name: &str) -> Result<(), Self::Error> {
339 let result = self.connection.execute(
340 "DELETE FROM object_store WHERE name = ?",
341 params![store_name.to_string()],
342 )?;
343 if result == 0 {
344 Err(Error::QueryReturnedNoRows)
345 } else if result > 1 {
346 Err(Error::QueryReturnedMoreThanOneRow)
347 } else {
348 Ok(())
349 }
350 }
351
352 fn close_store(&self, _store_name: &str) -> Result<(), Self::Error> {
353 Ok(())
355 }
356
357 fn delete_database(self) -> Result<(), Self::Error> {
358 let _ = self.connection.close();
360 if self.db_path.exists() {
361 if let Err(e) = std::fs::remove_dir_all(self.db_path.parent().unwrap()) {
362 error!("Failed to delete database: {:?}", e);
363 }
364 }
365 Ok(())
366 }
367
368 fn process_transaction(
369 &self,
370 transaction: KvsTransaction,
371 ) -> oneshot::Receiver<Option<Vec<u8>>> {
372 let (tx, rx) = oneshot::channel();
373
374 let spawning_pool = if transaction.mode == IndexedDBTxnMode::Readonly {
375 self.read_pool.clone()
376 } else {
377 self.write_pool.clone()
378 };
379 let path = self.db_path.clone();
380 spawning_pool.spawn(move || {
381 let connection = Connection::open(path).unwrap();
382 for request in transaction.requests {
383 let object_store = connection
384 .prepare("SELECT * FROM object_store WHERE name = ?")
385 .and_then(|mut stmt| {
386 stmt.query_row(params![request.store_name.to_string()], |row| {
387 object_store_model::Model::try_from(row)
388 })
389 .optional()
390 });
391 fn process_object_store<T>(
392 object_store: Result<Option<object_store_model::Model>, Error>,
393 sender: &IpcSender<BackendResult<T>>,
394 ) -> Result<object_store_model::Model, ()>
395 where
396 T: Serialize,
397 {
398 match object_store {
399 Ok(Some(store)) => Ok(store),
400 Ok(None) => {
401 let _ = sender.send(Err(BackendError::StoreNotFound));
402 Err(())
403 },
404 Err(e) => {
405 let _ = sender.send(Err(BackendError::DbErr(format!("{:?}", e))));
406 Err(())
407 },
408 }
409 }
410
411 match request.operation {
412 AsyncOperation::ReadWrite(AsyncReadWriteOperation::PutItem {
413 sender,
414 key,
415 value,
416 should_overwrite,
417 }) => {
418 let Ok(object_store) = process_object_store(object_store, &sender) else {
419 continue;
420 };
421 let key = match key
422 .map(Ok)
423 .unwrap_or_else(|| Self::generate_key(&connection, &object_store))
424 {
425 Ok(key) => key,
426 Err(e) => {
427 let _ = sender.send(Err(BackendError::DbErr(format!("{:?}", e))));
428 continue;
429 },
430 };
431 let serialized_key: Vec<u8> = bincode::serialize(&key).unwrap();
432 let _ = sender.send(
433 Self::put_item(
434 &connection,
435 object_store,
436 serialized_key,
437 value,
438 should_overwrite,
439 )
440 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
441 );
442 },
443 AsyncOperation::ReadOnly(AsyncReadOnlyOperation::GetItem {
444 sender,
445 key_range,
446 }) => {
447 let Ok(object_store) = process_object_store(object_store, &sender) else {
448 continue;
449 };
450 let _ = sender.send(
451 Self::get_item(&connection, object_store, key_range)
452 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
453 );
454 },
455 AsyncOperation::ReadOnly(AsyncReadOnlyOperation::GetAllKeys {
456 sender,
457 key_range,
458 count,
459 }) => {
460 let Ok(object_store) = process_object_store(object_store, &sender) else {
461 continue;
462 };
463 let _ = sender.send(
464 Self::get_all_keys(&connection, object_store, key_range, count)
465 .map(|keys| {
466 keys.into_iter()
467 .map(|k| bincode::deserialize(&k).unwrap())
468 .collect()
469 })
470 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
471 );
472 },
473 AsyncOperation::ReadOnly(AsyncReadOnlyOperation::GetAllItems {
474 sender,
475 key_range,
476 count,
477 }) => {
478 let Ok(object_store) = process_object_store(object_store, &sender) else {
479 continue;
480 };
481 let _ = sender.send(
482 Self::get_all_items(&connection, object_store, key_range, count)
483 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
484 );
485 },
486 AsyncOperation::ReadWrite(AsyncReadWriteOperation::RemoveItem {
487 sender,
488 key_range,
489 }) => {
490 let Ok(object_store) = process_object_store(object_store, &sender) else {
491 continue;
492 };
493 let _ = sender.send(
494 Self::delete_item(&connection, object_store, key_range)
495 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
496 );
497 },
498 AsyncOperation::ReadOnly(AsyncReadOnlyOperation::Count {
499 sender,
500 key_range,
501 }) => {
502 let Ok(object_store) = process_object_store(object_store, &sender) else {
503 continue;
504 };
505 let _ = sender.send(
506 Self::count(&connection, object_store, key_range)
507 .map(|r| r as u64)
508 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
509 );
510 },
511 AsyncOperation::ReadOnly(AsyncReadOnlyOperation::Iterate {
512 sender,
513 key_range,
514 }) => {
515 let Ok(object_store) = process_object_store(object_store, &sender) else {
516 continue;
517 };
518 let _ = sender.send(
519 Self::get_all_records(&connection, object_store, key_range)
520 .map(|records| {
521 records
522 .into_iter()
523 .map(|(key, data)| IndexedDBRecord {
524 key: bincode::deserialize(&key).unwrap(),
525 primary_key: bincode::deserialize(&key).unwrap(),
526 value: data,
527 })
528 .collect()
529 })
530 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
531 );
532 },
533 AsyncOperation::ReadWrite(AsyncReadWriteOperation::Clear(sender)) => {
534 let Ok(object_store) = process_object_store(object_store, &sender) else {
535 continue;
536 };
537 let _ = sender.send(
538 Self::clear(&connection, object_store)
539 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
540 );
541 },
542 AsyncOperation::ReadOnly(AsyncReadOnlyOperation::GetKey {
543 sender,
544 key_range,
545 }) => {
546 let Ok(object_store) = process_object_store(object_store, &sender) else {
547 continue;
548 };
549 let _ = sender.send(
550 Self::get_key(&connection, object_store, key_range)
551 .map(|key| key.map(|k| bincode::deserialize(&k).unwrap()))
552 .map_err(|e| BackendError::DbErr(format!("{:?}", e))),
553 );
554 },
555 }
556 }
557 let _ = tx.send(None);
558 });
559 rx
560 }
561
562 fn has_key_generator(&self, store_name: &str) -> bool {
564 self.connection
565 .prepare("SELECT * FROM object_store WHERE name = ?")
566 .and_then(|mut stmt| {
567 stmt.query_row(params![store_name.to_string()], |r| {
568 let object_store = object_store_model::Model::try_from(r).unwrap();
569 Ok(object_store.auto_increment)
570 })
571 })
572 .optional()
573 .unwrap()
574 .unwrap_or_default() !=
576 0
577 }
578
579 fn key_path(&self, store_name: &str) -> Option<KeyPath> {
580 self.connection
581 .prepare("SELECT * FROM object_store WHERE name = ?")
582 .and_then(|mut stmt| {
583 stmt.query_row(params![store_name.to_string()], |r| {
584 let object_store = object_store_model::Model::try_from(r).unwrap();
585 Ok(object_store
586 .key_path
587 .map(|key_path| bincode::deserialize(&key_path).unwrap()))
588 })
589 })
590 .optional()
591 .unwrap()
592 .unwrap_or_default()
594 }
595
596 fn create_index(
597 &self,
598 store_name: &str,
599 index_name: String,
600 key_path: KeyPath,
601 unique: bool,
602 multi_entry: bool,
603 ) -> Result<CreateObjectResult, Self::Error> {
604 let object_store = self.connection.query_row(
605 "SELECT * FROM object_store WHERE name = ?",
606 params![store_name.to_string()],
607 |row| object_store_model::Model::try_from(row),
608 )?;
609
610 let index_exists: bool = self.connection.query_row(
611 "SELECT EXISTS(SELECT * FROM object_store_index WHERE name = ? AND object_store_id = ?)",
612 params![index_name.to_string(), object_store.id],
613 |row| row.get(0),
614 )?;
615 if index_exists {
616 return Ok(CreateObjectResult::AlreadyExists);
617 }
618
619 self.connection.execute(
620 "INSERT INTO object_store_index (object_store_id, name, key_path, unique_index, multi_entry_index)\
621 VALUES (?, ?, ?, ?, ?)",
622 params![
623 object_store.id,
624 index_name.to_string(),
625 bincode::serialize(&key_path).unwrap(),
626 unique,
627 multi_entry,
628 ],
629 )?;
630 Ok(CreateObjectResult::Created)
631 }
632
633 fn delete_index(&self, store_name: &str, index_name: String) -> Result<(), Self::Error> {
634 let object_store = self.connection.query_row(
635 "SELECT * FROM object_store WHERE name = ?",
636 params![store_name.to_string()],
637 |r| Ok(object_store_model::Model::try_from(r).unwrap()),
638 )?;
639
640 let _ = self.connection.execute(
642 "DELETE FROM object_store_index WHERE name = ? AND object_store_id = ?",
643 params![index_name.to_string(), object_store.id],
644 )?;
645 Ok(())
646 }
647
648 fn version(&self) -> Result<u64, Self::Error> {
649 let version: i64 =
650 self.connection
651 .query_row("SELECT version FROM database LIMIT 1", [], |row| row.get(0))?;
652 Ok(u64::from_ne_bytes(version.to_ne_bytes()))
653 }
654
655 fn set_version(&self, version: u64) -> Result<(), Self::Error> {
656 let rows_affected = self.connection.execute(
657 "UPDATE database SET version = ?",
658 params![i64::from_ne_bytes(version.to_ne_bytes())],
659 )?;
660 if rows_affected == 0 {
661 return Err(Error::QueryReturnedNoRows);
662 }
663 Ok(())
664 }
665}
666
667#[cfg(test)]
668mod tests {
669 use std::collections::VecDeque;
670 use std::sync::Arc;
671
672 use base::threadpool::ThreadPool;
673 use serde::{Deserialize, Serialize};
674 use servo_url::ImmutableOrigin;
675 use storage_traits::indexeddb::{
676 AsyncOperation, AsyncReadOnlyOperation, AsyncReadWriteOperation, CreateObjectResult,
677 IndexedDBKeyRange, IndexedDBKeyType, IndexedDBTxnMode, KeyPath, PutItemResult,
678 };
679 use url::Host;
680
681 use crate::indexeddb::IndexedDBDescription;
682 use crate::indexeddb::engines::{KvsEngine, KvsOperation, KvsTransaction, SqliteEngine};
683
684 fn test_origin() -> ImmutableOrigin {
685 ImmutableOrigin::Tuple(
686 "test_origin".to_string(),
687 Host::Domain("localhost".to_string()),
688 80,
689 )
690 }
691
692 fn get_pool() -> Arc<ThreadPool> {
693 Arc::new(ThreadPool::new(1, "test".to_string()))
694 }
695
696 #[test]
697 fn test_cycle() {
698 let base_dir = tempfile::tempdir().expect("Failed to create temp dir");
699 let thread_pool = get_pool();
700 let _ = SqliteEngine::new(
702 base_dir.path(),
703 &IndexedDBDescription {
704 name: "test_db".to_string(),
705 origin: test_origin(),
706 },
707 thread_pool.clone(),
708 )
709 .unwrap();
710 let db = SqliteEngine::new(
712 base_dir.path(),
713 &IndexedDBDescription {
714 name: "test_db".to_string(),
715 origin: test_origin(),
716 },
717 thread_pool.clone(),
718 )
719 .unwrap();
720 let version = db.version().expect("Failed to get version");
721 assert_eq!(version, 0);
722 db.set_version(5).unwrap();
723 let new_version = db.version().expect("Failed to get new version");
724 assert_eq!(new_version, 5);
725 db.delete_database().expect("Failed to delete database");
726 }
727
728 #[test]
729 fn test_create_store() {
730 let base_dir = tempfile::tempdir().expect("Failed to create temp dir");
731 let thread_pool = get_pool();
732 let db = SqliteEngine::new(
733 base_dir.path(),
734 &IndexedDBDescription {
735 name: "test_db".to_string(),
736 origin: test_origin(),
737 },
738 thread_pool,
739 )
740 .unwrap();
741 let store_name = "test_store";
742 let result = db.create_store(store_name, None, true);
743 assert!(result.is_ok());
744 let create_result = result.unwrap();
745 assert_eq!(create_result, CreateObjectResult::Created);
746 let result = db.create_store(store_name, None, false);
748 assert!(result.is_ok());
749 let create_result = result.unwrap();
750 assert_eq!(create_result, CreateObjectResult::AlreadyExists);
751 assert!(db.has_key_generator(store_name));
753 }
754
755 #[test]
756 fn test_create_store_empty_name() {
757 let base_dir = tempfile::tempdir().expect("Failed to create temp dir");
758 let thread_pool = get_pool();
759 let db = SqliteEngine::new(
760 base_dir.path(),
761 &IndexedDBDescription {
762 name: "test_db".to_string(),
763 origin: test_origin(),
764 },
765 thread_pool,
766 )
767 .unwrap();
768 let store_name = "";
769 let result = db.create_store(store_name, None, true);
770 assert!(result.is_ok());
771 let create_result = result.unwrap();
772 assert_eq!(create_result, CreateObjectResult::Created);
773 }
774
775 #[test]
776 fn test_injection() {
777 let base_dir = tempfile::tempdir().expect("Failed to create temp dir");
778 let thread_pool = get_pool();
779 let db = SqliteEngine::new(
780 base_dir.path(),
781 &IndexedDBDescription {
782 name: "test_db".to_string(),
783 origin: test_origin(),
784 },
785 thread_pool,
786 )
787 .unwrap();
788 let store_name1 = "test_store";
790 let result = db.create_store(store_name1, None, true);
791 assert!(result.is_ok());
792 let create_result = result.unwrap();
793 assert_eq!(create_result, CreateObjectResult::Created);
794 let store_name2 = "' OR 1=1 -- -";
796 let result = db.create_store(store_name2, None, false);
797 assert!(result.is_ok());
798 let create_result = result.unwrap();
799 assert_eq!(create_result, CreateObjectResult::Created);
800 }
801
802 #[test]
803 fn test_key_path() {
804 let base_dir = tempfile::tempdir().expect("Failed to create temp dir");
805 let thread_pool = get_pool();
806 let db = SqliteEngine::new(
807 base_dir.path(),
808 &IndexedDBDescription {
809 name: "test_db".to_string(),
810 origin: test_origin(),
811 },
812 thread_pool,
813 )
814 .unwrap();
815 let store_name = "test_store";
816 let result = db.create_store(store_name, Some(KeyPath::String("test".to_string())), true);
817 assert!(result.is_ok());
818 assert_eq!(
819 db.key_path(store_name),
820 Some(KeyPath::String("test".to_string()))
821 );
822 }
823
824 #[test]
825 fn test_delete_store() {
826 let base_dir = tempfile::tempdir().expect("Failed to create temp dir");
827 let thread_pool = get_pool();
828 let db = SqliteEngine::new(
829 base_dir.path(),
830 &IndexedDBDescription {
831 name: "test_db".to_string(),
832 origin: test_origin(),
833 },
834 thread_pool,
835 )
836 .unwrap();
837 db.create_store("test_store", None, false)
838 .expect("Failed to create store");
839 db.delete_store("test_store")
841 .expect("Failed to delete store");
842 let result = db.delete_store("test_store");
844 assert!(result.is_err());
845 let result = db.delete_store("test_store");
847 assert!(result.is_err());
849 }
850
851 #[test]
852 fn test_async_operations() {
853 fn get_channel<T>() -> (
854 ipc_channel::ipc::IpcSender<T>,
855 ipc_channel::ipc::IpcReceiver<T>,
856 )
857 where
858 T: for<'de> Deserialize<'de> + Serialize,
859 {
860 ipc_channel::ipc::channel().unwrap()
861 }
862
863 let base_dir = tempfile::tempdir().expect("Failed to create temp dir");
864 let thread_pool = get_pool();
865 let db = SqliteEngine::new(
866 base_dir.path(),
867 &IndexedDBDescription {
868 name: "test_db".to_string(),
869 origin: test_origin(),
870 },
871 thread_pool,
872 )
873 .unwrap();
874 let store_name = "test_store";
875 db.create_store(store_name, None, false)
876 .expect("Failed to create store");
877 let put = get_channel();
878 let put2 = get_channel();
879 let put3 = get_channel();
880 let put_dup = get_channel();
881 let get_item_some = get_channel();
882 let get_item_none = get_channel();
883 let get_all_items = get_channel();
884 let count = get_channel();
885 let remove = get_channel();
886 let clear = get_channel();
887 let rx = db.process_transaction(KvsTransaction {
888 mode: IndexedDBTxnMode::Readwrite,
889 requests: VecDeque::from(vec![
890 KvsOperation {
891 store_name: store_name.to_owned(),
892 operation: AsyncOperation::ReadWrite(AsyncReadWriteOperation::PutItem {
893 sender: put.0,
894 key: Some(IndexedDBKeyType::Number(1.0)),
895 value: vec![1, 2, 3],
896 should_overwrite: false,
897 }),
898 },
899 KvsOperation {
900 store_name: store_name.to_owned(),
901 operation: AsyncOperation::ReadWrite(AsyncReadWriteOperation::PutItem {
902 sender: put2.0,
903 key: Some(IndexedDBKeyType::String("2.0".to_string())),
904 value: vec![4, 5, 6],
905 should_overwrite: false,
906 }),
907 },
908 KvsOperation {
909 store_name: store_name.to_owned(),
910 operation: AsyncOperation::ReadWrite(AsyncReadWriteOperation::PutItem {
911 sender: put3.0,
912 key: Some(IndexedDBKeyType::Array(vec![
913 IndexedDBKeyType::String("3".to_string()),
914 IndexedDBKeyType::Number(0.0),
915 ])),
916 value: vec![7, 8, 9],
917 should_overwrite: false,
918 }),
919 },
920 KvsOperation {
922 store_name: store_name.to_owned(),
923 operation: AsyncOperation::ReadWrite(AsyncReadWriteOperation::PutItem {
924 sender: put_dup.0,
925 key: Some(IndexedDBKeyType::Number(1.0)),
926 value: vec![10, 11, 12],
927 should_overwrite: false,
928 }),
929 },
930 KvsOperation {
931 store_name: store_name.to_owned(),
932 operation: AsyncOperation::ReadOnly(AsyncReadOnlyOperation::GetItem {
933 sender: get_item_some.0,
934 key_range: IndexedDBKeyRange::only(IndexedDBKeyType::Number(1.0)),
935 }),
936 },
937 KvsOperation {
938 store_name: store_name.to_owned(),
939 operation: AsyncOperation::ReadOnly(AsyncReadOnlyOperation::GetItem {
940 sender: get_item_none.0,
941 key_range: IndexedDBKeyRange::only(IndexedDBKeyType::Number(5.0)),
942 }),
943 },
944 KvsOperation {
945 store_name: store_name.to_owned(),
946 operation: AsyncOperation::ReadOnly(AsyncReadOnlyOperation::GetAllItems {
947 sender: get_all_items.0,
948 key_range: IndexedDBKeyRange::lower_bound(
949 IndexedDBKeyType::Number(0.0),
950 false,
951 ),
952 count: None,
953 }),
954 },
955 KvsOperation {
956 store_name: store_name.to_owned(),
957 operation: AsyncOperation::ReadOnly(AsyncReadOnlyOperation::Count {
958 sender: count.0,
959 key_range: IndexedDBKeyRange::only(IndexedDBKeyType::Number(1.0)),
960 }),
961 },
962 KvsOperation {
963 store_name: store_name.to_owned(),
964 operation: AsyncOperation::ReadWrite(AsyncReadWriteOperation::RemoveItem {
965 sender: remove.0,
966 key_range: IndexedDBKeyRange::only(IndexedDBKeyType::Number(1.0)),
967 }),
968 },
969 KvsOperation {
970 store_name: store_name.to_owned(),
971 operation: AsyncOperation::ReadWrite(AsyncReadWriteOperation::Clear(clear.0)),
972 },
973 ]),
974 });
975 let _ = rx.blocking_recv().unwrap();
976 put.1.recv().unwrap().unwrap();
977 put2.1.recv().unwrap().unwrap();
978 put3.1.recv().unwrap().unwrap();
979 let err = put_dup.1.recv().unwrap().unwrap();
980 assert_eq!(err, PutItemResult::CannotOverwrite);
981 let get_result = get_item_some.1.recv().unwrap();
982 let value = get_result.unwrap();
983 assert_eq!(value, Some(vec![1, 2, 3]));
984 let get_result = get_item_none.1.recv().unwrap();
985 let value = get_result.unwrap();
986 assert_eq!(value, None);
987 let all_items = get_all_items.1.recv().unwrap().unwrap();
988 assert_eq!(all_items.len(), 3);
989 assert!(all_items.contains(&vec![1, 2, 3]));
991 assert!(all_items.contains(&vec![4, 5, 6]));
992 assert!(all_items.contains(&vec![7, 8, 9]));
993 let amount = count.1.recv().unwrap().unwrap();
994 assert_eq!(amount, 1);
995 remove.1.recv().unwrap().unwrap();
996 clear.1.recv().unwrap().unwrap();
997 }
998}