Browse Source

working on wiki db transition

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
module/wiki
Stephan Richter 2 months ago
parent
commit
41eb4ca9dd
  1. 2
      core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java
  2. 27
      core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java
  3. 7
      notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java
  4. 2
      notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java
  5. 20
      notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java
  6. 95
      wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java
  7. 2
      wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java

2
core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java

@ -11,4 +11,6 @@ public interface NoteService { @@ -11,4 +11,6 @@ public interface NoteService {
Map<Long,Note> getNotes(String module, String entityId) throws UmbrellaException;
Note save(Note note);
void updateId(String module, Object oldId, Object newId);
}

27
core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java

@ -14,17 +14,19 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFi @@ -14,17 +14,19 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFi
public class WikiPage implements Mappable {
private String id;
private long id;
private String title;
private int version;
private final List<Integer> versions = new ArrayList<>();
private final Map<Long,Member> members = new HashMap<>();
private String content;
private Set<String> dirtyFields = new HashSet<>();
public WikiPage(String id, int version, String content) {
public WikiPage(long id, String title, int version, String content) {
this.id = id;
this.version = version;
this.content = content;
this.title = title;
}
public String content(){
@ -43,14 +45,12 @@ public class WikiPage implements Mappable { @@ -43,14 +45,12 @@ public class WikiPage implements Mappable {
return Set.copyOf(dirtyFields);
}
public String id(){
public long id(){
return id;
}
private WikiPage id(String newVal) {
if (id.equals(newVal)) return this;
public WikiPage id(long newVal){
id = newVal;
dirtyFields.add(ID);
return this;
}
@ -63,7 +63,7 @@ public class WikiPage implements Mappable { @@ -63,7 +63,7 @@ public class WikiPage implements Mappable {
}
public static WikiPage of(ResultSet rs) throws SQLException {
return new WikiPage(rs.getString(ID),rs.getInt(VERSION),rs.getString(CONTENT));
return new WikiPage(rs.getLong(ID), rs.getString(TITLE),rs.getInt(VERSION),rs.getString(CONTENT));
}
public WikiPage patch(JSONObject json, UserService users) {
@ -72,7 +72,7 @@ public class WikiPage implements Mappable { @@ -72,7 +72,7 @@ public class WikiPage implements Mappable {
switch (key){
case ID:
if (!(val instanceof String s)) throw invalidFieldException(ID,"String");
id(s);
title(s);
break;
case CONTENT:
if (!(val instanceof String s)) throw invalidFieldException(CONTENT,"String");
@ -106,6 +106,17 @@ public class WikiPage implements Mappable { @@ -106,6 +106,17 @@ public class WikiPage implements Mappable {
return this;
}
public String title(){
return title;
}
private WikiPage title(String newVal) {
if (title.equals(newVal)) return this;
title = newVal;
dirtyFields.add(TITLE);
return this;
}
@Override
public Map<String, Object> toMap() {
var memberMap = new HashMap<Long,Map<String,Object>>();

7
notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java

@ -9,11 +9,14 @@ import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE; @@ -9,11 +9,14 @@ import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE;
import static de.srsoftware.umbrella.core.Util.mapValues;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.notes.Constants.CONFIG_DATABASE;
import static de.srsoftware.umbrella.notes.Constants.TABLE_NOTES;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.configuration.Configuration;
import de.srsoftware.tools.Path;
import de.srsoftware.tools.SessionToken;
import de.srsoftware.tools.jdbc.Condition;
import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.ModuleRegistry;
import de.srsoftware.umbrella.core.api.NoteService;
@ -180,4 +183,8 @@ public class NoteModule extends BaseHandler implements NoteService { @@ -180,4 +183,8 @@ public class NoteModule extends BaseHandler implements NoteService {
return notesDb.save(note);
}
@Override
public void updateId(String module, Object oldId, Object newId) {
notesDb.updateId(module,oldId,newId);
}
}

2
notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java

@ -29,4 +29,6 @@ public interface NotesDb { @@ -29,4 +29,6 @@ public interface NotesDb {
Note load(long noteId);
Note save(Note note);
void updateId(String module, Object oldId, Object newId);
}

20
notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java

@ -6,6 +6,7 @@ import static de.srsoftware.tools.jdbc.Condition.like; @@ -6,6 +6,7 @@ import static de.srsoftware.tools.jdbc.Condition.like;
import static de.srsoftware.tools.jdbc.Query.*;
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
import static de.srsoftware.umbrella.notes.Constants.*;
import static java.lang.System.Logger.Level.*;
import static java.text.MessageFormat.format;
@ -177,7 +178,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -177,7 +178,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
rs.close();
return notes;
} catch (SQLException e) {
throw new UmbrellaException("Failed to search notes");
throw databaseException("Failed to search notes");
}
}
@ -194,7 +195,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -194,7 +195,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
rs.close();
return notes;
} catch (SQLException e) {
throw new UmbrellaException("Failed to load notes");
throw databaseException("Failed to load notes");
}
}
@ -210,7 +211,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -210,7 +211,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
rs.close();
return notes;
} catch (SQLException e) {
throw new UmbrellaException("Failed to load notes");
throw databaseException("Failed to load notes");
}
}
@ -223,7 +224,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -223,7 +224,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
rs.close();
return note;
} catch (SQLException e) {
throw new UmbrellaException("Failed to load note {0}",noteId);
throw databaseException("Failed to load note {0}",noteId);
}
}
@ -247,7 +248,16 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -247,7 +248,16 @@ CREATE TABLE IF NOT EXISTS "{0}" (
}
return note;
} catch (SQLException e){
throw new UmbrellaException("Failed to save note: {0}",note.text());
throw databaseException("Failed to save note: {0}",note.text());
}
}
@Override
public void updateId(String module, Object oldId, Object newId) {
try {
update(TABLE_NOTES).set(ENTITY_ID).where(MODULE,equal(module)).where(ENTITY_ID,equal(oldId)).prepare(db).apply(newId).close();
} catch (SQLException e) {
throw databaseException("Failed to update {0}.{1} → {0}.{2}",module,oldId,newId);
}
}
}

95
wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java

@ -3,7 +3,7 @@ package de.srsoftware.umbrella.wiki; @@ -3,7 +3,7 @@ package de.srsoftware.umbrella.wiki;
import de.srsoftware.tools.jdbc.Condition;
import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.BaseDb;
import de.srsoftware.umbrella.core.model.Hash;
import de.srsoftware.umbrella.core.ModuleRegistry;
import de.srsoftware.umbrella.core.model.Permission;
import de.srsoftware.umbrella.core.model.WikiPage;
@ -25,10 +25,11 @@ import static java.text.MessageFormat.format; @@ -25,10 +25,11 @@ import static java.text.MessageFormat.format;
public class SqliteDb extends BaseDb implements WikiDb {
private static final System.Logger LOG = System.getLogger("TaskDb");
private static final int INITIAL_DB_VERSION = 1;
private final ModuleRegistry registry;
public SqliteDb(Connection connection) {
public SqliteDb(Connection connection, ModuleRegistry registry) {
super(connection);
this.registry = registry;
}
@Override
@ -63,11 +64,26 @@ public class SqliteDb extends BaseDb implements WikiDb { @@ -63,11 +64,26 @@ public class SqliteDb extends BaseDb implements WikiDb {
var newUsers = TABLE_PAGES_USERS+"_new";
createNewTables(newPages, newUsers);
transferValues(newPages, newUsers);
//dropOldTables();
//moveNewTables();
dropOldTables();
moveNewTables(newPages, newUsers);
}
return setCurrentVersion(1);
return setCurrentVersion(2);
}
private void moveNewTables(String newPages, String newUsers) {
try {
db.prepareStatement(format("ALTER TABLE {0} RENAME TO {1}",newPages,TABLE_PAGES)).execute();
} catch (SQLException e) {
LOG.log(ERROR, "Failed to rename table {0} → {1}", newPages, TABLE_PAGES, e);
throw new RuntimeException(e);
}
try {
db.prepareStatement(format("ALTER TABLE {0} RENAME TO {1}",newUsers,TABLE_PAGES_USERS)).execute();
} catch (SQLException e) {
LOG.log(ERROR, "Failed to rename table {0} → {1}", newUsers, TABLE_PAGES_USERS, e);
throw new RuntimeException(e);
}
}
private void createNewTables(String newPages, String newUsers) {
@ -112,12 +128,27 @@ public class SqliteDb extends BaseDb implements WikiDb { @@ -112,12 +128,27 @@ public class SqliteDb extends BaseDb implements WikiDb {
}
}
private void dropOldTables() {
try {
db.prepareStatement(format("DROP TABLE {0}",TABLE_PAGES)).execute();
} catch (SQLException e) {
LOG.log(ERROR, "Failed to drop table {0}", TABLE_PAGES, e);
throw new RuntimeException(e);
}
try {
db.prepareStatement(format("DROP TABLE {0}",TABLE_PAGES_USERS)).execute();
} catch (SQLException e) {
LOG.log(ERROR, "Failed to drop table {0}", TABLE_PAGES, e);
throw new RuntimeException(e);
}
}
@Override
public List<String> listUserPages(long userId) {
try {
var rs = select(ID,"MAX(version) AS version").from(TABLE_PAGES).leftJoin(ID,TABLE_PAGES_USERS,PAGE_ID).where(USER_ID, Condition.equal(userId)).groupBy(ID).sort("ID COLLATE NOCASE ASC").exec(db);
var rs = select(TITLE,"MAX(version) AS version").from(TABLE_PAGES).leftJoin(ID,TABLE_PAGES_USERS,PAGE_ID).where(USER_ID, Condition.equal(userId)).groupBy(TITLE).sort("TITLE COLLATE NOCASE ASC").exec(db);
var set = new ArrayList<String>();
while (rs.next()) set.add(rs.getString(ID));
while (rs.next()) set.add(rs.getString(TITLE));
rs.close();
return set;
} catch (SQLException e) {
@ -126,8 +157,10 @@ public class SqliteDb extends BaseDb implements WikiDb { @@ -126,8 +157,10 @@ public class SqliteDb extends BaseDb implements WikiDb {
}
@Override
public WikiPage load(String id, Integer version) {
try {
public WikiPage load(String title, Integer version) {
WikiPage page = null;
try { // Try to load by id
long id = Long.parseLong(title);
var query = select(ALL).from(TABLE_PAGES).where(ID,Condition.equal(id));
if (version == null) {
query.sort(VERSION+" DESC").limit(1);
@ -135,17 +168,35 @@ public class SqliteDb extends BaseDb implements WikiDb { @@ -135,17 +168,35 @@ public class SqliteDb extends BaseDb implements WikiDb {
query.where(VERSION,Condition.equal(version));
}
var rs = query.exec(db);
WikiPage page = null;
if (rs.next()) page = WikiPage.of(rs);
rs.close();
if (page == null) throw notFound("Failed to load wiki page \"{0}\" from database!",id);
rs = select(VERSION).from(TABLE_PAGES).where(ID,Condition.equal(id)).sort(VERSION).exec(db);
} catch (NumberFormatException ignored){
// title is not an id, go on…
} catch (SQLException e) {
throw databaseException("Failed to load wiki page \"{0}\" from database!",title);
}
if (page == null) try { // page was not loaded by ID
var query = select(ALL).from(TABLE_PAGES).where(TITLE,Condition.equal(title));
if (version == null) {
query.sort(VERSION+" DESC").limit(1);
} else {
query.where(VERSION,Condition.equal(version));
}
var rs = query.exec(db);
if (rs.next()) page = WikiPage.of(rs);
rs.close();
} catch (SQLException e) {
throw databaseException("Failed to load wiki page \"{0}\" from database!",title);
}
if (page == null) throw notFound("Failed to load wiki page \"{0}\" from database!",title);
try {
var rs = select(VERSION).from(TABLE_PAGES).where(ID,Condition.equal(page.id())).sort(VERSION).exec(db);
var versions = page.versions();
while (rs.next()) versions.add(rs.getInt(VERSION));
rs.close();
return page;
} catch (SQLException e) {
throw databaseException("Failed to load wiki page \"{0}\" from database!",id);
throw databaseException("Failed to load wiki page \"{0}\" from database!",title);
}
}
@ -191,6 +242,12 @@ public class SqliteDb extends BaseDb implements WikiDb { @@ -191,6 +242,12 @@ public class SqliteDb extends BaseDb implements WikiDb {
throw new RuntimeException(e);
}
var notes = registry.noteService();
for (var entry : pageMap.entrySet()){
var oldId = entry.getKey();
var newId = entry.getValue();
notes.updateId("wiki",oldId,newId);
}
}
private int wikiPermissionCode(Permission perm){
@ -220,23 +277,23 @@ public class SqliteDb extends BaseDb implements WikiDb { @@ -220,23 +277,23 @@ public class SqliteDb extends BaseDb implements WikiDb {
rs.close();
return map;
} catch (SQLException e) {
throw databaseException("Failed to load members of \"{0}\" from database!",page.id());
throw databaseException("Failed to load members of \"{0}\" from database!",page.title());
}
}
@Override
public WikiPage save(WikiPage page) {
try {
if (page.isDirty(CONTENT) || page.isDirty(ID)) insertInto(TABLE_PAGES,ID,VERSION,CONTENT).values(page.id(),page.version(),page.content()).execute(db).close();
if (page.isDirty(CONTENT) || page.isDirty(ID)) insertInto(TABLE_PAGES,ID,VERSION,CONTENT).values(page.title(),page.version(),page.content()).execute(db).close();
if (page.isDirty(MEMBERS)){
Query.delete().from(TABLE_PAGES_USERS).where(PAGE_ID,Condition.equal(page.id())).where(USER_ID,Condition.notIn(page.members().keySet().toArray())).execute(db);
Query.delete().from(TABLE_PAGES_USERS).where(PAGE_ID,Condition.equal(page.title())).where(USER_ID,Condition.notIn(page.members().keySet().toArray())).execute(db);
var query = replaceInto(TABLE_PAGES_USERS,PAGE_ID,USER_ID,PERMISSIONS);
for (var member : page.members().entrySet()) query.values(page.id(),member.getKey(),wikiPermissionCode(member.getValue().permission()));
for (var member : page.members().entrySet()) query.values(page.title(),member.getKey(),wikiPermissionCode(member.getValue().permission()));
query.execute(db).close();
}
return page;
} catch (SQLException e) {
throw databaseException("Failed to write wiki page \"{0}\" to database",page.id(),e);
throw databaseException("Failed to write wiki page \"{0}\" to database",page.title(),e);
}
}
}

2
wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java

@ -29,7 +29,7 @@ public class WikiModule extends BaseHandler implements WikiService { @@ -29,7 +29,7 @@ public class WikiModule extends BaseHandler implements WikiService {
public WikiModule(ModuleRegistry registry, Configuration config) {
super(registry);
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
wikiDb = new SqliteDb(connect(dbFile));
wikiDb = new SqliteDb(connect(dbFile),registry);
}

Loading…
Cancel
Save