/* © SRSoftware 2025 */ package de.srsoftware.umbrella.bookmarks; import static de.srsoftware.tools.jdbc.Condition.equal; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.umbrella.bookmarks.Constants.*; import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.ERROR_FAILED_CREATE_TABLE; import static java.lang.System.Logger.Level.ERROR; import static java.text.MessageFormat.format; import static java.time.ZoneOffset.UTC; import de.srsoftware.umbrella.core.BaseDb; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Bookmark; import java.sql.Connection; import java.sql.SQLException; import java.time.LocalDateTime; import java.util.Collection; import java.util.HashMap; import java.util.Map; public class SqliteDb extends BaseDb implements BookmarkDb { public SqliteDb(Connection conn) { super(conn); } @Override protected int createTables() { var version = createSettingsTable(); switch (version){ case 0: createUrlsTable(); createUrlCommentsTable(); } return setCurrentVersion(1); } private void createUrlCommentsTable() { var sql = """ CREATE TABLE IF NOT EXISTS {0} ( `{1}` INTEGER NOT NULL, `{2}` INTEGER NOT NULL, `{3}` TEXT NOT NULL, `{4}` DATETIME NOT NULL, PRIMARY KEY (`{1}`,`{2}`) )"""; try { var stmt = db.prepareStatement(format(sql,TABLE_URL_COMMENTS,URL_ID,USER_ID,COMMENT,TIMESTAMP)); stmt.execute(); stmt.close(); } catch (SQLException e) { LOG.log(ERROR, ERROR_FAILED_CREATE_TABLE, TABLE_URL_COMMENTS, e); throw new RuntimeException(e); } } private void createUrlsTable() { var sql = "CREATE TABLE IF NOT EXISTS urls (ID INTEGER PRIMARY KEY, url TEXT UNIQUE NOT NULL)"; try { var stmt = db.prepareStatement(sql); stmt.execute(); stmt.close(); } catch (SQLException e) { LOG.log(ERROR, ERROR_FAILED_CREATE_TABLE, TABLE_URLS, e); throw new RuntimeException(e); } } @Override public Map list(long userId) { try { var map = new HashMap(); var rs = select(ALL).from(TABLE_URL_COMMENTS).leftJoin(URL_ID,TABLE_URLS,ID).where(USER_ID, equal(userId)).exec(db); while (rs.next()){ var bookmark = Bookmark.of(rs); map.put(bookmark.id(),bookmark); } rs.close();; return map; } catch (SQLException e) { throw new UmbrellaException("Failed to load bookmark list"); } } @Override public Bookmark load(long id, long userId) { try { Bookmark result = null; var rs = select(ALL).from(TABLE_URLS).leftJoin(ID,TABLE_URL_COMMENTS,URL_ID).where(ID,equal(id)).where(USER_ID,equal(userId)).exec(db); if (rs.next()) result = Bookmark.of(rs); rs.close(); if (result != null) return result; throw UmbrellaException.notFound("No bookmark with id {0}",id); } catch (SQLException e) { throw new UmbrellaException("Failed to load bookmark"); } } @Override public Bookmark save(String url, String comment, Collection userIds) { try { var timestamp = LocalDateTime.now(); var rs = select(ID).from(TABLE_URLS).where(URL, equal(url)).exec(db); var id = 0L; if (rs.next()) id = rs.getLong(ID); rs.close(); if (id == 0) { var stmt = insertInto(TABLE_URLS, URL).values(url).execute(db); rs = stmt.getGeneratedKeys(); if (rs.next()) id = rs.getLong(1); rs.close(); stmt.close(); } var query = replaceInto(TABLE_URL_COMMENTS,URL_ID,USER_ID,COMMENT, TIMESTAMP); for (long userId : userIds) query.values(id,userId,comment,timestamp.toEpochSecond(UTC)); query.execute(db).close(); return Bookmark.of(id,url,comment,timestamp); } catch (SQLException e) { throw new UmbrellaException("Failed to store url"); } } }