From b361731cabde3a7dbc797bc6fb48564600a2bb90 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Mon, 13 Oct 2025 14:52:15 +0200 Subject: [PATCH] working on transformation of stock tables --- build.gradle.kts | 2 +- .../srsoftware/umbrella/core/Constants.java | 1 + .../umbrella/core/model/Location.java | 51 +++--- .../srsoftware/umbrella/stock/SqliteDb.java | 148 +++++++++++++++--- 4 files changed, 147 insertions(+), 55 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 18ff58e..185edfd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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:2.0.0") + implementation("de.srsoftware:tools.jdbc:2.0.2") implementation("de.srsoftware:tools.http:6.0.5") implementation("de.srsoftware:tools.mime:1.1.3") implementation("de.srsoftware:tools.logging:1.3.2") diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Constants.java b/core/src/main/java/de/srsoftware/umbrella/core/Constants.java index 42818fa..a5d49b7 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/Constants.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/Constants.java @@ -8,6 +8,7 @@ public class Constants { private Constants(){} + public static final String ADDRESS = "address"; public static final String ALLOWED_STATES = "allowed_states"; public static final String ATTACHMENTS = "attachments"; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java index 8e3b209..47452a1 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java @@ -8,8 +8,8 @@ import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; public class Location { - long owner; - boolean ownerIsCompany = false; + private long owner; + private boolean ownerIsCompany = false; private long id; private Long parentLocationId; private String name; @@ -25,36 +25,29 @@ public class Location { this.description = description; } + public final long id(){ + return id; + } + + public String description() { + return description; + } + + public String name() { + return name; + } + public static Location of(ResultSet rs){ return null; } - public static Location ofLegacy(ResultSet rs) throws SQLException { - var id = rs.getString(ID); - var parent = rs.getString(LOCATION_ID); - var name = rs.getString(NAME); - var description = rs.getString(DESCRIPTION); - var ownerIsCompany = false; - var parts = id.split(":"); - if (parts.length != 3) throw databaseException("Legacy id expected to be of format ss:dd:ss, encountered {0}",id); - switch (parts[0]){ - case "company": - ownerIsCompany = true; break; - case "user": - break; - case null, default: - throw databaseException("Legacy id expected to start with 'company' or 'user', encountered {0}",id); - } - var owner = 0L; - try { - owner = Long.parseLong(parts[1]); - } catch (NumberFormatException nfe){ - throw databaseException("Legacy id expected to be of format ss:dd:ss, encountered {0}",id); - } - Long parentLocationId = null; - if (parent != null){ - // TODO - } - return new Location(owner, ownerIsCompany, id, parentLocationId, name, description); + + + public long ownerCoded(){ + return ownerIsCompany ? -owner : owner; + } + + public Long parent(){ + return parentLocationId; } } diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java index 8ca9794..941c04e 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java @@ -8,23 +8,42 @@ import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; import static de.srsoftware.umbrella.stock.Constants.*; import static java.lang.System.Logger.Level.ERROR; +import static java.lang.System.Logger.Level.WARNING; import static java.text.MessageFormat.format; import de.srsoftware.tools.Tuple; -import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseDb; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; -import de.srsoftware.umbrella.core.model.Hash; import de.srsoftware.umbrella.core.model.Item; import de.srsoftware.umbrella.core.model.Location; import java.sql.Connection; +import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; +import java.util.*; public class SqliteDb extends BaseDb implements StockDb { + + private record LegacyLocation(String id, String parent, String name, String description){ + public static LegacyLocation of(ResultSet rs) throws SQLException { + return new LegacyLocation(rs.getString(ID), rs.getString(LOCATION_ID), rs.getString(NAME), rs.getString(DESCRIPTION)); + } + + public long owner() { + var parts = id.split(":"); + if (parts.length != 3) throw databaseException("Expected legacy location id to be of the form ss:dd:ss, encountered {0}!",id); + try { + var owner = Long.parseLong(parts[1]); + switch (parts[0]){ + case "company": return -owner; + case "user": return owner; + case null, default: throw databaseException("Expected legacy location id to start with 'company:' or 'user:', encountered {0}!",id); + } + } catch (NumberFormatException nfe){ + throw databaseException("Expected legacy location id to be of the form ss:dd:ss, encountered {0}!",id); + } + } + }; + public SqliteDb(Connection connection) { super(connection); } @@ -39,10 +58,24 @@ public class SqliteDb extends BaseDb implements StockDb { createPropertiesTable(); createItemPropsTable(); case 1: - transformLocationsTable(); - + dropTokenTable(); + case 2: + transformTables(); + replaceLocationsTable(); } - return setCurrentVersion(2); + return setCurrentVersion(3); + } + + private void createIntermediateItemsTable() throws SQLException { // create intermediate table + var sql = "CREATE TABLE IF NOT EXISTS items_temp ({0} LONG NOT NULL, {1} LONG NOT NULL, {2} VARCHAR(255), {3} VARCHAR(255) NOT NULL, {4} LONG NOT NULL, PRIMARY KEY({0}, {1}))"; + sql = format(sql, OWNER, ID, CODE, NAME, LOCATION_ID); + db.prepareStatement(sql).execute(); + } + + private void createIntermediateLocationTable() throws SQLException { // create intermediate table + var sql = "CREATE TABLE IF NOT EXISTS locations_temp ({0} INTEGER PRIMARY KEY, {1} INT DEFAULT NULL, {2} LONG NOT NULL, {3} VARCHAR(255) NOT NULL, {4} TEXT)"; + sql = format(sql, ID, PARENT_LOCATION_ID, OWNER, NAME, DESCRIPTION); + db.prepareStatement(sql).execute(); } private void createItemsTable() { @@ -85,6 +118,14 @@ public class SqliteDb extends BaseDb implements StockDb { } } + private void dropTokenTable() { + try { + db.prepareStatement("DROP TABLE IF EXISTS tokens").execute(); + } catch (SQLException e) { + throw databaseException("Failed to drop table tokens!"); + } + } + @Override public Collection listItems(long companyId) throws UmbrellaException { return List.of(); @@ -95,27 +136,16 @@ public class SqliteDb extends BaseDb implements StockDb { return List.of(); } - private void transformLocationsTable(){ + private void transformTables(){ try { - var tempTable = "locations_temp"; db.setAutoCommit(false); - { // create intermediate table - var sql = "CREATE TABLE IF NOT EXISTS locations_temp ({0} LONG NOT NULL, {1} LONG NOT NULL, {2} LONG DEFAULT NULL, {3} VARCHAR(255) NOT NULL, {4} TEXT)"; - sql = format(sql, OWNER, ID, PARENT_LOCATION_ID, NAME, DESCRIPTION); - db.prepareStatement(sql).execute(); - } - var locations = new ArrayList(); - { // fill intermediate table - var rs = select(ALL).from(tempTable).exec(db); - while (rs.next()) locations.add(Location.ofLegacy(rs)); - rs.close(); + createIntermediateLocationTable(); + createIntermediateItemsTable(); + var oldLocationIdsToNew = transformLocations(); + transformItems(oldLocationIdsToNew); - var query = insertInto(tempTable, OWNER, ID, PARENT_LOCATION_ID, NAME, DESCRIPTION); - for (var location : locations){ - } - } db.setAutoCommit(true); } catch (Exception e) { try { @@ -126,4 +156,72 @@ public class SqliteDb extends BaseDb implements StockDb { throw databaseException("Failed to transform {0} table!",TABLE_LOCATIONS); } } + + private void replaceLocationsTable() { + try { + db.setAutoCommit(false); + db.prepareStatement(format("DROP TABLE {0}",TABLE_LOCATIONS)).execute(); + db.prepareStatement(format("ALTER TABLE {0} RENAME TO {1}","locations_temp",TABLE_LOCATIONS)).execute(); + db.setAutoCommit(true); + } catch (SQLException e){ + throw databaseException("Failed to replace locations table!"); + } + } + + private void transformItems(Map oldLocationIdsToNew) throws SQLException { + var rs = select(ALL).from(TABLE_ITEMS).exec(db); + var insert = insertInto("items_temp",OWNER, ID, CODE, NAME, LOCATION_ID); + while (rs.next()){ + var oldId = rs.getString(ID); + var parts = oldId.split(":"); + var owner = 0L; + var id = 0L; + try { + owner = Long.parseLong(parts[1]); + id = Long.parseLong(parts[2]); + } catch (NumberFormatException e){ + throw databaseException("Expected item id to be of format ss:dd:dd, but encountered \"{0}\"",oldId); + } + var ownerIsCompany = switch (parts[0]){ + case "company" -> true; + case "user" -> false; + case null, default -> throw databaseException("Expected item id to start with 'company:' or 'user:', encountered \"{0}\"",oldId); + }; + var oldLocationId = rs.getString(LOCATION_ID); + var locationId = oldLocationIdsToNew.get(oldLocationId); + if (locationId == null) throw databaseException("Item {0} of {1} {2} refers to location {3}, which is unknown!",id,parts[1],owner,oldLocationId); + insert.values(ownerIsCompany?-owner:owner, id, rs.getString(CODE), rs.getString(NAME), locationId).execute(db).getGeneratedKeys(); + } + rs.close(); + insert.execute(db); + } + + private Map transformLocations() throws SQLException { + var locations = new ArrayList(); + var oldToNew = new HashMap(); + var rs = select(ALL).from(TABLE_LOCATIONS).exec(db); + while (rs.next()) locations.add(LegacyLocation.of(rs)); + rs.close(); + + var query = insertInto("locations_temp", PARENT_LOCATION_ID, OWNER, NAME, DESCRIPTION); + while (!locations.isEmpty()){ + var legacyLocation = locations.removeFirst(); + var parentRef = nullIfEmpty(legacyLocation.parent()); + Long parentId = null; + if (parentRef != null) { + parentId = oldToNew.get(parentRef); + if (parentId == null) { // parent not processed, re-add to end of queue + LOG.log(WARNING,"Postpoining {0}, as {1} is not present…",legacyLocation.id,legacyLocation.parent); + locations.add(legacyLocation); + continue; + } + } + rs = query.values(parentId, legacyLocation.owner(), legacyLocation.name(), legacyLocation.description()).execute(db).getGeneratedKeys(); + var id = rs.getLong(1); + oldToNew.put(legacyLocation.id(),id); + rs.close(); + } + return oldToNew; + } + }