mirror of
https://github.com/servo/servo
synced 2026-04-26 01:25:32 +02:00
Due to old design choices, we had the layout of: ``` | - storage | - indexeddb | - mod.rs | - idb_thread.rs | - engines/ | - webstorage | - mod.rs | - webstorage_thread.rs | - engines/ ``` I merged the `*_thread` file into `mod.rs`, since `mod.rs` is pretty empty. This should be a better layout for when more threads are introduced. Testing: Refactor, none needed Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
105 lines
3.3 KiB
Rust
105 lines
3.3 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use base::threadpool::ThreadPool;
|
|
use log::error;
|
|
use rusqlite::Connection;
|
|
|
|
use crate::shared::{DB_INIT_PRAGMAS, DB_PRAGMAS};
|
|
use crate::webstorage::OriginEntry;
|
|
use crate::webstorage::engines::WebStorageEngine;
|
|
|
|
pub struct SqliteEngine {
|
|
connection: Connection,
|
|
}
|
|
|
|
impl SqliteEngine {
|
|
pub fn new(db_dir: &Option<PathBuf>, _pool: Arc<ThreadPool>) -> rusqlite::Result<Self> {
|
|
let connection = match db_dir {
|
|
Some(path) => {
|
|
let path = path.join("webstorage.sqlite");
|
|
Self::init_db(&path)?
|
|
},
|
|
None => Connection::open_in_memory()?,
|
|
};
|
|
// Initialize the database with necessary pragmas
|
|
for pragma in DB_PRAGMAS.iter() {
|
|
let _ = connection.execute(pragma, []);
|
|
}
|
|
Ok(SqliteEngine { connection })
|
|
}
|
|
|
|
pub fn init_db(path: &PathBuf) -> rusqlite::Result<Connection> {
|
|
if let Some(parent) = path.parent() {
|
|
let _ = std::fs::create_dir_all(parent);
|
|
}
|
|
let connection = Connection::open(path)?;
|
|
for pragma in DB_INIT_PRAGMAS.iter() {
|
|
let _ = connection.execute(pragma, []);
|
|
}
|
|
connection.execute("CREATE TABLE IF NOT EXISTS data (id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT, value TEXT);", [])?;
|
|
Ok(connection)
|
|
}
|
|
}
|
|
|
|
impl WebStorageEngine for SqliteEngine {
|
|
type Error = rusqlite::Error;
|
|
|
|
fn load(&self) -> Result<OriginEntry, Self::Error> {
|
|
let mut stmt = self.connection.prepare("SELECT key, value FROM data;")?;
|
|
let rows = stmt.query_map([], |row| {
|
|
let key: String = row.get(0)?;
|
|
let value: String = row.get(1)?;
|
|
Ok((key, value))
|
|
})?;
|
|
|
|
let mut map = OriginEntry::default();
|
|
for row in rows {
|
|
let (key, value) = row?;
|
|
map.insert(key, value);
|
|
}
|
|
Ok(map)
|
|
}
|
|
|
|
fn clear(&mut self) -> Result<(), Self::Error> {
|
|
self.connection.execute("DELETE FROM data;", [])?;
|
|
Ok(())
|
|
}
|
|
|
|
fn delete(&mut self, key: &str) -> Result<(), Self::Error> {
|
|
self.connection
|
|
.execute("DELETE FROM data WHERE key = ?;", [key])?;
|
|
Ok(())
|
|
}
|
|
|
|
fn set(&mut self, key: &str, value: &str) -> Result<(), Self::Error> {
|
|
// update or insert
|
|
self.connection.execute(
|
|
"INSERT INTO data (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value;",
|
|
[key, value],
|
|
)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn save(&mut self, data: &OriginEntry) {
|
|
fn save_inner(conn: &mut Connection, data: &OriginEntry) -> rusqlite::Result<()> {
|
|
let tx = conn.transaction()?;
|
|
tx.execute("DELETE FROM data;", [])?;
|
|
let mut stmt = tx.prepare("INSERT INTO data (key, value) VALUES (?, ?);")?;
|
|
for (key, value) in data.inner() {
|
|
stmt.execute(rusqlite::params![key, value])?;
|
|
}
|
|
drop(stmt);
|
|
tx.commit()?;
|
|
Ok(())
|
|
}
|
|
if let Err(e) = save_inner(&mut self.connection, data) {
|
|
error!("localstorage save error: {:?}", e);
|
|
}
|
|
}
|
|
}
|