diff --git a/Cargo.lock b/Cargo.lock
index 270337396..765e9af23 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -757,7 +757,6 @@ dependencies = [
"rmp",
"rmp-serde",
"rmpv",
- "rusqlite",
"serde",
"serde_derive",
"serde_json",
@@ -790,6 +789,7 @@ dependencies = [
"notify",
"notify-rust",
"reqwest",
+ "rusqlite",
"serde",
"serde_derive",
"serde_json",
diff --git a/Cargo.toml b/Cargo.toml
index 43792771a..c8e0a6c5c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,7 +44,6 @@ bincode = "1.2.0"
uuid = { version = "0.8.1", features = ["serde", "v4"] }
unicode-segmentation = "1.2.1" # >:c
libc = {version = "0.2.59", features = ["extra_traits",]}
-rusqlite = {version = "0.20.0", optional =true }
rmp = "^0.8"
rmpv = { version = "^0.4.2", features=["with-serde",] }
rmp-serde = "^0.14.0"
@@ -64,7 +63,7 @@ members = ["melib", "testing", ]
default = ["sqlite3", "notmuch"]
notmuch = ["melib/notmuch_backend", ]
jmap = ["melib/jmap_backend",]
-sqlite3 = ["rusqlite"]
+sqlite3 = ["melib/sqlite3"]
cli-docs = []
# Print tracing logs as meli runs in stderr
diff --git a/melib/Cargo.toml b/melib/Cargo.toml
index 64d77ca4a..feccd5a1e 100644
--- a/melib/Cargo.toml
+++ b/melib/Cargo.toml
@@ -40,11 +40,12 @@ reqwest = { version ="0.10.0-alpha.2", optional=true, features = ["json", "block
serde_json = { version = "1.0", optional = true, features = ["raw_value",] }
smallvec = { version = "1.1.0", features = ["serde", ] }
nix = "0.17.0"
+rusqlite = {version = "0.20.0", optional =true }
libloading = "0.5.2"
[features]
-default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard"]
+default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard", "sqlite3"]
debug-tracing = []
unicode_algorithms = ["unicode-segmentation"]
@@ -54,3 +55,4 @@ mbox_backend = ["notify", "notify-rust", "memmap"]
notmuch_backend = []
jmap_backend = ["reqwest", "serde_json" ]
vcard = []
+sqlite3 = ["rusqlite", ]
diff --git a/melib/src/lib.rs b/melib/src/lib.rs
index 2da14a5b2..3ffc3ac79 100644
--- a/melib/src/lib.rs
+++ b/melib/src/lib.rs
@@ -116,6 +116,9 @@ pub use crate::thread::*;
pub mod parsec;
pub mod search;
+#[cfg(feature = "sqlite3")]
+pub mod sqlite3;
+
#[macro_use]
extern crate serde_derive;
/* parser */
diff --git a/melib/src/sqlite3.rs b/melib/src/sqlite3.rs
new file mode 100644
index 000000000..20475be23
--- /dev/null
+++ b/melib/src/sqlite3.rs
@@ -0,0 +1,68 @@
+/*
+ * meli - melib
+ *
+ * Copyright 2020 Manos Pitsidianakis
+ *
+ * This file is part of meli.
+ *
+ * meli is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * meli is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with meli. If not, see .
+ */
+
+use crate::{error::*, logging::log};
+pub use rusqlite::{self, params, Connection};
+use std::path::PathBuf;
+
+pub fn db_path(name: &str) -> Result {
+ let data_dir =
+ xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?;
+ Ok(data_dir
+ .place_data_file(name)
+ .map_err(|e| MeliError::new(e.to_string()))?)
+}
+
+pub fn open_db(db_path: PathBuf) -> Result {
+ if !db_path.exists() {
+ return Err(MeliError::new("Database doesn't exist"));
+ }
+ Connection::open(&db_path).map_err(|e| MeliError::new(e.to_string()))
+}
+
+pub fn open_or_create_db(name: &str, init_script: Option<&str>) -> Result {
+ let db_path = db_path(name)?;
+ let mut set_mode = false;
+ if !db_path.exists() {
+ log(
+ format!("Creating {} database in {}", name, db_path.display()),
+ crate::INFO,
+ );
+ set_mode = true;
+ }
+ let conn = Connection::open(&db_path).map_err(|e| MeliError::new(e.to_string()))?;
+ if set_mode {
+ use std::os::unix::fs::PermissionsExt;
+ let file = std::fs::File::open(&db_path)?;
+ let metadata = file.metadata()?;
+ let mut permissions = metadata.permissions();
+
+ permissions.set_mode(0o600); // Read/write for owner only.
+ file.set_permissions(permissions)?;
+ }
+
+ if let Some(s) = init_script {
+ conn.execute_batch(s)
+ .map_err(|e| MeliError::new(e.to_string()))?;
+ }
+
+ Ok(conn)
+}
diff --git a/src/sqlite3.rs b/src/sqlite3.rs
index 6eec88844..69ac154f4 100644
--- a/src/sqlite3.rs
+++ b/src/sqlite3.rs
@@ -31,78 +31,17 @@ use melib::{
email::{Envelope, EnvelopeHash},
log,
thread::{SortField, SortOrder},
+ sqlite3::{self as melib_sqlite3, rusqlite::{self, params}},
MeliError, Result, ERROR,
};
-use rusqlite::{params, Connection};
+
use smallvec::SmallVec;
use std::convert::TryInto;
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
-pub fn db_path() -> Result {
- let data_dir =
- xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?;
- Ok(data_dir
- .place_data_file("index.db")
- .map_err(|e| MeliError::new(e.to_string()))?)
-}
-
-//#[inline(always)]
-//fn fts5_bareword(w: &str) -> Cow {
-// if w == "AND" || w == "OR" || w == "NOT" {
-// Cow::from(w)
-// } else {
-// if !w.is_ascii() {
-// Cow::from(format!("\"{}\"", escape_double_quote(w)))
-// } else {
-// for &b in w.as_bytes() {
-// if !(b > 0x2f && b < 0x3a)
-// || !(b > 0x40 && b < 0x5b)
-// || !(b > 0x60 && b < 0x7b)
-// || b != 0x60
-// || b != 26
-// {
-// return Cow::from(format!("\"{}\"", escape_double_quote(w)));
-// }
-// }
-// Cow::from(w)
-// }
-// }
-//}
-//
-pub fn open_db() -> Result {
- let db_path = db_path()?;
- if !db_path.exists() {
- return Err(MeliError::new(
- "Database hasn't been initialised. Run `reindex` command",
- ));
- }
- Connection::open(&db_path).map_err(|e| MeliError::new(e.to_string()))
-}
-
-pub fn open_or_create_db() -> Result {
- let db_path = db_path()?;
- let mut set_mode = false;
- if !db_path.exists() {
- log(
- format!("Creating index database in {}", db_path.display()),
- melib::INFO,
- );
- set_mode = true;
- }
- let conn = Connection::open(&db_path).map_err(|e| MeliError::new(e.to_string()))?;
- if set_mode {
- use std::os::unix::fs::PermissionsExt;
- let file = std::fs::File::open(&db_path)?;
- let metadata = file.metadata()?;
- let mut permissions = metadata.permissions();
-
- permissions.set_mode(0o600); // Read/write for owner only.
- file.set_permissions(permissions)?;
- }
-
- conn.execute_batch(
- "CREATE TABLE IF NOT EXISTS envelopes (
+const DB_NAME: &'static str = "index.db";
+const INIT_SCRIPT: &'static str = "CREATE TABLE IF NOT EXISTS envelopes (
id INTEGER PRIMARY KEY,
account_id INTEGER REFERENCES accounts ON UPDATE CASCADE,
hash BLOB NOT NULL UNIQUE,
@@ -164,19 +103,49 @@ END;
CREATE TRIGGER IF NOT EXISTS envelopes_au AFTER UPDATE ON envelopes BEGIN
INSERT INTO fts(fts, rowid, subject, body_text) VALUES('delete', old.id, old.subject, old.body_text);
INSERT INTO fts(rowid, subject, body_text) VALUES (new.id, new.subject, new.body_text);
-END; ",
- )
- .map_err(|e| MeliError::new(e.to_string()))?;
+END; ";
- Ok(conn)
+pub fn db_path() -> Result {
+ melib_sqlite3::db_path(DB_NAME)
}
+//#[inline(always)]
+//fn fts5_bareword(w: &str) -> Cow {
+// if w == "AND" || w == "OR" || w == "NOT" {
+// Cow::from(w)
+// } else {
+// if !w.is_ascii() {
+// Cow::from(format!("\"{}\"", escape_double_quote(w)))
+// } else {
+// for &b in w.as_bytes() {
+// if !(b > 0x2f && b < 0x3a)
+// || !(b > 0x40 && b < 0x5b)
+// || !(b > 0x60 && b < 0x7b)
+// || b != 0x60
+// || b != 26
+// {
+// return Cow::from(format!("\"{}\"", escape_double_quote(w)));
+// }
+// }
+// Cow::from(w)
+// }
+// }
+//}
+//
+//
pub fn insert(
envelope: &Envelope,
backend: &Arc>>,
acc_name: &str,
) -> Result<()> {
- let conn = open_db()?;
+ let db_path = melib_sqlite3::db_path(DB_NAME)?;
+ if !db_path.exists() {
+ return Err(MeliError::new(
+ "Database hasn't been initialised. Run `reindex` command",
+ ));
+ }
+
+ let conn = melib_sqlite3::open_db(db_path)?;
let backend_lck = backend.read().unwrap();
let op = backend_lck.operation(envelope.hash());
let body = match envelope.body(op) {
@@ -257,7 +226,14 @@ pub fn insert(
}
pub fn remove(env_hash: EnvelopeHash) -> Result<()> {
- let conn = open_db()?;
+ let db_path = melib_sqlite3::db_path(DB_NAME)?;
+ if !db_path.exists() {
+ return Err(MeliError::new(
+ "Database hasn't been initialised. Run `reindex` command",
+ ));
+ }
+
+ let conn = melib_sqlite3::open_db(db_path)?;
if let Err(err) = conn
.execute(
"DELETE FROM envelopes WHERE hash = ?",
@@ -310,7 +286,7 @@ pub fn index(context: &mut crate::state::Context, account_name: &str) -> Result<
account.backend.clone(),
)
};
- let conn = open_or_create_db()?;
+ let conn = melib_sqlite3::open_or_create_db(DB_NAME, Some(INIT_SCRIPT))?;
let work_context = context.work_controller().get_context();
let env_hashes = acc_mutex
.read()
@@ -421,7 +397,14 @@ pub fn search(
term: &str,
(sort_field, sort_order): (SortField, SortOrder),
) -> Result> {
- let conn = open_db()?;
+ let db_path = melib_sqlite3::db_path(DB_NAME)?;
+ if !db_path.exists() {
+ return Err(MeliError::new(
+ "Database hasn't been initialised. Run `reindex` command",
+ ));
+ }
+
+ let conn = melib_sqlite3::open_db(db_path)?;
let sort_field = match debug!(sort_field) {
SortField::Subject => "subject",