anotherim-desktop/qlite/src/query_builder.vala

174 lines
5 KiB
Vala
Raw Normal View History

2017-03-02 14:37:32 +00:00
using Sqlite;
namespace Qlite {
public class QueryBuilder : StatementBuilder {
private bool single_result;
// SELECT [...]
private string column_selector = "*";
2017-04-16 13:11:00 +00:00
private Column[] columns = {};
2017-03-02 14:37:32 +00:00
// FROM [...]
2017-04-16 13:11:00 +00:00
private Table? table;
private string? table_name;
2017-03-02 14:37:32 +00:00
// WHERE [...]
2017-04-16 13:11:00 +00:00
private string selection = "1";
private StatementBuilder.AbstractField[] selection_args = {};
2017-03-02 14:37:32 +00:00
// ORDER BY [...]
2017-04-16 13:11:00 +00:00
private OrderingTerm[]? order_by_terms = {};
2017-03-02 14:37:32 +00:00
// LIMIT [...]
private int limit_val;
internal QueryBuilder(Database db) {
2017-03-02 14:37:32 +00:00
base(db);
}
2017-04-16 13:11:00 +00:00
public QueryBuilder select(Column[] columns = {}) {
2017-03-02 14:37:32 +00:00
this.columns = columns;
2017-04-16 13:11:00 +00:00
if (columns.length == 0) {
2017-03-02 14:37:32 +00:00
for (int i = 0; i < columns.length; i++) {
if (column_selector == "*") {
column_selector = columns[0].name;
} else {
column_selector += ", " + columns[i].name;
}
}
} else {
column_selector = "*";
}
return this;
}
public QueryBuilder select_string(string column_selector) {
2017-04-16 13:11:00 +00:00
this.columns = {};
2017-03-02 14:37:32 +00:00
this.column_selector = column_selector;
return this;
}
2017-10-28 21:48:07 +00:00
public QueryBuilder from(Table table) {
if (this.table_name != null) error("cannot use from() multiple times.");
2017-03-02 14:37:32 +00:00
this.table = table;
this.table_name = table.name;
return this;
}
public QueryBuilder from_name(string table) {
this.table_name = table;
return this;
}
2017-10-28 21:48:07 +00:00
public QueryBuilder where(string selection, string[] selection_args = {}) {
if (this.selection != "1") error("selection was already done, but where() was called.");
2017-03-02 14:37:32 +00:00
this.selection = selection;
2017-04-16 13:11:00 +00:00
foreach (string arg in selection_args) {
this.selection_args += new StatementBuilder.StringField(arg);
2017-03-02 14:37:32 +00:00
}
return this;
}
public QueryBuilder with<T>(Column<T> column, string comp, T value) {
if ((column.unique || column.primary_key) && comp == "=") single_result = true;
2017-04-16 13:11:00 +00:00
selection_args += new Field<T>(column, value);
selection = @"($selection) AND $(column.name) $comp ?";
2017-03-02 14:37:32 +00:00
return this;
}
public QueryBuilder with_null<T>(Column<T> column) {
selection = @"($selection) AND $(column.name) ISNULL";
return this;
}
public QueryBuilder without_null<T>(Column<T> column) {
selection = @"($selection) AND $(column.name) NOT NULL";
return this;
}
public QueryBuilder order_by(Column column, string dir = "ASC") {
2017-04-16 13:11:00 +00:00
order_by_terms += new OrderingTerm(column, dir);
2017-03-02 14:37:32 +00:00
return this;
}
public QueryBuilder order_by_name(string name, string dir) {
2017-04-16 13:11:00 +00:00
order_by_terms += new OrderingTerm.by_name(name, dir);
2017-03-02 14:37:32 +00:00
return this;
}
public QueryBuilder limit(int limit) {
if (this.limit_val != 0 && limit > this.limit_val) error("tried to increase an existing limit");
2017-03-02 14:37:32 +00:00
this.limit_val = limit;
return this;
}
public QueryBuilder single() {
this.single_result = true;
return limit(1);
}
2017-10-28 21:48:07 +00:00
public int64 count() {
2017-03-02 14:37:32 +00:00
this.column_selector = @"COUNT($column_selector) AS count";
this.single_result = true;
2017-04-16 13:11:00 +00:00
return row().get_integer("count");
2017-03-02 14:37:32 +00:00
}
2017-10-28 21:48:07 +00:00
private Row? row_() {
if (!single_result) error("query is not suited to return a single row, but row() was called.");
2017-04-16 13:11:00 +00:00
return iterator().get_next();
2017-03-02 14:37:32 +00:00
}
2017-10-28 21:48:07 +00:00
public RowOption row() {
return new RowOption(row_());
}
public T get<T>(Column<T> field, T def = null) {
return row().get(field, def);
2017-03-02 14:37:32 +00:00
}
2017-10-28 21:48:07 +00:00
internal override Statement prepare() {
2017-04-16 13:11:00 +00:00
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" : "")");
2017-03-02 14:37:32 +00:00
for (int i = 0; i < selection_args.length; i++) {
selection_args[i].bind(stmt, i+1);
}
return stmt;
}
2017-10-28 21:48:07 +00:00
public RowIterator iterator() {
2017-03-22 22:55:19 +00:00
return new RowIterator.from_query_builder(db, this);
2017-03-02 14:37:32 +00:00
}
class OrderingTerm {
Column column;
string column_name;
string dir;
public OrderingTerm(Column column, string dir) {
this.column = column;
this.column_name = column.name;
this.dir = dir;
}
public OrderingTerm.by_name(string column_name, string dir) {
this.column_name = column_name;
this.dir = dir;
}
public string to_string() {
return @"$column_name $dir";
}
2017-04-16 13:11:00 +00:00
public static string all_to_string(OrderingTerm[]? terms) {
if (terms == null || terms.length == 0) return "";
2017-03-02 14:37:32 +00:00
string res = "ORDER BY "+terms[0].to_string();
for (int i = 1; i < terms.length; i++) {
res += @", $(terms[i])";
}
return res;
}
}
}
2017-10-28 21:48:07 +00:00
}