diff --git a/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOClient.java b/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOClient.java index 907513f45068b1d98da3c76701ab2ee8f660934e..34bda7de340cc554eeeb9c634bdb639f54183b34 100644 --- a/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOClient.java +++ b/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOClient.java @@ -1,6 +1,7 @@ package lc.esp.eo; import com.mongodb.client.MongoClients; +import lc.esp.eo.sdk.schema.Model; /** * This class implements access ot the back-end storage for the ESP/EO system. @@ -9,8 +10,8 @@ import com.mongodb.client.MongoClients; * @since mk20 (TOKYO PROTOCOL) */ public class EOClient implements AutoCloseable { - public EOTransaction getTransaction(String lparName) { - return new EOTransaction(MongoClients.create("mongodb://mgr0.gdn.leigh-co.com"), lparName); + public EOTransaction getTransaction(String lparName, Model model) { + return new EOTransaction(MongoClients.create("mongodb://mgr0.gdn.leigh-co.com"), lparName, model); } @Override diff --git a/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOTransaction.java b/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOTransaction.java index 0b3588d932ee045b0060dabaebc2ebe0a1b21822..497123677e2ded436ca035f2d63480294cc2b171 100644 --- a/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOTransaction.java +++ b/java/lc-esp-eo-engine/src/main/java/lc/esp/eo/EOTransaction.java @@ -14,6 +14,8 @@ import com.mongodb.client.gridfs.model.GridFSUploadOptions; import com.mongodb.client.result.DeleteResult; import lc.esp.eo.sdk.EO; import lc.esp.eo.sdk.EOId; +import lc.esp.eo.sdk.schema.AssociationSchema; +import lc.esp.eo.sdk.schema.Model; import lc.mecha.log.MechaLogger; import lc.mecha.log.MechaLoggerFactory; import org.bson.Document; @@ -56,8 +58,11 @@ public class EOTransaction implements AutoCloseable { private HashSet pendingFiles; - public EOTransaction(MongoClient client, String databaseName) { + private final Model model; + + public EOTransaction(MongoClient client, String databaseName, Model model) { this.client = client; + this.model = model; this.session = this.client.startSession(); this.session.startTransaction(TransactionOptions.builder().writeConcern(WriteConcern.ACKNOWLEDGED).build()); this.databaseName = "eo_" + databaseName; @@ -152,20 +157,34 @@ public class EOTransaction implements AutoCloseable { } /** - * Delete the given association. If this is bi-directional association, calling this method only deletes one side - * of the association. The method returns true if an association was deleted, or false + * Delete the given association. The method returns true if an association was deleted, or false * if none was found. */ - public boolean assocDelete(EOId srcObjectId, EOId dstObjectId, String type) { + public long assocDelete(EOId srcObjectId, EOId dstObjectId, String type) { MongoCollection col = db.getCollection(COLLECTION_ASSOC); + long cnt = 0; + // deleteOne() under the premise that they are unique DeleteResult result = col.deleteOne(session, new Document() .append(KEY_TYPE, type) .append(KEY_SRCOBJ, ((EOBsonId) srcObjectId).getObjectId()) .append(KEY_DSTOBJ, ((EOBsonId) dstObjectId).getObjectId())); - return result.getDeletedCount() == 1; + cnt += result.getDeletedCount(); + + if (model != null) { + AssociationSchema as = model.getAssocSchema(type); + if (as != null) { + result = col.deleteOne(session, new Document() + .append(KEY_TYPE, as.getInverseType()) + .append(KEY_SRCOBJ, ((EOBsonId) dstObjectId).getObjectId()) + .append(KEY_DSTOBJ, ((EOBsonId) srcObjectId).getObjectId())); + cnt += result.getDeletedCount(); + } + } + + return cnt; } /** diff --git a/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/EOTransactionTest.java b/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/EOTransactionTest.java index f2ec21df14790e4fc3a3bf4080404880e8736fe8..fec5b186a7c04a784e57b84077529cbf480aac0d 100644 --- a/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/EOTransactionTest.java +++ b/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/EOTransactionTest.java @@ -24,7 +24,7 @@ public class EOTransactionTest { @Test public void testObjCreate() { try (EOClient client = new EOClient()) { - try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID())) { + try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID(), null)) { try { EOId id = txn.objCreate("test", Map.of("first", "Alex")); EO obj = txn.objRead(id); @@ -42,7 +42,7 @@ public class EOTransactionTest { @Test public void testFileCreate() throws IOException { try (EOClient client = new EOClient()) { - try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID())) { + try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID(), null)) { try { // We basically just assume this will always be around in the build environment try (FileInputStream fis = new FileInputStream("build.gradle")) { @@ -65,7 +65,7 @@ public class EOTransactionTest { @Test public void testAssocCreate() throws IOException, InterruptedException { try (EOClient client = new EOClient()) { - try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID())) { + try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID(), null)) { try { txn.initialize(); EOId alexId = txn.objCreate("person", Map.of("first", "Alex")); @@ -83,7 +83,7 @@ public class EOTransactionTest { @Test public void testObjDelete() { try (EOClient client = new EOClient()) { - try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID())) { + try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID(), null)) { try { EOId id = txn.objCreate("test", Map.of("first", "Alex")); assert (id != null); diff --git a/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/ScenarioTest.java b/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/ScenarioTest.java index 22306ca227f3b5eb06f67938917e49150f30c8b4..7ea8317ec7bbdb1ffd4f676a09f26eed2d645ffc 100644 --- a/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/ScenarioTest.java +++ b/java/lc-esp-eo-engine/src/test/java/lc/esp/eo/ScenarioTest.java @@ -2,6 +2,9 @@ package lc.esp.eo; import lc.esp.eo.sdk.EO; import lc.esp.eo.sdk.EOId; +import lc.esp.eo.sdk.schema.AssociationSchema; +import lc.esp.eo.sdk.schema.Model; +import lc.esp.eo.sdk.schema.ObjectSchema; import lc.mecha.log.MechaLogger; import lc.mecha.log.MechaLoggerFactory; import lc.mecha.util.VelocityWatch; @@ -32,8 +35,15 @@ public class ScenarioTest { public void testScenario() { int followers = 10; + // Build our model + Model model = new Model(); + ObjectSchema person = new ObjectSchema(TYPE_PERSON); + model.putSchema(person); + model.putAssociation(new AssociationSchema("likes", "liked_by")); + model.putAssociation(new AssociationSchema("liked_by", "likes")); + try (EOClient client = new EOClient()) { - try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID())) { + try (EOTransaction txn = client.getTransaction("junit_" + UUID.randomUUID(), model)) { try { txn.initialize(); EOId popularPerson = txn.objCreate("test", Map.of("first", "Alex")); @@ -56,8 +66,9 @@ public class ScenarioTest { logger.info("Person is liked: {}", cnt); assertEquals(followers, cnt); - boolean found = txn.assocDelete(popularPerson, followerId, "liked_by"); - assert (found); + // Should be 2, since we have the inverse. + long deleted = txn.assocDelete(popularPerson, followerId, "liked_by"); + assertEquals(2, deleted); cnt = txn.assocCount(popularPerson, "liked_by"); logger.info("Person is liked: {}", cnt); diff --git a/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/AssociationSchema.java b/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/AssociationSchema.java index 637e174b6d6d335818cb51524b8b099497c95ed4..364b0e6f72e9c6ba84a1367d5b986e7e35e4f7aa 100644 --- a/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/AssociationSchema.java +++ b/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/AssociationSchema.java @@ -4,8 +4,14 @@ package lc.esp.eo.sdk.schema; * @since mk20 (TOKYO PROTOCOL) */ public class AssociationSchema extends FieldBearer{ + private final String inverseType; - public AssociationSchema(String type, boolean isRequired) { - super(type, isRequired); + public AssociationSchema(String type, String inverseType) { + super(type, false); + this.inverseType = inverseType; + } + + public String getInverseType() { + return inverseType; } } diff --git a/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/EOSchema.java b/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/EOSchema.java deleted file mode 100644 index 266f9ece1341fb9872839493c601b3344ac578a8..0000000000000000000000000000000000000000 --- a/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/EOSchema.java +++ /dev/null @@ -1,31 +0,0 @@ -package lc.esp.eo.sdk.schema; - -import java.util.HashMap; - -/** - * This class implements a descriptive schema for an {@link lc.esp.eo.sdk.EO}. - * - * @author Alex Leigh - * @since mk20 (TOKYO PROTOCOL) - */ - -public class EOSchema extends FieldBearer { - private HashMap associations = new HashMap<>(); - private final String type; - public EOSchema(String type) { - super(type, false); - this.type = type; - } - - public String getType() { - return type; - } - - public void putAssociation(AssociationSchema schema) { - associations.put(schema.getType(), schema); - } - - public AssociationSchema getAssociation(String name) { - return associations.get(name); - } -} diff --git a/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/Model.java b/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/Model.java index 65483b9ef5e1d1b559447784b50d80228ffa2f76..5093eed9b9aead23c15155e2fec20ac1adcc9f67 100644 --- a/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/Model.java +++ b/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/Model.java @@ -9,13 +9,22 @@ import java.util.HashMap; * @since mk20 (TOKYO PROTOCOL) */ public class Model { - private final HashMap schemas = new HashMap<>(); + private final HashMap objSchemas = new HashMap<>(); + private final HashMap assocSchemas = new HashMap<>(); - public void putSchema(EOSchema EOSchema) { - schemas.put(EOSchema.getType(), EOSchema); + public void putSchema(ObjectSchema objSchema) { + objSchemas.put(objSchema.getType(), objSchema); } - public EOSchema getSchema(String type) { - return schemas.get(type); + public ObjectSchema getObjectSchema(String type) { + return objSchemas.get(type); + } + + public void putAssociation(AssociationSchema assocSchema) { + assocSchemas.put(assocSchema.getType(), assocSchema); + } + + public AssociationSchema getAssocSchema(String type) { + return assocSchemas.get(type); } } diff --git a/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/ObjectSchema.java b/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/ObjectSchema.java new file mode 100644 index 0000000000000000000000000000000000000000..f30d8fff335c9ab3ede206c5d197360555a4b269 --- /dev/null +++ b/java/lc-esp-eo-sdk/src/main/java/lc/esp/eo/sdk/schema/ObjectSchema.java @@ -0,0 +1,21 @@ +package lc.esp.eo.sdk.schema; + +/** + * This class implements a descriptive schema for an {@link lc.esp.eo.sdk.EO}. + * + * @author Alex Leigh + * @since mk20 (TOKYO PROTOCOL) + */ + +public class ObjectSchema extends FieldBearer { + private final String type; + + public ObjectSchema(String type) { + super(type, false); + this.type = type; + } + + public String getType() { + return type; + } +}