|
|
|
@ -21,10 +21,19 @@ public class Database {
@@ -21,10 +21,19 @@ public class Database {
|
|
|
|
|
private static Database singleton = null; // we only need one db handle ever. This will be it.
|
|
|
|
|
private final Connection conn; // the actual db connection handle within the singleton
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* This class encapsulates a compiled request. |
|
|
|
|
* A compiled request is a ready-to execute sql string paired with a list of parameters |
|
|
|
|
*/ |
|
|
|
|
public class CompiledRequest{ |
|
|
|
|
private final String sql; |
|
|
|
|
private final List<Object> args; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* create new instance |
|
|
|
|
* @param sql final sql, ready to be executed |
|
|
|
|
* @param args arguments for the execution of the query |
|
|
|
|
*/ |
|
|
|
|
public CompiledRequest(String sql, List<Object> args){ |
|
|
|
|
this.sql = sql; |
|
|
|
|
this.args = args; |
|
|
|
@ -95,7 +104,7 @@ public class Database {
@@ -95,7 +104,7 @@ public class Database {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* conditions are assembled in the following form: |
|
|
|
|
* SELECT … FROM … WHERE <key> in (<values>) |
|
|
|
|
* SELECT … FROM … WHERE [key] in ([values]) |
|
|
|
|
* <values> are build as list of question marks, whose arguments are applied later |
|
|
|
|
* @param args |
|
|
|
|
*/ |
|
|
|
@ -125,6 +134,10 @@ public class Database {
@@ -125,6 +134,10 @@ public class Database {
|
|
|
|
|
return clone; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* finalize sql, save sql and arguments as compiled request |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public CompiledRequest compile(){ |
|
|
|
|
var args = new ArrayList<>(); |
|
|
|
|
applyValues(args); |
|
|
|
@ -132,6 +145,10 @@ public class Database {
@@ -132,6 +145,10 @@ public class Database {
|
|
|
|
|
return new CompiledRequest(sql.toString(),args); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* apply values (for insert or update statements) |
|
|
|
|
* @param args |
|
|
|
|
*/ |
|
|
|
|
private void applyValues(ArrayList<Object> args){ |
|
|
|
|
if (values.isEmpty()) return; |
|
|
|
|
var currentSql = sql(); |
|
|
|
@ -160,11 +177,21 @@ public class Database {
@@ -160,11 +177,21 @@ public class Database {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* set single value for a certain key |
|
|
|
|
* @param key |
|
|
|
|
* @param value |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request set(String key, Object value) { |
|
|
|
|
values.put(key,value); |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* get the current (i.e. non-final) sql |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public String sql() { |
|
|
|
|
return sql.toString(); |
|
|
|
|
} |
|
|
|
@ -174,34 +201,61 @@ public class Database {
@@ -174,34 +201,61 @@ public class Database {
|
|
|
|
|
return "Request("+clone().compile()+')'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* apply a map of values (for insert/update statements) |
|
|
|
|
* @param newValues |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request values(Map<String,Object> newValues) { |
|
|
|
|
values.putAll(newValues); |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* add a where condition in the form of … WHERE [key] in ([values]) |
|
|
|
|
* @param key |
|
|
|
|
* @param values |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request where(String key, Object ... values) { |
|
|
|
|
for (var val : values) where(key,val); |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* add a where condition in the form of … WHERE [key] in ([values]) |
|
|
|
|
* @param key |
|
|
|
|
* @param values |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request where(String key, Collection<? extends Object> values) { |
|
|
|
|
for (var val : values) where(key,val); |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* add a where condition in the form of … WHERE [key] in ([value]) |
|
|
|
|
* @param key |
|
|
|
|
* @param values |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
private Request where(String key, Object value) { |
|
|
|
|
var list = where.get(key); |
|
|
|
|
if (list == null) where.put(key,list = new ArrayList<>()); |
|
|
|
|
list.add(value); |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Database(Connection connection) { |
|
|
|
|
this.conn = connection; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* take care of table creation, if required tables do not exist |
|
|
|
|
* @return |
|
|
|
|
* @throws SQLException |
|
|
|
|
*/ |
|
|
|
|
private Database assertTables() throws SQLException { |
|
|
|
|
if (!tableExists(User.TABLE_NAME)) User.createTable(); |
|
|
|
|
if (!tableExists(MailingList.TABLE_NAME)) MailingList.createTable(); |
|
|
|
@ -209,18 +263,38 @@ public class Database {
@@ -209,18 +263,38 @@ public class Database {
|
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* prepare a deletion statement |
|
|
|
|
* @param tableName |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request deleteFrom(String tableName){ |
|
|
|
|
return new Request(new StringBuilder("DELETE FROM ").append(tableName).append(" ")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* prepare an insertion statement |
|
|
|
|
* @param tableName |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request insertInto(String tableName){ |
|
|
|
|
return new Request(new StringBuilder("INSERT INTO ").append(tableName).append(" ")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* check if we have an active db connection |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public boolean isOpen() { |
|
|
|
|
return conn instanceof Connection; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Open the database, if it is not open. |
|
|
|
|
* Will create the singleton on first call. |
|
|
|
|
* Consecutive calls will just return the singleton. |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public static Database open() { |
|
|
|
|
if (singleton == null){ |
|
|
|
|
Configuration config = Configuration.instance(); |
|
|
|
@ -238,10 +312,22 @@ public class Database {
@@ -238,10 +312,22 @@ public class Database {
|
|
|
|
|
return singleton; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Create a query from a pre-set StringBuilder |
|
|
|
|
* @param sql |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request query(StringBuilder sql) { |
|
|
|
|
return new Request(sql); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* create a SELECT [flields] FROM [table] request. |
|
|
|
|
* If no fields are supplied, a request in the form SELECT * FROM [table] will be generated. |
|
|
|
|
* @param tableName |
|
|
|
|
* @param fields |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request select(String tableName,String ... fields) { |
|
|
|
|
StringBuilder sql = new StringBuilder("SELECT "); |
|
|
|
|
if (fields == null || fields.length == 0){ |
|
|
|
@ -253,6 +339,12 @@ public class Database {
@@ -253,6 +339,12 @@ public class Database {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* check, whether a table with the provided name exists |
|
|
|
|
* @param tbName |
|
|
|
|
* @return |
|
|
|
|
* @throws SQLException |
|
|
|
|
*/ |
|
|
|
|
public boolean tableExists(String tbName) throws SQLException { |
|
|
|
|
try { |
|
|
|
|
var sql = new StringBuilder("SELECT EXISTS (SELECT name FROM sqlite_schema WHERE type='table' AND name='") |
|
|
|
@ -268,12 +360,12 @@ public class Database {
@@ -268,12 +360,12 @@ public class Database {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* create an UPDATE [tableName] query |
|
|
|
|
* @param tableName |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Request update(String tableName) { |
|
|
|
|
return new Request(new StringBuilder("UPDATE ").append(tableName)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static String xor(Object a, Object b){ |
|
|
|
|
// https://stackoverflow.com/a/16443025/1285585
|
|
|
|
|
return "(~("+a+"&"+b+"))&("+a+"|"+b+")"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|