qlite: cleanup, fix nullity issues
This commit is contained in:
parent
c6ff3387fa
commit
765c2605cd
|
@ -4,12 +4,12 @@ namespace Qlite {
|
||||||
|
|
||||||
public abstract class Column<T> {
|
public abstract class Column<T> {
|
||||||
public string name { get; private set; }
|
public string name { get; private set; }
|
||||||
public string default { get; set; }
|
public string? default { get; set; }
|
||||||
public int sqlite_type { get; private set; }
|
public int sqlite_type { get; private set; }
|
||||||
public bool primary_key { get; set; }
|
public bool primary_key { get; set; }
|
||||||
public bool auto_increment { get; set; }
|
public bool auto_increment { get; set; }
|
||||||
public bool unique { get; set; }
|
public bool unique { get; set; }
|
||||||
public bool not_null { get; set; }
|
public virtual bool not_null { get; set; }
|
||||||
public long min_version { get; set; default = -1; }
|
public long min_version { get; set; default = -1; }
|
||||||
public long max_version { get; set; default = long.MAX; }
|
public long max_version { get; set; default = long.MAX; }
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public abstract class Column<T> {
|
||||||
}
|
}
|
||||||
if (not_null) res += " NOT NULL";
|
if (not_null) res += " NOT NULL";
|
||||||
if (unique) res += " UNIQUE";
|
if (unique) res += " UNIQUE";
|
||||||
if (default != null) res += @" DEFAULT $default";
|
if (default != null) res += @" DEFAULT $((!) default)";
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -122,13 +122,33 @@ public abstract class Column<T> {
|
||||||
|
|
||||||
internal override void bind(Statement stmt, int index, string? value) {
|
internal override void bind(Statement stmt, int index, string? value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
stmt.bind_text(index, value);
|
stmt.bind_text(index, (!) value);
|
||||||
} else {
|
} else {
|
||||||
stmt.bind_null(index);
|
stmt.bind_null(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NonNullText : Column<string> {
|
||||||
|
public NonNullText(string name) {
|
||||||
|
base(name, TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool not_null { get { return true; } set {} }
|
||||||
|
|
||||||
|
public override string get(Row row) {
|
||||||
|
return (!)row.get_text(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool is_null(Row row) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void bind(Statement stmt, int index, string value) {
|
||||||
|
stmt.bind_text(index, (!) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class BoolText : Column<bool> {
|
public class BoolText : Column<bool> {
|
||||||
public BoolText(string name) {
|
public BoolText(string name) {
|
||||||
base(name, TEXT);
|
base(name, TEXT);
|
||||||
|
|
|
@ -17,11 +17,11 @@ public class Database {
|
||||||
private string file_name;
|
private string file_name;
|
||||||
private Sqlite.Database db;
|
private Sqlite.Database db;
|
||||||
private long expected_version;
|
private long expected_version;
|
||||||
private Table[] tables;
|
private Table[]? tables;
|
||||||
|
|
||||||
private Column<string> meta_name = new Column.Text("name") { primary_key = true };
|
private Column<string?> meta_name = new Column.Text("name") { primary_key = true };
|
||||||
private Column<long> meta_int_val = new Column.Long("int_val");
|
private Column<long> meta_int_val = new Column.Long("int_val");
|
||||||
private Column<string> meta_text_val = new Column.Text("text_val");
|
private Column<string?> meta_text_val = new Column.Text("text_val");
|
||||||
private Table meta_table;
|
private Table meta_table;
|
||||||
|
|
||||||
public bool debug = false;
|
public bool debug = false;
|
||||||
|
|
|
@ -5,12 +5,12 @@ namespace Qlite {
|
||||||
public class DeleteBuilder : StatementBuilder {
|
public class DeleteBuilder : StatementBuilder {
|
||||||
|
|
||||||
// DELETE FROM [...]
|
// DELETE FROM [...]
|
||||||
private Table table;
|
private Table? table;
|
||||||
private string table_name;
|
private string table_name;
|
||||||
|
|
||||||
// WHERE [...]
|
// WHERE [...]
|
||||||
private string selection;
|
private string selection = "1";
|
||||||
private StatementBuilder.Field[] selection_args;
|
private StatementBuilder.AbstractField[] selection_args = {};
|
||||||
|
|
||||||
internal DeleteBuilder(Database db) {
|
internal DeleteBuilder(Database db) {
|
||||||
base(db);
|
base(db);
|
||||||
|
@ -29,35 +29,22 @@ public class DeleteBuilder : StatementBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteBuilder where(string selection, string[]? selection_args = null) throws DatabaseError {
|
public DeleteBuilder where(string selection, string[]? selection_args = null) throws DatabaseError {
|
||||||
if (this.selection != null) throw new DatabaseError.ILLEGAL_QUERY("selection was already done, but where() was called.");
|
if (this.selection != "1") throw new DatabaseError.ILLEGAL_QUERY("selection was already done, but where() was called.");
|
||||||
this.selection = selection;
|
this.selection = selection;
|
||||||
if (selection_args != null) {
|
foreach (string arg in selection_args) {
|
||||||
this.selection_args = new StatementBuilder.Field[selection_args.length];
|
this.selection_args += new StatementBuilder.StringField(arg);
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
|
||||||
this.selection_args[i] = new StatementBuilder.StringField(selection_args[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteBuilder with<T>(Column<T> column, string comp, T value) {
|
public DeleteBuilder with<T>(Column<T> column, string comp, T value) {
|
||||||
if (selection == null) {
|
selection_args += new Field<T>(column, value);
|
||||||
selection = @"$(column.name) $comp ?";
|
|
||||||
selection_args = { new StatementBuilder.Field<T>(column, value) };
|
|
||||||
} else {
|
|
||||||
selection = @"($selection) AND $(column.name) $comp ?";
|
selection = @"($selection) AND $(column.name) $comp ?";
|
||||||
StatementBuilder.Field[] selection_args_new = new StatementBuilder.Field[selection_args.length+1];
|
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
|
||||||
selection_args_new[i] = selection_args[i];
|
|
||||||
}
|
|
||||||
selection_args_new[selection_args.length] = new Field<T>(column, value);
|
|
||||||
selection_args = selection_args_new;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override Statement prepare() throws DatabaseError {
|
internal override Statement prepare() throws DatabaseError {
|
||||||
Statement stmt = db.prepare(@"DELETE FROM $table_name $(selection != null ? @"WHERE $selection": "")");
|
Statement stmt = db.prepare(@"DELETE FROM $table_name WHERE $selection");
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
for (int i = 0; i < selection_args.length; i++) {
|
||||||
selection_args[i].bind(stmt, i+1);
|
selection_args[i].bind(stmt, i+1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@ public class InsertBuilder : StatementBuilder {
|
||||||
|
|
||||||
// INSERT [OR ...]
|
// INSERT [OR ...]
|
||||||
private bool replace_val;
|
private bool replace_val;
|
||||||
private string or_val;
|
private string? or_val;
|
||||||
|
|
||||||
// INTO [...]
|
// INTO [...]
|
||||||
private Table table;
|
private Table table;
|
||||||
private string table_name;
|
private string table_name;
|
||||||
|
|
||||||
// VALUES [...]
|
// VALUES [...]
|
||||||
private StatementBuilder.Field[] fields;
|
private StatementBuilder.AbstractField[] fields = {};
|
||||||
|
|
||||||
internal InsertBuilder(Database db) {
|
internal InsertBuilder(Database db) {
|
||||||
base(db);
|
base(db);
|
||||||
|
@ -41,31 +41,13 @@ public class InsertBuilder : StatementBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertBuilder value<T>(Column<T> column, T value) {
|
public InsertBuilder value<T>(Column<T> column, T value) {
|
||||||
if (fields == null) {
|
fields += new Field<T>(column, value);
|
||||||
fields = { new StatementBuilder.Field<T>(column, value) };
|
|
||||||
} else {
|
|
||||||
StatementBuilder.Field[] fields_new = new StatementBuilder.Field[fields.length+1];
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
|
||||||
fields_new[i] = fields[i];
|
|
||||||
}
|
|
||||||
fields_new[fields.length] = new Field<T>(column, value);
|
|
||||||
fields = fields_new;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertBuilder value_null<T>(Column<T> column) throws DatabaseError {
|
public InsertBuilder value_null<T>(Column<T> column) throws DatabaseError {
|
||||||
if (column.not_null) throw new DatabaseError.ILLEGAL_QUERY(@"Can't set non-null column $(column.name) to null");
|
if (column.not_null) throw new DatabaseError.ILLEGAL_QUERY(@"Can't set non-null column $(column.name) to null");
|
||||||
if (fields == null) {
|
fields += new NullField<T>(column);
|
||||||
fields = { new NullField<T>(column) };
|
|
||||||
} else {
|
|
||||||
StatementBuilder.Field[] fields_new = new StatementBuilder.Field[fields.length+1];
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
|
||||||
fields_new[i] = fields[i];
|
|
||||||
}
|
|
||||||
fields_new[fields.length] = new NullField<T>(column);
|
|
||||||
fields = fields_new;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,11 +59,11 @@ public class InsertBuilder : StatementBuilder {
|
||||||
value_qs += ", ";
|
value_qs += ", ";
|
||||||
fields_text += ", ";
|
fields_text += ", ";
|
||||||
}
|
}
|
||||||
fields_text += fields[i].column.name;
|
fields_text += ((!)fields[i].column).name;
|
||||||
value_qs += "?";
|
value_qs += "?";
|
||||||
}
|
}
|
||||||
string sql = replace_val ? "REPLACE" : "INSERT";
|
string sql = replace_val ? "REPLACE" : "INSERT";
|
||||||
if (!replace_val && or_val != null) sql += @" OR $or_val";
|
if (!replace_val && or_val != null) sql += @" OR $((!)or_val)";
|
||||||
sql += @" INTO $table_name ( $fields_text ) VALUES ($value_qs)";
|
sql += @" INTO $table_name ( $fields_text ) VALUES ($value_qs)";
|
||||||
Statement stmt = db.prepare(sql);
|
Statement stmt = db.prepare(sql);
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
|
|
|
@ -7,18 +7,18 @@ public class QueryBuilder : StatementBuilder {
|
||||||
|
|
||||||
// SELECT [...]
|
// SELECT [...]
|
||||||
private string column_selector = "*";
|
private string column_selector = "*";
|
||||||
private Column[] columns;
|
private Column[] columns = {};
|
||||||
|
|
||||||
// FROM [...]
|
// FROM [...]
|
||||||
private Table table;
|
private Table? table;
|
||||||
private string table_name;
|
private string? table_name;
|
||||||
|
|
||||||
// WHERE [...]
|
// WHERE [...]
|
||||||
private string selection;
|
private string selection = "1";
|
||||||
private StatementBuilder.Field[] selection_args;
|
private StatementBuilder.AbstractField[] selection_args = {};
|
||||||
|
|
||||||
// ORDER BY [...]
|
// ORDER BY [...]
|
||||||
private OrderingTerm[] order_by_terms;
|
private OrderingTerm[]? order_by_terms = {};
|
||||||
|
|
||||||
// LIMIT [...]
|
// LIMIT [...]
|
||||||
private int limit_val;
|
private int limit_val;
|
||||||
|
@ -27,9 +27,9 @@ public class QueryBuilder : StatementBuilder {
|
||||||
base(db);
|
base(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryBuilder select(Column[]? columns = null) {
|
public QueryBuilder select(Column[] columns = {}) {
|
||||||
this.columns = columns;
|
this.columns = columns;
|
||||||
if (columns != null) {
|
if (columns.length == 0) {
|
||||||
for (int i = 0; i < columns.length; i++) {
|
for (int i = 0; i < columns.length; i++) {
|
||||||
if (column_selector == "*") {
|
if (column_selector == "*") {
|
||||||
column_selector = columns[0].name;
|
column_selector = columns[0].name;
|
||||||
|
@ -44,7 +44,7 @@ public class QueryBuilder : StatementBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryBuilder select_string(string column_selector) {
|
public QueryBuilder select_string(string column_selector) {
|
||||||
this.columns = null;
|
this.columns = {};
|
||||||
this.column_selector = column_selector;
|
this.column_selector = column_selector;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -61,32 +61,19 @@ public class QueryBuilder : StatementBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryBuilder where(string selection, string[]? selection_args = null) throws DatabaseError {
|
public QueryBuilder where(string selection, string[] selection_args = {}) throws DatabaseError {
|
||||||
if (this.selection != null) throw new DatabaseError.ILLEGAL_QUERY("selection was already done, but where() was called.");
|
if (this.selection != "1") throw new DatabaseError.ILLEGAL_QUERY("selection was already done, but where() was called.");
|
||||||
this.selection = selection;
|
this.selection = selection;
|
||||||
if (selection_args != null) {
|
foreach (string arg in selection_args) {
|
||||||
this.selection_args = new StatementBuilder.Field[selection_args.length];
|
this.selection_args += new StatementBuilder.StringField(arg);
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
|
||||||
this.selection_args[i] = new StatementBuilder.StringField(selection_args[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryBuilder with<T>(Column<T> column, string comp, T value) {
|
public QueryBuilder with<T>(Column<T> column, string comp, T value) {
|
||||||
if ((column.unique || column.primary_key) && comp == "=") single_result = true;
|
if ((column.unique || column.primary_key) && comp == "=") single_result = true;
|
||||||
if (selection == null) {
|
selection_args += new Field<T>(column, value);
|
||||||
selection = @"$(column.name) $comp ?";
|
|
||||||
selection_args = { new StatementBuilder.Field<T>(column, value) };
|
|
||||||
} else {
|
|
||||||
selection = @"($selection) AND $(column.name) $comp ?";
|
selection = @"($selection) AND $(column.name) $comp ?";
|
||||||
StatementBuilder.Field[] selection_args_new = new StatementBuilder.Field[selection_args.length+1];
|
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
|
||||||
selection_args_new[i] = selection_args[i];
|
|
||||||
}
|
|
||||||
selection_args_new[selection_args.length] = new Field<T>(column, value);
|
|
||||||
selection_args = selection_args_new;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,26 +87,13 @@ public class QueryBuilder : StatementBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add_order_by(OrderingTerm term) {
|
|
||||||
if (order_by_terms == null) {
|
|
||||||
order_by_terms = { term };
|
|
||||||
} else {
|
|
||||||
OrderingTerm[] order_by_terms_new = new OrderingTerm[order_by_terms.length+1];
|
|
||||||
for (int i = 0; i < order_by_terms.length; i++) {
|
|
||||||
order_by_terms_new[i] = order_by_terms[i];
|
|
||||||
}
|
|
||||||
order_by_terms_new[order_by_terms.length] = term;
|
|
||||||
order_by_terms = order_by_terms_new;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueryBuilder order_by(Column column, string dir = "ASC") {
|
public QueryBuilder order_by(Column column, string dir = "ASC") {
|
||||||
add_order_by(new OrderingTerm(column, dir));
|
order_by_terms += new OrderingTerm(column, dir);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryBuilder order_by_name(string name, string dir) {
|
public QueryBuilder order_by_name(string name, string dir) {
|
||||||
add_order_by(new OrderingTerm.by_name(name, dir));
|
order_by_terms += new OrderingTerm.by_name(name, dir);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,12 +105,12 @@ public class QueryBuilder : StatementBuilder {
|
||||||
public int64 count() throws DatabaseError {
|
public int64 count() throws DatabaseError {
|
||||||
this.column_selector = @"COUNT($column_selector) AS count";
|
this.column_selector = @"COUNT($column_selector) AS count";
|
||||||
this.single_result = true;
|
this.single_result = true;
|
||||||
return row_().get_integer("count");
|
return row().get_integer("count");
|
||||||
}
|
}
|
||||||
|
|
||||||
private 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.");
|
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();
|
return iterator().get_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RowOption row() throws DatabaseError {
|
public RowOption row() throws DatabaseError {
|
||||||
|
@ -148,7 +122,7 @@ public class QueryBuilder : StatementBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override Statement prepare() throws DatabaseError {
|
internal override Statement prepare() throws DatabaseError {
|
||||||
Statement stmt = db.prepare(@"SELECT $column_selector FROM $table_name $(selection != null ? @"WHERE $selection" : "") $(order_by_terms != null ? OrderingTerm.all_to_string(order_by_terms) : "") $(limit_val > 0 ? @" LIMIT $limit_val" : "")");
|
Statement stmt = db.prepare(@"SELECT $column_selector $(table_name == null ? "" : @"FROM $((!) table_name)") WHERE $selection $(OrderingTerm.all_to_string(order_by_terms)) $(limit_val > 0 ? @" LIMIT $limit_val" : "")");
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
for (int i = 0; i < selection_args.length; i++) {
|
||||||
selection_args[i].bind(stmt, i+1);
|
selection_args[i].bind(stmt, i+1);
|
||||||
}
|
}
|
||||||
|
@ -179,8 +153,8 @@ public class QueryBuilder : StatementBuilder {
|
||||||
return @"$column_name $dir";
|
return @"$column_name $dir";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string all_to_string(OrderingTerm[] terms) {
|
public static string all_to_string(OrderingTerm[]? terms) {
|
||||||
if (terms.length == 0) return "";
|
if (terms == null || terms.length == 0) return "";
|
||||||
string res = "ORDER BY "+terms[0].to_string();
|
string res = "ORDER BY "+terms[0].to_string();
|
||||||
for (int i = 1; i < terms.length; i++) {
|
for (int i = 1; i < terms.length; i++) {
|
||||||
res += @", $(terms[i])";
|
res += @", $(terms[i])";
|
||||||
|
|
|
@ -4,7 +4,7 @@ using Sqlite;
|
||||||
namespace Qlite {
|
namespace Qlite {
|
||||||
|
|
||||||
public class Row {
|
public class Row {
|
||||||
private Map<string, string> text_map = new HashMap<string, string>();
|
private Map<string, string?> text_map = new HashMap<string, string?>();
|
||||||
private Map<string, long> int_map = new HashMap<string, long>();
|
private Map<string, long> int_map = new HashMap<string, long>();
|
||||||
private Map<string, double?> real_map = new HashMap<string, double?>();
|
private Map<string, double?> real_map = new HashMap<string, double?>();
|
||||||
|
|
||||||
|
@ -43,8 +43,8 @@ public class Row {
|
||||||
return int_map.has_key(field);
|
return int_map.has_key(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double get_real(string field) {
|
public double get_real(string field, double def = 0) {
|
||||||
return real_map[field];
|
return real_map[field] ?? def;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool has_real(string field) {
|
public bool has_real(string field) {
|
||||||
|
@ -71,11 +71,21 @@ public class RowIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Row? next_value() throws DatabaseError {
|
public bool next() {
|
||||||
int r = stmt.step();
|
int r = stmt.step();
|
||||||
if (r == Sqlite.ROW) return new Row(stmt);
|
if (r == Sqlite.ROW) return true;
|
||||||
if (r == Sqlite.DONE) return null;
|
if (r == Sqlite.DONE) return false;
|
||||||
throw new DatabaseError.EXEC_ERROR(@"SQLite error: $(db.errcode()) - $(db.errmsg())");
|
print(@"SQLite error: $(db.errcode()) - $(db.errmsg())\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Row get() {
|
||||||
|
return new Row(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Row? get_next() {
|
||||||
|
if (next()) return get();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +101,13 @@ public class RowOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
public T get<T>(Column<T> field, T def = null) {
|
public T get<T>(Column<T> field, T def = null) {
|
||||||
if (inner == null || field.is_null(inner)) return def;
|
if (inner == null || field.is_null((!)inner)) return def;
|
||||||
return field[inner];
|
return field[(!)inner];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal long get_integer(string field, long def = 0) {
|
||||||
|
if (inner == null || !((!)inner).has_integer(field)) return def;
|
||||||
|
return ((!)inner).get_integer(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,25 +11,32 @@ public abstract class StatementBuilder {
|
||||||
|
|
||||||
internal abstract Statement prepare() throws DatabaseError;
|
internal abstract Statement prepare() throws DatabaseError;
|
||||||
|
|
||||||
internal class Field<T> {
|
internal abstract class AbstractField<T> {
|
||||||
public T value;
|
public T value;
|
||||||
public Column<T>? column;
|
public Column<T>? column;
|
||||||
|
|
||||||
public Field(Column<T>? column, T value) {
|
public AbstractField(T value) {
|
||||||
this.column = column;
|
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual void bind(Statement stmt, int index) {
|
internal abstract void bind(Statement stmt, int index);
|
||||||
if (column != null) {
|
|
||||||
column.bind(stmt, index, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class Field<T> : AbstractField<T> {
|
||||||
|
public Field(Column<T> column, T value) {
|
||||||
|
base(value);
|
||||||
|
this.column = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void bind(Statement stmt, int index) {
|
||||||
|
((!)column).bind(stmt, index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NullField<T> : Field<T> {
|
internal class NullField<T> : AbstractField<T> {
|
||||||
public NullField(Column<T>? column) {
|
public NullField(Column<T> column) {
|
||||||
base(column, null);
|
base(null);
|
||||||
|
this.column = column;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void bind(Statement stmt, int index) {
|
internal override void bind(Statement stmt, int index) {
|
||||||
|
@ -37,9 +44,9 @@ public abstract class StatementBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class StringField : Field<string> {
|
internal class StringField : AbstractField<string> {
|
||||||
public StringField(string value) {
|
public StringField(string value) {
|
||||||
base(null, value);
|
base(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void bind(Statement stmt, int index) {
|
internal override void bind(Statement stmt, int index) {
|
||||||
|
|
|
@ -5,22 +5,21 @@ namespace Qlite {
|
||||||
public class Table {
|
public class Table {
|
||||||
protected Database db;
|
protected Database db;
|
||||||
public string name { get; private set; }
|
public string name { get; private set; }
|
||||||
protected Column[] columns;
|
protected Column[]? columns;
|
||||||
private string constraints;
|
private string constraints = "";
|
||||||
|
|
||||||
public Table(Database db, string name) {
|
public Table(Database db, string name) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Column[] columns, string? constraints = null) {
|
public void init(Column[] columns, string constraints = "") {
|
||||||
this.columns = columns;
|
this.columns = columns;
|
||||||
this.constraints = constraints;
|
this.constraints = constraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unique(Column[] columns, string? on_conflict = null) {
|
public void unique(Column[] columns, string? on_conflict = null) {
|
||||||
if (constraints == null) constraints = ""; else constraints += ", ";
|
constraints += ", UNIQUE (";
|
||||||
constraints += "UNIQUE (";
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
foreach (Column c in columns) {
|
foreach (Column c in columns) {
|
||||||
if (!first) constraints += ", ";
|
if (!first) constraints += ", ";
|
||||||
|
@ -29,7 +28,7 @@ public class Table {
|
||||||
}
|
}
|
||||||
constraints += ")";
|
constraints += ")";
|
||||||
if (on_conflict != null) {
|
if (on_conflict != null) {
|
||||||
constraints += "ON CONFLICT " + on_conflict;
|
constraints += "ON CONFLICT " + (!)on_conflict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +79,7 @@ public class Table {
|
||||||
sql += @"$(i > 0 ? "," : "") $c";
|
sql += @"$(i > 0 ? "," : "") $c";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (constraints != null) {
|
sql += @"$constraints)";
|
||||||
sql += ", " + constraints;
|
|
||||||
}
|
|
||||||
sql += ")";
|
|
||||||
db.exec(sql);
|
db.exec(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,10 +94,10 @@ public class Table {
|
||||||
|
|
||||||
public void delete_columns_for_version(long old_version, long new_version) throws DatabaseError {
|
public void delete_columns_for_version(long old_version, long new_version) throws DatabaseError {
|
||||||
bool column_deletion_required = false;
|
bool column_deletion_required = false;
|
||||||
string column_list = null;
|
string column_list = "";
|
||||||
foreach (Column c in columns) {
|
foreach (Column c in columns) {
|
||||||
if (c.min_version <= new_version && c.max_version >= new_version) {
|
if (c.min_version <= new_version && c.max_version >= new_version) {
|
||||||
if (column_list == null) {
|
if (column_list == "") {
|
||||||
column_list = c.name;
|
column_list = c.name;
|
||||||
} else {
|
} else {
|
||||||
column_list += ", " + c.name;
|
column_list += ", " + c.name;
|
||||||
|
|
|
@ -5,18 +5,18 @@ namespace Qlite {
|
||||||
public class UpdateBuilder : StatementBuilder {
|
public class UpdateBuilder : StatementBuilder {
|
||||||
|
|
||||||
// UPDATE [OR ...]
|
// UPDATE [OR ...]
|
||||||
private string or_val;
|
private string? or_val;
|
||||||
|
|
||||||
// [...]
|
// [...]
|
||||||
private Table table;
|
private Table? table;
|
||||||
private string table_name;
|
private string table_name;
|
||||||
|
|
||||||
// SET [...]
|
// SET [...]
|
||||||
private StatementBuilder.Field[] fields;
|
private StatementBuilder.AbstractField[] fields = {};
|
||||||
|
|
||||||
// WHERE [...]
|
// WHERE [...]
|
||||||
private string selection;
|
private string selection = "1";
|
||||||
private StatementBuilder.Field[] selection_args;
|
private StatementBuilder.AbstractField[] selection_args = {};
|
||||||
|
|
||||||
internal UpdateBuilder(Database db, Table table) {
|
internal UpdateBuilder(Database db, Table table) {
|
||||||
base(db);
|
base(db);
|
||||||
|
@ -35,59 +35,28 @@ public class UpdateBuilder : StatementBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateBuilder set<T>(Column<T> column, T value) {
|
public UpdateBuilder set<T>(Column<T> column, T value) {
|
||||||
if (fields == null) {
|
fields += new Field<T>(column, value);
|
||||||
fields = { new StatementBuilder.Field<T>(column, value) };
|
|
||||||
} else {
|
|
||||||
StatementBuilder.Field[] fields_new = new StatementBuilder.Field[fields.length+1];
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
|
||||||
fields_new[i] = fields[i];
|
|
||||||
}
|
|
||||||
fields_new[fields.length] = new Field<T>(column, value);
|
|
||||||
fields = fields_new;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateBuilder set_null<T>(Column<T> column) throws DatabaseError {
|
public UpdateBuilder set_null<T>(Column<T> column) throws DatabaseError {
|
||||||
if (column.not_null) throw new DatabaseError.ILLEGAL_QUERY(@"Can't set non-null column $(column.name) to null");
|
if (column.not_null) throw new DatabaseError.ILLEGAL_QUERY(@"Can't set non-null column $(column.name) to null");
|
||||||
if (fields == null) {
|
fields += new NullField<T>(column);
|
||||||
fields = { new NullField<T>(column) };
|
|
||||||
} else {
|
|
||||||
StatementBuilder.Field[] fields_new = new StatementBuilder.Field[fields.length+1];
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
|
||||||
fields_new[i] = fields[i];
|
|
||||||
}
|
|
||||||
fields_new[fields.length] = new NullField<T>(column);
|
|
||||||
fields = fields_new;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateBuilder where(string selection, string[]? selection_args = null) throws DatabaseError {
|
public UpdateBuilder where(string selection, string[] selection_args = {}) throws DatabaseError {
|
||||||
if (this.selection != null) throw new DatabaseError.ILLEGAL_QUERY("selection was already done, but where() was called.");
|
if (this.selection != "1") throw new DatabaseError.ILLEGAL_QUERY("selection was already done, but where() was called.");
|
||||||
this.selection = selection;
|
this.selection = selection;
|
||||||
if (selection_args != null) {
|
foreach (string arg in selection_args) {
|
||||||
this.selection_args = new StatementBuilder.Field[selection_args.length];
|
this.selection_args += new StatementBuilder.StringField(arg);
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
|
||||||
this.selection_args[i] = new StatementBuilder.StringField(selection_args[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateBuilder with<T>(Column<T> column, string comp, T value) {
|
public UpdateBuilder with<T>(Column<T> column, string comp, T value) {
|
||||||
if (selection == null) {
|
selection_args += new Field<T>(column, value);
|
||||||
selection = @"$(column.name) $comp ?";
|
|
||||||
selection_args = { new StatementBuilder.Field<T>(column, value) };
|
|
||||||
} else {
|
|
||||||
selection = @"($selection) AND $(column.name) $comp ?";
|
selection = @"($selection) AND $(column.name) $comp ?";
|
||||||
StatementBuilder.Field[] selection_args_new = new StatementBuilder.Field[selection_args.length+1];
|
|
||||||
for (int i = 0; i < selection_args.length; i++) {
|
|
||||||
selection_args_new[i] = selection_args[i];
|
|
||||||
}
|
|
||||||
selection_args_new[selection_args.length] = new Field<T>(column, value);
|
|
||||||
selection_args = selection_args_new;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,13 +72,13 @@ public class UpdateBuilder : StatementBuilder {
|
||||||
|
|
||||||
internal override Statement prepare() throws DatabaseError {
|
internal override Statement prepare() throws DatabaseError {
|
||||||
string sql = "UPDATE";
|
string sql = "UPDATE";
|
||||||
if (or_val != null) sql += @" OR $or_val";
|
if (or_val != null) sql += @" OR $((!)or_val)";
|
||||||
sql += @" $table_name SET ";
|
sql += @" $table_name SET ";
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
sql += ", ";
|
sql += ", ";
|
||||||
}
|
}
|
||||||
sql += @"$(fields[i].column.name) = ?";
|
sql += @"$(((!)fields[i].column).name) = ?";
|
||||||
}
|
}
|
||||||
sql += @" WHERE $selection";
|
sql += @" WHERE $selection";
|
||||||
Statement stmt = db.prepare(sql);
|
Statement stmt = db.prepare(sql);
|
||||||
|
@ -123,7 +92,7 @@ public class UpdateBuilder : StatementBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void perform() throws DatabaseError {
|
public void perform() throws DatabaseError {
|
||||||
if (fields == null || fields.length == 0) return;
|
if (fields.length == 0) return;
|
||||||
if (prepare().step() != DONE) {
|
if (prepare().step() != DONE) {
|
||||||
throw new DatabaseError.EXEC_ERROR(@"SQLite error: $(db.errcode()) - $(db.errmsg())");
|
throw new DatabaseError.EXEC_ERROR(@"SQLite error: $(db.errcode()) - $(db.errmsg())");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue