implemented transition from old bookmark database (tags.db) to separate database for bookmarks and tags

This commit is contained in:
2025-08-06 01:22:25 +02:00
parent deb9a7b5c7
commit 6f1fdc1f95
7 changed files with 84 additions and 34 deletions

View File

@@ -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";
}

View File

@@ -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);