|
|
|
@@ -17,121 +17,83 @@
|
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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<NodeData> table = new Table<>(NodeData.class);
|
|
|
|
|
class NodeData(id: EntityID<CompositeID>): 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<NodeData>(NodeDataTable) {
|
|
|
|
|
@JvmStatic
|
|
|
|
|
fun getLatest(node: SchematicNode) = useDb {
|
|
|
|
|
find { (NodeDataTable.nodeId eq node.nodeId) }.orderBy(NodeDataTable.createdAt to SortOrder.DESC).firstOrNull()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static final SelectStatement<NodeData> 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<NodeData> 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<NodeData> 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|