aboutsummaryrefslogtreecommitdiff
path: root/libdino/src/qlite/table.vala
diff options
context:
space:
mode:
authorMarvin W <git@larma.de>2026-08-23 19:32:25 +0200
committerMarvin W <git@larma.de>2026-10-23 16:59:51 +0200
commit98ef191bfb3cc5694b9d1001e46a9b00abbd7195 (patch)
treeb6d30b203266afe44f0b5ae8aaf479960e361273 /libdino/src/qlite/table.vala
parentb0456e13ed35e6ebf684b3a7f4d1cb4b6ec352cc (diff)
Move qlite into libdino
Diffstat (limited to 'libdino/src/qlite/table.vala')
-rw-r--r--libdino/src/qlite/table.vala218
1 files changed, 218 insertions, 0 deletions
diff --git a/libdino/src/qlite/table.vala b/libdino/src/qlite/table.vala
new file mode 100644
index 00000000..3b75e22e
--- /dev/null
+++ b/libdino/src/qlite/table.vala
@@ -0,0 +1,218 @@
+using Sqlite;
+
+namespace Dino.Qlite {
+
+public class Table {
+ protected Database db;
+ public string name { get; private set; }
+ protected Column[]? columns;
+ private string constraints = "";
+ private string[] post_statements = {};
+ private string[] create_statements = {};
+ internal Column[]? fts_columns;
+
+ public Table(Database db, string name) {
+ this.db = db;
+ this.name = name;
+ }
+
+ public void init(Column[] columns, string constraints = "") {
+ this.columns = columns;
+ this.constraints = constraints;
+
+ foreach(Column c in columns) {
+ c.table = this;
+ }
+ }
+
+ public void fts(Column[] columns) {
+ if (fts_columns != null) error("Only one FTS index may be used per table.");
+ fts_columns = columns;
+ string cs = "";
+ string cnames = "";
+ string cnews = "";
+ foreach (Column c in columns) {
+ cs += @", $(c.to_column_definition())";
+ cnames += @", $(c.name)";
+ cnews += @", new.$(c.name)";
+ }
+ add_create_statement(@"CREATE VIRTUAL TABLE IF NOT EXISTS _fts_$name USING fts4(tokenize=unicode61, content=\"$name\"$cs)");
+ add_post_statement(@"CREATE TRIGGER IF NOT EXISTS _fts_bu_$(name) BEFORE UPDATE ON $name BEGIN DELETE FROM _fts_$name WHERE docid=old.rowid; END");
+ add_post_statement(@"CREATE TRIGGER IF NOT EXISTS _fts_bd_$(name) BEFORE DELETE ON $name BEGIN DELETE FROM _fts_$name WHERE docid=old.rowid; END");
+ add_post_statement(@"CREATE TRIGGER IF NOT EXISTS _fts_au_$(name) AFTER UPDATE ON $name BEGIN INSERT INTO _fts_$name(docid$cnames) VALUES(new.rowid$cnews); END");
+ add_post_statement(@"CREATE TRIGGER IF NOT EXISTS _fts_ai_$(name) AFTER INSERT ON $name BEGIN INSERT INTO _fts_$name(docid$cnames) VALUES(new.rowid$cnews); END");
+ }
+
+ public void fts_rebuild() {
+ if (fts_columns == null) error("FTS not available on this table.");
+ try {
+ db.exec(@"INSERT INTO _fts_$name(_fts_$name) VALUES('rebuild');");
+ } catch (Error e) {
+ critical(@"Qlite Error: Rebuilding FTS index: $(e.message)");
+ }
+ }
+
+ public void unique(Column[] columns, string? on_conflict = null) {
+ constraints += ", UNIQUE (";
+ bool first = true;
+ foreach (Column c in columns) {
+ if (!first) constraints += ", ";
+ constraints += c.name;
+ first = false;
+ }
+ constraints += ")";
+ if (on_conflict != null) {
+ constraints += " ON CONFLICT " + (!)on_conflict;
+ }
+ }
+
+ public void add_post_statement(string stmt) {
+ post_statements += stmt;
+ }
+
+ public void add_create_statement(string stmt) {
+ create_statements += stmt;
+ }
+
+ public void index(string index_name, Column[] columns, bool unique = false) {
+ string stmt = @"CREATE $(unique ? "UNIQUE" : "") INDEX IF NOT EXISTS $index_name ON $name (";
+ bool first = true;
+ foreach (Column c in columns) {
+ if (!first) stmt += ", ";
+ stmt += c.name;
+ first = false;
+ }
+ stmt += ")";
+ add_post_statement(stmt);
+ }
+
+ private void ensure_init() {
+ if (columns == null) error("Table %s was not initialized, call init()", name);
+ }
+
+ public QueryBuilder select(Column[]? columns = null) {
+ ensure_init();
+ return db.select(columns).from(this);
+ }
+
+ private MatchQueryBuilder match_query() {
+ ensure_init();
+ return db.match_query(this);
+ }
+
+ public MatchQueryBuilder match(Column<string> column, string query) {
+ return match_query().match(column, query);
+ }
+
+ public InsertBuilder insert() {
+ ensure_init();
+ return db.insert().into(this);
+ }
+
+ public UpdateBuilder update() {
+ ensure_init();
+ return db.update(this);
+ }
+
+ public UpsertBuilder upsert() {
+ ensure_init();
+ return db.upsert(this);
+ }
+
+ public DeleteBuilder delete() {
+ ensure_init();
+ return db.delete().from(this);
+ }
+
+ public RowOption row_with<T>(Column<T> column, T value) {
+ ensure_init();
+ if (!column.unique && !column.primary_key) error("%s is not suited to identify a row, but used with row_with()", column.name);
+ return select().with(column, "=", value).row();
+ }
+
+ public bool is_known_column(string column) {
+ ensure_init();
+ foreach (Column c in columns) {
+ if (c.name == column) return true;
+ }
+ return false;
+ }
+
+ public void create_table_at_version(long version) {
+ ensure_init();
+ string sql = @"CREATE TABLE IF NOT EXISTS $name (";
+ bool first = true;
+ for (int i = 0; i < columns.length; i++) {
+ Column c = columns[i];
+ if (c.min_version <= version && c.max_version >= version) {
+ sql += @"$(!first ? "," : "") $(c.to_column_definition())";
+ first = false;
+ }
+ }
+ sql += @"$constraints)";
+ try {
+ db.exec(sql);
+ } catch (Error e) {
+ error(@"Qlite Error: Create table at version: $(e.message)");
+ }
+ foreach (string stmt in create_statements) {
+ try {
+ db.exec(stmt);
+ } catch (Error e) {
+ error(@"Qlite Error: Create table at version: $(e.message)");
+ }
+ }
+ }
+
+ public void add_columns_for_version(long old_version, long new_version) {
+ ensure_init();
+ foreach (Column c in columns) {
+ if (c.min_version <= new_version && c.max_version >= new_version && c.min_version > old_version) {
+ try {
+ db.exec(@"ALTER TABLE $name ADD COLUMN $(c.to_column_definition())");
+ } catch (Error e) {
+ critical(@"Qlite Error: Add columns for version: $(e.message)");
+ }
+ }
+ }
+ }
+
+ public void delete_columns_for_version(long old_version, long new_version) {
+ bool column_deletion_required = false;
+ string column_list = "";
+ foreach (Column c in columns) {
+ if (c.min_version <= new_version && c.max_version >= new_version) {
+ if (column_list == "") {
+ column_list = c.name;
+ } else {
+ column_list += ", " + c.name;
+ }
+ }
+ if (!(c.min_version <= new_version && c.max_version >= new_version) && c.min_version <= old_version && c.max_version >= old_version) {
+ column_deletion_required = true;
+ }
+ }
+ if (column_deletion_required) {
+ try {
+ db.exec(@"ALTER TABLE $name RENAME TO _$(name)_$old_version");
+ create_table_at_version(new_version);
+ db.exec(@"INSERT INTO $name ($column_list) SELECT $column_list FROM _$(name)_$old_version");
+ db.exec(@"DROP TABLE _$(name)_$old_version");
+ } catch (Error e) {
+ error(@"Qlite Error: Delete columns for version change: $(e.message)");
+ }
+ }
+ }
+
+ internal void post() {
+ foreach (string stmt in post_statements) {
+ try {
+ db.exec(stmt);
+ } catch (Error e) {
+ error(@"Qlite Error: Post: $(e.message)");
+ }
+ }
+ }
+}
+
+}