Browse Source
- successfully connects to db - updated db sheme - succeeds in listing appointments Signed-off-by: Stephan Richter <s.richter@srsoftware.de>main
12 changed files with 214 additions and 29 deletions
@ -1,38 +1,47 @@ |
|||||||
/* © SRSoftware 2024 */ |
/* © SRSoftware 2024 */ |
||||||
package de.srsoftware.cal.app; |
package de.srsoftware.cal.app; |
||||||
|
|
||||||
import de.srsoftware.cal.importer.jena.Kassablanca; |
import de.srsoftware.cal.db.Database; |
||||||
|
import de.srsoftware.cal.db.MariaDB; |
||||||
|
import de.srsoftware.configuration.Configuration; |
||||||
|
import de.srsoftware.configuration.JsonConfig; |
||||||
|
import java.io.IOException; |
||||||
import java.security.NoSuchAlgorithmException; |
import java.security.NoSuchAlgorithmException; |
||||||
import java.sql.Connection; |
|
||||||
import java.sql.DriverManager; |
|
||||||
import java.sql.SQLException; |
import java.sql.SQLException; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
/** |
/** |
||||||
* Test application |
* Test application |
||||||
*/ |
*/ |
||||||
public class Application { |
public class Application { |
||||||
|
private static final String JDBC = "opencloudcal.db.jdbc"; |
||||||
|
private static final String USER = "opencloudcal.db.user"; |
||||||
|
private static final String PASS = "opencloudcal.db.pass"; |
||||||
|
private static final String MISSING = "missing required configuration property \"%s\""; |
||||||
|
|
||||||
private Application() { |
private Application() { |
||||||
} |
} |
||||||
|
|
||||||
|
private static Database connect(Configuration config) throws SQLException { |
||||||
|
Optional<String> jdbc = config.get(JDBC); |
||||||
|
if (jdbc.isEmpty()) throw new RuntimeException(MISSING.formatted(JDBC)); |
||||||
|
|
||||||
|
String user = config.get(USER, "opencloudcal"); |
||||||
|
|
||||||
|
Optional<String> pass = config.get(PASS); |
||||||
|
if (pass.isEmpty()) throw new RuntimeException(MISSING.formatted(PASS)); |
||||||
|
|
||||||
|
return MariaDB.connect(jdbc.get(), user, pass.get()); |
||||||
|
} |
||||||
|
|
||||||
/** |
/** |
||||||
* sandbox |
* sandbox |
||||||
* @param args default |
* @param args default |
||||||
*/ |
*/ |
||||||
public static void main(String[] args) throws NoSuchAlgorithmException { |
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, SQLException { |
||||||
|
JsonConfig jsonConfig = new JsonConfig("OpenCloudCal"); |
||||||
String host = null; |
var db = connect(jsonConfig); |
||||||
String database = null; |
var appointments = db.list(null, null); |
||||||
String user = null; |
for (var event : appointments) System.out.println(event); |
||||||
String pass = null; |
|
||||||
int port = 3306; |
|
||||||
|
|
||||||
// TODO: we need configuration here!
|
|
||||||
|
|
||||||
try (Connection con = DriverManager |
|
||||||
.getConnection("jdbc:mysql://%s:%s/%s".formatted(host,port,database), user, pass)) { |
|
||||||
// use con here
|
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,9 @@ |
|||||||
|
description = "OpenCloudCal : Base" |
||||||
|
|
||||||
|
dependencies { |
||||||
|
implementation(project(":de.srsoftware.cal.api")) |
||||||
|
|
||||||
|
implementation("de.srsoftware:tools.optionals:1.0.0") |
||||||
|
implementation("de.srsoftware:tools.util:1.2.0") |
||||||
|
implementation("de.srsoftware:tools.web:1.3.3") |
||||||
|
} |
@ -1,5 +1,5 @@ |
|||||||
/* © SRSoftware 2024 */ |
/* © SRSoftware 2024 */ |
||||||
package de.srsoftware.cal.importer; |
package de.srsoftware.cal; |
||||||
|
|
||||||
import static de.srsoftware.tools.Optionals.nullable; |
import static de.srsoftware.tools.Optionals.nullable; |
||||||
|
|
@ -1,4 +1,10 @@ |
|||||||
description = "OpenCloudCal : Database" |
description = "OpenCloudCal : Database" |
||||||
|
|
||||||
dependencies { |
dependencies { |
||||||
|
implementation(project(":de.srsoftware.cal.api")) |
||||||
|
implementation(project(":de.srsoftware.cal.base")) |
||||||
|
|
||||||
|
implementation("de.srsoftware:tools.jdbc:1.0.0") |
||||||
|
implementation("de.srsoftware:tools.optionals:1.0.0") |
||||||
|
implementation("de.srsoftware:tools.util:1.2.0") |
||||||
} |
} |
||||||
|
@ -0,0 +1,36 @@ |
|||||||
|
/* © SRSoftware 2024 */ |
||||||
|
package de.srsoftware.cal.db; |
||||||
|
|
||||||
|
import de.srsoftware.cal.api.Appointment; |
||||||
|
import java.sql.SQLException; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface for calendar database |
||||||
|
*/ |
||||||
|
public interface Database { |
||||||
|
/** |
||||||
|
* add an appointment to the database |
||||||
|
* @param appointment the appointment to store |
||||||
|
* @return the Database object |
||||||
|
*/ |
||||||
|
public Database add(Appointment appointment); |
||||||
|
|
||||||
|
/** |
||||||
|
* list appointments unfiltered |
||||||
|
* @param count the maximum number of appointments to return |
||||||
|
* @param offset the number of appointments to skip |
||||||
|
* @return the list of appointments fetched from the db |
||||||
|
*/ |
||||||
|
public List<Appointment> list(Integer count, Integer offset) throws SQLException; |
||||||
|
|
||||||
|
/** |
||||||
|
* list appointments |
||||||
|
* @param tags only list appointments which have matching tags |
||||||
|
* @param count the maximum number of appointments to return |
||||||
|
* @param offset the number of appointments to skip |
||||||
|
* @return the list of appointments fetched from the db |
||||||
|
*/ |
||||||
|
public List<Appointment> listByTags(Set<String> tags, Integer count, Integer offset); |
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
/* © SRSoftware 2024 */ |
||||||
|
package de.srsoftware.cal.db; |
||||||
|
|
||||||
|
import static de.srsoftware.tools.Optionals.allEmpty; |
||||||
|
import static de.srsoftware.tools.Optionals.nullable; |
||||||
|
|
||||||
|
import de.srsoftware.cal.BaseAppointment; |
||||||
|
import de.srsoftware.cal.api.Appointment; |
||||||
|
import de.srsoftware.tools.Calc; |
||||||
|
import de.srsoftware.tools.jdbc.Query; |
||||||
|
import java.sql.Connection; |
||||||
|
import java.sql.DriverManager; |
||||||
|
import java.sql.SQLException; |
||||||
|
import java.sql.Timestamp; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
public class MariaDB implements Database { |
||||||
|
private static final String SELECT_APPOINTMENTS = "SELECT * FROM appointments"; |
||||||
|
private static final String SELECT_APPOINTMENTS_WITH_HASHES = SELECT_APPOINTMENTS + " a LEFT JOIN appointment_hashes h ON a.aid = h.aid"; |
||||||
|
private static final String SELECT_VERSION = "SELECT value FROM config WHERE keyname = 'dbversion'"; |
||||||
|
private static final String CREATE_HASHES = "CREATE TABLE appointment_hashes (aid INT NOT NULL, hash VARCHAR(255) NOT NULL, UNIQUE(aid), UNIQUE(hash))"; |
||||||
|
private static final String INSERT_HASH = "INSERT INTO appointment_hashes (aid, hash) values (?, ?) ON DUPLICATE KEY UPDATE hash=hash;"; |
||||||
|
private static final String UPDATE_DB_VERSION = "UPDATE config SET value = ? WHERE keyname = 'dbversion'"; |
||||||
|
private static Connection connection; |
||||||
|
|
||||||
|
private MariaDB(Connection conn) throws SQLException { |
||||||
|
connection = conn; |
||||||
|
applyUpdates(); |
||||||
|
} |
||||||
|
|
||||||
|
private void applyUpdates() throws SQLException { |
||||||
|
var rs = Query.of(SELECT_VERSION).execute(connection); |
||||||
|
var version = 0; |
||||||
|
if (rs.next()) { |
||||||
|
version = rs.getInt("value"); |
||||||
|
} |
||||||
|
rs.close(); |
||||||
|
switch (version) { |
||||||
|
case 0: |
||||||
|
createTables(); |
||||||
|
case 1: |
||||||
|
update1(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void update1() throws SQLException { |
||||||
|
var list = new ArrayList<Appointment>(); |
||||||
|
var results = Query.of(SELECT_APPOINTMENTS).execute(connection); |
||||||
|
while (results.next()) { |
||||||
|
var id = results.getInt("aid"); |
||||||
|
var title = results.getString("title"); |
||||||
|
var description = results.getString("description"); |
||||||
|
if (allEmpty(title, description)) continue; |
||||||
|
var stamp = results.getTimestamp("start"); |
||||||
|
var start = nullable(stamp).map(Timestamp::toLocalDateTime).orElse(null); |
||||||
|
var end = nullable(results.getTimestamp("end")).map(Timestamp::toLocalDateTime).orElse(null); |
||||||
|
var location = results.getString("location"); |
||||||
|
Calc //
|
||||||
|
.hash(start + "@" + location) |
||||||
|
.map(hash -> new BaseAppointment(id, title, description, start, end, location, hash)) |
||||||
|
.ifPresent(list::add); |
||||||
|
} |
||||||
|
results.close(); |
||||||
|
connection.setAutoCommit(false); |
||||||
|
|
||||||
|
Query.of(CREATE_HASHES).statement(connection).execute(); |
||||||
|
for (var appointment : list) { |
||||||
|
var stmt = Query.of(INSERT_HASH).statement(connection); |
||||||
|
stmt.setLong(1, appointment.id()); |
||||||
|
stmt.setString(2, appointment.hash()); |
||||||
|
stmt.execute(); |
||||||
|
} |
||||||
|
connection.commit(); |
||||||
|
var stmt = Query.of(UPDATE_DB_VERSION).statement(connection); |
||||||
|
stmt.setLong(1, 2); |
||||||
|
stmt.execute(); |
||||||
|
connection.setAutoCommit(true); |
||||||
|
} |
||||||
|
|
||||||
|
private void createTables() { |
||||||
|
throw new RuntimeException("%s.createTables() not implemented!"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public Database add(Appointment appointment) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public static Database connect(String jdbc, String user, String pass) throws SQLException { |
||||||
|
return new MariaDB(DriverManager.getConnection(jdbc, user, pass)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public List<Appointment> list(Integer count, Integer offset) throws SQLException { |
||||||
|
var list = new ArrayList<Appointment>(); |
||||||
|
var results = Query.of(SELECT_APPOINTMENTS_WITH_HASHES).execute(connection); |
||||||
|
while (results.next()) { |
||||||
|
var id = results.getInt("aid"); |
||||||
|
var title = results.getString("title"); |
||||||
|
var description = results.getString("description"); |
||||||
|
if (allEmpty(title, description)) continue; |
||||||
|
var start = results.getTimestamp("start").toLocalDateTime(); |
||||||
|
var end = nullable(results.getTimestamp("end")).map(Timestamp::toLocalDateTime).orElse(null); |
||||||
|
var location = results.getString("location"); |
||||||
|
var hash = results.getString("hash"); |
||||||
|
if (hash == null) hash = Calc.hash(start + "@" + location).orElse(null); |
||||||
|
list.add(new BaseAppointment(id, title, description, start, end, location, hash)); |
||||||
|
} |
||||||
|
results.close(); |
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<Appointment> listByTags(Set<String> tags, Integer count, Integer offset) { |
||||||
|
return List.of(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue