From c2643a45b0dc05c4fd82ec7d32577700dae7450e Mon Sep 17 00:00:00 2001 From: Marvin W Date: Sun, 12 Mar 2017 19:33:31 +0100 Subject: Qlite: Return OptionalRow instead of Row?, add ability to remove columns on version upgrade --- qlite/src/database.vala | 20 ++++++++++-------- qlite/src/query_builder.vala | 18 ++++++++-------- qlite/src/row.vala | 49 +++++++++++++++++++++++++++++--------------- qlite/src/table.vala | 27 ++++++++++++++++++++---- 4 files changed, 77 insertions(+), 37 deletions(-) (limited to 'qlite/src') diff --git a/qlite/src/database.vala b/qlite/src/database.vala index 6d26b2b4..9fea7708 100644 --- a/qlite/src/database.vala +++ b/qlite/src/database.vala @@ -51,15 +51,19 @@ public class Database { meta_table.create_table_at_version(expected_version); long old_version = 0; try { - Row? row = meta_table.row_with(meta_name, "version"); - old_version = row == null ? -1 : (long) row[meta_int_val]; + old_version = meta_table.row_with(meta_name, "version")[meta_int_val, -1]; } catch (DatabaseError e) { old_version = -1; } - foreach (Table t in tables) { - t.create_table_at_version(old_version); - } - if (expected_version != old_version) { + if (old_version == -1) { + foreach (Table t in tables) { + t.create_table_at_version(expected_version); + } + meta_table.insert().value(meta_name, "version").value(meta_int_val, expected_version).perform(); + } else if (expected_version != old_version) { + foreach (Table t in tables) { + t.create_table_at_version(old_version); + } foreach (Table t in tables) { t.add_columns_for_version(old_version, expected_version); } @@ -117,9 +121,9 @@ public class Database { return new DeleteBuilder(this); } - public Row.RowIterator query_sql(string sql, string[]? args = null) throws DatabaseError { + public RowIterator query_sql(string sql, string[]? args = null) throws DatabaseError { ensure_init(); - return new Row.RowIterator(this, sql, args); + return new RowIterator(this, sql, args); } public Statement prepare(string sql) throws DatabaseError { diff --git a/qlite/src/query_builder.vala b/qlite/src/query_builder.vala index 65cbb8f6..37f9b261 100644 --- a/qlite/src/query_builder.vala +++ b/qlite/src/query_builder.vala @@ -131,20 +131,20 @@ public class QueryBuilder : StatementBuilder { public int64 count() throws DatabaseError { this.column_selector = @"COUNT($column_selector) AS count"; this.single_result = true; - return row().get_integer("count"); + return row_().get_integer("count"); } - public Row? row() throws DatabaseError { + private Row? row_() throws DatabaseError { if (!single_result) throw new DatabaseError.NON_UNIQUE("query is not suited to return a single row, but row() was called."); return iterator().next_value(); } + public RowOption row() throws DatabaseError { + return new RowOption(row_()); + } + public T get(Column field) throws DatabaseError { - Row row = row(); - if (row != null) { - return row[field]; - } - return null; + return row()[field]; } public override Statement prepare() throws DatabaseError { @@ -155,8 +155,8 @@ public class QueryBuilder : StatementBuilder { return stmt; } - public Row.RowIterator iterator() throws DatabaseError { - return new Row.RowIterator.from_query_builder(this); + public RowIterator iterator() throws DatabaseError { + return new RowIterator.from_query_builder(this); } class OrderingTerm { diff --git a/qlite/src/row.vala b/qlite/src/row.vala index ff98405f..de10751f 100644 --- a/qlite/src/row.vala +++ b/qlite/src/row.vala @@ -50,29 +50,46 @@ public class Row { public bool has_real(string field) { return real_map.has_key(field) && real_map[field] != null; } +} - public class RowIterator { - private Statement stmt; +public class RowIterator { + private Statement stmt; - public RowIterator.from_query_builder(QueryBuilder query) throws DatabaseError { - this.stmt = query.prepare(); - } + public RowIterator.from_query_builder(QueryBuilder query) throws DatabaseError { + this.stmt = query.prepare(); + } - public RowIterator(Database db, string sql, string[]? args = null) throws DatabaseError { - this.stmt = db.prepare(sql); - if (args != null) { - for (int i = 0; i < args.length; i++) { - stmt.bind_text(i, sql, sql.length); - } + public RowIterator(Database db, string sql, string[]? args = null) throws DatabaseError { + this.stmt = db.prepare(sql); + if (args != null) { + for (int i = 0; i < args.length; i++) { + stmt.bind_text(i, sql, sql.length); } } + } - public Row? next_value() { - if (stmt.step() == Sqlite.ROW) { - return new Row(stmt); - } - return null; + public Row? next_value() { + if (stmt.step() == Sqlite.ROW) { + return new Row(stmt); } + return null; + } +} + +public class RowOption { + public Row? inner { get; private set; } + + public RowOption(Row? row) { + this.inner = row; + } + + public bool is_present() { + return inner != null; + } + + public T get(Column field, T def = null) { + if (inner == null || field.is_null(inner)) return def; + return field[inner]; } } diff --git a/qlite/src/table.vala b/qlite/src/table.vala index 7396136e..357e18d4 100644 --- a/qlite/src/table.vala +++ b/qlite/src/table.vala @@ -22,7 +22,7 @@ public class Table { if (constraints == null) constraints = ""; else constraints += ", "; constraints += "UNIQUE ("; bool first = true; - foreach(Column c in columns) { + foreach (Column c in columns) { if (!first) constraints += ", "; constraints += c.name; first = false; @@ -57,7 +57,7 @@ public class Table { return db.delete().from(this); } - public Row? row_with(Column column, T value) throws DatabaseError { + public RowOption row_with(Column column, T value) throws DatabaseError { ensure_init(); if (!column.unique && !column.primary_key) throw new DatabaseError.NON_UNIQUE(@"$(column.name) is not suited to identify a row, but used with row_with()"); return select().with(column, "=", value).row(); @@ -74,7 +74,7 @@ public class Table { public void create_table_at_version(long version) throws DatabaseError { ensure_init(); string sql = @"CREATE TABLE IF NOT EXISTS $name ("; - for(int i = 0; i < columns.length; i++) { + for (int i = 0; i < columns.length; i++) { Column c = columns[i]; if (c.min_version <= version && c.max_version >= version) { sql += @"$(i > 0 ? "," : "") $c"; @@ -97,7 +97,26 @@ public class Table { } public void delete_columns_for_version(long old_version, long new_version) throws DatabaseError { - // TODO: Rename old table, create table at new_version, transfer data + bool column_deletion_required = false; + string column_list = null; + foreach (Column c in columns) { + if (c.min_version <= new_version && c.max_version >= new_version) { + if (column_list == null) { + 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) { + 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"); + } } } -- cgit v1.2.3-70-g09d2