package de.srsoftware.widerhall.data; import de.srsoftware.widerhall.Configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; import static de.srsoftware.widerhall.Util.t; public class Database { public static final String EMAIL = "email"; public static final String NAME = "name"; public static final String HASHED_PASS = "hashedPassword"; public static final String SALT = "salt"; private static final Logger LOG = LoggerFactory.getLogger(Database.class); private static final String VARCHAR = "VARCHAR(255)"; private static Database singleton = null; private static Connection conn; public Request insertInto(String tbName) { return query("INSERT INTO "+tbName); } public class Request{ private final String sql; private HashMap> where = new HashMap<>(); private HashMap values = new HashMap<>(); public Request(String sql) { this.sql = sql; } public Request where(String key, Object ... values) { for (var val : values) where(key,val); return this; } public 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 Request values(Map newValues) { values.putAll(newValues); return this; } public Request values(String key, Object value) { values.put(key,value); return this; } public void run() throws SQLException { var sb = new StringBuilder(sql); var args = new ArrayList(); if (!values.isEmpty()){ var keys = new ArrayList(); for (var entry : values.entrySet()) { keys.add(entry.getKey()); args.add(entry.getValue()); } sb.append("("+String.join(", ",keys)+")"); sb.append(" VALUES "); var arr = new String[args.size()]; Arrays.fill(arr,"?"); var marks = String.join(", ",arr); sb.append("(").append(marks).append(")"); } var sql = sb.toString(); LOG.debug(sql); try { var stmt = conn.prepareStatement(sql); if (!args.isEmpty()) { for (int i = 0; i < args.size(); i++) stmt.setObject(i+1, args.get(i)); } stmt.execute(); } catch (SQLException sqle) { throw new SQLException(t("Query '{}' failed:",sql),sqle); } } public ResultSet exec() throws SQLException { var sb = new StringBuilder(sql); var args = new ArrayList(); if (!where.isEmpty()){ var clauses = new ArrayList(); sb.append(" WHERE "); for (var entry : where.entrySet()){ var arr = new String[entry.getValue().size()]; Arrays.fill(arr,"?"); var marks = String.join(", ",arr); clauses.add("("+entry.getKey()+" IN ("+marks+"))"); args.addAll(entry.getValue()); } sb.append(String.join(" AND ",clauses)); } var sql = sb.toString(); LOG.debug(sql); try { var stmt = conn.prepareStatement(sql); if (!args.isEmpty()) { for (int i = 0; i < args.size(); i++) stmt.setObject(i+1, args.get(i)); } return stmt.executeQuery(); } catch (SQLException sqle) { throw new SQLException(t("Query '{}' failed:",sql),sqle); } } } public Database(Connection connection) { this.conn = connection; } public static Database open() { if (singleton == null){ Configuration config = Configuration.instance(); var dbFile = config.dbFile(); String url = "jdbc:sqlite:"+dbFile; LOG.debug("Opening {}",url); dbFile.getParentFile().mkdirs(); try { singleton = new Database(DriverManager.getConnection(url)).assertTables(); } catch (SQLException sqle) { sqle.printStackTrace(); } } return singleton; } private Database assertTables() throws SQLException { if (!tableExists("Users")) createUsersTable(); return this; } private void createUsersTable() throws SQLException { query("CREATE TABLE Users ("+EMAIL+" "+ VARCHAR +", "+SALT+" "+VARCHAR+", "+HASHED_PASS+" "+VARCHAR+", "+NAME+" "+VARCHAR+");").run(); } private boolean tableExists(String tbName) throws SQLException { try { ResultSet rs = query("SELECT EXISTS (SELECT name FROM sqlite_schema WHERE type='table' AND name='" + tbName + "')").exec(); int val = 0; if (rs.next()) val = rs.getInt(1); rs.close(); return val > 0; } catch (SQLException e) { throw new SQLException(t("Was not able to check existence of table {}!",tbName),e); } } public Request query(String sql) { return new Request(sql); } }