Files
appchk-app/main/DB/DBCommon.swift
relikd b17fb3c354 Refactoring I.
- Revamp whole DB to Display flow
- Filter Pipeline, arbitrary filtering and sorting
- Binary tree arrays for faster lookup & manipulation
- DB: introducing custom functions
- DB scheme: split req into heap & cache
- cache written by GlassVPN only
- heap written by Main App only
- Introducing DB separation: DBCore, DBCommon, DBAppOnly
- Introducing DB data sources: TestDataSource, GroupedDomainDataSource, RecordingsDB, DomainFilter
- Background sync: Move entries from cache to heap and notify all observers
- GlassVPN: Binary tree filter lookup
- GlassVPN: Reusing prepared statement
2020-06-02 21:45:08 +02:00

89 lines
2.4 KiB
Swift

import Foundation
import SQLite3
enum CreateTable {} // used for CREATE TABLE statements
extension SQLiteDatabase {
func initCommonScheme() {
try? run(sql: CreateTable.cache)
try? run(sql: CreateTable.filter)
}
}
// MARK: - transit
extension CreateTable {
/// `ts`: Timestamp, `dns`: String, `opt`: Int
static var cache: String {"""
CREATE TABLE IF NOT EXISTS cache(
ts INTEGER DEFAULT (strftime('%s','now')),
dns TEXT NOT NULL,
opt INTEGER
);
"""}
}
extension SQLiteDatabase {
/// `INSERT INTO cache (dns, opt) VALUES (?, ?);`
func logWritePrepare() throws -> OpaquePointer {
try prepare(sql: "INSERT INTO cache (dns, opt) VALUES (?, ?);")
}
/// `prep` must exist and be initialized with `logWritePrepare()`
func logWrite(_ pStmt: OpaquePointer!, _ domain: String, blocked: Bool = false) throws {
guard let prep = pStmt else {
return
}
try prepared(run: prep, bind: [BindText(domain), BindInt32(blocked ? 1 : 0)])
}
}
// MARK: - filter
extension CreateTable {
/// `domain`: String, `opt`: Int
static var filter: String {"""
CREATE TABLE IF NOT EXISTS filter(
domain TEXT UNIQUE NOT NULL,
opt INTEGER
);
"""}
}
struct FilterOptions: OptionSet {
let rawValue: Int32
static let none = FilterOptions([])
static let blocked = FilterOptions(rawValue: 1 << 0)
static let ignored = FilterOptions(rawValue: 1 << 1)
static let any = FilterOptions(rawValue: 0b11)
}
extension SQLiteDatabase {
func loadFilters(where matching: FilterOptions? = nil) -> [String : FilterOptions]? {
let rv = matching?.rawValue ?? 0
return try? run(sql: "SELECT domain, opt FROM filter \(rv>0 ? "WHERE opt & ?" : "");",
bind: rv>0 ? [BindInt32(rv)] : []) {
allRowsKeyed($0) {
(key: readText($0, 0) ?? "",
value: FilterOptions(rawValue: sqlite3_column_int($0, 1)))
}
}
}
func setFilter(_ domain: String, _ value: FilterOptions?) {
if let rv = value?.rawValue, rv > 0 {
try? run(sql: "INSERT OR REPLACE INTO filter (domain, opt) VALUES (?, ?);",
bind: [BindText(domain), BindInt32(rv)]) { _ = sqlite3_step($0) }
} else {
try? run(sql: "DELETE FROM filter WHERE domain = ? LIMIT 1;",
bind: [BindText(domain)]) { _ = sqlite3_step($0) }
}
}
// func loadFilterCount() -> (blocked: Int32, ignored: Int32)? {
// try? run(sql: "SELECT SUM(opt&1), SUM(opt&2)/2 FROM filter;") {
// try ifStep($0, SQLITE_ROW)
// return (sqlite3_column_int($0, 0), sqlite3_column_int($0, 1))
// }
// }
}