extern crate linked_hash_set;
extern crate regex;
extern crate rusqlite;
extern crate serde;
extern crate serde_json;
use self::linked_hash_set::LinkedHashSet;
use self::regex::Regex;
use self::rusqlite::types::ToSql;
use self::rusqlite::{Connection, NO_PARAMS};
use std::iter::FromIterator;
use {KVStringI64, Note};
mod filter;
pub mod image;
mod search;
mod select;
mod utils;
pub use self::filter::{filter, filter_by_tag, filter_count};
pub use self::search::{search, search_by_day, search_by_tag, search_count};
pub use self::select::{select, select_by_day, select_by_tag, select_count};
pub fn sync_via_attach(conn: &Connection, uri: &str) -> String {
if let Ok(_) = conn.execute("attach ? as 'other'", &[uri]) {
match conn.execute_batch("BEGIN;
insert into note (title, url, tags, description, comments, annotations, created_at, is_public)
select title, url, tags, description, comments, annotations, created_at, is_public
from other.note
where not exists (
select 1 from note
where note.title = other.note.title
and note.url = other.note.url
and note.tags = other.note.tags
and note.description = other.note.description
and note.comments = other.note.comments
and note.annotations= other.note.annotations
and note.created_at = other.note.created_at
and note.is_public = other.note.is_public
);
insert into other.note (title, url, tags, description, comments, annotations, created_at, is_public)
select title, url, tags, description, comments, annotations, created_at, is_public
from note
where not exists (
select 1 from other.note as o
where o.title = note.title
and o.url = note.url
and o.tags = note.tags
and o.description = note.description
and o.comments = note.comments
and o.annotations= note.annotations
and o.created_at = note.created_at
and o.is_public = note.is_public
);
COMMIT;
detach database other;
"){
Ok(_) => {
format!(r#"{{"sync-via-attach-done": "{}"}}"#, uri)
}
Err(err) => {
eprintln!("Err {:?}", err);
format!(r#"{{"error": "{}"}}"#, err.to_string())
}
}
} else {
format!(r#"{{"error": "can not attach {}"}}"#, uri)
}
}
pub fn count(conn: &Connection, tbl: &str) -> i64 {
let mut stmt = conn
.prepare(&format!("select count(1) as cnt from {}", tbl))
.unwrap();
let rs = stmt.query_row(NO_PARAMS, |row| row.get(0)).unwrap();
rs
}
pub fn delete(conn: &Connection, rowid: i64) {
conn.execute("delete from note where rowid = ?1", &[&rowid])
.unwrap();
}
pub fn make_tags(input: &str) -> String {
let re1 = Regex::new(r",+").unwrap();
let re2 = Regex::new(r"\s+").unwrap();
let s1 = re1.replace_all(input, " ");
let s2 = re2.replace_all(s1.trim(), ",");
let v1 = s2.split(",");
let h1: LinkedHashSet<&str> = LinkedHashSet::from_iter(v1);
let mut s = "".to_string();
for e in h1 {
s.push_str(e);
s.push_str(",")
}
s.pop();
s.to_string()
}
pub fn insert(note: Note) {
let conn = &mut super::exe::get_sqlite_connection();
let tx = conn.transaction().unwrap();
{
tx.execute(
"
INSERT INTO note (title, url, tags, description, comments, annotations, created_at, is_public)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);
",
&[
¬e.title,
¬e.url,
&make_tags(¬e.tags),
¬e.description,
¬e.comments,
¬e.annotations,
¬e.created_at,
¬e.is_public as &ToSql,
],
).unwrap();
}
{
tx.execute(
"
UPDATE ssb SET is_last_note = 0
WHERE is_active_author = 1
",
NO_PARAMS,
)
.unwrap();
}
tx.commit().unwrap();
}
pub fn create(conn: &Connection) {
conn.execute_batch(
"BEGIN;
CREATE TABLE IF NOT EXISTS note (
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
url TEXT NOT NULL,
tags TEXT NOT NULL,
description TEXT NOT NULL,
comments TEXT NOT NULL,
annotations TEXT NOT NULL,
created_at TEXT NOT NULL,
is_public BOOLEAN NOT NULL default 0
);
CREATE TABLE IF NOT EXISTS ssb (
note_rowid INTEGER NOT NULL UNIQUE,
author TEXT PRIMARY KEY,
is_active_author BOOLEAN NOT NULL,
is_last_note BOOLEAN NOT NULL,
ts INTEGER NOT NULL,
seq INTEGER NOT NULL,
key TEXT NOT NULL,
prev TEXT NOT NULL
) WITHOUT ROWID;
COMMIT;",
)
.unwrap();
}
pub fn clear(conn: &Connection) {
conn.execute_batch(
"BEGIN;
drop TABLE IF EXISTS note;
drop TABLE IF EXISTS ssb;
COMMIT;
",
)
.unwrap();
}