From 6ea73f4890934d9dc0407fdbbbf058fb7cd4b5e8 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Tue, 28 Oct 2025 22:25:31 +0100 Subject: [PATCH] Refactor NodeData Signed-off-by: Chaoscaot --- .../SQL/src/de/steamwar/sql/NodeData.kt | 154 +++++++----------- .../SQL/src/de/steamwar/sql/SchematicNode.kt | 2 +- .../SQL/src/de/steamwar/sql/UserConfig.kt | 6 +- .../steamwar/sql/internal/KotlinDatabase.kt | 6 +- .../src/de/steamwar/routes/Schematic.kt | 1 + 5 files changed, 70 insertions(+), 99 deletions(-) diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.kt b/CommonCore/SQL/src/de/steamwar/sql/NodeData.kt index 63d8ccaf..fd9a2446 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/NodeData.kt +++ b/CommonCore/SQL/src/de/steamwar/sql/NodeData.kt @@ -17,121 +17,83 @@ * along with this program. If not, see . */ -package de.steamwar.sql; +package de.steamwar.sql -import de.steamwar.sql.internal.*; -import lombok.AllArgsConstructor; -import lombok.Getter; +import de.steamwar.sql.internal.useDb +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.dao.id.CompositeID +import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.statements.api.ExposedBlob +import org.jetbrains.exposed.v1.dao.CompositeEntity +import org.jetbrains.exposed.v1.dao.CompositeEntityClass +import org.jetbrains.exposed.v1.javatime.timestamp +import org.jetbrains.exposed.v1.jdbc.insertIgnore +import java.io.InputStream +import java.util.zip.GZIPInputStream -import javax.swing.plaf.nimbus.State; -import java.io.*; -import java.sql.PreparedStatement; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.List; -import java.util.Optional; -import java.util.zip.GZIPInputStream; +object NodeDataTable: CompositeIdTable("NodeData") { + val nodeId = reference("NodeId", SchematicNodeTable) + val createdAt = timestamp("CreatedAt").entityId() + val nodeFormat = enumeration("NodeFormat", NodeData.SchematicFormat::class) + val schemData = blob("SchemData") -@AllArgsConstructor -@Getter -public class NodeData { - static { - new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); - new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); - new SqlTypeMapper<>(BufferedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("BufferedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); + override val primaryKey = PrimaryKey(nodeId, createdAt) - SqlTypeMapper.ordinalEnumMapper(SchematicFormat.class); + init { + addIdColumn(nodeId) } +} - private static final Table table = new Table<>(NodeData.class); +class NodeData(id: EntityID): CompositeEntity(id) { + val nodeId by NodeDataTable.nodeId + val createdAt by NodeDataTable.createdAt + val nodeFormat by NodeDataTable.nodeFormat + val schemData by NodeDataTable.schemData - private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?)", true); - private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ? AND CreatedAt = ?"); - private static final Statement delete = table.delete(Table.PRIMARY); + companion object: CompositeEntityClass(NodeDataTable) { + @JvmStatic + fun getLatest(node: SchematicNode) = useDb { + find { (NodeDataTable.nodeId eq node.nodeId) }.orderBy(NodeDataTable.createdAt to SortOrder.DESC).firstOrNull() + } - private static final SelectStatement get = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt "); - private static final Statement getRevisions = new Statement("SELECT COUNT(DISTINCT CreatedAt) as CNT FROM NodeData WHERE NodeId = ?"); - private static final SelectStatement getLatest = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt DESC LIMIT 1"); + @JvmStatic + fun get(node: SchematicNode) = useDb { + find { (NodeDataTable.nodeId eq node.nodeId) }.orderBy(NodeDataTable.createdAt to SortOrder.ASC).toList() + } - public static NodeData getLatest(SchematicNode node) { - if (node.isDir()) throw new IllegalArgumentException("Node is dir"); - return Optional.ofNullable(getLatest.select(node)).orElseGet(() -> new NodeData(node.getId(), Timestamp.from(Instant.now()), SchematicFormat.MCEDIT)); - } + @JvmStatic + fun get(node: SchematicNode, revision: Int) = useDb { + find { NodeDataTable.nodeId eq node.nodeId }.orderBy(NodeDataTable.createdAt to SortOrder.ASC).toList().get(revision - 1) + } - public static List get(SchematicNode node) { - return get.listSelect(node); - } + @JvmStatic + fun getRevisions(node: SchematicNode) = useDb { + count(NodeDataTable.nodeId eq node.nodeId).toInt() + } - public static NodeData get(SchematicNode node, int revision) { - return get.listSelect(node).get(revision - 1); - } - - public static int getRevisions(SchematicNode node) { - return getRevisions.select(rs -> { - if (rs.next()) { - return rs.getInt("CNT"); - } else { - return 0; + @JvmStatic + fun saveFromStream(node: SchematicNode, blob: InputStream, format: SchematicFormat) { + NodeDataTable.insertIgnore { + it[NodeDataTable.nodeId] = EntityID(node.getId(), SchematicNodeTable) + it[NodeDataTable.nodeFormat] = format + it[NodeDataTable.schemData] = ExposedBlob(blob) } - }, node); - } - - public static void saveFromStream(SchematicNode node, InputStream blob, SchematicFormat format) { - updateDatabase.update(node.getId(), format, blob); - } - - @Field(keys = {Table.PRIMARY}) - private final int nodeId; - - @Field(keys = {Table.PRIMARY}) - private Timestamp createdAt; - - @Field - public SchematicFormat nodeFormat; - - public InputStream schemData() throws IOException { - return schemData(true); - } - - public InputStream schemData(boolean decompress) throws IOException { - try { - return selSchemData.select(rs -> { - rs.next(); - InputStream schemData = rs.getBinaryStream("SchemData"); - try { - if(rs.wasNull() || schemData.available() == 0) { - throw new SecurityException("SchemData is null"); - } - if (decompress) { - return new GZIPInputStream(schemData); - } else { - return schemData; - } - } catch (IOException e) { - throw new SecurityException("SchemData is wrong", e); - } - }, nodeId, createdAt); - } catch (Exception e) { - throw new IOException(e); } } - @Deprecated - public void saveFromStream(InputStream blob, SchematicFormat newFormat) { - saveFromStream(SchematicNode.getSchematicNode(nodeId), blob, newFormat); + fun schemData(decompress: Boolean) = useDb { + schemData.inputStream.let { if(decompress) GZIPInputStream(it) else it } } - public void delete() { - delete.update(nodeId, createdAt); - } + fun schemData() = schemData(true) - @AllArgsConstructor - @Getter - public enum SchematicFormat { + override fun delete() = useDb { super.delete() } + + enum class SchematicFormat(val fileEnding: String) { MCEDIT(".schematic"), SPONGE_V2(".schem"), SPONGE_V3(".schem"); - - public final String fileEnding; } -} +} \ No newline at end of file diff --git a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt index d1495b46..5117eb13 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt +++ b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt @@ -335,7 +335,7 @@ class SchematicNode(id: EntityID) : IntEntity(id) { val members: Set by lazy { NodeMember.getNodeMembers(nodeId) } private lateinit var breadcrumbs: String - fun getFileEnding(): String = checkDir { NodeData.getLatest(this).nodeFormat.fileEnding } + fun getFileEnding(): String = checkDir { NodeData.getLatest(this)!!.nodeFormat.fileEnding } fun getId() = nodeId fun isDir() = nodeType == null diff --git a/CommonCore/SQL/src/de/steamwar/sql/UserConfig.kt b/CommonCore/SQL/src/de/steamwar/sql/UserConfig.kt index 11bc2e4d..14dcd201 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/UserConfig.kt +++ b/CommonCore/SQL/src/de/steamwar/sql/UserConfig.kt @@ -32,10 +32,14 @@ import java.util.UUID object UserConfigTable: CompositeIdTable("UserConfig") { val userId = reference("User", SteamwarUserTable) - val config = varchar("Config", 32) + val config = varchar("Config", 32).entityId() val value = text("Value", eagerLoading = true) override val primaryKey = PrimaryKey(userId, config) + + init { + addIdColumn(userId) + } } class UserConfig(id: EntityID): CompositeEntity(id) { diff --git a/CommonCore/SQL/src/de/steamwar/sql/internal/KotlinDatabase.kt b/CommonCore/SQL/src/de/steamwar/sql/internal/KotlinDatabase.kt index 4da6e413..735d4e22 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/internal/KotlinDatabase.kt +++ b/CommonCore/SQL/src/de/steamwar/sql/internal/KotlinDatabase.kt @@ -23,6 +23,7 @@ import org.intellij.lang.annotations.Language import org.jetbrains.exposed.v1.core.ColumnType import org.jetbrains.exposed.v1.core.Expression import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.StdOutSqlLogger import org.jetbrains.exposed.v1.core.statements.StatementType import org.jetbrains.exposed.v1.core.statements.api.RowApi import org.jetbrains.exposed.v1.dao.IntEntity @@ -64,7 +65,10 @@ object KotlinDatabase { fun useDb(statement: JdbcTransaction.() -> T): T { KotlinDatabase.ensureConnected() - return TransactionManager.currentOrNull()?.statement() ?: transaction(KotlinDatabase.db, statement) + return TransactionManager.currentOrNull()?.statement() ?: transaction(KotlinDatabase.db) { + addLogger(StdOutSqlLogger) + statement() + } } fun IntEntityClass.fromSql( diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt index d429af5c..d1ada3fa 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt @@ -36,6 +36,7 @@ import kotlinx.serialization.Serializable import java.io.BufferedInputStream import java.io.ByteArrayInputStream import java.io.DataInputStream +import java.io.InputStream import java.security.MessageDigest import java.time.Duration import java.time.Instant