anotherim-desktop/qlite/src/table.vala

219 lines
7.3 KiB
Vala
Raw Normal View History

2017-03-02 14:37:32 +00:00
using Sqlite;
namespace Qlite {
public class Table {
protected Database db;
public string name { get; private set; }
2017-04-16 13:11:00 +00:00
protected Column[]? columns;
private string constraints = "";
2017-04-23 08:23:11 +00:00
private string[] post_statements = {};
2018-06-17 23:47:43 +00:00
private string[] create_statements = {};
internal Column[]? fts_columns;
2017-03-02 14:37:32 +00:00
public Table(Database db, string name) {
this.db = db;
this.name = name;
}
2017-04-16 13:11:00 +00:00
public void init(Column[] columns, string constraints = "") {
2017-03-02 14:37:32 +00:00
this.columns = columns;
2017-03-09 20:46:16 +00:00
this.constraints = constraints;
foreach(Column c in columns) {
c.table = this;
}
2017-03-09 20:46:16 +00:00
}
2018-06-17 23:47:43 +00:00
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())";
2018-06-17 23:47:43 +00:00
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) {
2019-12-15 18:03:02 +00:00
critical(@"Qlite Error: Rebuilding FTS index: $(e.message)");
2018-06-17 23:47:43 +00:00
}
}
2017-03-09 20:46:16 +00:00
public void unique(Column[] columns, string? on_conflict = null) {
2017-04-16 13:11:00 +00:00
constraints += ", UNIQUE (";
2017-03-09 20:46:16 +00:00
bool first = true;
foreach (Column c in columns) {
2017-03-09 20:46:16 +00:00
if (!first) constraints += ", ";
constraints += c.name;
first = false;
}
constraints += ")";
if (on_conflict != null) {
2017-05-21 21:30:30 +00:00
constraints += " ON CONFLICT " + (!)on_conflict;
2017-03-09 20:46:16 +00:00
}
2017-03-02 14:37:32 +00:00
}
2017-04-23 08:23:11 +00:00
public void add_post_statement(string stmt) {
post_statements += stmt;
}
2018-06-17 23:47:43 +00:00
public void add_create_statement(string stmt) {
create_statements += stmt;
}
2017-04-23 08:23:11 +00:00
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);
}
2017-10-28 21:48:07 +00:00
private void ensure_init() {
if (columns == null) error("Table %s was not initialized, call init()", name);
2017-03-02 14:37:32 +00:00
}
2017-10-28 21:48:07 +00:00
public QueryBuilder select(Column[]? columns = null) {
2017-03-02 14:37:32 +00:00
ensure_init();
return db.select(columns).from(this);
}
2018-06-17 23:47:43 +00:00
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);
}
2017-10-28 21:48:07 +00:00
public InsertBuilder insert() {
2017-03-02 14:37:32 +00:00
ensure_init();
return db.insert().into(this);
}
2017-10-28 21:48:07 +00:00
public UpdateBuilder update() {
2017-03-02 14:37:32 +00:00
ensure_init();
return db.update(this);
}
2017-10-28 21:48:07 +00:00
public UpsertBuilder upsert() {
2017-08-25 22:05:36 +00:00
ensure_init();
return db.upsert(this);
}
2017-10-28 21:48:07 +00:00
public DeleteBuilder delete() {
2017-03-02 14:37:32 +00:00
ensure_init();
return db.delete().from(this);
}
2017-10-28 21:48:07 +00:00
public RowOption row_with<T>(Column<T> column, T value) {
2017-03-02 14:37:32 +00:00
ensure_init();
2017-10-28 21:48:07 +00:00
if (!column.unique && !column.primary_key) error("%s is not suited to identify a row, but used with row_with()", column.name);
2017-03-02 14:37:32 +00:00
return select().with(column, "=", value).row();
}
2017-10-28 21:48:07 +00:00
public bool is_known_column(string column) {
2017-03-02 14:37:32 +00:00
ensure_init();
foreach (Column c in columns) {
if (c.name == column) return true;
}
return false;
}
2017-10-28 21:48:07 +00:00
public void create_table_at_version(long version) {
2017-03-02 14:37:32 +00:00
ensure_init();
string sql = @"CREATE TABLE IF NOT EXISTS $name (";
2018-06-19 10:26:31 +00:00
bool first = true;
for (int i = 0; i < columns.length; i++) {
2017-03-02 14:37:32 +00:00
Column c = columns[i];
if (c.min_version <= version && c.max_version >= version) {
sql += @"$(!first ? "," : "") $(c.to_column_definition())";
2018-06-19 10:26:31 +00:00
first = false;
2017-03-02 14:37:32 +00:00
}
}
2017-04-16 13:11:00 +00:00
sql += @"$constraints)";
2017-10-29 14:15:28 +00:00
try {
db.exec(sql);
} catch (Error e) {
error(@"Qlite Error: Create table at version: $(e.message)");
2017-10-29 14:15:28 +00:00
}
2018-06-17 23:47:43 +00:00
foreach (string stmt in create_statements) {
try {
db.exec(stmt);
} catch (Error e) {
error(@"Qlite Error: Create table at version: $(e.message)");
2018-06-17 23:47:43 +00:00
}
}
2017-03-02 14:37:32 +00:00
}
2017-10-28 21:48:07 +00:00
public void add_columns_for_version(long old_version, long new_version) {
2017-03-02 14:37:32 +00:00
ensure_init();
foreach (Column c in columns) {
if (c.min_version <= new_version && c.max_version >= new_version && c.min_version > old_version) {
2017-10-29 14:15:28 +00:00
try {
db.exec(@"ALTER TABLE $name ADD COLUMN $(c.to_column_definition())");
2017-10-29 14:15:28 +00:00
} catch (Error e) {
2019-12-15 18:03:02 +00:00
critical(@"Qlite Error: Add columns for version: $(e.message)");
2017-10-29 14:15:28 +00:00
}
2017-03-02 14:37:32 +00:00
}
}
}
2017-10-28 21:48:07 +00:00
public void delete_columns_for_version(long old_version, long new_version) {
bool column_deletion_required = false;
2017-04-16 13:11:00 +00:00
string column_list = "";
foreach (Column c in columns) {
if (c.min_version <= new_version && c.max_version >= new_version) {
2017-04-16 13:11:00 +00:00
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) {
2017-10-29 14:15:28 +00:00
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)");
2017-10-29 14:15:28 +00:00
}
}
2017-03-02 14:37:32 +00:00
}
2017-04-23 08:23:11 +00:00
2017-10-28 21:48:07 +00:00
internal void post() {
2017-04-23 08:23:11 +00:00
foreach (string stmt in post_statements) {
2017-10-29 14:15:28 +00:00
try {
db.exec(stmt);
} catch (Error e) {
error(@"Qlite Error: Post: $(e.message)");
2017-10-29 14:15:28 +00:00
}
2017-04-23 08:23:11 +00:00
}
}
2017-03-02 14:37:32 +00:00
}
2017-10-28 21:48:07 +00:00
}