working on wiki db transition
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -11,4 +11,6 @@ public interface NoteService {
|
|||||||
Map<Long,Note> getNotes(String module, String entityId) throws UmbrellaException;
|
Map<Long,Note> getNotes(String module, String entityId) throws UmbrellaException;
|
||||||
|
|
||||||
Note save(Note note);
|
Note save(Note note);
|
||||||
|
|
||||||
|
void updateId(String module, Object oldId, Object newId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,19 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFi
|
|||||||
|
|
||||||
public class WikiPage implements Mappable {
|
public class WikiPage implements Mappable {
|
||||||
|
|
||||||
private String id;
|
private long id;
|
||||||
|
private String title;
|
||||||
private int version;
|
private int version;
|
||||||
private final List<Integer> versions = new ArrayList<>();
|
private final List<Integer> versions = new ArrayList<>();
|
||||||
private final Map<Long,Member> members = new HashMap<>();
|
private final Map<Long,Member> members = new HashMap<>();
|
||||||
private String content;
|
private String content;
|
||||||
private Set<String> dirtyFields = new HashSet<>();
|
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.id = id;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String content(){
|
public String content(){
|
||||||
@@ -43,14 +45,12 @@ public class WikiPage implements Mappable {
|
|||||||
return Set.copyOf(dirtyFields);
|
return Set.copyOf(dirtyFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String id(){
|
public long id(){
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WikiPage id(String newVal) {
|
public WikiPage id(long newVal){
|
||||||
if (id.equals(newVal)) return this;
|
|
||||||
id = newVal;
|
id = newVal;
|
||||||
dirtyFields.add(ID);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ public class WikiPage implements Mappable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static WikiPage of(ResultSet rs) throws SQLException {
|
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) {
|
public WikiPage patch(JSONObject json, UserService users) {
|
||||||
@@ -72,7 +72,7 @@ public class WikiPage implements Mappable {
|
|||||||
switch (key){
|
switch (key){
|
||||||
case ID:
|
case ID:
|
||||||
if (!(val instanceof String s)) throw invalidFieldException(ID,"String");
|
if (!(val instanceof String s)) throw invalidFieldException(ID,"String");
|
||||||
id(s);
|
title(s);
|
||||||
break;
|
break;
|
||||||
case CONTENT:
|
case CONTENT:
|
||||||
if (!(val instanceof String s)) throw invalidFieldException(CONTENT,"String");
|
if (!(val instanceof String s)) throw invalidFieldException(CONTENT,"String");
|
||||||
@@ -106,6 +106,17 @@ public class WikiPage implements Mappable {
|
|||||||
return this;
|
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
|
@Override
|
||||||
public Map<String, Object> toMap() {
|
public Map<String, Object> toMap() {
|
||||||
var memberMap = new HashMap<Long,Map<String,Object>>();
|
var memberMap = new HashMap<Long,Map<String,Object>>();
|
||||||
|
|||||||
@@ -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.Util.mapValues;
|
||||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
||||||
import static de.srsoftware.umbrella.notes.Constants.CONFIG_DATABASE;
|
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 com.sun.net.httpserver.HttpExchange;
|
||||||
import de.srsoftware.configuration.Configuration;
|
import de.srsoftware.configuration.Configuration;
|
||||||
import de.srsoftware.tools.Path;
|
import de.srsoftware.tools.Path;
|
||||||
import de.srsoftware.tools.SessionToken;
|
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.BaseHandler;
|
||||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||||
import de.srsoftware.umbrella.core.api.NoteService;
|
import de.srsoftware.umbrella.core.api.NoteService;
|
||||||
@@ -180,4 +183,8 @@ public class NoteModule extends BaseHandler implements NoteService {
|
|||||||
return notesDb.save(note);
|
return notesDb.save(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateId(String module, Object oldId, Object newId) {
|
||||||
|
notesDb.updateId(module,oldId,newId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,6 @@ public interface NotesDb {
|
|||||||
Note load(long noteId);
|
Note load(long noteId);
|
||||||
|
|
||||||
Note save(Note note);
|
Note save(Note note);
|
||||||
|
|
||||||
|
void updateId(String module, Object oldId, Object newId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.*;
|
||||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
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 de.srsoftware.umbrella.notes.Constants.*;
|
||||||
import static java.lang.System.Logger.Level.*;
|
import static java.lang.System.Logger.Level.*;
|
||||||
import static java.text.MessageFormat.format;
|
import static java.text.MessageFormat.format;
|
||||||
@@ -177,7 +178,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
|||||||
rs.close();
|
rs.close();
|
||||||
return notes;
|
return notes;
|
||||||
} catch (SQLException e) {
|
} 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}" (
|
|||||||
rs.close();
|
rs.close();
|
||||||
return notes;
|
return notes;
|
||||||
} catch (SQLException e) {
|
} 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}" (
|
|||||||
rs.close();
|
rs.close();
|
||||||
return notes;
|
return notes;
|
||||||
} catch (SQLException e) {
|
} 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}" (
|
|||||||
rs.close();
|
rs.close();
|
||||||
return note;
|
return note;
|
||||||
} catch (SQLException e) {
|
} 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}" (
|
|||||||
}
|
}
|
||||||
return note;
|
return note;
|
||||||
} catch (SQLException e){
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package de.srsoftware.umbrella.wiki;
|
|||||||
import de.srsoftware.tools.jdbc.Condition;
|
import de.srsoftware.tools.jdbc.Condition;
|
||||||
import de.srsoftware.tools.jdbc.Query;
|
import de.srsoftware.tools.jdbc.Query;
|
||||||
import de.srsoftware.umbrella.core.BaseDb;
|
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.Permission;
|
||||||
import de.srsoftware.umbrella.core.model.WikiPage;
|
import de.srsoftware.umbrella.core.model.WikiPage;
|
||||||
|
|
||||||
@@ -25,10 +25,11 @@ import static java.text.MessageFormat.format;
|
|||||||
|
|
||||||
public class SqliteDb extends BaseDb implements WikiDb {
|
public class SqliteDb extends BaseDb implements WikiDb {
|
||||||
private static final System.Logger LOG = System.getLogger("TaskDb");
|
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);
|
super(connection);
|
||||||
|
this.registry = registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,11 +64,26 @@ public class SqliteDb extends BaseDb implements WikiDb {
|
|||||||
var newUsers = TABLE_PAGES_USERS+"_new";
|
var newUsers = TABLE_PAGES_USERS+"_new";
|
||||||
createNewTables(newPages, newUsers);
|
createNewTables(newPages, newUsers);
|
||||||
transferValues(newPages, newUsers);
|
transferValues(newPages, newUsers);
|
||||||
//dropOldTables();
|
dropOldTables();
|
||||||
//moveNewTables();
|
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) {
|
private void createNewTables(String newPages, String newUsers) {
|
||||||
@@ -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
|
@Override
|
||||||
public List<String> listUserPages(long userId) {
|
public List<String> listUserPages(long userId) {
|
||||||
try {
|
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>();
|
var set = new ArrayList<String>();
|
||||||
while (rs.next()) set.add(rs.getString(ID));
|
while (rs.next()) set.add(rs.getString(TITLE));
|
||||||
rs.close();
|
rs.close();
|
||||||
return set;
|
return set;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@@ -126,8 +157,10 @@ public class SqliteDb extends BaseDb implements WikiDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WikiPage load(String id, Integer version) {
|
public WikiPage load(String title, Integer version) {
|
||||||
try {
|
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));
|
var query = select(ALL).from(TABLE_PAGES).where(ID,Condition.equal(id));
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
query.sort(VERSION+" DESC").limit(1);
|
query.sort(VERSION+" DESC").limit(1);
|
||||||
@@ -135,17 +168,35 @@ public class SqliteDb extends BaseDb implements WikiDb {
|
|||||||
query.where(VERSION,Condition.equal(version));
|
query.where(VERSION,Condition.equal(version));
|
||||||
}
|
}
|
||||||
var rs = query.exec(db);
|
var rs = query.exec(db);
|
||||||
WikiPage page = null;
|
|
||||||
if (rs.next()) page = WikiPage.of(rs);
|
if (rs.next()) page = WikiPage.of(rs);
|
||||||
rs.close();
|
rs.close();
|
||||||
if (page == null) throw notFound("Failed to load wiki page \"{0}\" from database!",id);
|
} catch (NumberFormatException ignored){
|
||||||
rs = select(VERSION).from(TABLE_PAGES).where(ID,Condition.equal(id)).sort(VERSION).exec(db);
|
// 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();
|
var versions = page.versions();
|
||||||
while (rs.next()) versions.add(rs.getInt(VERSION));
|
while (rs.next()) versions.add(rs.getInt(VERSION));
|
||||||
rs.close();
|
rs.close();
|
||||||
return page;
|
return page;
|
||||||
} catch (SQLException e) {
|
} 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 {
|
|||||||
throw new RuntimeException(e);
|
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){
|
private int wikiPermissionCode(Permission perm){
|
||||||
@@ -220,23 +277,23 @@ public class SqliteDb extends BaseDb implements WikiDb {
|
|||||||
rs.close();
|
rs.close();
|
||||||
return map;
|
return map;
|
||||||
} catch (SQLException e) {
|
} 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
|
@Override
|
||||||
public WikiPage save(WikiPage page) {
|
public WikiPage save(WikiPage page) {
|
||||||
try {
|
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)){
|
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);
|
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();
|
query.execute(db).close();
|
||||||
}
|
}
|
||||||
return page;
|
return page;
|
||||||
} catch (SQLException e) {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class WikiModule extends BaseHandler implements WikiService {
|
|||||||
public WikiModule(ModuleRegistry registry, Configuration config) {
|
public WikiModule(ModuleRegistry registry, Configuration config) {
|
||||||
super(registry);
|
super(registry);
|
||||||
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
|
||||||
wikiDb = new SqliteDb(connect(dbFile));
|
wikiDb = new SqliteDb(connect(dbFile),registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user