From e7bc45a0d64f152d50bdf001ebe032e6517ee1a7 Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Mon, 14 Aug 2023 23:24:53 +0200 Subject: [PATCH 1/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../caosdb/server/database/DatabaseUtils.java | 124 ++++++++++++++++-- .../MySQL/MySQLRetrieveProperties.java | 86 ++++++------ .../interfaces/RetrievePropertiesImpl.java | 4 +- .../transaction/RetrieveProperties.java | 46 ++++--- .../server/database/proto/ProtoProperty.java | 19 ++- .../server/entity/wrapper/Property.java | 48 ++++--- .../entity/xml/EntityToElementStrategy.java | 10 +- .../entity/xml/PropertyToElementStrategy.java | 5 + .../caosdb/server/database/InsertTest.java | 8 +- 9 files changed, 251 insertions(+), 99 deletions(-) diff --git a/src/main/java/org/caosdb/server/database/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/DatabaseUtils.java index 5280de17..8f4a59bb 100644 --- a/src/main/java/org/caosdb/server/database/DatabaseUtils.java +++ b/src/main/java/org/caosdb/server/database/DatabaseUtils.java @@ -25,16 +25,21 @@ package org.caosdb.server.database; import com.google.common.base.Objects; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.caosdb.server.database.proto.FlatProperty; import org.caosdb.server.database.proto.ProtoProperty; import org.caosdb.server.database.proto.SparseEntity; import org.caosdb.server.database.proto.VerySparseEntity; import org.caosdb.server.datatype.AbstractCollectionDatatype; import org.caosdb.server.datatype.CollectionValue; +import org.caosdb.server.datatype.GenericValue; import org.caosdb.server.datatype.IndexedSingleValue; import org.caosdb.server.datatype.ReferenceValue; import org.caosdb.server.datatype.SingleValue; @@ -175,9 +180,9 @@ public class DatabaseUtils { } public static List<FlatProperty> parsePropertyResultset(final ResultSet rs) throws SQLException { - final ArrayList<FlatProperty> ret = new ArrayList<FlatProperty>(); + final List<FlatProperty> ret = new LinkedList<>(); while (rs.next()) { - final FlatProperty fp = new FlatProperty(); + FlatProperty fp = new FlatProperty(); fp.id = rs.getInt("PropertyID"); fp.value = bytes2UTF8(rs.getBytes("PropertyValue")); fp.status = bytes2UTF8(rs.getBytes("PropertyStatus")); @@ -354,27 +359,120 @@ public class DatabaseUtils { } } - public static ArrayList<Property> parseFromProtoProperties(final List<ProtoProperty> protos) { + public static ArrayList<Property> parseFromProtoProperties( + EntityInterface entity, List<ProtoProperty> protos) { final ArrayList<Property> ret = new ArrayList<Property>(); for (final ProtoProperty pp : protos) { - final Property property = parseFlatProperty(pp.property); - parseFromFlatProperties(property.getProperties(), pp.subProperties); - ret.add(property); + if (pp.id.equals(entity.getId().toInteger())) { + if (pp.value != null) { + entity.setValue(new GenericValue(pp.value)); + } + if (pp.collValues != null) { + CollectionValue value = new CollectionValue(); + for (Object next : pp.collValues) { + if (next == null) { + value.add(null); + } else { + value.add(new GenericValue(next.toString())); + } + } + entity.setValue(value); + } + + } else { + final Property property = parseFlatProperty(pp); + // parseFromFlatProperties(property.getProperties(), pp.subProperties); + ret.add(property); + } } return ret; } private static void parseFromFlatProperties( - final List<Property> properties, final List<FlatProperty> props) { - for (final FlatProperty fp : props) { - final Property property = parseFlatProperty(fp); - properties.add(property); - } + final List<Property> properties, final List<ProtoProperty> props) { + if (props != null) + for (final ProtoProperty fp : props) { + final Property property = parseFlatProperty(fp); + parseFromFlatProperties(properties, fp.subProperties); + properties.add(property); + } } - private static Property parseFlatProperty(final FlatProperty fp) { + private static Property parseFlatProperty(final ProtoProperty fp) { final Property property = new Property(new RetrieveEntity()); - property.parseFlatProperty(fp); + property.parseProtoProperty(fp); return property; } + + @SuppressWarnings("unchecked") + public static LinkedList<ProtoProperty> transformToDeepPropertyTree( + List<ProtoProperty> properties) { + LinkedList<ProtoProperty> result = new LinkedList<>(); + Map<String, ProtoProperty> replacements = new HashMap<>(); + for (ProtoProperty pp : properties) { + if (pp.status.equals(StatementStatus.REPLACEMENT.toString())) { + replacements.put(pp.value, null); + } + } + Iterator<ProtoProperty> iterator = properties.iterator(); + while (iterator.hasNext()) { + ProtoProperty pp = iterator.next(); + if (replacements.containsKey(pp.id.toString())) { + ProtoProperty other = replacements.get(pp.id.toString()); + // handle collection values + if (other != null) { + if (other.collValues == null) { + other.collValues = new LinkedList<>(); + Entry<Integer, String> obj = new SimpleEntry<>(other.idx, other.value); + other.collValues.add(obj); + other.value = null; + } + other.collValues.add(new SimpleEntry<>(pp.idx, pp.value)); + } else { + replacements.put(pp.id.toString(), pp); + } + iterator.remove(); + } + } + for (ProtoProperty pp : properties) { + if (pp.status.equals(StatementStatus.REPLACEMENT.toString())) { + replace(pp, replacements.get(pp.value)); + } + if (pp.collValues != null) { + // sort + pp.collValues.sort( + (x, y) -> { + return ((Entry<Integer, String>) x).getKey() - ((Entry<Integer, String>) y).getKey(); + }); + pp.collValues = + pp.collValues + .stream() + .map((x) -> (Object) ((Entry<Integer, String>) x).getValue()) + .toList(); + } + result.add(pp); + } + return result; + } + + private static void replace(ProtoProperty pp, ProtoProperty replacement) { + if (replacement == null) { + throw new NullPointerException("Replacement was null"); + // // entity has been deleted (we are processing properties of an old entity version) + // p.setValue(null); + // p.addWarning( + // new Message( + // "The referenced entity has been deleted in the mean time and is not longer + // available.")); + // return; + } + pp.desc = replacement.desc; + pp.name = replacement.name; + pp.type = replacement.type; + pp.collection = replacement.collection; + pp.value = replacement.value; + pp.collValues = replacement.collValues; + pp.status = replacement.status; + pp.subProperties = replacement.subProperties; + } } diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java index 6bcfeac0..b0c5d5b7 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java @@ -26,7 +26,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; -import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; @@ -44,29 +44,23 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev private static final String stmtStr = "call retrieveEntityProperties(?,?,?)"; private static final String stmtStr2 = "call retrieveOverrides(?,?,?)"; + private static final String isCollectionStmt = "call isCollection(?,?)"; @Override - public ArrayList<ProtoProperty> execute(final EntityID entity, final String version) + public LinkedList<ProtoProperty> execute(final EntityID entity, final String version) throws TransactionException { try { final PreparedStatement prepareStatement = prepareStatement(stmtStr); - final List<FlatProperty> props = + final List<ProtoProperty> propsStage1 = retrieveFlatPropertiesStage1(0, entity.toInteger(), version, prepareStatement); - final ArrayList<ProtoProperty> protos = new ArrayList<ProtoProperty>(); - for (final FlatProperty p : props) { - final ProtoProperty proto = new ProtoProperty(); - proto.property = p; + for (final ProtoProperty p : propsStage1) { - final List<FlatProperty> subProps = + p.subProperties = retrieveFlatPropertiesStage1(entity.toInteger(), p.id, version, prepareStatement); - - proto.subProperties = subProps; - - protos.add(proto); } - return protos; + return DatabaseUtils.transformToDeepPropertyTree(propsStage1); } catch (final SQLException e) { throw new TransactionException(e); } catch (final ConnectionException e) { @@ -74,68 +68,76 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev } } - private List<FlatProperty> retrieveFlatPropertiesStage1( + private List<ProtoProperty> retrieveFlatPropertiesStage1( final Integer domain, final Integer entity, final String version, final PreparedStatement stmt) throws SQLException, ConnectionException { - ResultSet rs = null; - try { - if (domain != null && domain >= 0) { - stmt.setInt(1, domain); - } else { - stmt.setInt(1, 0); - } + if (domain != null && domain >= 0) { + stmt.setInt(1, domain); + } else { + stmt.setInt(1, 0); + } - stmt.setInt(2, entity); - if (version == null) { - stmt.setNull(3, Types.VARBINARY); - } else { - stmt.setString(3, version); - } + stmt.setInt(2, entity); + if (version == null) { + stmt.setNull(3, Types.VARBINARY); + } else { + stmt.setString(3, version); + } - final long t1 = System.currentTimeMillis(); - rs = stmt.executeQuery(); + final long t1 = System.currentTimeMillis(); + + try (ResultSet rs = stmt.executeQuery()) { final long t2 = System.currentTimeMillis(); addMeasurement(this.getClass().getSimpleName() + ".retrieveFlatPropertiesStage1", t2 - t1); final List<FlatProperty> props = DatabaseUtils.parsePropertyResultset(rs); - final PreparedStatement stmt2 = prepareStatement(stmtStr2); + final PreparedStatement retrieveOverrides = prepareStatement(stmtStr2); - retrieveOverrides(domain, entity, version, stmt2, props); + retrieveOverrides(domain, entity, version, retrieveOverrides, props); - return props; - } finally { - if (rs != null && !rs.isClosed()) { - rs.close(); - } + PreparedStatement isCollectionStatement = prepareStatement(isCollectionStmt); + + return handleCollectionValues(props, isCollectionStatement); } } + public List<ProtoProperty> handleCollectionValues( + List<FlatProperty> props, PreparedStatement isCollectionStatement) throws SQLException { + + List<ProtoProperty> result = new LinkedList<>(); + for (FlatProperty fp : props) { + result.add(new ProtoProperty(fp)); + } + return result; + } + private void retrieveOverrides( final Integer domain, final Integer entity, final String version, - final PreparedStatement stmt2, + final PreparedStatement retrieveOverrides, final List<FlatProperty> props) throws SQLException { ResultSet rs = null; try { - stmt2.setInt(1, domain); - stmt2.setInt(2, entity); + retrieveOverrides.setInt(1, domain); + retrieveOverrides.setInt(2, entity); if (version == null) { - stmt2.setNull(3, Types.VARBINARY); + retrieveOverrides.setNull(3, Types.VARBINARY); } else { - stmt2.setString(3, version); + retrieveOverrides.setString(3, version); } final long t1 = System.currentTimeMillis(); - rs = stmt2.executeQuery(); + rs = retrieveOverrides.executeQuery(); final long t2 = System.currentTimeMillis(); addMeasurement(this.getClass().getSimpleName() + ".retrieveOverrides", t2 - t1); DatabaseUtils.parseOverrides(props, rs); + } finally { if (rs != null && !rs.isClosed()) { rs.close(); diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java index dc1d5aa0..69fc9e70 100644 --- a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java +++ b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java @@ -22,12 +22,12 @@ */ package org.caosdb.server.database.backend.interfaces; -import java.util.ArrayList; +import java.util.LinkedList; import org.caosdb.server.database.exceptions.TransactionException; import org.caosdb.server.database.proto.ProtoProperty; import org.caosdb.server.entity.EntityID; public interface RetrievePropertiesImpl extends BackendTransactionImpl { - public ArrayList<ProtoProperty> execute(EntityID id, String version) throws TransactionException; + public LinkedList<ProtoProperty> execute(EntityID id, String version) throws TransactionException; } diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java index 726382f2..5cd7ace1 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java @@ -24,7 +24,8 @@ */ package org.caosdb.server.database.backend.transaction; -import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import org.apache.commons.jcs.access.behavior.ICacheAccess; import org.caosdb.server.caching.Cache; import org.caosdb.server.database.CacheableBackendTransaction; @@ -37,11 +38,11 @@ import org.caosdb.server.entity.Role; import org.caosdb.server.entity.wrapper.Property; public class RetrieveProperties - extends CacheableBackendTransaction<String, ArrayList<ProtoProperty>> { + extends CacheableBackendTransaction<String, LinkedList<ProtoProperty>> { private final EntityInterface entity; public static final String CACHE_REGION = "BACKEND_EntityProperties"; - private static final ICacheAccess<String, ArrayList<ProtoProperty>> cache = + private static final ICacheAccess<String, LinkedList<ProtoProperty>> cache = Cache.getCache(CACHE_REGION); /** @@ -61,40 +62,45 @@ public class RetrieveProperties } @Override - public ArrayList<ProtoProperty> executeNoCache() throws TransactionException { + public LinkedList<ProtoProperty> executeNoCache() throws TransactionException { final RetrievePropertiesImpl t = getImplementation(RetrievePropertiesImpl.class); return t.execute(this.entity.getId(), this.entity.getVersion().getId()); } @Override - protected void process(final ArrayList<ProtoProperty> t) throws TransactionException { + protected void process(final LinkedList<ProtoProperty> t) throws TransactionException { this.entity.getProperties().clear(); - final ArrayList<Property> props = DatabaseUtils.parseFromProtoProperties(t); + final List<Property> props = DatabaseUtils.parseFromProtoProperties(this.entity, t); + this.entity.getProperties().addAll(props); - for (final Property p : props) { + retrieveSparseSubproperties(props); + } + + private void retrieveSparseSubproperties(List<Property> properties) { + for (final Property p : properties) { // retrieve sparse properties stage 1 + + // handle corner case where a record type is used as a property with an overridden name. + boolean isNameOverride = p.isNameOverride(); + String overrideName = p.getName(); + p.setNameOverride(false); + final RetrieveSparseEntity t1 = new RetrieveSparseEntity(p); execute(t1); + String originalName = p.getName(); + if (isNameOverride) { + p.setNameOverride(isNameOverride); + p.setName(overrideName); + } - // add default data type for record types if (!p.hasDatatype() && p.getRole() == Role.RecordType) { - p.setDatatype(p.getName()); + p.setDatatype(originalName); } // retrieve sparse properties stage 2 - for (final EntityInterface subP : p.getProperties()) { - final RetrieveSparseEntity t2 = new RetrieveSparseEntity(subP); - execute(t2); - - // add default data type for record types - if (!subP.hasDatatype() && subP.getRole() == Role.RecordType) { - subP.setDatatype(subP.getName()); - } - } + retrieveSparseSubproperties(p.getProperties()); } - - DatabaseUtils.transformToDeepPropertyTree(this.entity, props); } @Override diff --git a/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java b/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java index 44acaa02..898565ac 100644 --- a/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java +++ b/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java @@ -25,9 +25,22 @@ package org.caosdb.server.database.proto; import java.io.Serializable; import java.util.List; -public class ProtoProperty implements Serializable { +public class ProtoProperty extends FlatProperty implements Serializable { + + public ProtoProperty(FlatProperty fp) { + id = fp.id; + value = fp.value; + status = fp.status; + idx = fp.idx; + name = fp.name; + desc = fp.desc; + type = fp.type; + collection = fp.collection; + } + + public ProtoProperty() {} private static final long serialVersionUID = 7731301985162924975L; - public List<FlatProperty> subProperties = null; - public FlatProperty property = null; + public List<ProtoProperty> subProperties = null; + public List<Object> collValues = null; } diff --git a/src/main/java/org/caosdb/server/entity/wrapper/Property.java b/src/main/java/org/caosdb/server/entity/wrapper/Property.java index efa1a685..9268d7f3 100644 --- a/src/main/java/org/caosdb/server/entity/wrapper/Property.java +++ b/src/main/java/org/caosdb/server/entity/wrapper/Property.java @@ -25,11 +25,13 @@ package org.caosdb.server.entity.wrapper; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.Permission; import org.apache.shiro.subject.Subject; -import org.caosdb.server.database.proto.FlatProperty; +import org.caosdb.server.database.proto.ProtoProperty; import org.caosdb.server.datatype.AbstractCollectionDatatype; +import org.caosdb.server.datatype.CollectionValue; import org.caosdb.server.datatype.GenericValue; import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.EntityInterface; +import org.caosdb.server.entity.RetrieveEntity; import org.caosdb.server.entity.xml.PropertyToElementStrategy; public class Property extends EntityWrapper { @@ -72,29 +74,45 @@ public class Property extends EntityWrapper { return this; } - public Property parseFlatProperty(final FlatProperty fp) { - setId(new EntityID(fp.id)); - setStatementStatus(fp.status); - setPIdx(fp.idx); - if (fp.name != null) { - setName(fp.name); + public Property parseProtoProperty(final ProtoProperty pp) { + setId(new EntityID(pp.id)); + setStatementStatus(pp.status); + setPIdx(pp.idx); + if (pp.name != null) { + setName(pp.name); setNameOverride(true); } - if (fp.desc != null) { - setDescription(fp.desc); + if (pp.desc != null) { + setDescription(pp.desc); setDescOverride(true); } - if (fp.type != null) { - if (fp.collection != null) { + if (pp.type != null) { + if (pp.collection != null) { this.setDatatype( - AbstractCollectionDatatype.collectionDatatypeFactory(fp.collection, fp.type)); + AbstractCollectionDatatype.collectionDatatypeFactory(pp.collection, pp.type)); } else { - this.setDatatype(fp.type); + this.setDatatype(pp.type); } setDatatypeOverride(true); } - if (fp.value != null) { - setValue(new GenericValue(fp.value)); + if (pp.value != null) { + setValue(new GenericValue(pp.value)); + } + if (pp.collValues != null) { + CollectionValue value = new CollectionValue(); + for (Object next : pp.collValues) { + if (next == null) { + value.add(null); + } else { + value.add(new GenericValue(next.toString())); + } + } + setValue(value); + } + if (pp.subProperties != null) { + for (ProtoProperty subP : pp.subProperties) { + this.addProperty(new Property(new RetrieveEntity()).parseProtoProperty(subP)); + } } return this; } diff --git a/src/main/java/org/caosdb/server/entity/xml/EntityToElementStrategy.java b/src/main/java/org/caosdb/server/entity/xml/EntityToElementStrategy.java index 7f6e6dca..35d94aa7 100644 --- a/src/main/java/org/caosdb/server/entity/xml/EntityToElementStrategy.java +++ b/src/main/java/org/caosdb/server/entity/xml/EntityToElementStrategy.java @@ -85,9 +85,7 @@ public class EntityToElementStrategy implements ToElementStrategy { // @review Florian Spreckelsen 2022-03-22 - if (entity.getEntityACL() != null) { - element.addContent(entity.getEntityACL().getPermissionsFor(SecurityUtils.getSubject())); - } + addPermissions(entity, element); if (serializeFieldStrategy.isToBeSet("id") && entity.hasId()) { element.setAttribute("id", entity.getId().toString()); } @@ -135,6 +133,12 @@ public class EntityToElementStrategy implements ToElementStrategy { } } + protected void addPermissions(EntityInterface entity, Element element) { + if (entity.getEntityACL() != null) { + element.addContent(entity.getEntityACL().getPermissionsFor(SecurityUtils.getSubject())); + } + } + /** * Set the value of the entity. * diff --git a/src/main/java/org/caosdb/server/entity/xml/PropertyToElementStrategy.java b/src/main/java/org/caosdb/server/entity/xml/PropertyToElementStrategy.java index 23fd8a55..7109a0d8 100644 --- a/src/main/java/org/caosdb/server/entity/xml/PropertyToElementStrategy.java +++ b/src/main/java/org/caosdb/server/entity/xml/PropertyToElementStrategy.java @@ -35,6 +35,11 @@ public class PropertyToElementStrategy extends EntityToElementStrategy { super("Property"); } + @Override + protected void addPermissions(EntityInterface entity, Element element) { + // don't + } + @Override public Element addToElement( final EntityInterface entity, diff --git a/src/test/java/org/caosdb/server/database/InsertTest.java b/src/test/java/org/caosdb/server/database/InsertTest.java index 524e7add..59aa6f55 100644 --- a/src/test/java/org/caosdb/server/database/InsertTest.java +++ b/src/test/java/org/caosdb/server/database/InsertTest.java @@ -124,7 +124,7 @@ public class InsertTest { final LinkedList<EntityInterface> stage1Inserts = new LinkedList<EntityInterface>(); final LinkedList<EntityInterface> stage2Inserts = new LinkedList<EntityInterface>(); - new LinkedList<EntityInterface>(); + deriveStage1Inserts(stage1Inserts, r); assertEquals(7, stage1Inserts.size()); @@ -166,34 +166,40 @@ public class InsertTest { assertEquals(Role.Property, stage2Inserts.get(0).getRole()); assertEquals(new EntityID(3), stage2Inserts.get(0).getId()); assertEquals("V3", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString()); + assertEquals(new EntityID(2), stage2Inserts.get(0).getDomain()); assertFalse(stage2Inserts.get(0).hasReplacement()); assertEquals(Role.Property, stage2Inserts.get(1).getRole()); assertEquals(new EntityID(5), stage2Inserts.get(1).getId()); assertEquals("V5", ((SingleValue) stage2Inserts.get(1).getValue()).toDatabaseString()); assertTrue(stage2Inserts.get(1).hasReplacement()); + assertEquals(new EntityID(4), stage2Inserts.get(1).getDomain()); assertEquals(stage1Inserts.get(3), stage2Inserts.get(1).getReplacement()); assertEquals(Role.Property, stage2Inserts.get(2).getRole()); assertEquals(new EntityID(6), stage2Inserts.get(2).getId()); assertEquals("V6", ((SingleValue) stage2Inserts.get(2).getValue()).toDatabaseString()); + assertEquals(new EntityID(5), stage2Inserts.get(2).getDomain()); assertFalse(stage2Inserts.get(2).hasReplacement()); assertEquals(Role.Property, stage2Inserts.get(3).getRole()); assertEquals(new EntityID(8), stage2Inserts.get(3).getId()); assertEquals("V8", ((SingleValue) stage2Inserts.get(3).getValue()).toDatabaseString()); assertTrue(stage2Inserts.get(3).hasReplacement()); + assertEquals(new EntityID(7), stage2Inserts.get(3).getDomain()); assertEquals(stage1Inserts.get(5), stage2Inserts.get(3).getReplacement()); assertEquals(Role.Property, stage2Inserts.get(4).getRole()); assertEquals(new EntityID(9), stage2Inserts.get(4).getId()); assertEquals("V9", ((SingleValue) stage2Inserts.get(4).getValue()).toDatabaseString()); assertTrue(stage2Inserts.get(4).hasReplacement()); + assertEquals(new EntityID(8), stage2Inserts.get(4).getDomain()); assertEquals(stage1Inserts.get(6), stage2Inserts.get(4).getReplacement()); assertEquals(Role.Property, stage2Inserts.get(5).getRole()); assertEquals(new EntityID(10), stage2Inserts.get(5).getId()); assertEquals("V10", ((SingleValue) stage2Inserts.get(5).getValue()).toDatabaseString()); + assertEquals(new EntityID(9), stage2Inserts.get(5).getDomain()); assertFalse(stage2Inserts.get(5).hasReplacement()); } -- GitLab From 236a8d7bde090676b52a757be2e6cde4cc2f2026 Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Tue, 15 Aug 2023 10:43:16 +0200 Subject: [PATCH 2/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../caosdb/server/database/DatabaseUtils.java | 142 +++--------------- .../MySQL/MySQLRetrieveProperties.java | 15 +- .../interfaces/RetrievePropertiesImpl.java | 3 +- .../transaction/RetrieveProperties.java | 3 +- 4 files changed, 33 insertions(+), 130 deletions(-) diff --git a/src/main/java/org/caosdb/server/database/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/DatabaseUtils.java index 8f4a59bb..5799d23f 100644 --- a/src/main/java/org/caosdb/server/database/DatabaseUtils.java +++ b/src/main/java/org/caosdb/server/database/DatabaseUtils.java @@ -40,9 +40,6 @@ import org.caosdb.server.database.proto.VerySparseEntity; import org.caosdb.server.datatype.AbstractCollectionDatatype; import org.caosdb.server.datatype.CollectionValue; import org.caosdb.server.datatype.GenericValue; -import org.caosdb.server.datatype.IndexedSingleValue; -import org.caosdb.server.datatype.ReferenceValue; -import org.caosdb.server.datatype.SingleValue; import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.EntityInterface; import org.caosdb.server.entity.Message; @@ -55,6 +52,9 @@ import org.caosdb.server.entity.wrapper.Property; public class DatabaseUtils { + private static final String DELETED_REFERENCE_IN_PREVIOUS_VERSION = + "DELETED_REFERENCE_IN_PREVIOUS_VERSION"; + public static final String bytes2UTF8(final byte[] bytes) { if (bytes == null) { return null; @@ -265,100 +265,6 @@ public class DatabaseUtils { } } - private static void replace( - final Property p, final Map<EntityID, Property> domainMap, final boolean isHead) { - // ... find the corresponding domain and replace it - ReferenceValue ref; - try { - ref = ReferenceValue.parseReference(p.getValue()); - } catch (final Message e) { - throw new RuntimeException("This should never happen."); - } - final EntityInterface replacement = domainMap.get(ref.getId()); - if (replacement == null) { - if (isHead) { - throw new NullPointerException("Replacement was null"); - } - // entity has been deleted (we are processing properties of an old entity version) - p.setValue(null); - p.addWarning( - new Message( - "The referenced entity has been deleted in the mean time and is not longer available.")); - return; - } - if (replacement.isDescOverride()) { - p.setDescOverride(true); - p.setDescription(replacement.getDescription()); - } - if (replacement.isNameOverride()) { - p.setNameOverride(true); - p.setName(replacement.getName()); - } - if (replacement.isDatatypeOverride()) { - p.setDatatypeOverride(true); - p.setDatatype(replacement.getDatatype()); - } - p.setProperties(replacement.getProperties()); - p.setStatementStatus(replacement.getStatementStatus()); - p.setValue(replacement.getValue()); - } - - public static void transformToDeepPropertyTree( - final EntityInterface e, final List<Property> protoProperties) { - // here we will store every domain we can find and we will index it by - // its id. - final Map<EntityID, Property> domainMap = new HashMap<>(); - - // loop over all properties and collect the domains - for (final Property p : protoProperties) { - // if this is a domain it represents a deeper branch of the property - // tree. - if (p.getRole() == Role.Domain) { - if (domainMap.containsKey(p.getId())) { - // aggregate the multiple values. - final Property domain = domainMap.get(p.getId()); - if (!(domain.getValue() instanceof CollectionValue)) { - final SingleValue singleValue = (SingleValue) domain.getValue(); - final CollectionValue vals = new CollectionValue(); - final IndexedSingleValue iSingleValue = - new IndexedSingleValue(domain.getPIdx(), singleValue); - vals.add(iSingleValue); - domain.setValue(vals); - } - ((CollectionValue) domain.getValue()).add(p.getPIdx(), p.getValue()); - } else { - domainMap.put(p.getId(), p); - } - } - } - - // loop over all properties - final boolean isHead = - e.getVersion().getSuccessors() == null || e.getVersion().getSuccessors().isEmpty(); - for (final Property p : protoProperties) { - - // if this is a replacement - if (p.getStatementStatus() == StatementStatus.REPLACEMENT) { - replace(p, domainMap, isHead); - } - - for (final Property subP : p.getProperties()) { - if (subP.getStatementStatus() == StatementStatus.REPLACEMENT) { - replace(subP, domainMap, isHead); - } - } - - if (p.getId().equals(e.getId())) { - // this is the value of an abstract property. - e.setValue(p.getValue()); - } else if (p.getRole() != Role.Domain) { - // if this is not a domain it is to be added to the properties - // of e. - e.addProperty(p); - } - } - } - public static ArrayList<Property> parseFromProtoProperties( EntityInterface entity, List<ProtoProperty> protos) { final ArrayList<Property> ret = new ArrayList<Property>(); @@ -380,24 +286,23 @@ public class DatabaseUtils { } } else { + Message warning = null; + if (pp.status == DELETED_REFERENCE_IN_PREVIOUS_VERSION) { + pp.status = StatementStatus.FIX.name(); + warning = + new Message( + "The referenced entity has been deleted in the mean time and is not longer available."); + } final Property property = parseFlatProperty(pp); - // parseFromFlatProperties(property.getProperties(), pp.subProperties); + if (warning != null) { + property.addWarning(warning); + } ret.add(property); } } return ret; } - private static void parseFromFlatProperties( - final List<Property> properties, final List<ProtoProperty> props) { - if (props != null) - for (final ProtoProperty fp : props) { - final Property property = parseFlatProperty(fp); - parseFromFlatProperties(properties, fp.subProperties); - properties.add(property); - } - } - private static Property parseFlatProperty(final ProtoProperty fp) { final Property property = new Property(new RetrieveEntity()); property.parseProtoProperty(fp); @@ -406,7 +311,7 @@ public class DatabaseUtils { @SuppressWarnings("unchecked") public static LinkedList<ProtoProperty> transformToDeepPropertyTree( - List<ProtoProperty> properties) { + List<ProtoProperty> properties, boolean isHead) { LinkedList<ProtoProperty> result = new LinkedList<>(); Map<String, ProtoProperty> replacements = new HashMap<>(); for (ProtoProperty pp : properties) { @@ -436,7 +341,7 @@ public class DatabaseUtils { } for (ProtoProperty pp : properties) { if (pp.status.equals(StatementStatus.REPLACEMENT.toString())) { - replace(pp, replacements.get(pp.value)); + replace(pp, replacements.get(pp.value), isHead); } if (pp.collValues != null) { // sort @@ -455,16 +360,15 @@ public class DatabaseUtils { return result; } - private static void replace(ProtoProperty pp, ProtoProperty replacement) { + private static void replace(ProtoProperty pp, ProtoProperty replacement, boolean isHead) { if (replacement == null) { - throw new NullPointerException("Replacement was null"); - // // entity has been deleted (we are processing properties of an old entity version) - // p.setValue(null); - // p.addWarning( - // new Message( - // "The referenced entity has been deleted in the mean time and is not longer - // available.")); - // return; + if (isHead) { + throw new NullPointerException("Replacement was null"); + } + // entity has been deleted (we are processing properties of an old entity version) + pp.value = null; + pp.status = DELETED_REFERENCE_IN_PREVIOUS_VERSION; + return; } pp.desc = replacement.desc; pp.name = replacement.name; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java index b0c5d5b7..c8843f9c 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java @@ -44,11 +44,10 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev private static final String stmtStr = "call retrieveEntityProperties(?,?,?)"; private static final String stmtStr2 = "call retrieveOverrides(?,?,?)"; - private static final String isCollectionStmt = "call isCollection(?,?)"; @Override - public LinkedList<ProtoProperty> execute(final EntityID entity, final String version) - throws TransactionException { + public LinkedList<ProtoProperty> execute( + final EntityID entity, final String version, boolean isHead) throws TransactionException { try { final PreparedStatement prepareStatement = prepareStatement(stmtStr); @@ -60,7 +59,7 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev p.subProperties = retrieveFlatPropertiesStage1(entity.toInteger(), p.id, version, prepareStatement); } - return DatabaseUtils.transformToDeepPropertyTree(propsStage1); + return DatabaseUtils.transformToDeepPropertyTree(propsStage1, isHead); } catch (final SQLException e) { throw new TransactionException(e); } catch (final ConnectionException e) { @@ -99,14 +98,12 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev retrieveOverrides(domain, entity, version, retrieveOverrides, props); - PreparedStatement isCollectionStatement = prepareStatement(isCollectionStmt); - - return handleCollectionValues(props, isCollectionStatement); + return handleCollectionValues(props); } } - public List<ProtoProperty> handleCollectionValues( - List<FlatProperty> props, PreparedStatement isCollectionStatement) throws SQLException { + @Deprecated + public List<ProtoProperty> handleCollectionValues(List<FlatProperty> props) throws SQLException { List<ProtoProperty> result = new LinkedList<>(); for (FlatProperty fp : props) { diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java index 69fc9e70..6bf2051a 100644 --- a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java +++ b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java @@ -29,5 +29,6 @@ import org.caosdb.server.entity.EntityID; public interface RetrievePropertiesImpl extends BackendTransactionImpl { - public LinkedList<ProtoProperty> execute(EntityID id, String version) throws TransactionException; + public LinkedList<ProtoProperty> execute(EntityID id, String version, boolean isHead) + throws TransactionException; } diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java index 5cd7ace1..caa4b6cf 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java @@ -64,7 +64,8 @@ public class RetrieveProperties @Override public LinkedList<ProtoProperty> executeNoCache() throws TransactionException { final RetrievePropertiesImpl t = getImplementation(RetrievePropertiesImpl.class); - return t.execute(this.entity.getId(), this.entity.getVersion().getId()); + return t.execute( + this.entity.getId(), this.entity.getVersion().getId(), this.entity.getVersion().isHead()); } @Override -- GitLab From 0326111fc575abeddfad65c546cf6f075464c8bf Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Wed, 16 Aug 2023 00:00:44 +0200 Subject: [PATCH 3/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../server/database/BackendTransaction.java | 3 - .../caosdb/server/database/DatabaseUtils.java | 80 +++++---- .../caosdb/server/database/Replacement.java | 41 +++++ .../MySQL/MySQLInsertEntityProperties.java | 147 ++++++++++++++++- .../MySQL/MySQLRegisterSubDomain.java | 64 ------- .../InsertEntityPropertiesImpl.java | 9 +- .../interfaces/RegisterSubDomainImpl.java | 32 ---- .../transaction/InsertEntityProperties.java | 137 +-------------- .../transaction/InsertEntityTransaction.java | 4 +- .../transaction/RegisterSubDomain.java | 49 ------ .../server/database/proto/FlatProperty.java | 13 ++ .../server/database/proto/ProtoProperty.java | 11 +- .../caosdb/server/database/InsertTest.java | 156 ++++++++---------- .../caosdb/server/database/InsertTest2.java | 148 +++++++++++++++++ 14 files changed, 466 insertions(+), 428 deletions(-) create mode 100644 src/main/java/org/caosdb/server/database/Replacement.java delete mode 100644 src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRegisterSubDomain.java delete mode 100644 src/main/java/org/caosdb/server/database/backend/interfaces/RegisterSubDomainImpl.java delete mode 100644 src/main/java/org/caosdb/server/database/backend/transaction/RegisterSubDomain.java create mode 100644 src/test/java/org/caosdb/server/database/InsertTest2.java diff --git a/src/main/java/org/caosdb/server/database/BackendTransaction.java b/src/main/java/org/caosdb/server/database/BackendTransaction.java index 5addf3f3..05ea26c2 100644 --- a/src/main/java/org/caosdb/server/database/BackendTransaction.java +++ b/src/main/java/org/caosdb/server/database/BackendTransaction.java @@ -47,7 +47,6 @@ import org.caosdb.server.database.backend.implementation.MySQL.MySQLIsSubType; import org.caosdb.server.database.backend.implementation.MySQL.MySQLListRoles; import org.caosdb.server.database.backend.implementation.MySQL.MySQLListUsers; import org.caosdb.server.database.backend.implementation.MySQL.MySQLLogUserVisit; -import org.caosdb.server.database.backend.implementation.MySQL.MySQLRegisterSubDomain; import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveAll; import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveAllUncheckedFiles; import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveDatatypes; @@ -106,7 +105,6 @@ import org.caosdb.server.database.backend.interfaces.IsSubTypeImpl; import org.caosdb.server.database.backend.interfaces.ListRolesImpl; import org.caosdb.server.database.backend.interfaces.ListUsersImpl; import org.caosdb.server.database.backend.interfaces.LogUserVisitImpl; -import org.caosdb.server.database.backend.interfaces.RegisterSubDomainImpl; import org.caosdb.server.database.backend.interfaces.RetrieveAllImpl; import org.caosdb.server.database.backend.interfaces.RetrieveAllUncheckedFilesImpl; import org.caosdb.server.database.backend.interfaces.RetrieveDatatypesImpl; @@ -177,7 +175,6 @@ public abstract class BackendTransaction implements Undoable { setImpl(IsSubTypeImpl.class, MySQLIsSubType.class); setImpl(UpdateSparseEntityImpl.class, MySQLUpdateSparseEntity.class); setImpl(RetrieveAllImpl.class, MySQLRetrieveAll.class); - setImpl(RegisterSubDomainImpl.class, MySQLRegisterSubDomain.class); setImpl(RetrieveDatatypesImpl.class, MySQLRetrieveDatatypes.class); setImpl(RetrieveUserImpl.class, MySQLRetrieveUser.class); setImpl(RetrieveParentsImpl.class, MySQLRetrieveParents.class); diff --git a/src/main/java/org/caosdb/server/database/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/DatabaseUtils.java index 5799d23f..6d72d965 100644 --- a/src/main/java/org/caosdb/server/database/DatabaseUtils.java +++ b/src/main/java/org/caosdb/server/database/DatabaseUtils.java @@ -27,6 +27,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; +import java.util.Deque; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -44,9 +45,7 @@ import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.EntityInterface; import org.caosdb.server.entity.Message; import org.caosdb.server.entity.RetrieveEntity; -import org.caosdb.server.entity.Role; import org.caosdb.server.entity.StatementStatus; -import org.caosdb.server.entity.wrapper.Domain; import org.caosdb.server.entity.wrapper.Parent; import org.caosdb.server.entity.wrapper.Property; @@ -63,39 +62,33 @@ public class DatabaseUtils { } } - private static Domain makeReplacement(final EntityInterface p) { - // add a new helper domain. - final Domain d = - new Domain(p.getProperties(), p.getDatatype(), p.getValue(), p.getStatementStatus()); - d.setDescOverride(p.isDescOverride()); - d.setNameOverride(p.isNameOverride()); - d.setDatatypeOverride(p.isDatatypeOverride()); - d.setName(p.getName()); - d.setDescription(p.getDescription()); - p.setReplacement(d); - return d; - } - - public static void deriveStage1Inserts( - final List<EntityInterface> stage1Inserts, final EntityInterface e) { + public static int deriveStage1Inserts( + final List<Property> stage1Inserts, final EntityInterface e) { // entity value if (e.hasValue()) { final Property p = new Property(e); p.setStatementStatus(StatementStatus.FIX); - p.setPIdx(0); p.setDatatype(e.getDatatype()); p.setValue(e.getValue()); + p.setPIdx(0); processPropertiesStage1(stage1Inserts, p, e); } - for (final EntityInterface p : e.getProperties()) { + for (final Property p : e.getProperties()) { processPropertiesStage1(stage1Inserts, p, e); } + int replacementCount = 0; + for (EntityInterface pp : stage1Inserts) { + if (pp instanceof Replacement) { + replacementCount++; + } + } + return replacementCount; } private static void processPropertiesStage1( - final List<EntityInterface> stage1Inserts, final EntityInterface p, final EntityInterface e) { - stage1Inserts.add(p); + final List<Property> stage1Inserts, final Property p, final EntityInterface e) { + if (!p.isDescOverride() && !p.isNameOverride() && !p.isDatatypeOverride() @@ -105,25 +98,40 @@ public class DatabaseUtils { // setReplacement(null) because there is a corner case (related to the inheritance of // properties) where there is a replacement present which belongs to the parent entity, see // https://gitlab.com/caosdb/caosdb-server/-/issues/216. - p.setReplacement(null); + stage1Inserts.add(p); } else { - stage1Inserts.add(makeReplacement(p)); + Replacement r = new Replacement(p); + stage1Inserts.add(r); + stage1Inserts.add(r.replacement); } processSubPropertiesStage1(stage1Inserts, p); } - public static int deriveStage2Inserts( - final List<EntityInterface> stage2Inserts, final List<EntityInterface> stage1Inserts) { - int domainCount = 0; - for (final EntityInterface p : stage1Inserts) { - if (p.hasRole() && p.getRole() == Role.Domain) { - domainCount++; - } - if (!p.hasReplacement() && p.hasProperties()) { - stage2Inserts.addAll(p.getProperties()); + public static void deriveStage2Inserts( + final List<Property> stage2Inserts, + final List<Property> stage1Inserts, + Deque<EntityID> replacementIds, + EntityInterface entity) { + for (final Property p : stage1Inserts) { + if (p instanceof Replacement) { + + EntityID replacementId = replacementIds.pop(); + ((Replacement) p).setReplacementId(replacementId); + + if (p.hasProperties()) { + for (Property subP : p.getProperties()) { + subP.setDomain(p); + stage2Inserts.add(subP); + } + } + } else { + if (p.hasProperties()) { + for (Property subP : p.getProperties()) { + stage2Inserts.add(subP); + } + } } } - return domainCount; } private static boolean hasUniquePropertyId(final EntityInterface p, final EntityInterface e) { @@ -137,10 +145,10 @@ public class DatabaseUtils { } private static void processSubPropertiesStage1( - final List<EntityInterface> stage1Inserts, final EntityInterface p) { - for (final EntityInterface subP : p.getProperties()) { + final List<Property> stage1Inserts, final EntityInterface p) { + for (final Property subP : p.getProperties()) { if (subP.hasProperties()) { - stage1Inserts.add(makeReplacement(subP)); + stage1Inserts.add(new Replacement(subP)); processSubPropertiesStage1(stage1Inserts, subP); } } diff --git a/src/main/java/org/caosdb/server/database/Replacement.java b/src/main/java/org/caosdb/server/database/Replacement.java new file mode 100644 index 00000000..8606d51b --- /dev/null +++ b/src/main/java/org/caosdb/server/database/Replacement.java @@ -0,0 +1,41 @@ +package org.caosdb.server.database; + +import org.caosdb.server.datatype.ReferenceValue; +import org.caosdb.server.entity.EntityID; +import org.caosdb.server.entity.RetrieveEntity; +import org.caosdb.server.entity.StatementStatus; +import org.caosdb.server.entity.wrapper.Property; + +public class Replacement extends Property { + + public Property replacement; + public EntityID replacementId; + + @Override + public EntityID getId() { + return replacementId; + } + + public void setReplacementId(EntityID id) { + replacementId.link(id); + } + + public Replacement(Property p) { + super(p); + replacementId = new EntityID(); + replacement = new Property(new RetrieveEntity()); + + replacement.setDomain(p.getDomainEntity()); + // replacement.setDatatypeOverride(p.isDatatypeOverride()); + // replacement.setDatatype(p.getDatatype()); + // replacement.setNameOverride(p.isNameOverride()); + // replacement.setName(p.getName()); + // replacement.setDescOverride(p.isDescOverride()); + // replacement.setDescription(p.getDescription()); + + replacement.setId(replacementId); + replacement.setStatementStatus(StatementStatus.REPLACEMENT); + replacement.setValue(new ReferenceValue(p.getId())); + replacement.setPIdx(0); + } +} diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java index 7c3c5a33..5c9ca6f9 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java @@ -25,15 +25,30 @@ package org.caosdb.server.database.backend.implementation.MySQL; import static java.sql.Types.BIGINT; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.InsertEntityPropertiesImpl; import org.caosdb.server.database.exceptions.IntegrityException; import org.caosdb.server.database.exceptions.TransactionException; import org.caosdb.server.database.proto.FlatProperty; +import org.caosdb.server.datatype.AbstractCollectionDatatype; import org.caosdb.server.datatype.AbstractDatatype.Table; +import org.caosdb.server.datatype.CollectionValue; +import org.caosdb.server.datatype.IndexedSingleValue; +import org.caosdb.server.datatype.ReferenceValue; +import org.caosdb.server.datatype.SingleValue; import org.caosdb.server.entity.EntityID; +import org.caosdb.server.entity.EntityInterface; +import org.caosdb.server.entity.StatementStatus; +import org.caosdb.server.entity.wrapper.Property; public class MySQLInsertEntityProperties extends MySQLTransaction implements InsertEntityPropertiesImpl { @@ -46,7 +61,27 @@ public class MySQLInsertEntityProperties extends MySQLTransaction } @Override - public void execute( + public void execute(EntityInterface entity) { + final List<Property> stage1Inserts = new LinkedList<>(); + final List<Property> stage2Inserts = new LinkedList<>(); + + final int domainCount = DatabaseUtils.deriveStage1Inserts(stage1Inserts, entity); + + try { + final Deque<EntityID> replacementIds = registerReplacementId(domainCount); + + DatabaseUtils.deriveStage2Inserts(stage2Inserts, stage1Inserts, replacementIds, entity); + + insertStages(stage1Inserts, entity.getDomain(), entity.getId()); + insertStages(stage2Inserts, entity.getId(), null); + } catch (final SQLIntegrityConstraintViolationException exc) { + throw new IntegrityException(exc); + } catch (SQLException | ConnectionException e) { + throw new TransactionException(e); + } + } + + private void insertFlatProperty( final EntityID domain, final EntityID entity, final FlatProperty fp, @@ -76,10 +111,114 @@ public class MySQLInsertEntityProperties extends MySQLTransaction stmt.execute(); } catch (final SQLIntegrityConstraintViolationException exc) { throw new IntegrityException(exc); - } catch (final SQLException exc) { - throw new TransactionException(exc); - } catch (final ConnectionException exc) { + } catch (final SQLException | ConnectionException exc) { throw new TransactionException(exc); } } + + private void insertStages( + final List<Property> stage1Inserts, final EntityID domain, final EntityID entity) + throws TransactionException { + + for (final Property property : stage1Inserts) { + + // prepare flat property + final FlatProperty fp = new FlatProperty(); + Table table = Table.null_data; + Long unit_sig = null; + fp.id = property.getId().toInteger(); + fp.idx = property.getPIdx(); + fp.status = property.getStatementStatus().name(); + + if (property.getStatementStatus() == StatementStatus.REPLACEMENT) { + table = Table.reference_data; + fp.value = fp.id.toString(); + fp.id = ((ReferenceValue) property.getValue()).getId().toInteger(); + } else { + + if (property.hasUnit()) { + unit_sig = property.getUnit().getSignature(); + } + if (property.hasValue()) { + if (property.getValue() instanceof CollectionValue) { + // insert collection of values + final CollectionValue v = (CollectionValue) property.getValue(); + final Iterator<IndexedSingleValue> iterator = v.iterator(); + final SingleValue firstValue = iterator.next(); + + // insert 2nd to nth item + for (int i = 1; i < v.size(); i++) { + final SingleValue vi = iterator.next(); + fp.idx = i; + if (vi == null) { + fp.value = null; + table = Table.null_data; + } else { + fp.value = vi.toDatabaseString(); + table = vi.getTable(); + } + insertFlatProperty( + domain, entity != null ? entity : property.getDomain(), fp, table, unit_sig); + } + + // insert first item + fp.idx = 0; + if (firstValue == null) { + fp.value = null; + table = Table.null_data; + } else { + fp.value = firstValue.toDatabaseString(); + table = firstValue.getTable(); + } + + } else { + // insert single value + fp.value = ((SingleValue) property.getValue()).toDatabaseString(); + if (property instanceof Property && ((Property) property).isName()) { + table = Table.name_data; + } else { + table = ((SingleValue) property.getValue()).getTable(); + } + } + } + if (property.isNameOverride()) { + fp.name = property.getName(); + } + if (property.isDescOverride()) { + fp.desc = property.getDescription(); + } + if (property.isDatatypeOverride()) { + if (property.getDatatype() instanceof AbstractCollectionDatatype) { + fp.type = + ((AbstractCollectionDatatype) property.getDatatype()) + .getDatatype() + .getId() + .toString(); + fp.collection = + ((AbstractCollectionDatatype) property.getDatatype()).getCollectionName(); + } else { + fp.type = property.getDatatype().getId().toString(); + } + } + } + + insertFlatProperty( + domain, entity != null ? entity : property.getDomain(), fp, table, unit_sig); + } + } + + public static final String STMT_REGISTER_SUBDOMAIN = "call registerSubdomain(?)"; + + public Deque<EntityID> registerReplacementId(final int domainCount) + throws SQLException, ConnectionException { + final PreparedStatement stmt = prepareStatement(STMT_REGISTER_SUBDOMAIN); + stmt.setInt(1, domainCount); + try (final ResultSet rs = stmt.executeQuery()) { + final Deque<EntityID> ret = new ArrayDeque<>(); + while (rs.next()) { + ret.add(new EntityID(rs.getInt(1))); + } + return ret; + } + } } diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRegisterSubDomain.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRegisterSubDomain.java deleted file mode 100644 index 1e14600e..00000000 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRegisterSubDomain.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.database.backend.implementation.MySQL; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayDeque; -import java.util.Deque; -import org.caosdb.server.database.access.Access; -import org.caosdb.server.database.backend.interfaces.RegisterSubDomainImpl; -import org.caosdb.server.database.exceptions.TransactionException; -import org.caosdb.server.entity.EntityID; - -public class MySQLRegisterSubDomain extends MySQLTransaction implements RegisterSubDomainImpl { - - public MySQLRegisterSubDomain(final Access access) { - super(access); - } - - public static final String STMT_REGISTER_SUBDOMAIN = "call registerSubdomain(?)"; - - @Override - public Deque<EntityID> execute(final int domainCount) throws TransactionException { - try { - final PreparedStatement stmt = prepareStatement(STMT_REGISTER_SUBDOMAIN); - stmt.setInt(1, domainCount); - final ResultSet rs = stmt.executeQuery(); - try { - final Deque<EntityID> ret = new ArrayDeque<>(); - while (rs.next()) { - ret.add(new EntityID(rs.getInt(1))); - } - return ret; - } finally { - rs.close(); - } - } catch (final SQLException e) { - throw new TransactionException(e); - } catch (final ConnectionException e) { - throw new TransactionException(e); - } - } -} diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/InsertEntityPropertiesImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/InsertEntityPropertiesImpl.java index 2406d489..f17643fd 100644 --- a/src/main/java/org/caosdb/server/database/backend/interfaces/InsertEntityPropertiesImpl.java +++ b/src/main/java/org/caosdb/server/database/backend/interfaces/InsertEntityPropertiesImpl.java @@ -22,15 +22,10 @@ */ package org.caosdb.server.database.backend.interfaces; -import org.caosdb.server.database.exceptions.TransactionException; -import org.caosdb.server.database.proto.FlatProperty; -import org.caosdb.server.datatype.AbstractDatatype.Table; -import org.caosdb.server.entity.EntityID; +import org.caosdb.server.entity.EntityInterface; import org.caosdb.server.utils.Undoable; public interface InsertEntityPropertiesImpl extends BackendTransactionImpl, Undoable { - public abstract void execute( - EntityID domain, EntityID entity, FlatProperty fp, Table table, Long unit_sig) - throws TransactionException; + public abstract void execute(EntityInterface entity); } diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/RegisterSubDomainImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/RegisterSubDomainImpl.java deleted file mode 100644 index 87ea0c85..00000000 --- a/src/main/java/org/caosdb/server/database/backend/interfaces/RegisterSubDomainImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.database.backend.interfaces; - -import java.util.Deque; -import org.caosdb.server.database.exceptions.TransactionException; -import org.caosdb.server.entity.EntityID; - -public interface RegisterSubDomainImpl extends BackendTransactionImpl { - - public abstract Deque<EntityID> execute(int domainCount) throws TransactionException; -} diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityProperties.java b/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityProperties.java index f9af6a48..8de8afc0 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityProperties.java @@ -22,25 +22,10 @@ */ package org.caosdb.server.database.backend.transaction; -import java.util.ArrayList; -import java.util.Deque; -import java.util.Iterator; -import java.util.List; import org.caosdb.server.database.BackendTransaction; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.backend.interfaces.InsertEntityPropertiesImpl; import org.caosdb.server.database.exceptions.TransactionException; -import org.caosdb.server.database.proto.FlatProperty; -import org.caosdb.server.datatype.AbstractCollectionDatatype; -import org.caosdb.server.datatype.AbstractDatatype.Table; -import org.caosdb.server.datatype.CollectionValue; -import org.caosdb.server.datatype.IndexedSingleValue; -import org.caosdb.server.datatype.SingleValue; -import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.EntityInterface; -import org.caosdb.server.entity.Role; -import org.caosdb.server.entity.StatementStatus; -import org.caosdb.server.entity.wrapper.Property; public class InsertEntityProperties extends BackendTransaction { @@ -54,126 +39,6 @@ public class InsertEntityProperties extends BackendTransaction { public void execute() throws TransactionException { final InsertEntityPropertiesImpl t = getImplementation(InsertEntityPropertiesImpl.class); - - final ArrayList<EntityInterface> stage1Inserts = new ArrayList<EntityInterface>(); - final ArrayList<EntityInterface> stage2Inserts = new ArrayList<EntityInterface>(); - - DatabaseUtils.deriveStage1Inserts(stage1Inserts, this.entity); - - final int domainCount = DatabaseUtils.deriveStage2Inserts(stage2Inserts, stage1Inserts); - - final Deque<EntityID> domainIds = execute(new RegisterSubDomain(domainCount)).getDomains(); - - insertStages(t, domainIds, stage1Inserts, this.entity.getDomain(), this.entity.getId()); - insertStages(t, domainIds, stage2Inserts, this.entity.getId(), null); - } - - private void insertStages( - final InsertEntityPropertiesImpl t, - final Deque<EntityID> domainIds, - final List<EntityInterface> stage1Inserts, - final EntityID domain, - final EntityID entity) - throws TransactionException { - - for (final EntityInterface property : stage1Inserts) { - if (property.hasRole() && property.getRole() == Role.Domain && !property.hasId()) { - property.setId(domainIds.removeFirst()); - } - int pIdx; - if (property instanceof Property) { - // this is a normal property - pIdx = ((Property) property).getPIdx(); - } else { - // this is a replacement - pIdx = 0; - } - - // prepare flat property - final FlatProperty fp = new FlatProperty(); - Table table = Table.null_data; - Long unit_sig = null; - fp.id = property.getId().toInteger(); - fp.idx = pIdx; - - if (property.hasReplacement()) { - if (!property.getReplacement().hasId()) { - property.getReplacement().setId(domainIds.removeFirst()); - } - - fp.value = property.getReplacement().getId().toString(); - fp.status = StatementStatus.REPLACEMENT.toString(); - - table = Table.reference_data; - } else { - if (property.hasUnit()) { - unit_sig = property.getUnit().getSignature(); - } - fp.status = property.getStatementStatus().toString(); - if (property.hasValue()) { - if (property.getValue() instanceof CollectionValue) { - // insert collection of values - final CollectionValue v = (CollectionValue) property.getValue(); - final Iterator<IndexedSingleValue> iterator = v.iterator(); - final SingleValue firstValue = iterator.next(); - - // insert 2nd to nth item - for (int i = 1; i < v.size(); i++) { - final SingleValue vi = iterator.next(); - fp.idx = i; - if (vi == null) { - fp.value = null; - table = Table.null_data; - } else { - fp.value = vi.toDatabaseString(); - table = vi.getTable(); - } - t.execute( - domain, entity != null ? entity : property.getDomain(), fp, table, unit_sig); - } - - // insert first item - fp.idx = 0; - if (firstValue == null) { - fp.value = null; - table = Table.null_data; - } else { - fp.value = firstValue.toDatabaseString(); - table = firstValue.getTable(); - } - - } else { - // insert single value - fp.value = ((SingleValue) property.getValue()).toDatabaseString(); - if (property instanceof Property && ((Property) property).isName()) { - table = Table.name_data; - } else { - table = ((SingleValue) property.getValue()).getTable(); - } - } - } - if (property.isNameOverride()) { - fp.name = property.getName(); - } - if (property.isDescOverride()) { - fp.desc = property.getDescription(); - } - if (property.isDatatypeOverride()) { - if (property.getDatatype() instanceof AbstractCollectionDatatype) { - fp.type = - ((AbstractCollectionDatatype) property.getDatatype()) - .getDatatype() - .getId() - .toString(); - fp.collection = - ((AbstractCollectionDatatype) property.getDatatype()).getCollectionName(); - } else { - fp.type = property.getDatatype().getId().toString(); - } - } - } - - t.execute(domain, entity != null ? entity : property.getDomain(), fp, table, unit_sig); - } + t.execute(this.entity); } } diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityTransaction.java b/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityTransaction.java index 5871c97e..2846fa64 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityTransaction.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/InsertEntityTransaction.java @@ -54,7 +54,9 @@ public class InsertEntityTransaction extends BackendTransaction { if (newEntity.hasFileProperties()) { execute(new InsertFile(newEntity)); } - execute(new InsertEntityProperties(newEntity)); + if (newEntity.hasProperties() || newEntity.hasValue()) { + execute(new InsertEntityProperties(newEntity)); + } execute(new InsertParents(newEntity)); if (newEntity.getEntityStatus() == EntityStatus.QUALIFIED) { diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RegisterSubDomain.java b/src/main/java/org/caosdb/server/database/backend/transaction/RegisterSubDomain.java deleted file mode 100644 index 0321a621..00000000 --- a/src/main/java/org/caosdb/server/database/backend/transaction/RegisterSubDomain.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.database.backend.transaction; - -import java.util.Deque; -import org.caosdb.server.database.BackendTransaction; -import org.caosdb.server.database.backend.interfaces.RegisterSubDomainImpl; -import org.caosdb.server.database.exceptions.TransactionException; -import org.caosdb.server.entity.EntityID; - -public class RegisterSubDomain extends BackendTransaction { - - private final int domainCount; - private Deque<EntityID> list; - - public RegisterSubDomain(final int domainCount) { - this.domainCount = domainCount; - } - - @Override - public void execute() throws TransactionException { - final RegisterSubDomainImpl t = getImplementation(RegisterSubDomainImpl.class); - this.list = t.execute(this.domainCount); - } - - public Deque<EntityID> getDomains() { - return this.list; - } -} diff --git a/src/main/java/org/caosdb/server/database/proto/FlatProperty.java b/src/main/java/org/caosdb/server/database/proto/FlatProperty.java index b92d3def..b4f0f62a 100644 --- a/src/main/java/org/caosdb/server/database/proto/FlatProperty.java +++ b/src/main/java/org/caosdb/server/database/proto/FlatProperty.java @@ -26,6 +26,19 @@ import java.io.Serializable; public class FlatProperty implements Serializable { + public FlatProperty() {} + + public FlatProperty(FlatProperty fp) { + id = fp.id; + value = fp.value; + status = fp.status; + idx = fp.idx; + name = fp.name; + desc = fp.desc; + type = fp.type; + collection = fp.collection; + } + private static final long serialVersionUID = 6039288034435124195L; public Integer id = null; public String value = null; diff --git a/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java b/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java index 898565ac..c6cdbd54 100644 --- a/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java +++ b/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java @@ -26,21 +26,14 @@ import java.io.Serializable; import java.util.List; public class ProtoProperty extends FlatProperty implements Serializable { + private static final long serialVersionUID = 7731301985162924975L; public ProtoProperty(FlatProperty fp) { - id = fp.id; - value = fp.value; - status = fp.status; - idx = fp.idx; - name = fp.name; - desc = fp.desc; - type = fp.type; - collection = fp.collection; + super(fp); } public ProtoProperty() {} - private static final long serialVersionUID = 7731301985162924975L; public List<ProtoProperty> subProperties = null; public List<Object> collValues = null; } diff --git a/src/test/java/org/caosdb/server/database/InsertTest.java b/src/test/java/org/caosdb/server/database/InsertTest.java index 59aa6f55..e385d6cb 100644 --- a/src/test/java/org/caosdb/server/database/InsertTest.java +++ b/src/test/java/org/caosdb/server/database/InsertTest.java @@ -28,13 +28,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.LinkedList; import org.caosdb.server.datatype.CollectionValue; import org.caosdb.server.datatype.GenericValue; +import org.caosdb.server.datatype.ReferenceValue; import org.caosdb.server.datatype.SingleValue; import org.caosdb.server.entity.Entity; import org.caosdb.server.entity.EntityID; -import org.caosdb.server.entity.EntityInterface; import org.caosdb.server.entity.InsertEntity; import org.caosdb.server.entity.RetrieveEntity; import org.caosdb.server.entity.Role; @@ -44,6 +46,14 @@ import org.junit.jupiter.api.Test; public class InsertTest { + private Deque<EntityID> registerReplacementIds(int count) { + Deque<EntityID> replacementIds = new ArrayDeque<>(); + for (int i = 1; i < count + 1; i++) { + replacementIds.add(new EntityID(-i)); + } + return replacementIds; + } + /** * Record with very deep property tree. * @@ -122,85 +132,67 @@ public class InsertTest { p10.setStatementStatus(StatementStatus.OBLIGATORY); p9.addProperty(p10); - final LinkedList<EntityInterface> stage1Inserts = new LinkedList<EntityInterface>(); - final LinkedList<EntityInterface> stage2Inserts = new LinkedList<EntityInterface>(); + final LinkedList<Property> stage1Inserts = new LinkedList<>(); + final LinkedList<Property> stage2Inserts = new LinkedList<>(); - deriveStage1Inserts(stage1Inserts, r); + int replacementCount = deriveStage1Inserts(stage1Inserts, r); + assertEquals(3, replacementCount); + + deriveStage2Inserts(stage2Inserts, stage1Inserts, registerReplacementIds(replacementCount), r); assertEquals(7, stage1Inserts.size()); - assertEquals(Role.Property, stage1Inserts.get(0).getRole()); - assertEquals(new EntityID(1), stage1Inserts.get(0).getId()); + assertFalse(stage1Inserts.get(0) instanceof Replacement); + assertEquals(1, stage1Inserts.get(0).getId().toInteger()); assertEquals("V1", ((SingleValue) stage1Inserts.get(0).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(0).hasReplacement()); - assertEquals(Role.Property, stage1Inserts.get(1).getRole()); - assertEquals(new EntityID(2), stage1Inserts.get(1).getId()); + assertFalse(stage1Inserts.get(1) instanceof Replacement); + assertEquals(2, stage1Inserts.get(1).getId().toInteger()); assertEquals("V2", ((SingleValue) stage1Inserts.get(1).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(1).hasReplacement()); - assertEquals(Role.Property, stage1Inserts.get(2).getRole()); - assertEquals(new EntityID(4), stage1Inserts.get(2).getId()); + assertFalse(stage1Inserts.get(2) instanceof Replacement); + assertEquals(4, stage1Inserts.get(2).getId().toInteger()); assertEquals("V4", ((SingleValue) stage1Inserts.get(2).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(2).hasReplacement()); - assertEquals(Role.Domain, stage1Inserts.get(3).getRole()); + assertTrue(stage1Inserts.get(3) instanceof Replacement); + assertEquals(5, stage1Inserts.get(3).getId().toInteger()); assertEquals("V5", ((SingleValue) stage1Inserts.get(3).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(3).hasReplacement()); - assertEquals(Role.Property, stage1Inserts.get(4).getRole()); - assertEquals(new EntityID(7), stage1Inserts.get(4).getId()); + assertFalse(stage1Inserts.get(4) instanceof Replacement); + assertEquals(7, stage1Inserts.get(4).getId().toInteger()); assertEquals("V7", ((SingleValue) stage1Inserts.get(4).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(4).hasReplacement()); - assertEquals(Role.Domain, stage1Inserts.get(5).getRole()); + assertTrue(stage1Inserts.get(5) instanceof Replacement); + assertEquals(8, stage1Inserts.get(5).getId().toInteger()); assertEquals("V8", ((SingleValue) stage1Inserts.get(5).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(5).hasReplacement()); - assertEquals(Role.Domain, stage1Inserts.get(6).getRole()); + assertTrue(stage1Inserts.get(6) instanceof Replacement); + assertEquals(9, stage1Inserts.get(6).getId().toInteger()); assertEquals("V9", ((SingleValue) stage1Inserts.get(6).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(6).hasReplacement()); - - deriveStage2Inserts(stage2Inserts, stage1Inserts); assertEquals(6, stage2Inserts.size()); - assertEquals(Role.Property, stage2Inserts.get(0).getRole()); assertEquals(new EntityID(3), stage2Inserts.get(0).getId()); assertEquals("V3", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString()); assertEquals(new EntityID(2), stage2Inserts.get(0).getDomain()); - assertFalse(stage2Inserts.get(0).hasReplacement()); - assertEquals(Role.Property, stage2Inserts.get(1).getRole()); assertEquals(new EntityID(5), stage2Inserts.get(1).getId()); assertEquals("V5", ((SingleValue) stage2Inserts.get(1).getValue()).toDatabaseString()); - assertTrue(stage2Inserts.get(1).hasReplacement()); assertEquals(new EntityID(4), stage2Inserts.get(1).getDomain()); - assertEquals(stage1Inserts.get(3), stage2Inserts.get(1).getReplacement()); - assertEquals(Role.Property, stage2Inserts.get(2).getRole()); assertEquals(new EntityID(6), stage2Inserts.get(2).getId()); assertEquals("V6", ((SingleValue) stage2Inserts.get(2).getValue()).toDatabaseString()); - assertEquals(new EntityID(5), stage2Inserts.get(2).getDomain()); - assertFalse(stage2Inserts.get(2).hasReplacement()); + assertEquals(new EntityID(-1), stage2Inserts.get(2).getDomain()); - assertEquals(Role.Property, stage2Inserts.get(3).getRole()); assertEquals(new EntityID(8), stage2Inserts.get(3).getId()); assertEquals("V8", ((SingleValue) stage2Inserts.get(3).getValue()).toDatabaseString()); - assertTrue(stage2Inserts.get(3).hasReplacement()); assertEquals(new EntityID(7), stage2Inserts.get(3).getDomain()); - assertEquals(stage1Inserts.get(5), stage2Inserts.get(3).getReplacement()); - assertEquals(Role.Property, stage2Inserts.get(4).getRole()); assertEquals(new EntityID(9), stage2Inserts.get(4).getId()); assertEquals("V9", ((SingleValue) stage2Inserts.get(4).getValue()).toDatabaseString()); - assertTrue(stage2Inserts.get(4).hasReplacement()); - assertEquals(new EntityID(8), stage2Inserts.get(4).getDomain()); - assertEquals(stage1Inserts.get(6), stage2Inserts.get(4).getReplacement()); + assertEquals(new EntityID(-2), stage2Inserts.get(4).getDomain()); - assertEquals(Role.Property, stage2Inserts.get(5).getRole()); assertEquals(new EntityID(10), stage2Inserts.get(5).getId()); assertEquals("V10", ((SingleValue) stage2Inserts.get(5).getValue()).toDatabaseString()); - assertEquals(new EntityID(9), stage2Inserts.get(5).getDomain()); - assertFalse(stage2Inserts.get(5).hasReplacement()); + assertEquals(new EntityID(-3), stage2Inserts.get(5).getDomain()); } /** @@ -233,34 +225,31 @@ public class InsertTest { subp.setStatementStatus(StatementStatus.FIX); p2.addProperty(subp); - final LinkedList<EntityInterface> stage1Inserts = new LinkedList<EntityInterface>(); - final LinkedList<EntityInterface> stage2Inserts = new LinkedList<EntityInterface>(); + final LinkedList<Property> stage1Inserts = new LinkedList<>(); + final LinkedList<Property> stage2Inserts = new LinkedList<>(); - deriveStage1Inserts(stage1Inserts, r); + int replacementCount = deriveStage1Inserts(stage1Inserts, r); + deriveStage2Inserts(stage2Inserts, stage1Inserts, registerReplacementIds(replacementCount), r); assertEquals(3, stage1Inserts.size()); - assertEquals(Role.Property, stage1Inserts.get(0).getRole()); + + assertFalse(stage1Inserts.get(0) instanceof Replacement); assertEquals(new EntityID(1), stage1Inserts.get(0).getId()); assertEquals("V1-1", ((SingleValue) stage1Inserts.get(0).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(0).hasReplacement()); - assertEquals(Role.Property, stage1Inserts.get(1).getRole()); + assertTrue(stage1Inserts.get(1) instanceof Replacement); assertEquals("V1-2", ((SingleValue) stage1Inserts.get(1).getValue()).toDatabaseString()); assertEquals(new EntityID(1), stage1Inserts.get(1).getId()); - assertTrue(stage1Inserts.get(1).hasReplacement()); - assertEquals(stage1Inserts.get(2), stage1Inserts.get(1).getReplacement()); - - assertEquals(Role.Domain, stage1Inserts.get(2).getRole()); - assertEquals("V1-2", ((SingleValue) stage1Inserts.get(2).getValue()).toDatabaseString()); - assertFalse(stage1Inserts.get(2).hasReplacement()); - deriveStage2Inserts(stage2Inserts, stage1Inserts); + assertFalse(stage1Inserts.get(2) instanceof Replacement); + assertEquals(new EntityID(-1), stage1Inserts.get(2).getId()); + assertEquals("1", ((SingleValue) stage1Inserts.get(2).getValue()).toDatabaseString()); assertEquals(1, stage2Inserts.size()); - assertEquals(Role.Property, stage2Inserts.get(0).getRole()); + + assertFalse(stage2Inserts.get(0) instanceof Replacement); assertEquals(new EntityID(2), stage2Inserts.get(0).getId()); assertEquals("V2", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString()); - assertFalse(stage2Inserts.get(0).hasReplacement()); } /** @@ -297,39 +286,33 @@ public class InsertTest { sub1.setStatementStatus(StatementStatus.FIX); p1.addProperty(sub1); - final LinkedList<EntityInterface> stage1Inserts = new LinkedList<EntityInterface>(); - final LinkedList<EntityInterface> stage2Inserts = new LinkedList<EntityInterface>(); + final LinkedList<Property> stage1Inserts = new LinkedList<>(); + final LinkedList<Property> stage2Inserts = new LinkedList<>(); - deriveStage1Inserts(stage1Inserts, r); + int count = deriveStage1Inserts(stage1Inserts, r); + deriveStage2Inserts(stage2Inserts, stage1Inserts, registerReplacementIds(count), r); assertEquals(4, stage1Inserts.size()); - assertEquals(Role.Property, stage1Inserts.get(0).getRole()); + assertTrue(stage1Inserts.get(0) instanceof Replacement); assertEquals(new EntityID(1), stage1Inserts.get(0).getId()); - assertTrue(stage1Inserts.get(0).hasReplacement()); - assertEquals(stage1Inserts.get(1), stage1Inserts.get(0).getReplacement()); assertEquals(null, stage1Inserts.get(0).getValue()); - assertEquals(Role.Domain, stage1Inserts.get(1).getRole()); - assertFalse(stage1Inserts.get(1).hasReplacement()); - assertEquals(null, stage1Inserts.get(1).getValue()); + assertFalse(stage1Inserts.get(1) instanceof Replacement); + assertEquals(new EntityID(-1), stage1Inserts.get(1).getId()); + assertEquals(1, ((ReferenceValue) stage1Inserts.get(1).getValue()).getId().toInteger()); - assertEquals(Role.Property, stage1Inserts.get(2).getRole()); + assertFalse(stage1Inserts.get(2) instanceof Replacement); assertEquals(new EntityID(1), stage1Inserts.get(2).getId()); - assertFalse(stage1Inserts.get(2).hasReplacement()); assertEquals(null, stage1Inserts.get(2).getValue()); - assertEquals(Role.Property, stage1Inserts.get(3).getRole()); + assertFalse(stage1Inserts.get(3) instanceof Replacement); assertEquals(new EntityID(1), stage1Inserts.get(3).getId()); - assertFalse(stage1Inserts.get(3).hasReplacement()); assertEquals(null, stage1Inserts.get(3).getValue()); - deriveStage2Inserts(stage2Inserts, stage1Inserts); - assertEquals(1, stage2Inserts.size()); - assertEquals(Role.Property, stage2Inserts.get(0).getRole()); assertEquals(new EntityID(2), stage2Inserts.get(0).getId()); assertEquals("V1", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString()); - assertFalse(stage2Inserts.get(0).hasReplacement()); + assertEquals(new EntityID(-1), stage2Inserts.get(0).getDomain()); } /** @@ -366,32 +349,31 @@ public class InsertTest { p3.setStatementStatus(StatementStatus.FIX); r.addProperty(p3); - final LinkedList<EntityInterface> stage1Inserts = new LinkedList<EntityInterface>(); - final LinkedList<EntityInterface> stage2Inserts = new LinkedList<EntityInterface>(); + final LinkedList<Property> stage1Inserts = new LinkedList<>(); + final LinkedList<Property> stage2Inserts = new LinkedList<>(); - deriveStage1Inserts(stage1Inserts, r); + int count = deriveStage1Inserts(stage1Inserts, r); + deriveStage2Inserts(stage2Inserts, stage1Inserts, registerReplacementIds(count), r); assertEquals(4, stage1Inserts.size()); - assertEquals(Role.Property, stage1Inserts.get(0).getRole()); + + assertFalse(stage1Inserts.get(0) instanceof Replacement); assertEquals(new EntityID(1), stage1Inserts.get(0).getId()); assertFalse(stage1Inserts.get(0).hasReplacement()); assertEquals("V1", ((SingleValue) stage1Inserts.get(0).getValue()).toDatabaseString()); - assertEquals(Role.Property, stage1Inserts.get(1).getRole()); + assertTrue(stage1Inserts.get(1) instanceof Replacement); assertEquals(new EntityID(2), stage1Inserts.get(1).getId()); - assertTrue(stage1Inserts.get(1).hasReplacement()); - assertEquals(stage1Inserts.get(2), stage1Inserts.get(1).getReplacement()); assertTrue(stage1Inserts.get(1).getValue() instanceof CollectionValue); - assertEquals(Role.Domain, stage1Inserts.get(2).getRole()); - assertFalse(stage1Inserts.get(2).hasReplacement()); - assertTrue(stage1Inserts.get(2).getValue() instanceof CollectionValue); + assertFalse(stage1Inserts.get(2) instanceof Replacement); + assertEquals(new EntityID(-1), stage1Inserts.get(2).getId()); + assertEquals(2, ((ReferenceValue) stage1Inserts.get(2).getValue()).getId().toInteger()); - assertEquals(Role.Property, stage1Inserts.get(3).getRole()); + assertFalse(stage1Inserts.get(3) instanceof Replacement); assertEquals(new EntityID(3), stage1Inserts.get(3).getId()); - assertFalse(stage1Inserts.get(3).hasReplacement()); assertEquals("V3", ((SingleValue) stage1Inserts.get(3).getValue()).toDatabaseString()); - deriveStage2Inserts(stage2Inserts, stage1Inserts); + assertEquals(0, stage2Inserts.size()); } } diff --git a/src/test/java/org/caosdb/server/database/InsertTest2.java b/src/test/java/org/caosdb/server/database/InsertTest2.java new file mode 100644 index 00000000..58cc5850 --- /dev/null +++ b/src/test/java/org/caosdb/server/database/InsertTest2.java @@ -0,0 +1,148 @@ +package org.caosdb.server.database; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import org.caosdb.server.entity.Entity; +import org.caosdb.server.entity.EntityID; +import org.caosdb.server.entity.InsertEntity; +import org.caosdb.server.entity.RetrieveEntity; +import org.caosdb.server.entity.Role; +import org.caosdb.server.entity.StatementStatus; +import org.caosdb.server.entity.wrapper.Property; +import org.junit.jupiter.api.Test; + +public class InsertTest2 { + + private Deque<EntityID> registerReplacementIds(int count) { + Deque<EntityID> replacementIds = new ArrayDeque<>(); + for (int i = 1; i < count + 1; i++) { + replacementIds.add(new EntityID(-i)); + } + return replacementIds; + } + + @Test + public void transformation5() { + final Entity r = new InsertEntity("Test", Role.RecordType); + final Property p1 = new Property(new RetrieveEntity(new EntityID(1))); + p1.setRole("Property"); + p1.setDatatype("TEXT"); + p1.setDescription("desc1"); + p1.setDescOverride(true); + p1.setName("P1"); + p1.setNameOverride(true); + p1.setStatementStatus(StatementStatus.RECOMMENDED); + r.addProperty(p1); + + final Property p2 = new Property(new RetrieveEntity(new EntityID(2))); + p2.setRole("Property"); + p2.setDatatype("TEXT"); + p2.setDescription("desc2"); + p2.setDescOverride(true); + p2.setName("P2"); + p2.setNameOverride(true); + p2.setStatementStatus(StatementStatus.RECOMMENDED); + r.addProperty(p2); + + final Property p21 = new Property(new RetrieveEntity(new EntityID(1))); + p21.setRole("Property"); + p21.setDatatype("TEXT"); + p21.setDescription("desc21"); + p21.setDescOverride(true); + p21.setName("P21"); + p21.setNameOverride(true); + p21.setStatementStatus(StatementStatus.RECOMMENDED); + p2.addProperty(p21); + + final Property p22 = new Property(new RetrieveEntity(new EntityID(2))); + p22.setRole("Property"); + p22.setDatatype("TEXT"); + p22.setDescription("desc22"); + p22.setDescOverride(true); + p22.setName("P22"); + p22.setNameOverride(true); + p22.setStatementStatus(StatementStatus.RECOMMENDED); + p2.addProperty(p22); + + final Property p3 = new Property(new RetrieveEntity(new EntityID(3))); + p3.setRole("Property"); + p3.setDatatype("TEXT"); + p3.setDescription("desc3"); + p3.setDescOverride(true); + p3.setName("P3"); + p3.setNameOverride(true); + p3.setStatementStatus(StatementStatus.RECOMMENDED); + r.addProperty(p3); + + final Property p31 = new Property(new RetrieveEntity(new EntityID(1))); + p31.setRole("Property"); + p31.setDatatype("TEXT"); + p31.setDescription("desc31"); + p31.setDescOverride(true); + p31.setName("P31"); + p31.setNameOverride(true); + p31.setStatementStatus(StatementStatus.RECOMMENDED); + p3.addProperty(p31); + + final Property p32 = new Property(new RetrieveEntity(new EntityID(2))); + p32.setRole("Property"); + p32.setDatatype("TEXT"); + p32.setDescription("desc32"); + p32.setDescOverride(true); + p32.setName("P32"); + p32.setNameOverride(true); + p32.setStatementStatus(StatementStatus.RECOMMENDED); + p3.addProperty(p32); + + final Property p321 = new Property(new RetrieveEntity(new EntityID(1))); + p321.setRole("Property"); + p321.setDatatype("TEXT"); + p321.setDescription("desc321"); + p321.setDescOverride(true); + p321.setName("P321"); + p321.setNameOverride(true); + p321.setStatementStatus(StatementStatus.RECOMMENDED); + p32.addProperty(p321); + + final Property p322 = new Property(new RetrieveEntity(new EntityID(2))); + p322.setRole("Property"); + p322.setDatatype("TEXT"); + p322.setDescription("desc322"); + p322.setDescOverride(true); + p322.setName("P322"); + p322.setNameOverride(true); + p322.setStatementStatus(StatementStatus.RECOMMENDED); + p32.addProperty(p322); + + final Property p323 = new Property(new RetrieveEntity(new EntityID(3))); + p323.setRole("Property"); + p323.setDatatype("TEXT"); + p323.setDescription("desc323"); + p323.setDescOverride(true); + p323.setName("P323"); + p323.setNameOverride(true); + p323.setStatementStatus(StatementStatus.RECOMMENDED); + p32.addProperty(p323); + + final Property p33 = new Property(new RetrieveEntity(new EntityID(3))); + p33.setRole("Property"); + p33.setDatatype("TEXT"); + p33.setDescription("desc33"); + p33.setDescOverride(true); + p33.setName("P33"); + p33.setNameOverride(true); + p33.setStatementStatus(StatementStatus.RECOMMENDED); + p3.addProperty(p33); + + List<Property> stage1Inserts = new LinkedList<>(); + List<Property> stage2Inserts = new LinkedList<>(); + int c = DatabaseUtils.deriveStage1Inserts(stage1Inserts, r); + DatabaseUtils.deriveStage2Inserts(stage2Inserts, stage1Inserts, registerReplacementIds(c), r); + assertEquals(7, stage1Inserts.size()); + assertEquals(8, stage2Inserts.size()); + } +} -- GitLab From d186c1b94b24f52cd2919660401431e9fcfab18c Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Wed, 16 Aug 2023 00:10:26 +0200 Subject: [PATCH 4/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../java/org/caosdb/server/entity/Entity.java | 18 --- .../caosdb/server/entity/EntityInterface.java | 7 - .../caosdb/server/entity/wrapper/Domain.java | 59 ------- .../server/entity/wrapper/EntityWrapper.java | 15 -- .../caosdb/server/database/InsertTest.java | 138 +++++++++++++++- .../caosdb/server/database/InsertTest2.java | 148 ------------------ 6 files changed, 131 insertions(+), 254 deletions(-) delete mode 100644 src/main/java/org/caosdb/server/entity/wrapper/Domain.java delete mode 100644 src/test/java/org/caosdb/server/database/InsertTest2.java diff --git a/src/main/java/org/caosdb/server/entity/Entity.java b/src/main/java/org/caosdb/server/entity/Entity.java index e1acfbdc..843449ce 100644 --- a/src/main/java/org/caosdb/server/entity/Entity.java +++ b/src/main/java/org/caosdb/server/entity/Entity.java @@ -47,7 +47,6 @@ import org.caosdb.server.datatype.Value; import org.caosdb.server.entity.Message.MessageType; import org.caosdb.server.entity.container.ParentContainer; import org.caosdb.server.entity.container.PropertyContainer; -import org.caosdb.server.entity.wrapper.Domain; import org.caosdb.server.entity.wrapper.Parent; import org.caosdb.server.entity.wrapper.Property; import org.caosdb.server.entity.xml.EntityToElementStrategy; @@ -849,23 +848,6 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa } } - @Override - public void setReplacement(final Domain d) { - this.replacement = d; - } - - @Override - public boolean hasReplacement() { - return this.replacement != null; - } - - @Override - public Domain getReplacement() { - return this.replacement; - } - - private Domain replacement = null; - private final HashMap<String, String> flags = new HashMap<String, String>(); @Override diff --git a/src/main/java/org/caosdb/server/entity/EntityInterface.java b/src/main/java/org/caosdb/server/entity/EntityInterface.java index f967b307..d97970de 100644 --- a/src/main/java/org/caosdb/server/entity/EntityInterface.java +++ b/src/main/java/org/caosdb/server/entity/EntityInterface.java @@ -31,7 +31,6 @@ import org.caosdb.server.datatype.AbstractDatatype; import org.caosdb.server.datatype.Value; import org.caosdb.server.entity.container.ParentContainer; import org.caosdb.server.entity.container.PropertyContainer; -import org.caosdb.server.entity.wrapper.Domain; import org.caosdb.server.entity.wrapper.Parent; import org.caosdb.server.entity.wrapper.Property; import org.caosdb.server.entity.xml.SerializeFieldStrategy; @@ -127,12 +126,6 @@ public interface EntityInterface public abstract void setProperties(PropertyContainer properties); - public abstract void setReplacement(Domain d); - - public abstract boolean hasReplacement(); - - public abstract Domain getReplacement(); - public abstract EntityInterface setDescOverride(boolean b); public abstract boolean isDescOverride(); diff --git a/src/main/java/org/caosdb/server/entity/wrapper/Domain.java b/src/main/java/org/caosdb/server/entity/wrapper/Domain.java deleted file mode 100644 index 146706ef..00000000 --- a/src/main/java/org/caosdb/server/entity/wrapper/Domain.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.entity.wrapper; - -import org.caosdb.server.datatype.AbstractDatatype; -import org.caosdb.server.datatype.Value; -import org.caosdb.server.entity.Entity; -import org.caosdb.server.entity.EntityInterface; -import org.caosdb.server.entity.Role; -import org.caosdb.server.entity.container.PropertyContainer; - -public class Domain extends Entity { - - private boolean descO; - - public Domain( - final PropertyContainer properties, - final AbstractDatatype datatype, - final Value value, - final org.caosdb.server.entity.StatementStatus statementStatus) { - - setRole(Role.Domain); - setProperties(properties); - setDatatype(datatype); - setValue(value); - setStatementStatus(statementStatus); - } - - @Override - public EntityInterface setDescOverride(final boolean b) { - this.descO = b; - return this; - } - - @Override - public boolean isDescOverride() { - return this.descO; - } -} diff --git a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java index 7da94573..f23408df 100644 --- a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java +++ b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java @@ -376,21 +376,6 @@ public abstract class EntityWrapper implements EntityInterface { this.entity.setProperties(properties); } - @Override - public void setReplacement(final Domain d) { - this.entity.setReplacement(d); - } - - @Override - public boolean hasReplacement() { - return this.entity.hasReplacement(); - } - - @Override - public Domain getReplacement() { - return this.entity.getReplacement(); - } - @Override public Map<String, String> getFlags() { return this.entity.getFlags(); diff --git a/src/test/java/org/caosdb/server/database/InsertTest.java b/src/test/java/org/caosdb/server/database/InsertTest.java index e385d6cb..0484e623 100644 --- a/src/test/java/org/caosdb/server/database/InsertTest.java +++ b/src/test/java/org/caosdb/server/database/InsertTest.java @@ -31,6 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayDeque; import java.util.Deque; import java.util.LinkedList; +import java.util.List; import org.caosdb.server.datatype.CollectionValue; import org.caosdb.server.datatype.GenericValue; import org.caosdb.server.datatype.ReferenceValue; @@ -154,7 +155,7 @@ public class InsertTest { assertEquals("V4", ((SingleValue) stage1Inserts.get(2).getValue()).toDatabaseString()); assertTrue(stage1Inserts.get(3) instanceof Replacement); - assertEquals(5, stage1Inserts.get(3).getId().toInteger()); + assertEquals(-1, stage1Inserts.get(3).getId().toInteger()); assertEquals("V5", ((SingleValue) stage1Inserts.get(3).getValue()).toDatabaseString()); assertFalse(stage1Inserts.get(4) instanceof Replacement); @@ -162,11 +163,11 @@ public class InsertTest { assertEquals("V7", ((SingleValue) stage1Inserts.get(4).getValue()).toDatabaseString()); assertTrue(stage1Inserts.get(5) instanceof Replacement); - assertEquals(8, stage1Inserts.get(5).getId().toInteger()); + assertEquals(-2, stage1Inserts.get(5).getId().toInteger()); assertEquals("V8", ((SingleValue) stage1Inserts.get(5).getValue()).toDatabaseString()); assertTrue(stage1Inserts.get(6) instanceof Replacement); - assertEquals(9, stage1Inserts.get(6).getId().toInteger()); + assertEquals(-3, stage1Inserts.get(6).getId().toInteger()); assertEquals("V9", ((SingleValue) stage1Inserts.get(6).getValue()).toDatabaseString()); assertEquals(6, stage2Inserts.size()); @@ -239,7 +240,7 @@ public class InsertTest { assertTrue(stage1Inserts.get(1) instanceof Replacement); assertEquals("V1-2", ((SingleValue) stage1Inserts.get(1).getValue()).toDatabaseString()); - assertEquals(new EntityID(1), stage1Inserts.get(1).getId()); + assertEquals(new EntityID(-1), stage1Inserts.get(1).getId()); assertFalse(stage1Inserts.get(2) instanceof Replacement); assertEquals(new EntityID(-1), stage1Inserts.get(2).getId()); @@ -294,7 +295,7 @@ public class InsertTest { assertEquals(4, stage1Inserts.size()); assertTrue(stage1Inserts.get(0) instanceof Replacement); - assertEquals(new EntityID(1), stage1Inserts.get(0).getId()); + assertEquals(new EntityID(-1), stage1Inserts.get(0).getId()); assertEquals(null, stage1Inserts.get(0).getValue()); assertFalse(stage1Inserts.get(1) instanceof Replacement); @@ -359,11 +360,10 @@ public class InsertTest { assertFalse(stage1Inserts.get(0) instanceof Replacement); assertEquals(new EntityID(1), stage1Inserts.get(0).getId()); - assertFalse(stage1Inserts.get(0).hasReplacement()); assertEquals("V1", ((SingleValue) stage1Inserts.get(0).getValue()).toDatabaseString()); assertTrue(stage1Inserts.get(1) instanceof Replacement); - assertEquals(new EntityID(2), stage1Inserts.get(1).getId()); + assertEquals(new EntityID(-1), stage1Inserts.get(1).getId()); assertTrue(stage1Inserts.get(1).getValue() instanceof CollectionValue); assertFalse(stage1Inserts.get(2) instanceof Replacement); @@ -376,4 +376,128 @@ public class InsertTest { assertEquals(0, stage2Inserts.size()); } + + /** Deeply nested properties without any values, with overridden name and description */ + @Test + public void testTransformation5() { + final Entity r = new InsertEntity("Test", Role.RecordType); + final Property p1 = new Property(new RetrieveEntity(new EntityID(1))); + p1.setRole("Property"); + p1.setDatatype("TEXT"); + p1.setDescription("desc1"); + p1.setDescOverride(true); + p1.setName("P1"); + p1.setNameOverride(true); + p1.setStatementStatus(StatementStatus.RECOMMENDED); + r.addProperty(p1); + + final Property p2 = new Property(new RetrieveEntity(new EntityID(2))); + p2.setRole("Property"); + p2.setDatatype("TEXT"); + p2.setDescription("desc2"); + p2.setDescOverride(true); + p2.setName("P2"); + p2.setNameOverride(true); + p2.setStatementStatus(StatementStatus.RECOMMENDED); + r.addProperty(p2); + + final Property p21 = new Property(new RetrieveEntity(new EntityID(1))); + p21.setRole("Property"); + p21.setDatatype("TEXT"); + p21.setDescription("desc21"); + p21.setDescOverride(true); + p21.setName("P21"); + p21.setNameOverride(true); + p21.setStatementStatus(StatementStatus.FIX); + p2.addProperty(p21); + + final Property p22 = new Property(new RetrieveEntity(new EntityID(2))); + p22.setRole("Property"); + p22.setDatatype("TEXT"); + p22.setDescription("desc22"); + p22.setDescOverride(true); + p22.setName("P22"); + p22.setNameOverride(true); + p22.setStatementStatus(StatementStatus.FIX); + p2.addProperty(p22); + + final Property p3 = new Property(new RetrieveEntity(new EntityID(3))); + p3.setRole("Property"); + p3.setDatatype("TEXT"); + p3.setDescription("desc3"); + p3.setDescOverride(true); + p3.setName("P3"); + p3.setNameOverride(true); + p3.setStatementStatus(StatementStatus.RECOMMENDED); + r.addProperty(p3); + + final Property p31 = new Property(new RetrieveEntity(new EntityID(1))); + p31.setRole("Property"); + p31.setDatatype("TEXT"); + p31.setDescription("desc31"); + p31.setDescOverride(true); + p31.setName("P31"); + p31.setNameOverride(true); + p31.setStatementStatus(StatementStatus.FIX); + p3.addProperty(p31); + + final Property p32 = new Property(new RetrieveEntity(new EntityID(2))); + p32.setRole("Property"); + p32.setDatatype("TEXT"); + p32.setDescription("desc32"); + p32.setDescOverride(true); + p32.setName("P32"); + p32.setNameOverride(true); + p32.setStatementStatus(StatementStatus.FIX); + p3.addProperty(p32); + + final Property p321 = new Property(new RetrieveEntity(new EntityID(1))); + p321.setRole("Property"); + p321.setDatatype("TEXT"); + p321.setDescription("desc321"); + p321.setDescOverride(true); + p321.setName("P321"); + p321.setNameOverride(true); + p321.setStatementStatus(StatementStatus.FIX); + p32.addProperty(p321); + + final Property p322 = new Property(new RetrieveEntity(new EntityID(2))); + p322.setRole("Property"); + p322.setDatatype("TEXT"); + p322.setDescription("desc322"); + p322.setDescOverride(true); + p322.setName("P322"); + p322.setNameOverride(true); + p322.setStatementStatus(StatementStatus.FIX); + p32.addProperty(p322); + + final Property p323 = new Property(new RetrieveEntity(new EntityID(3))); + p323.setRole("Property"); + p323.setDatatype("TEXT"); + p323.setDescription("desc323"); + p323.setDescOverride(true); + p323.setName("P323"); + p323.setNameOverride(true); + p323.setStatementStatus(StatementStatus.FIX); + p32.addProperty(p323); + + final Property p33 = new Property(new RetrieveEntity(new EntityID(3))); + p33.setRole("Property"); + p33.setDatatype("TEXT"); + p33.setDescription("desc33"); + p33.setDescOverride(true); + p33.setName("P33"); + p33.setNameOverride(true); + p33.setStatementStatus(StatementStatus.FIX); + p3.addProperty(p33); + + List<Property> stage1Inserts = new LinkedList<>(); + List<Property> stage2Inserts = new LinkedList<>(); + int c = DatabaseUtils.deriveStage1Inserts(stage1Inserts, r); + DatabaseUtils.deriveStage2Inserts(stage2Inserts, stage1Inserts, registerReplacementIds(c), r); + + assertEquals(4, c); + assertEquals(7, stage1Inserts.size()); + assertEquals(8, stage2Inserts.size()); + } } diff --git a/src/test/java/org/caosdb/server/database/InsertTest2.java b/src/test/java/org/caosdb/server/database/InsertTest2.java deleted file mode 100644 index 58cc5850..00000000 --- a/src/test/java/org/caosdb/server/database/InsertTest2.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.caosdb.server.database; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; -import org.caosdb.server.entity.Entity; -import org.caosdb.server.entity.EntityID; -import org.caosdb.server.entity.InsertEntity; -import org.caosdb.server.entity.RetrieveEntity; -import org.caosdb.server.entity.Role; -import org.caosdb.server.entity.StatementStatus; -import org.caosdb.server.entity.wrapper.Property; -import org.junit.jupiter.api.Test; - -public class InsertTest2 { - - private Deque<EntityID> registerReplacementIds(int count) { - Deque<EntityID> replacementIds = new ArrayDeque<>(); - for (int i = 1; i < count + 1; i++) { - replacementIds.add(new EntityID(-i)); - } - return replacementIds; - } - - @Test - public void transformation5() { - final Entity r = new InsertEntity("Test", Role.RecordType); - final Property p1 = new Property(new RetrieveEntity(new EntityID(1))); - p1.setRole("Property"); - p1.setDatatype("TEXT"); - p1.setDescription("desc1"); - p1.setDescOverride(true); - p1.setName("P1"); - p1.setNameOverride(true); - p1.setStatementStatus(StatementStatus.RECOMMENDED); - r.addProperty(p1); - - final Property p2 = new Property(new RetrieveEntity(new EntityID(2))); - p2.setRole("Property"); - p2.setDatatype("TEXT"); - p2.setDescription("desc2"); - p2.setDescOverride(true); - p2.setName("P2"); - p2.setNameOverride(true); - p2.setStatementStatus(StatementStatus.RECOMMENDED); - r.addProperty(p2); - - final Property p21 = new Property(new RetrieveEntity(new EntityID(1))); - p21.setRole("Property"); - p21.setDatatype("TEXT"); - p21.setDescription("desc21"); - p21.setDescOverride(true); - p21.setName("P21"); - p21.setNameOverride(true); - p21.setStatementStatus(StatementStatus.RECOMMENDED); - p2.addProperty(p21); - - final Property p22 = new Property(new RetrieveEntity(new EntityID(2))); - p22.setRole("Property"); - p22.setDatatype("TEXT"); - p22.setDescription("desc22"); - p22.setDescOverride(true); - p22.setName("P22"); - p22.setNameOverride(true); - p22.setStatementStatus(StatementStatus.RECOMMENDED); - p2.addProperty(p22); - - final Property p3 = new Property(new RetrieveEntity(new EntityID(3))); - p3.setRole("Property"); - p3.setDatatype("TEXT"); - p3.setDescription("desc3"); - p3.setDescOverride(true); - p3.setName("P3"); - p3.setNameOverride(true); - p3.setStatementStatus(StatementStatus.RECOMMENDED); - r.addProperty(p3); - - final Property p31 = new Property(new RetrieveEntity(new EntityID(1))); - p31.setRole("Property"); - p31.setDatatype("TEXT"); - p31.setDescription("desc31"); - p31.setDescOverride(true); - p31.setName("P31"); - p31.setNameOverride(true); - p31.setStatementStatus(StatementStatus.RECOMMENDED); - p3.addProperty(p31); - - final Property p32 = new Property(new RetrieveEntity(new EntityID(2))); - p32.setRole("Property"); - p32.setDatatype("TEXT"); - p32.setDescription("desc32"); - p32.setDescOverride(true); - p32.setName("P32"); - p32.setNameOverride(true); - p32.setStatementStatus(StatementStatus.RECOMMENDED); - p3.addProperty(p32); - - final Property p321 = new Property(new RetrieveEntity(new EntityID(1))); - p321.setRole("Property"); - p321.setDatatype("TEXT"); - p321.setDescription("desc321"); - p321.setDescOverride(true); - p321.setName("P321"); - p321.setNameOverride(true); - p321.setStatementStatus(StatementStatus.RECOMMENDED); - p32.addProperty(p321); - - final Property p322 = new Property(new RetrieveEntity(new EntityID(2))); - p322.setRole("Property"); - p322.setDatatype("TEXT"); - p322.setDescription("desc322"); - p322.setDescOverride(true); - p322.setName("P322"); - p322.setNameOverride(true); - p322.setStatementStatus(StatementStatus.RECOMMENDED); - p32.addProperty(p322); - - final Property p323 = new Property(new RetrieveEntity(new EntityID(3))); - p323.setRole("Property"); - p323.setDatatype("TEXT"); - p323.setDescription("desc323"); - p323.setDescOverride(true); - p323.setName("P323"); - p323.setNameOverride(true); - p323.setStatementStatus(StatementStatus.RECOMMENDED); - p32.addProperty(p323); - - final Property p33 = new Property(new RetrieveEntity(new EntityID(3))); - p33.setRole("Property"); - p33.setDatatype("TEXT"); - p33.setDescription("desc33"); - p33.setDescOverride(true); - p33.setName("P33"); - p33.setNameOverride(true); - p33.setStatementStatus(StatementStatus.RECOMMENDED); - p3.addProperty(p33); - - List<Property> stage1Inserts = new LinkedList<>(); - List<Property> stage2Inserts = new LinkedList<>(); - int c = DatabaseUtils.deriveStage1Inserts(stage1Inserts, r); - DatabaseUtils.deriveStage2Inserts(stage2Inserts, stage1Inserts, registerReplacementIds(c), r); - assertEquals(7, stage1Inserts.size()); - assertEquals(8, stage2Inserts.size()); - } -} -- GitLab From ce345f40b927ac1bcd1d159ec4383d768a678bbe Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Wed, 16 Aug 2023 00:59:18 +0200 Subject: [PATCH 5/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../java/org/caosdb/server/CaosDBServer.java | 1 - .../server/accessControl/ACMPermissions.java | 3 - .../caosdb/server/database/Replacement.java | 41 -------------- .../implementation/MySQL}/DatabaseUtils.java | 55 +++++-------------- .../MySQL/MySQLGetAllNames.java | 1 - .../MySQL/MySQLInsertEntityProperties.java | 1 - .../MySQL/MySQLInsertSparseEntity.java | 1 - .../MySQL/MySQLRetrieveAll.java | 1 - .../MySQL/MySQLRetrieveDatatypes.java | 5 +- .../MySQL/MySQLRetrieveParents.java | 5 +- .../MySQL/MySQLRetrievePasswordValidator.java | 2 +- .../MySQL/MySQLRetrieveProperties.java | 20 ++----- .../MySQL/MySQLRetrieveSparseEntity.java | 1 - .../MySQL/MySQLRetrieveUser.java | 2 +- .../MySQL/MySQLRetrieveVersionHistory.java | 1 - .../MySQL/MySQLUpdateSparseEntity.java | 1 - .../implementation/MySQL/Replacement.java | 53 ++++++++++++++++++ .../interfaces/RetrieveDatatypesImpl.java | 4 +- .../interfaces/RetrieveParentsImpl.java | 4 +- .../transaction/RetrieveDatatypes.java | 4 +- .../backend/transaction/RetrieveParents.java | 27 ++++++--- .../transaction/RetrieveProperties.java | 2 +- .../transaction/RetrieveSparseEntity.java | 7 ++- .../server/database/proto/FlatProperty.java | 13 ----- .../server/database/proto/ProtoProperty.java | 6 -- .../caosdb/server/query/Backreference.java | 2 +- .../org/caosdb/server/query/Conjunction.java | 2 +- .../org/caosdb/server/query/Disjunction.java | 2 +- .../org/caosdb/server/query/Negation.java | 2 +- .../java/org/caosdb/server/query/POV.java | 2 +- .../java/org/caosdb/server/query/Query.java | 2 +- .../org/caosdb/server/query/SubProperty.java | 2 +- .../server/utils/ResultSetIterator.java | 2 +- .../implementation/MySQL}/InsertTest.java | 6 +- 34 files changed, 119 insertions(+), 164 deletions(-) delete mode 100644 src/main/java/org/caosdb/server/database/Replacement.java rename src/main/java/org/caosdb/server/database/{ => backend/implementation/MySQL}/DatabaseUtils.java (87%) create mode 100644 src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java rename src/test/java/org/caosdb/server/database/{ => backend/implementation/MySQL}/InsertTest.java (98%) diff --git a/src/main/java/org/caosdb/server/CaosDBServer.java b/src/main/java/org/caosdb/server/CaosDBServer.java index 05fb9485..deca9aae 100644 --- a/src/main/java/org/caosdb/server/CaosDBServer.java +++ b/src/main/java/org/caosdb/server/CaosDBServer.java @@ -223,7 +223,6 @@ public class CaosDBServer extends Application { public boolean notifyObserver(String e, Observable sender) { if (e.equals(ServerProperties.KEY_TIMEZONE)) { - String[] availableIDs = TimeZone.getAvailableIDs(); TimeZone newZoneId = TimeZone.getTimeZone(getServerProperty(ServerProperties.KEY_TIMEZONE)); TimeZone.setDefault(newZoneId); diff --git a/src/main/java/org/caosdb/server/accessControl/ACMPermissions.java b/src/main/java/org/caosdb/server/accessControl/ACMPermissions.java index 854fc07f..07503692 100644 --- a/src/main/java/org/caosdb/server/accessControl/ACMPermissions.java +++ b/src/main/java/org/caosdb/server/accessControl/ACMPermissions.java @@ -26,12 +26,9 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ACMPermissions implements Comparable<ACMPermissions> { - private static Logger LOGGER = LoggerFactory.getLogger(ACMPermissions.class); public static final String USER_PARAMETER = "?USER?"; public static final String REALM_PARAMETER = "?REALM?"; public static final String ROLE_PARAMETER = "?ROLE?"; diff --git a/src/main/java/org/caosdb/server/database/Replacement.java b/src/main/java/org/caosdb/server/database/Replacement.java deleted file mode 100644 index 8606d51b..00000000 --- a/src/main/java/org/caosdb/server/database/Replacement.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.caosdb.server.database; - -import org.caosdb.server.datatype.ReferenceValue; -import org.caosdb.server.entity.EntityID; -import org.caosdb.server.entity.RetrieveEntity; -import org.caosdb.server.entity.StatementStatus; -import org.caosdb.server.entity.wrapper.Property; - -public class Replacement extends Property { - - public Property replacement; - public EntityID replacementId; - - @Override - public EntityID getId() { - return replacementId; - } - - public void setReplacementId(EntityID id) { - replacementId.link(id); - } - - public Replacement(Property p) { - super(p); - replacementId = new EntityID(); - replacement = new Property(new RetrieveEntity()); - - replacement.setDomain(p.getDomainEntity()); - // replacement.setDatatypeOverride(p.isDatatypeOverride()); - // replacement.setDatatype(p.getDatatype()); - // replacement.setNameOverride(p.isNameOverride()); - // replacement.setName(p.getName()); - // replacement.setDescOverride(p.isDescOverride()); - // replacement.setDescription(p.getDescription()); - - replacement.setId(replacementId); - replacement.setStatementStatus(StatementStatus.REPLACEMENT); - replacement.setValue(new ReferenceValue(p.getId())); - replacement.setPIdx(0); - } -} diff --git a/src/main/java/org/caosdb/server/database/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java similarity index 87% rename from src/main/java/org/caosdb/server/database/DatabaseUtils.java rename to src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java index 6d72d965..0347028b 100644 --- a/src/main/java/org/caosdb/server/database/DatabaseUtils.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the CaosDB Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,10 +18,8 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ -package org.caosdb.server.database; +package org.caosdb.server.database.backend.implementation.MySQL; import com.google.common.base.Objects; import java.sql.ResultSet; @@ -46,7 +45,6 @@ import org.caosdb.server.entity.EntityInterface; import org.caosdb.server.entity.Message; import org.caosdb.server.entity.RetrieveEntity; import org.caosdb.server.entity.StatementStatus; -import org.caosdb.server.entity.wrapper.Parent; import org.caosdb.server.entity.wrapper.Property; public class DatabaseUtils { @@ -154,13 +152,7 @@ public class DatabaseUtils { } } - public static void parseFromSparseEntities(final EntityInterface e, final SparseEntity spe) { - if (spe != null) { - e.parseSparseEntity(spe); - } - } - - public static void parseOverrides(final List<FlatProperty> properties, final ResultSet rs) + public static void parseOverrides(final List<ProtoProperty> properties, final ResultSet rs) throws SQLException { while (rs.next()) { final int property_id = rs.getInt("property_id"); @@ -187,15 +179,15 @@ public class DatabaseUtils { } } - public static List<FlatProperty> parsePropertyResultset(final ResultSet rs) throws SQLException { - final List<FlatProperty> ret = new LinkedList<>(); + public static List<ProtoProperty> parsePropertyResultset(final ResultSet rs) throws SQLException { + final List<ProtoProperty> ret = new LinkedList<>(); while (rs.next()) { - FlatProperty fp = new FlatProperty(); - fp.id = rs.getInt("PropertyID"); - fp.value = bytes2UTF8(rs.getBytes("PropertyValue")); - fp.status = bytes2UTF8(rs.getBytes("PropertyStatus")); - fp.idx = rs.getInt("PropertyIndex"); - ret.add(fp); + ProtoProperty pp = new ProtoProperty(); + pp.id = rs.getInt("PropertyID"); + pp.value = bytes2UTF8(rs.getBytes("PropertyValue")); + pp.status = bytes2UTF8(rs.getBytes("PropertyStatus")); + pp.idx = rs.getInt("PropertyIndex"); + ret.add(pp); } return ret; } @@ -239,9 +231,9 @@ public class DatabaseUtils { return ret; } - public static ArrayList<VerySparseEntity> parseParentResultSet(final ResultSet rs) + public static LinkedList<VerySparseEntity> parseParentResultSet(final ResultSet rs) throws SQLException { - final ArrayList<VerySparseEntity> ret = new ArrayList<VerySparseEntity>(); + final LinkedList<VerySparseEntity> ret = new LinkedList<>(); while (rs.next()) { final VerySparseEntity vsp = new VerySparseEntity(); vsp.id = rs.getInt("ParentID"); @@ -254,25 +246,6 @@ public class DatabaseUtils { return ret; } - public static <K extends EntityInterface> K parseEntityFromVerySparseEntity( - final K entity, final VerySparseEntity vse) { - entity.setId(new EntityID(vse.id)); - entity.setName(vse.name); - entity.setRole(vse.role); - entity.setDescription(vse.description); - return entity; - } - - public static void parseParentsFromVerySparseEntity( - final EntityInterface entity, final List<VerySparseEntity> pars) { - for (final VerySparseEntity vsp : pars) { - final Parent p = new Parent(new RetrieveEntity(new EntityID(vsp.id))); - p.setName(vsp.name); - p.setDescription(vsp.description); - entity.addParent(p); - } - } - public static ArrayList<Property> parseFromProtoProperties( EntityInterface entity, List<ProtoProperty> protos) { final ArrayList<Property> ret = new ArrayList<Property>(); diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetAllNames.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetAllNames.java index 09cae688..474048f1 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetAllNames.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetAllNames.java @@ -5,7 +5,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.GetAllNamesImpl; import org.caosdb.server.database.exceptions.TransactionException; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java index 5c9ca6f9..f3977068 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java @@ -33,7 +33,6 @@ import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.InsertEntityPropertiesImpl; import org.caosdb.server.database.exceptions.IntegrityException; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java index 1b945acf..27227926 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java @@ -26,7 +26,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLIntegrityConstraintViolationException; import java.sql.Types; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.InsertSparseEntityImpl; import org.caosdb.server.database.exceptions.IntegrityException; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java index f847bf63..9a2ea816 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java @@ -27,7 +27,6 @@ import java.sql.SQLException; import java.util.LinkedList; import java.util.List; import org.apache.shiro.SecurityUtils; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.RetrieveAllImpl; import org.caosdb.server.database.exceptions.TransactionException; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveDatatypes.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveDatatypes.java index e085f051..68524941 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveDatatypes.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveDatatypes.java @@ -25,8 +25,7 @@ package org.caosdb.server.database.backend.implementation.MySQL; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import org.caosdb.server.database.DatabaseUtils; +import java.util.List; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.RetrieveDatatypesImpl; import org.caosdb.server.database.exceptions.TransactionException; @@ -53,7 +52,7 @@ public class MySQLRetrieveDatatypes extends MySQLTransaction implements Retrieve + "FROM entities AS e WHERE e.role='DATATYPE'"; @Override - public ArrayList<VerySparseEntity> execute() throws TransactionException { + public List<VerySparseEntity> execute() throws TransactionException { try { final PreparedStatement stmt = prepareStatement(STMT_GET_DATATYPE); diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java index 64ce7e90..1e2a6621 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java @@ -26,8 +26,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; -import java.util.ArrayList; -import org.caosdb.server.database.DatabaseUtils; +import java.util.LinkedList; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.RetrieveParentsImpl; import org.caosdb.server.database.exceptions.TransactionException; @@ -43,7 +42,7 @@ public class MySQLRetrieveParents extends MySQLTransaction implements RetrievePa private static final String stmtStr = "call retrieveEntityParents(?, ?)"; @Override - public ArrayList<VerySparseEntity> execute(final EntityID id, final String version) + public LinkedList<VerySparseEntity> execute(final EntityID id, final String version) throws TransactionException { try { ResultSet rs = null; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrievePasswordValidator.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrievePasswordValidator.java index 1ff7dd7a..9fd7e0a8 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrievePasswordValidator.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrievePasswordValidator.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.database.backend.implementation.MySQL; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.security.NoSuchAlgorithmException; import java.sql.PreparedStatement; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java index c8843f9c..100df4ce 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java @@ -28,11 +28,9 @@ import java.sql.SQLException; import java.sql.Types; import java.util.LinkedList; import java.util.List; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.RetrievePropertiesImpl; import org.caosdb.server.database.exceptions.TransactionException; -import org.caosdb.server.database.proto.FlatProperty; import org.caosdb.server.database.proto.ProtoProperty; import org.caosdb.server.entity.EntityID; @@ -92,32 +90,22 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev final long t2 = System.currentTimeMillis(); addMeasurement(this.getClass().getSimpleName() + ".retrieveFlatPropertiesStage1", t2 - t1); - final List<FlatProperty> props = DatabaseUtils.parsePropertyResultset(rs); + final List<ProtoProperty> properties = DatabaseUtils.parsePropertyResultset(rs); final PreparedStatement retrieveOverrides = prepareStatement(stmtStr2); - retrieveOverrides(domain, entity, version, retrieveOverrides, props); + retrieveOverrides(domain, entity, version, retrieveOverrides, properties); - return handleCollectionValues(props); + return properties; } } - @Deprecated - public List<ProtoProperty> handleCollectionValues(List<FlatProperty> props) throws SQLException { - - List<ProtoProperty> result = new LinkedList<>(); - for (FlatProperty fp : props) { - result.add(new ProtoProperty(fp)); - } - return result; - } - private void retrieveOverrides( final Integer domain, final Integer entity, final String version, final PreparedStatement retrieveOverrides, - final List<FlatProperty> props) + final List<ProtoProperty> props) throws SQLException { ResultSet rs = null; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java index ca3bd078..48cd84b3 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java @@ -26,7 +26,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.RetrieveSparseEntityImpl; import org.caosdb.server.database.exceptions.TransactionException; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java index bde1878d..40f036f1 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.database.backend.implementation.MySQL; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.sql.PreparedStatement; import java.sql.ResultSet; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java index 585be49a..6c4c2629 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java @@ -27,7 +27,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.LinkedList; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.RetrieveVersionHistoryImpl; import org.caosdb.server.database.exceptions.TransactionException; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java index 1c803925..b2d0fb9e 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java @@ -27,7 +27,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; import java.sql.Types; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.UpdateSparseEntityImpl; import org.caosdb.server.database.exceptions.IntegrityException; diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java new file mode 100644 index 00000000..66bf99c4 --- /dev/null +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java @@ -0,0 +1,53 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.caosdb.server.database.backend.implementation.MySQL; + +import org.caosdb.server.datatype.ReferenceValue; +import org.caosdb.server.entity.EntityID; +import org.caosdb.server.entity.RetrieveEntity; +import org.caosdb.server.entity.StatementStatus; +import org.caosdb.server.entity.wrapper.Property; + +public class Replacement extends Property { + + public Property replacement; + public EntityID replacementId; + + @Override + public EntityID getId() { + return replacementId; + } + + public void setReplacementId(EntityID id) { + replacementId.link(id); + } + + public Replacement(Property p) { + super(p); + replacementId = new EntityID(); + replacement = new Property(new RetrieveEntity()); + + replacement.setDomain(p.getDomainEntity()); + replacement.setId(replacementId); + replacement.setStatementStatus(StatementStatus.REPLACEMENT); + replacement.setValue(new ReferenceValue(p.getId())); + replacement.setPIdx(0); + } +} diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveDatatypesImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveDatatypesImpl.java index 91c68dc5..0886ff43 100644 --- a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveDatatypesImpl.java +++ b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveDatatypesImpl.java @@ -22,11 +22,11 @@ */ package org.caosdb.server.database.backend.interfaces; -import java.util.ArrayList; +import java.util.List; import org.caosdb.server.database.exceptions.TransactionException; import org.caosdb.server.database.proto.VerySparseEntity; public interface RetrieveDatatypesImpl extends BackendTransactionImpl { - public abstract ArrayList<VerySparseEntity> execute() throws TransactionException; + public abstract List<VerySparseEntity> execute() throws TransactionException; } diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java index 9bfddba1..9f7eba82 100644 --- a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java +++ b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java @@ -22,13 +22,13 @@ */ package org.caosdb.server.database.backend.interfaces; -import java.util.ArrayList; +import java.util.LinkedList; import org.caosdb.server.database.exceptions.TransactionException; import org.caosdb.server.database.proto.VerySparseEntity; import org.caosdb.server.entity.EntityID; public interface RetrieveParentsImpl extends BackendTransactionImpl { - public ArrayList<VerySparseEntity> execute(EntityID id, String version) + public LinkedList<VerySparseEntity> execute(EntityID id, String version) throws TransactionException; } diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveDatatypes.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveDatatypes.java index b4a726da..1ca9f60e 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveDatatypes.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveDatatypes.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.database.backend.transaction; -import java.util.ArrayList; +import java.util.List; import org.caosdb.server.database.BackendTransaction; import org.caosdb.server.database.backend.interfaces.RetrieveDatatypesImpl; import org.caosdb.server.database.exceptions.TransactionException; @@ -35,7 +35,7 @@ import org.caosdb.server.entity.container.Container; public class RetrieveDatatypes extends BackendTransaction { - private ArrayList<VerySparseEntity> list; + private List<VerySparseEntity> list; @Override public void execute() throws TransactionException { diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveParents.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveParents.java index b551430a..262ee271 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveParents.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveParents.java @@ -24,15 +24,18 @@ */ package org.caosdb.server.database.backend.transaction; -import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import org.apache.commons.jcs.access.behavior.ICacheAccess; import org.caosdb.server.caching.Cache; import org.caosdb.server.database.CacheableBackendTransaction; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.backend.interfaces.RetrieveParentsImpl; import org.caosdb.server.database.exceptions.TransactionException; import org.caosdb.server.database.proto.VerySparseEntity; +import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.EntityInterface; +import org.caosdb.server.entity.RetrieveEntity; +import org.caosdb.server.entity.wrapper.Parent; // TODO Problem with the caching. // When an old entity version has a parent which is deleted, the name is @@ -47,9 +50,9 @@ import org.caosdb.server.entity.EntityInterface; // See also a failing test in caosdb-pyinttest: // tests/test_version.py::test_bug_cached_parent_name_in_old_version public class RetrieveParents - extends CacheableBackendTransaction<String, ArrayList<VerySparseEntity>> { + extends CacheableBackendTransaction<String, LinkedList<VerySparseEntity>> { - private static final ICacheAccess<String, ArrayList<VerySparseEntity>> cache = + private static final ICacheAccess<String, LinkedList<VerySparseEntity>> cache = Cache.getCache("BACKEND_EntityParents"); /** @@ -71,16 +74,26 @@ public class RetrieveParents } @Override - public ArrayList<VerySparseEntity> executeNoCache() throws TransactionException { + public LinkedList<VerySparseEntity> executeNoCache() throws TransactionException { final RetrieveParentsImpl t = getImplementation(RetrieveParentsImpl.class); return t.execute(this.entity.getId(), this.entity.getVersion().getId()); } @Override - protected void process(final ArrayList<VerySparseEntity> t) throws TransactionException { + protected void process(final LinkedList<VerySparseEntity> t) throws TransactionException { this.entity.getParents().clear(); - DatabaseUtils.parseParentsFromVerySparseEntity(this.entity, t); + parseParentsFromVerySparseEntity(this.entity, t); + } + + private void parseParentsFromVerySparseEntity( + final EntityInterface entity, final List<VerySparseEntity> pars) { + for (final VerySparseEntity vsp : pars) { + final Parent p = new Parent(new RetrieveEntity(new EntityID(vsp.id))); + p.setName(vsp.name); + p.setDescription(vsp.description); + entity.addParent(p); + } } @Override diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java index caa4b6cf..f9c11303 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveProperties.java @@ -29,7 +29,7 @@ import java.util.List; import org.apache.commons.jcs.access.behavior.ICacheAccess; import org.caosdb.server.caching.Cache; import org.caosdb.server.database.CacheableBackendTransaction; -import org.caosdb.server.database.DatabaseUtils; +import org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils; import org.caosdb.server.database.backend.interfaces.RetrievePropertiesImpl; import org.caosdb.server.database.exceptions.TransactionException; import org.caosdb.server.database.proto.ProtoProperty; diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java index aabd490b..f1ba8354 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java @@ -27,7 +27,6 @@ package org.caosdb.server.database.backend.transaction; import org.apache.commons.jcs.access.behavior.ICacheAccess; import org.caosdb.server.caching.Cache; import org.caosdb.server.database.CacheableBackendTransaction; -import org.caosdb.server.database.DatabaseUtils; import org.caosdb.server.database.backend.interfaces.RetrieveSparseEntityImpl; import org.caosdb.server.database.exceptions.TransactionException; import org.caosdb.server.database.proto.SparseEntity; @@ -81,8 +80,10 @@ public class RetrieveSparseEntity extends CacheableBackendTransaction<String, Sp @Override protected void process(final SparseEntity t) throws TransactionException { - DatabaseUtils.parseFromSparseEntities(this.entity, t); - this.entity.setEntityStatus(EntityStatus.VALID); + if (t != null) { + this.entity.parseSparseEntity(t); + this.entity.setEntityStatus(EntityStatus.VALID); + } } @Override diff --git a/src/main/java/org/caosdb/server/database/proto/FlatProperty.java b/src/main/java/org/caosdb/server/database/proto/FlatProperty.java index b4f0f62a..b92d3def 100644 --- a/src/main/java/org/caosdb/server/database/proto/FlatProperty.java +++ b/src/main/java/org/caosdb/server/database/proto/FlatProperty.java @@ -26,19 +26,6 @@ import java.io.Serializable; public class FlatProperty implements Serializable { - public FlatProperty() {} - - public FlatProperty(FlatProperty fp) { - id = fp.id; - value = fp.value; - status = fp.status; - idx = fp.idx; - name = fp.name; - desc = fp.desc; - type = fp.type; - collection = fp.collection; - } - private static final long serialVersionUID = 6039288034435124195L; public Integer id = null; public String value = null; diff --git a/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java b/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java index c6cdbd54..7a11cd4d 100644 --- a/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java +++ b/src/main/java/org/caosdb/server/database/proto/ProtoProperty.java @@ -28,12 +28,6 @@ import java.util.List; public class ProtoProperty extends FlatProperty implements Serializable { private static final long serialVersionUID = 7731301985162924975L; - public ProtoProperty(FlatProperty fp) { - super(fp); - } - - public ProtoProperty() {} - public List<ProtoProperty> subProperties = null; public List<Object> collValues = null; } diff --git a/src/main/java/org/caosdb/server/query/Backreference.java b/src/main/java/org/caosdb/server/query/Backreference.java index 7d551fd4..b801ffaf 100644 --- a/src/main/java/org/caosdb/server/query/Backreference.java +++ b/src/main/java/org/caosdb/server/query/Backreference.java @@ -23,7 +23,7 @@ package org.caosdb.server.query; import static java.sql.Types.VARCHAR; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.sql.CallableStatement; import java.sql.Connection; diff --git a/src/main/java/org/caosdb/server/query/Conjunction.java b/src/main/java/org/caosdb/server/query/Conjunction.java index 03b33124..59dfd57b 100644 --- a/src/main/java/org/caosdb/server/query/Conjunction.java +++ b/src/main/java/org/caosdb/server/query/Conjunction.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.query; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.sql.CallableStatement; import java.sql.Connection; diff --git a/src/main/java/org/caosdb/server/query/Disjunction.java b/src/main/java/org/caosdb/server/query/Disjunction.java index edd2e6da..925ef859 100644 --- a/src/main/java/org/caosdb/server/query/Disjunction.java +++ b/src/main/java/org/caosdb/server/query/Disjunction.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.query; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.sql.CallableStatement; import java.sql.Connection; diff --git a/src/main/java/org/caosdb/server/query/Negation.java b/src/main/java/org/caosdb/server/query/Negation.java index cfdfd05e..431124df 100644 --- a/src/main/java/org/caosdb/server/query/Negation.java +++ b/src/main/java/org/caosdb/server/query/Negation.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.query; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.sql.CallableStatement; import java.sql.Connection; diff --git a/src/main/java/org/caosdb/server/query/POV.java b/src/main/java/org/caosdb/server/query/POV.java index 0de160cd..ebc35a16 100644 --- a/src/main/java/org/caosdb/server/query/POV.java +++ b/src/main/java/org/caosdb/server/query/POV.java @@ -25,7 +25,7 @@ package org.caosdb.server.query; import static java.sql.Types.DOUBLE; import static java.sql.Types.INTEGER; import static java.sql.Types.VARCHAR; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import de.timmfitschen.easyunits.parser.ParserException; import java.sql.CallableStatement; diff --git a/src/main/java/org/caosdb/server/query/Query.java b/src/main/java/org/caosdb/server/query/Query.java index c4a45863..abaca436 100644 --- a/src/main/java/org/caosdb/server/query/Query.java +++ b/src/main/java/org/caosdb/server/query/Query.java @@ -21,7 +21,7 @@ */ package org.caosdb.server.query; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.io.Serializable; import java.sql.CallableStatement; diff --git a/src/main/java/org/caosdb/server/query/SubProperty.java b/src/main/java/org/caosdb/server/query/SubProperty.java index 8ff167ea..d5ce9234 100644 --- a/src/main/java/org/caosdb/server/query/SubProperty.java +++ b/src/main/java/org/caosdb/server/query/SubProperty.java @@ -23,7 +23,7 @@ package org.caosdb.server.query; import static java.sql.Types.VARCHAR; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.sql.CallableStatement; import java.sql.Connection; diff --git a/src/main/java/org/caosdb/server/utils/ResultSetIterator.java b/src/main/java/org/caosdb/server/utils/ResultSetIterator.java index 0912d278..71429f1a 100644 --- a/src/main/java/org/caosdb/server/utils/ResultSetIterator.java +++ b/src/main/java/org/caosdb/server/utils/ResultSetIterator.java @@ -1,6 +1,6 @@ package org.caosdb.server.utils; -import static org.caosdb.server.database.DatabaseUtils.bytes2UTF8; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/src/test/java/org/caosdb/server/database/InsertTest.java b/src/test/java/org/caosdb/server/database/backend/implementation/MySQL/InsertTest.java similarity index 98% rename from src/test/java/org/caosdb/server/database/InsertTest.java rename to src/test/java/org/caosdb/server/database/backend/implementation/MySQL/InsertTest.java index 0484e623..03bd185c 100644 --- a/src/test/java/org/caosdb/server/database/InsertTest.java +++ b/src/test/java/org/caosdb/server/database/backend/implementation/MySQL/InsertTest.java @@ -20,10 +20,10 @@ * * ** end header */ -package org.caosdb.server.database; +package org.caosdb.server.database.backend.implementation.MySQL; -import static org.caosdb.server.database.DatabaseUtils.deriveStage1Inserts; -import static org.caosdb.server.database.DatabaseUtils.deriveStage2Inserts; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.deriveStage1Inserts; +import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.deriveStage2Inserts; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -- GitLab From ac56b7746d683050512ef58288e526f92c056397 Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Wed, 16 Aug 2023 01:10:28 +0200 Subject: [PATCH 6/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../backend/implementation/MySQL/DatabaseUtils.java | 3 ++- .../backend/implementation/MySQL/Replacement.java | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java index 0347028b..20d43389 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java @@ -33,6 +33,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Collectors; import org.caosdb.server.database.proto.FlatProperty; import org.caosdb.server.database.proto.ProtoProperty; import org.caosdb.server.database.proto.SparseEntity; @@ -334,7 +335,7 @@ public class DatabaseUtils { pp.collValues .stream() .map((x) -> (Object) ((Entry<Integer, String>) x).getValue()) - .toList(); + .collect(Collectors.toList()); } result.add(pp); } diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java index 66bf99c4..fa2fb7cb 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java @@ -28,24 +28,22 @@ import org.caosdb.server.entity.wrapper.Property; public class Replacement extends Property { public Property replacement; - public EntityID replacementId; @Override public EntityID getId() { - return replacementId; + return replacement.getId(); } public void setReplacementId(EntityID id) { - replacementId.link(id); + replacement.getId().link(id); } public Replacement(Property p) { super(p); - replacementId = new EntityID(); replacement = new Property(new RetrieveEntity()); replacement.setDomain(p.getDomainEntity()); - replacement.setId(replacementId); + replacement.setId(new EntityID()); replacement.setStatementStatus(StatementStatus.REPLACEMENT); replacement.setValue(new ReferenceValue(p.getId())); replacement.setPIdx(0); -- GitLab From cc12cb76926f2e01eb1c64aa51aa22aedd701d7e Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Wed, 16 Aug 2023 11:11:32 +0200 Subject: [PATCH 7/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../implementation/MySQL/DatabaseUtils.java | 9 ++++-- .../MySQL/MySQLInsertEntityProperties.java | 14 +++++---- .../implementation/MySQL/Replacement.java | 16 ++++++++-- .../java/org/caosdb/server/entity/Entity.java | 6 ++-- .../caosdb/server/entity/EntityInterface.java | 4 +-- .../caosdb/server/entity/StatementStatus.java | 8 +---- .../entity/StatementStatusInterface.java | 29 +++++++++++++++++++ .../server/entity/wrapper/EntityWrapper.java | 8 ++--- .../server/grpc/CaosDBToGrpcConverters.java | 5 ++-- 9 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/caosdb/server/entity/StatementStatusInterface.java diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java index 20d43389..c123b467 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java @@ -297,7 +297,7 @@ public class DatabaseUtils { LinkedList<ProtoProperty> result = new LinkedList<>(); Map<String, ProtoProperty> replacements = new HashMap<>(); for (ProtoProperty pp : properties) { - if (pp.status.equals(StatementStatus.REPLACEMENT.toString())) { + if (pp.status.equals(ReplacementStatus.REPLACEMENT.name())) { replacements.put(pp.value, null); } } @@ -322,7 +322,7 @@ public class DatabaseUtils { } } for (ProtoProperty pp : properties) { - if (pp.status.equals(StatementStatus.REPLACEMENT.toString())) { + if (pp.status.equals(ReplacementStatus.REPLACEMENT.name())) { replace(pp, replacements.get(pp.value), isHead); } if (pp.collValues != null) { @@ -342,6 +342,11 @@ public class DatabaseUtils { return result; } + /* + * This replace function is used during the retrieval of properties. It is + * basically the opposite of the Replacement class. It copies the information + * from the replacement object back into the Property. + */ private static void replace(ProtoProperty pp, ProtoProperty replacement, boolean isHead) { if (replacement == null) { if (isHead) { diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java index f3977068..b57719f5 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java @@ -46,7 +46,6 @@ import org.caosdb.server.datatype.ReferenceValue; import org.caosdb.server.datatype.SingleValue; import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.EntityInterface; -import org.caosdb.server.entity.StatementStatus; import org.caosdb.server.entity.wrapper.Property; public class MySQLInsertEntityProperties extends MySQLTransaction @@ -116,10 +115,10 @@ public class MySQLInsertEntityProperties extends MySQLTransaction } private void insertStages( - final List<Property> stage1Inserts, final EntityID domain, final EntityID entity) + final List<Property> inserts, final EntityID domain, final EntityID entity) throws TransactionException { - for (final Property property : stage1Inserts) { + for (final Property property : inserts) { // prepare flat property final FlatProperty fp = new FlatProperty(); @@ -129,10 +128,15 @@ public class MySQLInsertEntityProperties extends MySQLTransaction fp.idx = property.getPIdx(); fp.status = property.getStatementStatus().name(); - if (property.getStatementStatus() == StatementStatus.REPLACEMENT) { - table = Table.reference_data; + if (property.getStatementStatus() == ReplacementStatus.REPLACEMENT) { + // special treatment: swap value and id. This is part of the back-end specification for the + // representation of replacement. + + // value should be the fp.value = fp.id.toString(); + fp.id = ((ReferenceValue) property.getValue()).getId().toInteger(); + table = Table.reference_data; } else { if (property.hasUnit()) { diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java index fa2fb7cb..61e431ba 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java @@ -22,9 +22,21 @@ package org.caosdb.server.database.backend.implementation.MySQL; import org.caosdb.server.datatype.ReferenceValue; import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.RetrieveEntity; -import org.caosdb.server.entity.StatementStatus; +import org.caosdb.server.entity.StatementStatusInterface; import org.caosdb.server.entity.wrapper.Property; +enum ReplacementStatus implements StatementStatusInterface { + REPLACEMENT +} +/** + * A wrapper of {@link Property} objects used by the back-end implementation for the MySQL/MariaDB + * back-end. + * + * <p>This class helps to transform deeply nested properties, properties with overridden data types, + * and much more to the flat (row-like) representation used internally by the back-end (which is an + * implementation detail of the back-end or part of the non-public API of the back-end from that + * point of view). + */ public class Replacement extends Property { public Property replacement; @@ -44,7 +56,7 @@ public class Replacement extends Property { replacement.setDomain(p.getDomainEntity()); replacement.setId(new EntityID()); - replacement.setStatementStatus(StatementStatus.REPLACEMENT); + replacement.setStatementStatus(ReplacementStatus.REPLACEMENT); replacement.setValue(new ReferenceValue(p.getId())); replacement.setPIdx(0); } diff --git a/src/main/java/org/caosdb/server/entity/Entity.java b/src/main/java/org/caosdb/server/entity/Entity.java index 843449ce..614397c5 100644 --- a/src/main/java/org/caosdb/server/entity/Entity.java +++ b/src/main/java/org/caosdb/server/entity/Entity.java @@ -421,7 +421,7 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa } } - private StatementStatus statementStatus = null; + private StatementStatusInterface statementStatus = null; /** * statementStatus getter. @@ -429,7 +429,7 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa * @return */ @Override - public StatementStatus getStatementStatus() { + public StatementStatusInterface getStatementStatus() { return this.statementStatus; } @@ -439,7 +439,7 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa * @return */ @Override - public void setStatementStatus(final StatementStatus statementStatus) { + public void setStatementStatus(final StatementStatusInterface statementStatus) { this.statementStatus = statementStatus; } diff --git a/src/main/java/org/caosdb/server/entity/EntityInterface.java b/src/main/java/org/caosdb/server/entity/EntityInterface.java index d97970de..ba77b5c4 100644 --- a/src/main/java/org/caosdb/server/entity/EntityInterface.java +++ b/src/main/java/org/caosdb/server/entity/EntityInterface.java @@ -57,9 +57,9 @@ public interface EntityInterface public abstract boolean hasId(); - public abstract StatementStatus getStatementStatus(); + public abstract StatementStatusInterface getStatementStatus(); - public abstract void setStatementStatus(StatementStatus statementStatus); + public abstract void setStatementStatus(StatementStatusInterface statementStatus); public abstract void setStatementStatus(String statementStatus); diff --git a/src/main/java/org/caosdb/server/entity/StatementStatus.java b/src/main/java/org/caosdb/server/entity/StatementStatus.java index 0a797175..83d0c57e 100644 --- a/src/main/java/org/caosdb/server/entity/StatementStatus.java +++ b/src/main/java/org/caosdb/server/entity/StatementStatus.java @@ -33,17 +33,11 @@ package org.caosdb.server.entity; * href="../../../../../specification/RecordType.html">the documentation of RecordTypes</a> for more * information. * - * <p>2. Marking an entity as a ``REPLACEMENT`` which is needed for flat representation of deeply - * nested properties. This constant is only used for internal processes and has no meaning in the - * API. That is also the reason why this enum is not called "Importance". Apart from that, in most - * cases its meaning is identical to the importance of an entity. - * * @author Timm Fitschen (t.fitschen@indiscale.com) */ -public enum StatementStatus { +public enum StatementStatus implements StatementStatusInterface { OBLIGATORY, RECOMMENDED, SUGGESTED, FIX, - REPLACEMENT } diff --git a/src/main/java/org/caosdb/server/entity/StatementStatusInterface.java b/src/main/java/org/caosdb/server/entity/StatementStatusInterface.java new file mode 100644 index 00000000..d1596afd --- /dev/null +++ b/src/main/java/org/caosdb/server/entity/StatementStatusInterface.java @@ -0,0 +1,29 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.caosdb.server.entity; + +/** + * Interface for the StatementStatus. This may be used by back-end implementations to use back-end + * specific implementations (e.g. + * org.caosdb.server.database.backend.implementation.MySQL.ReplacementStatus). + */ +public interface StatementStatusInterface { + public String name(); +} diff --git a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java index f23408df..b294a17e 100644 --- a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java +++ b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java @@ -38,7 +38,7 @@ import org.caosdb.server.entity.EntityInterface; import org.caosdb.server.entity.FileProperties; import org.caosdb.server.entity.Message; import org.caosdb.server.entity.Role; -import org.caosdb.server.entity.StatementStatus; +import org.caosdb.server.entity.StatementStatusInterface; import org.caosdb.server.entity.Version; import org.caosdb.server.entity.container.ParentContainer; import org.caosdb.server.entity.container.PropertyContainer; @@ -112,13 +112,13 @@ public abstract class EntityWrapper implements EntityInterface { } @Override - public StatementStatus getStatementStatus() { + public StatementStatusInterface getStatementStatus() { return this.entity.getStatementStatus(); } @Override - public void setStatementStatus(final StatementStatus statementStatus) { - this.entity.setStatementStatus(statementStatus); + public void setStatementStatus(final StatementStatusInterface replacement) { + this.entity.setStatementStatus(replacement); } @Override diff --git a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java index 1b70a729..8ab8b057 100644 --- a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java +++ b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java @@ -75,6 +75,7 @@ import org.caosdb.server.entity.MagicTypes; import org.caosdb.server.entity.Message; import org.caosdb.server.entity.Role; import org.caosdb.server.entity.StatementStatus; +import org.caosdb.server.entity.StatementStatusInterface; import org.caosdb.server.entity.container.ParentContainer; import org.caosdb.server.entity.container.RetrieveContainer; import org.caosdb.server.entity.wrapper.Property; @@ -359,8 +360,8 @@ public class CaosDBToGrpcConverters { return convertScalarValue(v.getWrapped()).build(); } - private Importance convert(final StatementStatus statementStatus) { - switch (statementStatus) { + private Importance convert(final StatementStatusInterface statementStatus) { + switch ((StatementStatus) statementStatus) { case FIX: return Importance.IMPORTANCE_FIX; case OBLIGATORY: -- GitLab From 5d5ea96303228064c854194d1ce60b7c4ab298d7 Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Wed, 16 Aug 2023 11:24:17 +0200 Subject: [PATCH 8/9] WIP: MAINT: refactor retrieve properties (move backend-logic to backend) --- .../MySQL/MySQLInsertEntityProperties.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java index b57719f5..becb56a2 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java @@ -130,11 +130,16 @@ public class MySQLInsertEntityProperties extends MySQLTransaction if (property.getStatementStatus() == ReplacementStatus.REPLACEMENT) { // special treatment: swap value and id. This is part of the back-end specification for the - // representation of replacement. + // representation of replacement. The reason why this happens here (and + // not in the replacement class for instance) is that the original + // Property must not be changed for this. Otherwise we would have to + // change it back after the insertion or internally used replacement ids + // would be leaked. - // value should be the + // value is to be the id of the property which is being replaced fp.value = fp.id.toString(); + // id is to be the replacement id (an internally used/private id) fp.id = ((ReferenceValue) property.getValue()).getId().toInteger(); table = Table.reference_data; } else { -- GitLab From f9f540e17d9eaee27d542f90e5eb10b94a7ce6be Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Thu, 17 Aug 2023 17:48:21 +0000 Subject: [PATCH 9/9] REVIEW: apply suggested changes --- .../database/backend/implementation/MySQL/DatabaseUtils.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java index c123b467..f7d364ae 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java @@ -93,10 +93,6 @@ public class DatabaseUtils { && !p.isDatatypeOverride() && (!p.hasProperties() || hasUniquePropertyId(p, e)) && !(p.getDatatype() instanceof AbstractCollectionDatatype)) { - // this property can be represented without any replacement. We explicitly - // setReplacement(null) because there is a corner case (related to the inheritance of - // properties) where there is a replacement present which belongs to the parent entity, see - // https://gitlab.com/caosdb/caosdb-server/-/issues/216. stage1Inserts.add(p); } else { Replacement r = new Replacement(p); -- GitLab