implemented transition from old bookmark database (tags.db) to separate database for bookmarks and tags
This commit is contained in:
@@ -105,7 +105,7 @@ public class BookmarkApi extends BaseHandler {
|
||||
|
||||
if (json.has(TAGS) && json.get(TAGS) instanceof JSONArray tagList){
|
||||
var list = tagList.toList().stream().map(Object::toString).toList();
|
||||
tags.save(BOOKMARK,bookmark.id(), userList, list);
|
||||
tags.save(BOOKMARK,bookmark.urlId(), userList, list);
|
||||
}
|
||||
return sendContent(ex,bookmark);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ package de.srsoftware.umbrella.bookmarks;
|
||||
public class Constants {
|
||||
public static final String CONFIG_DATABASE = "umbrella.modules.bookmark.database";
|
||||
public static final String SHARE = "share";
|
||||
public static final String SAVE = "save";
|
||||
public static final String TABLE_TOKENS = "tokens";
|
||||
public static final String TABLE_URLS = "urls";
|
||||
public static final String TABLE_URL_COMMENTS = "url_comments";
|
||||
public static final String URL_ID = "url_id";
|
||||
|
||||
@@ -75,7 +75,7 @@ CREATE TABLE IF NOT EXISTS {0} (
|
||||
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);
|
||||
map.put(bookmark.urlId(),bookmark);
|
||||
}
|
||||
rs.close();;
|
||||
return map;
|
||||
@@ -92,7 +92,7 @@ CREATE TABLE IF NOT EXISTS {0} (
|
||||
if (rs.next()) result = Bookmark.of(rs);
|
||||
rs.close();
|
||||
if (result != null) return result;
|
||||
throw UmbrellaException.notFound("No bookmark with id {0}",id);
|
||||
throw UmbrellaException.notFound("No bookmark with urlId {0}",id);
|
||||
} catch (SQLException e) {
|
||||
throw new UmbrellaException("Failed to load bookmark");
|
||||
}
|
||||
@@ -102,20 +102,20 @@ CREATE TABLE IF NOT EXISTS {0} (
|
||||
public Bookmark save(String url, String comment, Collection<Long> userIds, LocalDateTime timestamp) {
|
||||
try {
|
||||
var rs = select(ID).from(TABLE_URLS).where(URL, equal(url)).exec(db);
|
||||
var id = 0L;
|
||||
if (rs.next()) id = rs.getLong(ID);
|
||||
var urlId = 0L;
|
||||
if (rs.next()) urlId = rs.getLong(ID);
|
||||
rs.close();
|
||||
if (id == 0) {
|
||||
if (urlId == 0) {
|
||||
var stmt = insertInto(TABLE_URLS, URL).values(url).execute(db);
|
||||
rs = stmt.getGeneratedKeys();
|
||||
if (rs.next()) id = rs.getLong(1);
|
||||
if (rs.next()) urlId = 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));
|
||||
for (long userId : userIds) query.values(urlId,userId,comment,timestamp.toEpochSecond(UTC));
|
||||
query.execute(db).close();
|
||||
return Bookmark.of(id,url,comment,timestamp);
|
||||
return Bookmark.of(urlId,url,comment,timestamp);
|
||||
} catch (SQLException e) {
|
||||
throw new UmbrellaException("Failed to store url");
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ subprojects {
|
||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
implementation("de.srsoftware:configuration.api:1.0.2")
|
||||
implementation("de.srsoftware:tools.jdbc:1.3.3")
|
||||
implementation("de.srsoftware:tools.jdbc:2.0.0")
|
||||
implementation("de.srsoftware:tools.http:6.0.4")
|
||||
implementation("de.srsoftware:tools.logging:1.3.2")
|
||||
implementation("de.srsoftware:tools.optionals:1.0.0")
|
||||
|
||||
@@ -13,20 +13,20 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public record Bookmark(long id, String url, String comment, LocalDateTime timestamp, Collection<String> tags) implements Mappable {
|
||||
public record Bookmark(long urlId, String url, String comment, LocalDateTime timestamp, Collection<String> tags) implements Mappable {
|
||||
|
||||
public static Bookmark of(ResultSet rs) throws SQLException {
|
||||
return new Bookmark(rs.getLong(ID),rs.getString(URL),rs.getString(COMMENT),LocalDateTime.ofEpochSecond(rs.getLong(TIMESTAMP),0, UTC),new ArrayList<>());
|
||||
}
|
||||
|
||||
public static Bookmark of(long id, String url, String comment, LocalDateTime timestamp){
|
||||
return new Bookmark(id,url,comment,timestamp,new ArrayList<>());
|
||||
public static Bookmark of(long urlId, String url, String comment, LocalDateTime timestamp){
|
||||
return new Bookmark(urlId,url,comment,timestamp,new ArrayList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return Map.of(
|
||||
ID,id,
|
||||
ID, urlId,
|
||||
URL, url,
|
||||
COMMENT, Map.of(SOURCE,comment,RENDERED,markdown(comment)),
|
||||
TAGS, tags,
|
||||
|
||||
@@ -8,6 +8,7 @@ public class Constants {
|
||||
public static final String CONFIG_DATABASE = "umbrella.modules.tags.database";
|
||||
public static final String TABLE_COMMENTS = "comments";
|
||||
public static final String TABLE_TAGS = "tags";
|
||||
public static final String TABLE_TAGS_NEW = "tags_new";
|
||||
public static final String TAG = "tag";
|
||||
public static final String URL_HASH = "url_hash";
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ import static de.srsoftware.tools.Optionals.isSet;
|
||||
import static de.srsoftware.tools.jdbc.Condition.equal;
|
||||
import static de.srsoftware.tools.jdbc.Condition.isNull;
|
||||
import static de.srsoftware.tools.jdbc.Query.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.Dialect.SQLITE;
|
||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||
import static de.srsoftware.umbrella.bookmarks.Constants.TABLE_URLS;
|
||||
import static de.srsoftware.umbrella.bookmarks.Constants.TABLE_URL_COMMENTS;
|
||||
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 de.srsoftware.umbrella.core.Constants.USER_ID;
|
||||
@@ -24,8 +24,8 @@ import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SqliteDb extends BaseDb implements TagDB{
|
||||
private static final System.Logger LOG = System.getLogger("TagDB");
|
||||
@@ -49,30 +49,55 @@ public class SqliteDb extends BaseDb implements TagDB{
|
||||
createLegacyUrlCommentsTable();
|
||||
createLegacyTagsTable();
|
||||
case 1:
|
||||
createNewTagTable();
|
||||
splitContentToBookmarks();
|
||||
createTagTables();
|
||||
dropOldTables();
|
||||
renameNewTagTable();
|
||||
}
|
||||
|
||||
return setCurrentVersion(2);
|
||||
}
|
||||
|
||||
private void splitContentToBookmarks() {
|
||||
var pattern = Pattern.compile("/([^/]+)/(\\d+)/view");
|
||||
try {
|
||||
var sql = "CREATE TABLE IF NOT EXISTS tags_new (TAG)";
|
||||
db.prepareStatement(sql).execute();
|
||||
// IMPORT BOOKMARKS
|
||||
var commentedURLS = select(ALL).from(TABLE_URLS).leftJoin(HASH,TABLE_URL_COMMENTS,URL_HASH).leftJoin(COMMENT_HASH,TABLE_COMMENTS,HASH).exec(db);
|
||||
|
||||
while (commentedURLS.next()){
|
||||
var userId = commentedURLS.getLong(USER_ID);
|
||||
var urlHash = commentedURLS.getString(URL_HASH);
|
||||
if (userId == 0) continue;
|
||||
var url = commentedURLS.getString(URL);
|
||||
LOG.log(DEBUG,url);
|
||||
var timestamp = commentedURLS.getLong(TIMESTAMP);
|
||||
var comment = commentedURLS.getString(COMMENT);
|
||||
if (!isSet(comment)) comment = "";
|
||||
var dt = is0(timestamp) ? LocalDateTime.now() : LocalDateTime.ofEpochSecond(timestamp,0,UTC);
|
||||
bookmarks.save(url,comment,List.of(userId),dt.withNano(0));
|
||||
var bm = bookmarks.save(url,comment,List.of(userId),dt.withNano(0));
|
||||
|
||||
String module = null;
|
||||
long entityId = 0;
|
||||
var matcher = pattern.matcher(url);
|
||||
if (matcher.find()){
|
||||
module = matcher.group(1);
|
||||
entityId = Long.parseLong(matcher.group(2));
|
||||
LOG.log(DEBUG,"This module is referring to Umbrella`s {0} {1}",module,entityId);
|
||||
}
|
||||
|
||||
var urlTags = select(ALL).from(TABLE_TAGS).where(URL_HASH,equal(urlHash)).where(USER_ID,equal(userId)).exec(db);
|
||||
var insertQuery = insertInto(TABLE_TAGS_NEW,TAG,MODULE,ENTITY_ID,USER_ID).ignoreDuplicates(SQLITE);
|
||||
while (urlTags.next()){
|
||||
var tag = urlTags.getString(TAG);
|
||||
insertQuery.values(tag,BOOKMARK,bm.urlId(),userId);
|
||||
if (module != null && entityId != 0) insertQuery.values(tag,module,entityId,userId);
|
||||
}
|
||||
insertQuery.execute(db).close();
|
||||
urlTags.close();
|
||||
}
|
||||
commentedURLS.close();
|
||||
|
||||
// UPDATE TAGS
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -127,9 +152,9 @@ public class SqliteDb extends BaseDb implements TagDB{
|
||||
}
|
||||
|
||||
|
||||
private void createTagTables() {
|
||||
private void createNewTagTable() {
|
||||
var createTable = """
|
||||
CREATE TABLE IF NOT EXISTS "{0}" (
|
||||
CREATE TABLE IF NOT EXISTS {0} (
|
||||
{1} VARCHAR(255) NOT NULL,
|
||||
{2} VARCHAR(20) NOT NULL,
|
||||
{3} INTEGER NOT NULL,
|
||||
@@ -137,11 +162,35 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
||||
PRIMARY KEY ({1}, {2}, {3}, {4})
|
||||
)""";
|
||||
try {
|
||||
var stmt = db.prepareStatement(format(createTable,TABLE_TAGS, TAG, MODULE, ID, USER_ID));
|
||||
var stmt = db.prepareStatement(format(createTable,TABLE_TAGS_NEW, TAG, MODULE, ENTITY_ID, USER_ID));
|
||||
stmt.execute();
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS,e);
|
||||
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS_NEW,e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void dropOldTables(){
|
||||
var sql = "DROP TABLE IF EXISTS {0}";
|
||||
for (var table : List.of(TABLE_TAGS,TABLE_COMMENTS,TABLE_TOKENS,TABLE_URL_COMMENTS,TABLE_URLS)) try {
|
||||
var stmt = db.prepareStatement(format(sql,table));
|
||||
stmt.execute();
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS_NEW,e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void renameNewTagTable() {
|
||||
var sql = "ALTER TABLE {0} RENAME TO {1}";
|
||||
try {
|
||||
var stmt = db.prepareStatement(format(sql,TABLE_TAGS_NEW, TABLE_TAGS));
|
||||
stmt.execute();
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS_NEW,e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -150,10 +199,10 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
||||
public String delete(long userId, String module, long entityId, String tag) {
|
||||
try {
|
||||
Query.delete().from(TABLE_TAGS)
|
||||
.where(TAG,equal(tag)).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,equal(userId))
|
||||
.where(TAG,equal(tag)).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,equal(userId))
|
||||
.execute(db);
|
||||
Query.delete().from(TABLE_TAGS)
|
||||
.where(TAG,equal(tag)).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,isNull())
|
||||
.where(TAG,equal(tag)).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,isNull())
|
||||
.execute(db);
|
||||
return tag;
|
||||
} catch (SQLException e){
|
||||
@@ -165,7 +214,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
||||
public void deleteEntity(String module, long entityId) {
|
||||
try {
|
||||
Query.delete().from(TABLE_TAGS)
|
||||
.where(MODULE,equal(module)).where(ID,equal(entityId))
|
||||
.where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId))
|
||||
.execute(db);
|
||||
} catch (SQLException e){
|
||||
throw new UmbrellaException("Failed to save tags ({0} {1})",module,entityId);
|
||||
@@ -179,14 +228,14 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
||||
var result = new HashMap<String,List<Long>>();
|
||||
while (rs.next()){
|
||||
var module = rs.getString(MODULE);
|
||||
var entityId = rs.getLong(ID);
|
||||
var entityId = rs.getLong(ENTITY_ID);
|
||||
result.computeIfAbsent(module, k -> new ArrayList<>()).add(entityId);
|
||||
}
|
||||
rs.close();
|
||||
rs = select(ALL).from(TABLE_TAGS).where(TAG,equal(tag)).where(USER_ID,isNull()).exec(db);
|
||||
while (rs.next()){
|
||||
var module = rs.getString(MODULE);
|
||||
var entityId = rs.getLong(ID);
|
||||
var entityId = rs.getLong(ENTITY_ID);
|
||||
result.computeIfAbsent(module, k -> new ArrayList<>()).add(entityId);
|
||||
}
|
||||
rs.close();
|
||||
@@ -205,9 +254,9 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
||||
public Set<String> list(long userId, String module, long entityId) {
|
||||
try {
|
||||
var tags = new HashSet<String>();
|
||||
var rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,equal(userId)).exec(db);
|
||||
var rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,equal(userId)).exec(db);
|
||||
while (rs.next()) tags.add(rs.getString(1));
|
||||
rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,isNull()).exec(db);
|
||||
rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,isNull()).exec(db);
|
||||
while (rs.next()) tags.add(rs.getString(1));
|
||||
rs.close();
|
||||
return tags;
|
||||
@@ -219,7 +268,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
||||
@Override
|
||||
public void save(Collection<Long> userIds, String module, long entityId, Collection<String> tags) {
|
||||
try {
|
||||
var query = replaceInto(TABLE_TAGS,USER_ID,MODULE,ID,TAG);
|
||||
var query = replaceInto(TABLE_TAGS,USER_ID,MODULE,ENTITY_ID,TAG);
|
||||
for (var tag : tags) {
|
||||
if (userIds == null) { // tags not assigned to a user are available to all users
|
||||
query.values(null, module, entityId, tag);
|
||||
|
||||
Reference in New Issue
Block a user