From b530cb629b6270c782d9513fd41a75307481dde7 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Tue, 22 Apr 2025 11:30:58 +0200 Subject: [PATCH] [FEAT] add capability to use @ManyToManyLocal that is an implementation compatible with NoSql MAny-ToMany link This feature manage to update the 2 side of the local stored of the data --- .../archidata/annotation/ManyToManyLocal.java | 27 + .../archidata/dataAccess/DBAccessSQL.java | 6 +- .../addOnSQL/AddOnManyToManyLocal.java | 464 +++++++++++++++ .../dataAccess/TestManyToManyLocalOID.java | 563 ++++++++++++++++++ .../model/TypeManyToManyLocalOIDRemote.java | 17 + .../model/TypeManyToManyLocalOIDRoot.java | 18 + .../TypeManyToManyLocalOIDRootExpand.java | 20 + 7 files changed, 1113 insertions(+), 2 deletions(-) create mode 100644 src/main/org/atriasoft/archidata/annotation/ManyToManyLocal.java create mode 100644 src/main/org/atriasoft/archidata/dataAccess/addOnSQL/AddOnManyToManyLocal.java create mode 100644 src/test/test/atriasoft/archidata/dataAccess/TestManyToManyLocalOID.java create mode 100644 src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRemote.java create mode 100644 src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRoot.java create mode 100644 src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRootExpand.java diff --git a/src/main/org/atriasoft/archidata/annotation/ManyToManyLocal.java b/src/main/org/atriasoft/archidata/annotation/ManyToManyLocal.java new file mode 100644 index 0000000..c1c0eef --- /dev/null +++ b/src/main/org/atriasoft/archidata/annotation/ManyToManyLocal.java @@ -0,0 +1,27 @@ +package org.atriasoft.archidata.annotation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * In NoSql entity the relation is stored in the 2 part of the entity, + * then it is needed to define the field that store the relation data value in the remote elements. + */ +@Retention(RUNTIME) +@Target({ FIELD, METHOD }) +public @interface ManyToManyLocal { + /** + * The entity class that is the target of the + * association. + */ + Class targetEntity(); + + /** + * The field that owns the revert value. empty if the relationship is unidirectional. + */ + String remoteField() default ""; +} diff --git a/src/main/org/atriasoft/archidata/dataAccess/DBAccessSQL.java b/src/main/org/atriasoft/archidata/dataAccess/DBAccessSQL.java index 5da27d3..9a05b17 100644 --- a/src/main/org/atriasoft/archidata/dataAccess/DBAccessSQL.java +++ b/src/main/org/atriasoft/archidata/dataAccess/DBAccessSQL.java @@ -29,6 +29,7 @@ import org.atriasoft.archidata.annotation.CreationTimestamp; import org.atriasoft.archidata.annotation.UpdateTimestamp; import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson; import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnManyToMany; +import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnManyToManyLocal; import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnManyToOne; import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnOneToMany; import org.atriasoft.archidata.dataAccess.addOnSQL.DataAccessAddOn; @@ -70,7 +71,9 @@ public class DBAccessSQL extends DBAccess { new AddOnManyToMany(), // new AddOnManyToOne(), // new AddOnOneToMany(), // - new AddOnDataJson()); + new AddOnDataJson(), // + new AddOnManyToManyLocal()); + private final DbIoSql db; public DBAccessSQL(final DbIoSql db) throws IOException { @@ -1239,7 +1242,6 @@ public class DBAccessSQL extends DBAccess { query.append(" "); final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); condition.whereAppendQuery(query, tableName, null, deletedFieldName); - // If the first field is not set, then nothing to update n the main base: if (!firstField) { LOGGER.debug("generate update query: '{}'", query.toString()); diff --git a/src/main/org/atriasoft/archidata/dataAccess/addOnSQL/AddOnManyToManyLocal.java b/src/main/org/atriasoft/archidata/dataAccess/addOnSQL/AddOnManyToManyLocal.java new file mode 100644 index 0000000..4dbe58d --- /dev/null +++ b/src/main/org/atriasoft/archidata/dataAccess/addOnSQL/AddOnManyToManyLocal.java @@ -0,0 +1,464 @@ +package org.atriasoft.archidata.dataAccess.addOnSQL; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import org.atriasoft.archidata.annotation.AnnotationTools; +import org.atriasoft.archidata.annotation.AnnotationTools.FieldName; +import org.atriasoft.archidata.annotation.ManyToManyLocal; +import org.atriasoft.archidata.dataAccess.CountInOut; +import org.atriasoft.archidata.dataAccess.DBAccess; +import org.atriasoft.archidata.dataAccess.DBAccessSQL; +import org.atriasoft.archidata.dataAccess.DataFactory; +import org.atriasoft.archidata.dataAccess.LazyGetter; +import org.atriasoft.archidata.dataAccess.QueryInList; +import org.atriasoft.archidata.dataAccess.QueryOptions; +import org.atriasoft.archidata.dataAccess.addOnSQL.model.TableCoversGeneric; +import org.atriasoft.archidata.dataAccess.options.Condition; +import org.atriasoft.archidata.dataAccess.options.OptionRenameColumn; +import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType; +import org.atriasoft.archidata.dataAccess.options.OverrideTableName; +import org.atriasoft.archidata.exception.SystemException; +import org.atriasoft.archidata.tools.ContextGenericTools; +import org.bson.types.ObjectId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import jakarta.validation.constraints.NotNull; + +public class AddOnManyToManyLocal implements DataAccessAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToManyLocal.class); + static final String SEPARATOR_LONG = "-"; + static final String SEPARATOR_UUID = "_"; + + @Override + public Class getAnnotationClass() { + return ManyToManyLocal.class; + } + + @Override + public boolean isCompatibleField(final Field field) { + if (field.getType() != List.class) { + return false; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass == Long.class || objectClass == UUID.class || objectClass == ObjectId.class) { + return true; + } + final ManyToManyLocal decorators = field.getDeclaredAnnotation(ManyToManyLocal.class); + if (decorators == null) { + return false; + } + if (decorators.targetEntity() == objectClass) { + return true; + } + return false; + } + + @Override + public void insertData( + final DBAccessSQL ioDb, + final PreparedStatement ps, + final Field field, + final Object rootObject, + final CountInOut iii) + throws SQLException, IllegalArgumentException, IllegalAccessException, JsonProcessingException { + final Object data = field.get(rootObject); + if (data == null) { + ps.setNull(iii.value, Types.VARCHAR); + } + final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper(); + final String dataString = objectMapper.writeValueAsString(data); + ps.setString(iii.value, dataString); + iii.inc(); + } + + @Override + public boolean isUpdateAsync(final Field field) { + return true; + } + + @Override + public void asyncUpdate( + final DBAccessSQL ioDb, + final Object previousData, + final String tableName, + final Object primaryKeyValue, + final Field field, + final Object insertedData, + final List actions, + final QueryOptions options) throws Exception { + final Object previousDataValue = field.get(previousData); + Collection previousDataCollection = new ArrayList<>(); + if (previousDataValue instanceof final Collection tmpCollection) { + previousDataCollection = tmpCollection; + } + final Object insertedDataValue = insertedData; + Collection insertedDataCollection = new ArrayList<>(); + if (insertedDataValue instanceof final Collection tmpCollection) { + insertedDataCollection = tmpCollection; + } + // add new Values + for (final Object value : insertedDataCollection) { + if (previousDataCollection.contains(value)) { + continue; + } + actions.add(() -> { + addLinkRemote(ioDb, field, primaryKeyValue, value); + }); + } + // remove old values: + for (final Object value : previousDataCollection) { + if (insertedDataCollection.contains(value)) { + continue; + } + actions.add(() -> { + removeLinkRemote(ioDb, field, primaryKeyValue, value); + }); + } + + } + + /** Some action must be done asynchronously for update or remove element + * @param field + * @return */ + @Override + public boolean isInsertAsync(final Field field) throws Exception { + return true; + } + + /** When insert is mark async, this function permit to create or update the data + * @param tableName Name of the Table. + * @param localId Local ID of the current table + * @param field Field that is updated. + * @param data Data that might be inserted. + * @param actions Asynchronous action to do after main request. */ + @Override + public void asyncInsert( + final DBAccessSQL ioDb, + final String tableName, + final Object primaryKeyValue, + final Field field, + final Object data, + final List actions, + final QueryOptions options) throws Exception { + final Object insertedData = data; + if (insertedData == null) { + return; + } + if (insertedData instanceof final Collection insertedDataCollection) { + for (final Object value : insertedDataCollection) { + actions.add(() -> { + addLinkRemote(ioDb, field, primaryKeyValue, value); + }); + } + } + } + + @Override + public boolean isPreviousDataNeeded(final Field field) { + return true; + } + + @Override + public boolean canInsert(final Field field) { + return isCompatibleField(field); + } + + @Override + public boolean canRetrieve(final Field field) { + return isCompatibleField(field); + } + + @Override + public void generateQuery( + @NotNull final String tableName, + @NotNull final String primaryKey, + @NotNull final Field field, + @NotNull final StringBuilder querySelect, + @NotNull final StringBuilder query, + @NotNull final String name, + @NotNull final CountInOut count, + final QueryOptions options) throws Exception { + querySelect.append(" "); + querySelect.append(tableName); + querySelect.append("."); + querySelect.append(name); + count.inc(); + } + + @Override + public void fillFromQuery( + final DBAccessSQL ioDb, + final ResultSet rs, + final Field field, + final Object data, + final CountInOut count, + final QueryOptions options, + final List lazyCall) throws Exception { + if (field.getType() != List.class) { + throw new SystemException("@ManyToManyLocal must contain a List"); + } + final String jsonData = rs.getString(count.value); + count.inc(); + if (rs.wasNull()) { + return; + } + final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper(); + final ParameterizedType listType = (ParameterizedType) field.getGenericType(); + final Class objectClass = (Class) listType.getActualTypeArguments()[0]; + if (objectClass == Long.class) { + final List dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {}); + field.set(data, dataParsed); + return; + } + if (objectClass == String.class) { + final List dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {}); + field.set(data, dataParsed); + return; + } + if (objectClass == UUID.class) + + { + final List dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {}); + field.set(data, dataParsed); + return; + } + if (objectClass == ObjectId.class) { + final List dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {}); + field.set(data, dataParsed); + return; + } + final ManyToManyLocal decorators = field.getDeclaredAnnotation(ManyToManyLocal.class); + if (decorators == null) { + return; + } + if (objectClass == decorators.targetEntity()) { + final Class foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType(); + if (foreignKeyType == Long.class) { + final List idList = objectMapper.readValue(jsonData, new TypeReference>() {}); + if (idList != null && idList.size() > 0) { + final FieldName idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass), + options); + // In the lazy mode, the request is done in asynchronous mode, they will be done after... + final LazyGetter lambda = () -> { + // TODO: update to have get with abstract types .... + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), + new Condition(new QueryInList<>(idField.inTable(), idList))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } else if (foreignKeyType == UUID.class) { + final List idList = objectMapper.readValue(jsonData, new TypeReference>() {}); + if (idList != null && idList.size() > 0) { + final FieldName idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass), + options); + // In the lazy mode, the request is done in asynchronous mode, they will be done after... + final LazyGetter lambda = () -> { + final List childs = new ArrayList<>(idList); + // TODO: update to have get with abstract types .... + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), + new Condition(new QueryInList<>(idField.inTable(), childs))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } else if (foreignKeyType == ObjectId.class) { + final List idList = objectMapper.readValue(jsonData, new TypeReference>() {}); + if (idList != null && idList.size() > 0) { + final FieldName idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass), + options); + // In the lazy mode, the request is done in asynchronous mode, they will be done after... + final LazyGetter lambda = () -> { + final List childs = new ArrayList<>(idList); + // TODO: update to have get with abstract types .... + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), + new Condition(new QueryInList<>(idField.inTable(), childs))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } + } + } + + @Override + public void createTables( + final String tableName, + final Field primaryField, + final Field field, + final StringBuilder mainTableBuilder, + final List preActionList, + final List postActionList, + final boolean createIfNotExist, + final boolean createDrop, + final int fieldId, + final QueryOptions options) throws Exception { + // store data as json to response like a no-sql + DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList, + postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class, options); + } + + private static void addLinkLocal( + final DBAccess ioDb, + final Class clazz, + final String clazzPrimaryKeyName, + final Object clazzPrimaryKeyValue, + final String fieldNameToUpdate, + final Object valueToAdd) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + final QueryOptions options = new QueryOptions(new OverrideTableName(tableName), + new OptionSpecifyType("idOfTheObject", clazzPrimaryKeyValue.getClass()), + new OptionSpecifyType("filedNameOfTheObject", valueToAdd.getClass(), true)); + options.add(new OptionRenameColumn("idOfTheObject", clazzPrimaryKeyName)); + options.add(new OptionRenameColumn("filedNameOfTheObject", fieldNameToUpdate)); + final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray()); + if (data.filedNameOfTheObject == null) { + data.filedNameOfTheObject = new ArrayList<>(); + } + for (final Object elem : data.filedNameOfTheObject) { + if (elem.equals(valueToAdd)) { + return; + } + } + data.filedNameOfTheObject.add(valueToAdd); + ioDb.update(data, data.idOfTheObject, List.of("filedNameOfTheObject"), options.getAllArray()); + } + + public static void addLink( + final DBAccess ioDb, + final Class clazz, + final Object clazzPrimaryKeyValue, + final String fieldNameToUpdate, + final Object valueToAdd) throws Exception { + final Field localField = AnnotationTools.getFieldNamed(clazz, fieldNameToUpdate); + { + //get local field to find the remote field name: + final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(clazz); + final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null); + final FieldName localFieldName = AnnotationTools.getFieldName(localField, null); + addLinkLocal(ioDb, clazz, primaryKeyColomnName.inTable(), clazzPrimaryKeyValue, localFieldName.inTable(), + valueToAdd); + } + addLinkRemote(ioDb, localField, clazzPrimaryKeyValue, valueToAdd); + } + + private static void addLinkRemote( + final DBAccess ioDb, + final Field localField, + final Object localPrimaryKeyValue, + final Object remotePrimaryKeyValue) throws Exception { + final ManyToManyLocal manyLocal = AnnotationTools.get(localField, ManyToManyLocal.class); + // Update the remote elements: + if (manyLocal == null || manyLocal.targetEntity() == null || manyLocal.remoteField() == null + || manyLocal.remoteField().isEmpty()) { + return; + } + { + //get local field to find the remote field name: + final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(manyLocal.targetEntity()); + final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null); + final Field remoteField = AnnotationTools.getFieldNamed(manyLocal.targetEntity(), manyLocal.remoteField()); + final FieldName localFieldName = AnnotationTools.getFieldName(remoteField, null); + addLinkLocal(ioDb, manyLocal.targetEntity(), primaryKeyColomnName.inTable(), remotePrimaryKeyValue, + localFieldName.inTable(), localPrimaryKeyValue); + } + } + + private static void removeLinkLocal( + final DBAccess ioDb, + final Class clazz, + final String clazzPrimaryKeyName, + final Object clazzPrimaryKeyValue, + final String fieldNameToUpdate, + final Object valueToRemove) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + final QueryOptions options = new QueryOptions(new OverrideTableName(tableName), + new OptionSpecifyType("idOfTheObject", clazzPrimaryKeyValue.getClass()), + new OptionSpecifyType("filedNameOfTheObject", valueToRemove.getClass(), true)); + options.add(new OptionRenameColumn("idOfTheObject", clazzPrimaryKeyName)); + options.add(new OptionRenameColumn("filedNameOfTheObject", fieldNameToUpdate)); + final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray()); + if (data.filedNameOfTheObject == null) { + return; + } + final List newList = new ArrayList<>(); + for (final Object elem : data.filedNameOfTheObject) { + if (elem.equals(valueToRemove)) { + continue; + } + newList.add(elem); + } + data.filedNameOfTheObject = newList; + if (data.filedNameOfTheObject.isEmpty()) { + data.filedNameOfTheObject = null; + } + ioDb.update(data, data.idOfTheObject, List.of("filedNameOfTheObject"), options.getAllArray()); + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final Object clazzPrimaryKeyValue, + final String fieldNameToUpdate, + final Object valueToRemove) throws Exception { + + final Field localField = AnnotationTools.getFieldNamed(clazz, fieldNameToUpdate); + { + //get local field to find the remote field name: + final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(clazz); + final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null); + final FieldName localFieldName = AnnotationTools.getFieldName(localField, null); + removeLinkLocal(ioDb, clazz, primaryKeyColomnName.inTable(), clazzPrimaryKeyValue, localFieldName.inTable(), + valueToRemove); + } + removeLinkRemote(ioDb, localField, clazzPrimaryKeyValue, valueToRemove); + } + + private static void removeLinkRemote( + final DBAccess ioDb, + final Field localField, + final Object localPrimaryKeyValue, + final Object remotePrimaryKeyValue) throws Exception { + final ManyToManyLocal manyLocal = AnnotationTools.get(localField, ManyToManyLocal.class); + // Update the remote elements: + if (manyLocal == null || manyLocal.targetEntity() == null || manyLocal.remoteField() == null + || manyLocal.remoteField().isEmpty()) { + return; + } + { + //get local field to find the remote field name: + final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(manyLocal.targetEntity()); + final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null); + final Field remoteField = AnnotationTools.getFieldNamed(manyLocal.targetEntity(), manyLocal.remoteField()); + final FieldName localFieldName = AnnotationTools.getFieldName(remoteField, null); + removeLinkLocal(ioDb, manyLocal.targetEntity(), primaryKeyColomnName.inTable(), remotePrimaryKeyValue, + localFieldName.inTable(), localPrimaryKeyValue); + } + } + +} diff --git a/src/test/test/atriasoft/archidata/dataAccess/TestManyToManyLocalOID.java b/src/test/test/atriasoft/archidata/dataAccess/TestManyToManyLocalOID.java new file mode 100644 index 0000000..953c8e6 --- /dev/null +++ b/src/test/test/atriasoft/archidata/dataAccess/TestManyToManyLocalOID.java @@ -0,0 +1,563 @@ +package test.atriasoft.archidata.dataAccess; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.atriasoft.archidata.dataAccess.DBAccessSQL; +import org.atriasoft.archidata.dataAccess.DataFactory; +import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnManyToManyLocal; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import test.atriasoft.archidata.ConfigureDb; +import test.atriasoft.archidata.StepwiseExtension; +import test.atriasoft.archidata.dataAccess.model.TypeManyToManyLocalOIDRemote; +import test.atriasoft.archidata.dataAccess.model.TypeManyToManyLocalOIDRoot; +import test.atriasoft.archidata.dataAccess.model.TypeManyToManyLocalOIDRootExpand; + +@ExtendWith(StepwiseExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestManyToManyLocalOID { + final static private Logger LOGGER = LoggerFactory.getLogger(TestManyToManyLocalOID.class); + + @BeforeAll + public static void configureWebServer() throws Exception { + ConfigureDb.configure(); + } + + @AfterAll + public static void removeDataBase() throws IOException { + ConfigureDb.clear(); + } + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class SimpleTestInsertionAndRetrieve { + + @BeforeAll + public void testCreateTable() throws Exception { + final List sqlCommand2 = DataFactory.createTable(TypeManyToManyLocalOIDRoot.class); + final List sqlCommand = DataFactory.createTable(TypeManyToManyLocalOIDRemote.class); + sqlCommand.addAll(sqlCommand2); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } + } + } + + @AfterAll + public void dropTables() throws Exception { + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + daSQL.drop(TypeManyToManyLocalOIDRoot.class); + daSQL.drop(TypeManyToManyLocalOIDRemote.class); + } + } + + @Order(2) + @Test + public void testSimpleInsertAndRetieve() throws Exception { + final TypeManyToManyLocalOIDRoot test = new TypeManyToManyLocalOIDRoot(); + test.otherData = "root insert"; + final TypeManyToManyLocalOIDRoot insertedData = ConfigureDb.da.insert(test); + Assertions.assertNotNull(insertedData); + Assertions.assertNotNull(insertedData.oid); + Assertions.assertNull(insertedData.remote); + + // Try to retrieve all the data: + final TypeManyToManyLocalOIDRoot retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + insertedData.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(insertedData.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.otherData); + Assertions.assertEquals(insertedData.otherData, retrieve.otherData); + Assertions.assertNull(retrieve.remote); + + ConfigureDb.da.delete(TypeManyToManyLocalOIDRoot.class, insertedData.oid); + } + } + + // TODO: add and remove link from remote class + @Order(3) + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class AddLinkInsertInRoot { + TypeManyToManyLocalOIDRemote insertedRemote1; + TypeManyToManyLocalOIDRemote insertedRemote2; + TypeManyToManyLocalOIDRoot insertedData; + + @BeforeAll + public void testCreateTable() throws Exception { + final List sqlCommand2 = DataFactory.createTable(TypeManyToManyLocalOIDRoot.class); + final List sqlCommand = DataFactory.createTable(TypeManyToManyLocalOIDRemote.class); + sqlCommand.addAll(sqlCommand2); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } + } + } + + @AfterAll + public void dropTables() throws Exception { + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + daSQL.drop(TypeManyToManyLocalOIDRoot.class); + daSQL.drop(TypeManyToManyLocalOIDRemote.class); + } + } + + // --------------------------------------------------------------- + // -- Add remote: + // --------------------------------------------------------------- + @Order(1) + @Test + public void addRemotes() throws Exception { + + TypeManyToManyLocalOIDRemote remote = new TypeManyToManyLocalOIDRemote(); + for (int iii = 0; iii < 100; iii++) { + remote.data = "tmp" + iii; + this.insertedRemote1 = ConfigureDb.da.insert(remote); + ConfigureDb.da.delete(TypeManyToManyLocalOIDRemote.class, this.insertedRemote1.oid); + } + remote = new TypeManyToManyLocalOIDRemote(); + remote.data = "remote1"; + this.insertedRemote1 = ConfigureDb.da.insert(remote); + Assertions.assertEquals(this.insertedRemote1.data, remote.data); + + remote = new TypeManyToManyLocalOIDRemote(); + remote.data = "remote2"; + this.insertedRemote2 = ConfigureDb.da.insert(remote); + Assertions.assertEquals(this.insertedRemote2.data, remote.data); + } + + @Order(2) + @Test + public void insertDataWithoutRemote() throws Exception { + + final TypeManyToManyLocalOIDRoot test = new TypeManyToManyLocalOIDRoot(); + test.otherData = "root insert 55"; + this.insertedData = ConfigureDb.da.insert(test); + Assertions.assertNotNull(this.insertedData); + Assertions.assertNotNull(this.insertedData.oid); + Assertions.assertNull(this.insertedData.remote); + + // Try to retrieve all the data: + final TypeManyToManyLocalOIDRoot retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedData.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(this.insertedData.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.otherData); + Assertions.assertEquals(this.insertedData.otherData, retrieve.otherData); + Assertions.assertNull(retrieve.remote); + } + + @Order(3) + @Test + public void addLinksRemotes() throws Exception { + // Add remote elements + AddOnManyToManyLocal.addLink(ConfigureDb.da, // + TypeManyToManyLocalOIDRoot.class, // + this.insertedData.oid, // + "remote", this.insertedRemote1.oid); + AddOnManyToManyLocal.addLink(ConfigureDb.da, // + TypeManyToManyLocalOIDRoot.class, // + this.insertedData.oid, // + "remote", this.insertedRemote2.oid); + + final TypeManyToManyLocalOIDRoot retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedData.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(this.insertedData.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.otherData); + Assertions.assertEquals(this.insertedData.otherData, retrieve.otherData); + Assertions.assertNotNull(retrieve.remote); + Assertions.assertEquals(2, retrieve.remote.size()); + Assertions.assertEquals(retrieve.remote.get(0), this.insertedRemote1.oid); + Assertions.assertEquals(retrieve.remote.get(1), this.insertedRemote2.oid); + + // -- Verify remote is linked: + final TypeManyToManyLocalOIDRemote retrieveRemote = ConfigureDb.da.get(TypeManyToManyLocalOIDRemote.class, + this.insertedRemote1.oid); + + Assertions.assertNotNull(retrieveRemote); + Assertions.assertNotNull(retrieveRemote.oid); + Assertions.assertEquals(this.insertedRemote1.oid, retrieveRemote.oid); + Assertions.assertNotNull(retrieveRemote.data); + Assertions.assertEquals(this.insertedRemote1.data, retrieveRemote.data); + Assertions.assertNotNull(retrieveRemote.remoteToParent); + Assertions.assertEquals(1, retrieveRemote.remoteToParent.size()); + Assertions.assertEquals(this.insertedData.oid, retrieveRemote.remoteToParent.get(0)); + } + + @Order(3) + @Test + public void testExpand() throws Exception { + final TypeManyToManyLocalOIDRootExpand retrieveExpand = ConfigureDb.da + .get(TypeManyToManyLocalOIDRootExpand.class, this.insertedData.oid); + + Assertions.assertNotNull(retrieveExpand); + Assertions.assertNotNull(retrieveExpand.oid); + Assertions.assertEquals(this.insertedData.oid, retrieveExpand.oid); + Assertions.assertNotNull(retrieveExpand.otherData); + Assertions.assertEquals(this.insertedData.otherData, retrieveExpand.otherData); + Assertions.assertNotNull(retrieveExpand.remote); + Assertions.assertEquals(2, retrieveExpand.remote.size()); + Assertions.assertEquals(retrieveExpand.remote.get(0).oid, this.insertedRemote1.oid); + Assertions.assertEquals(retrieveExpand.remote.get(0).data, this.insertedRemote1.data); + Assertions.assertEquals(retrieveExpand.remote.get(1).oid, this.insertedRemote2.oid); + Assertions.assertEquals(retrieveExpand.remote.get(1).data, this.insertedRemote2.data); + } + + @Order(4) + @Test + public void removeLinksRemotes() throws Exception { + // Remove an element + AddOnManyToManyLocal.removeLink(ConfigureDb.da, TypeManyToManyLocalOIDRoot.class, // + this.insertedData.oid, // + "remote", this.insertedRemote1.oid); + + TypeManyToManyLocalOIDRoot retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedData.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(this.insertedData.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.otherData); + Assertions.assertEquals(this.insertedData.otherData, retrieve.otherData); + Assertions.assertNotNull(retrieve.remote); + Assertions.assertEquals(retrieve.remote.size(), 1); + Assertions.assertEquals(retrieve.remote.get(0), this.insertedRemote2.oid); + + // Remove the second element + AddOnManyToManyLocal.removeLink(ConfigureDb.da, TypeManyToManyLocalOIDRoot.class, // + retrieve.oid, // + "remote", this.insertedRemote2.oid); + + retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, this.insertedData.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(this.insertedData.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.otherData); + Assertions.assertEquals(this.insertedData.otherData, retrieve.otherData); + Assertions.assertNull(retrieve.remote); + + ConfigureDb.da.delete(TypeManyToManyLocalOIDRoot.class, this.insertedData.oid); + } + } + + @Order(4) + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class directInsertAndRemoveInRoot { + TypeManyToManyLocalOIDRemote insertedRemote1; + TypeManyToManyLocalOIDRemote insertedRemote2; + TypeManyToManyLocalOIDRoot insertedRoot1; + TypeManyToManyLocalOIDRoot insertedRoot2; + + @BeforeAll + public void testCreateTable() throws Exception { + final List sqlCommand2 = DataFactory.createTable(TypeManyToManyLocalOIDRoot.class); + final List sqlCommand = DataFactory.createTable(TypeManyToManyLocalOIDRemote.class); + sqlCommand.addAll(sqlCommand2); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } + } + } + + @AfterAll + public void dropTables() throws Exception { + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + daSQL.drop(TypeManyToManyLocalOIDRoot.class); + daSQL.drop(TypeManyToManyLocalOIDRemote.class); + } + } + + // --------------------------------------------------------------- + // -- Add remote: + // --------------------------------------------------------------- + @Order(1) + @Test + public void addRemotes() throws Exception { + + TypeManyToManyLocalOIDRemote remote = new TypeManyToManyLocalOIDRemote(); + for (int iii = 0; iii < 100; iii++) { + remote.data = "tmp" + iii; + this.insertedRemote1 = ConfigureDb.da.insert(remote); + ConfigureDb.da.delete(TypeManyToManyLocalOIDRemote.class, this.insertedRemote1.oid); + } + remote = new TypeManyToManyLocalOIDRemote(); + remote.data = "remote 1"; + this.insertedRemote1 = ConfigureDb.da.insert(remote); + Assertions.assertEquals(this.insertedRemote1.data, remote.data); + + remote = new TypeManyToManyLocalOIDRemote(); + remote.data = "remote 2"; + this.insertedRemote2 = ConfigureDb.da.insert(remote); + Assertions.assertEquals(this.insertedRemote2.data, remote.data); + + TypeManyToManyLocalOIDRoot root = new TypeManyToManyLocalOIDRoot(); + root.otherData = "root 1"; + this.insertedRoot1 = ConfigureDb.da.insert(root); + + root = new TypeManyToManyLocalOIDRoot(); + root.otherData = "root 2"; + this.insertedRoot2 = ConfigureDb.da.insert(root); + } + + @Order(3) + @Test + public void addLinksRemotes() throws Exception { + // Add remote elements + AddOnManyToManyLocal.addLink(ConfigureDb.da, TypeManyToManyLocalOIDRemote.class, // + this.insertedRemote2.oid, // + "remoteToParent", this.insertedRoot1.oid); + AddOnManyToManyLocal.addLink(ConfigureDb.da, TypeManyToManyLocalOIDRemote.class, // + this.insertedRemote2.oid, // + "remoteToParent", this.insertedRoot2.oid); + + final TypeManyToManyLocalOIDRemote retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRemote.class, + this.insertedRemote2.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(this.insertedRemote2.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.data); + Assertions.assertEquals(this.insertedRemote2.data, retrieve.data); + Assertions.assertNotNull(retrieve.remoteToParent); + Assertions.assertEquals(2, retrieve.remoteToParent.size()); + Assertions.assertEquals(this.insertedRoot1.oid, retrieve.remoteToParent.get(0)); + Assertions.assertEquals(this.insertedRoot2.oid, retrieve.remoteToParent.get(1)); + + final TypeManyToManyLocalOIDRoot retrieveExpand = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedRoot1.oid); + + Assertions.assertNotNull(retrieveExpand); + Assertions.assertNotNull(retrieveExpand.oid); + Assertions.assertEquals(this.insertedRoot1.oid, retrieveExpand.oid); + Assertions.assertNotNull(retrieveExpand.otherData); + Assertions.assertEquals(this.insertedRoot1.otherData, retrieveExpand.otherData); + Assertions.assertNotNull(retrieveExpand.remote); + Assertions.assertEquals(1, retrieveExpand.remote.size()); + Assertions.assertEquals(this.insertedRemote2.oid, retrieveExpand.remote.get(0)); + + // -- Verify remote is linked: + final TypeManyToManyLocalOIDRoot retrieveRemote = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedRoot2.oid); + + Assertions.assertNotNull(retrieveRemote); + Assertions.assertNotNull(retrieveRemote.oid); + Assertions.assertEquals(this.insertedRoot2.oid, retrieveRemote.oid); + Assertions.assertNotNull(retrieveRemote.otherData); + Assertions.assertEquals(this.insertedRoot2.otherData, retrieveRemote.otherData); + Assertions.assertNotNull(retrieveRemote.remote); + Assertions.assertEquals(1, retrieveRemote.remote.size()); + Assertions.assertEquals(this.insertedRemote2.oid, retrieveRemote.remote.get(0)); + } + + @Order(4) + @Test + public void removeLinksRemotes() throws Exception { + // Remove root elements + AddOnManyToManyLocal.removeLink(ConfigureDb.da, TypeManyToManyLocalOIDRemote.class, // + this.insertedRemote2.oid, // + "remoteToParent", this.insertedRoot2.oid); + + final TypeManyToManyLocalOIDRemote retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRemote.class, + this.insertedRemote2.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(this.insertedRemote2.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.data); + Assertions.assertEquals(this.insertedRemote2.data, retrieve.data); + Assertions.assertNotNull(retrieve.remoteToParent); + Assertions.assertEquals(1, retrieve.remoteToParent.size()); + Assertions.assertEquals(this.insertedRoot1.oid, retrieve.remoteToParent.get(0)); + + // -- Verify remote is linked: + final TypeManyToManyLocalOIDRoot retrieveExpand = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedRoot1.oid); + + Assertions.assertNotNull(retrieveExpand); + Assertions.assertNotNull(retrieveExpand.oid); + Assertions.assertEquals(this.insertedRoot1.oid, retrieveExpand.oid); + Assertions.assertNotNull(retrieveExpand.otherData); + Assertions.assertEquals(this.insertedRoot1.otherData, retrieveExpand.otherData); + Assertions.assertNotNull(retrieveExpand.remote); + Assertions.assertEquals(1, retrieveExpand.remote.size()); + Assertions.assertEquals(this.insertedRemote2.oid, retrieveExpand.remote.get(0)); + + // -- Verify remote is un-linked: + final TypeManyToManyLocalOIDRoot retrieveRemote = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedRoot2.oid); + + Assertions.assertNotNull(retrieveRemote); + Assertions.assertNotNull(retrieveRemote.oid); + Assertions.assertEquals(this.insertedRoot2.oid, retrieveRemote.oid); + Assertions.assertNotNull(retrieveRemote.otherData); + Assertions.assertEquals(this.insertedRoot2.otherData, retrieveRemote.otherData); + Assertions.assertNull(retrieveRemote.remote); + + } + + @Order(5) + @Test + public void removeSecondLinksRemotes() throws Exception { + // Remove root elements + AddOnManyToManyLocal.removeLink(ConfigureDb.da, TypeManyToManyLocalOIDRemote.class, // + this.insertedRemote2.oid, // + "remoteToParent", this.insertedRoot1.oid); + + final TypeManyToManyLocalOIDRemote retrieve = ConfigureDb.da.get(TypeManyToManyLocalOIDRemote.class, + this.insertedRemote2.oid); + + Assertions.assertNotNull(retrieve); + Assertions.assertNotNull(retrieve.oid); + Assertions.assertEquals(this.insertedRemote2.oid, retrieve.oid); + Assertions.assertNotNull(retrieve.data); + Assertions.assertEquals(this.insertedRemote2.data, retrieve.data); + Assertions.assertNull(retrieve.remoteToParent); + + // -- Verify remote is linked: + final TypeManyToManyLocalOIDRootExpand retrieveExpand = ConfigureDb.da + .get(TypeManyToManyLocalOIDRootExpand.class, this.insertedRoot1.oid); + + Assertions.assertNotNull(retrieveExpand); + Assertions.assertNotNull(retrieveExpand.oid); + Assertions.assertEquals(this.insertedRoot1.oid, retrieveExpand.oid); + Assertions.assertNotNull(retrieveExpand.otherData); + Assertions.assertEquals(this.insertedRoot1.otherData, retrieveExpand.otherData); + Assertions.assertNull(retrieveExpand.remote); + + // -- Verify remote is un-linked: + final TypeManyToManyLocalOIDRootExpand retrieveRemote = ConfigureDb.da + .get(TypeManyToManyLocalOIDRootExpand.class, this.insertedRoot2.oid); + + Assertions.assertNotNull(retrieveRemote); + Assertions.assertNotNull(retrieveRemote.oid); + Assertions.assertEquals(this.insertedRoot2.oid, retrieveRemote.oid); + Assertions.assertNotNull(retrieveRemote.otherData); + Assertions.assertEquals(this.insertedRoot2.otherData, retrieveRemote.otherData); + Assertions.assertNull(retrieveRemote.remote); + + } + + TypeManyToManyLocalOIDRemote insertedParameters; + + // --------------------------------------------------------------- + // -- Add parent with manyToMany in parameters: + // --------------------------------------------------------------- + @Order(6) + @Test + public void AddParentWithManyToManyInParameters() throws Exception { + final TypeManyToManyLocalOIDRemote test = new TypeManyToManyLocalOIDRemote(); + test.data = "insert with remote"; + test.remoteToParent = new ArrayList<>(); + test.remoteToParent.add(this.insertedRoot1.oid); + test.remoteToParent.add(this.insertedRoot2.oid); + this.insertedParameters = ConfigureDb.da.insert(test); + Assertions.assertNotNull(this.insertedParameters); + Assertions.assertNotNull(this.insertedParameters.oid); + Assertions.assertNotNull(this.insertedParameters.remoteToParent); + Assertions.assertEquals(2, this.insertedParameters.remoteToParent.size()); + Assertions.assertEquals(this.insertedRoot1.oid, this.insertedParameters.remoteToParent.get(0)); + Assertions.assertEquals(this.insertedRoot2.oid, this.insertedParameters.remoteToParent.get(1)); + + // -- Verify remote is linked: + TypeManyToManyLocalOIDRoot retrieveRoot = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedRoot1.oid); + + Assertions.assertNotNull(retrieveRoot); + Assertions.assertNotNull(retrieveRoot.oid); + Assertions.assertEquals(this.insertedRoot1.oid, retrieveRoot.oid); + Assertions.assertNotNull(retrieveRoot.otherData); + Assertions.assertEquals(this.insertedRoot1.otherData, retrieveRoot.otherData); + Assertions.assertNotNull(retrieveRoot.remote); + Assertions.assertEquals(1, retrieveRoot.remote.size()); + Assertions.assertEquals(this.insertedParameters.oid, retrieveRoot.remote.get(0)); + + retrieveRoot = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, this.insertedRoot2.oid); + + Assertions.assertNotNull(retrieveRoot); + Assertions.assertNotNull(retrieveRoot.oid); + Assertions.assertEquals(this.insertedRoot2.oid, retrieveRoot.oid); + Assertions.assertNotNull(retrieveRoot.otherData); + Assertions.assertEquals(this.insertedRoot2.otherData, retrieveRoot.otherData); + Assertions.assertNotNull(retrieveRoot.remote); + Assertions.assertEquals(1, retrieveRoot.remote.size()); + Assertions.assertEquals(this.insertedParameters.oid, retrieveRoot.remote.get(0)); + + } + + // --------------------------------------------------------------- + // -- Update Parent Data: + // --------------------------------------------------------------- + @Order(7) + @Test + public void updateRequest() throws Exception { + final TypeManyToManyLocalOIDRemote testUpdate = new TypeManyToManyLocalOIDRemote(); + testUpdate.remoteToParent = new ArrayList<>(); + testUpdate.remoteToParent.add(this.insertedRoot2.oid); + final long numberUpdate = ConfigureDb.da.update(testUpdate, this.insertedParameters.oid); + Assertions.assertEquals(1, numberUpdate); + + final TypeManyToManyLocalOIDRemote insertedDataUpdate = ConfigureDb.da + .get(TypeManyToManyLocalOIDRemote.class, this.insertedParameters.oid); + Assertions.assertNotNull(insertedDataUpdate); + Assertions.assertNotNull(insertedDataUpdate.oid); + Assertions.assertNotNull(insertedDataUpdate.remoteToParent); + Assertions.assertEquals(1, insertedDataUpdate.remoteToParent.size()); + Assertions.assertEquals(this.insertedRoot2.oid, insertedDataUpdate.remoteToParent.get(0)); + + // -- Verify remote is linked (removed): + TypeManyToManyLocalOIDRoot retrieveRoot = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, + this.insertedRoot1.oid); + + Assertions.assertNotNull(retrieveRoot); + Assertions.assertNotNull(retrieveRoot.oid); + Assertions.assertEquals(this.insertedRoot1.oid, retrieveRoot.oid); + Assertions.assertNotNull(retrieveRoot.otherData); + Assertions.assertEquals(this.insertedRoot1.otherData, retrieveRoot.otherData); + Assertions.assertNull(retrieveRoot.remote); + + // -- Verify remote is linked (keep): + retrieveRoot = ConfigureDb.da.get(TypeManyToManyLocalOIDRoot.class, this.insertedRoot2.oid); + + Assertions.assertNotNull(retrieveRoot); + Assertions.assertNotNull(retrieveRoot.oid); + Assertions.assertEquals(this.insertedRoot2.oid, retrieveRoot.oid); + Assertions.assertNotNull(retrieveRoot.otherData); + Assertions.assertEquals(this.insertedRoot2.otherData, retrieveRoot.otherData); + Assertions.assertNotNull(retrieveRoot.remote); + Assertions.assertEquals(1, retrieveRoot.remote.size()); + Assertions.assertEquals(this.insertedParameters.oid, retrieveRoot.remote.get(0)); + + } + } +} diff --git a/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRemote.java b/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRemote.java new file mode 100644 index 0000000..8ecad8f --- /dev/null +++ b/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRemote.java @@ -0,0 +1,17 @@ +package test.atriasoft.archidata.dataAccess.model; + +import java.util.List; + +import org.atriasoft.archidata.annotation.ManyToManyLocal; +import org.atriasoft.archidata.model.OIDGenericData; +import org.bson.types.ObjectId; + +import dev.morphia.annotations.Entity; + +@Entity +public class TypeManyToManyLocalOIDRemote extends OIDGenericData { + @ManyToManyLocal(targetEntity = TypeManyToManyLocalOIDRoot.class, remoteField = "remote") + public List remoteToParent; + public String data; + +} \ No newline at end of file diff --git a/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRoot.java b/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRoot.java new file mode 100644 index 0000000..390e22e --- /dev/null +++ b/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRoot.java @@ -0,0 +1,18 @@ +package test.atriasoft.archidata.dataAccess.model; + +import java.util.List; + +import org.atriasoft.archidata.annotation.ManyToManyLocal; +import org.atriasoft.archidata.model.OIDGenericData; +import org.bson.types.ObjectId; + +import dev.morphia.annotations.Entity; + +@Entity +public class TypeManyToManyLocalOIDRoot extends OIDGenericData { + + public String otherData; + + @ManyToManyLocal(targetEntity = TypeManyToManyLocalOIDRemote.class, remoteField = "remoteToParent") + public List remote; +} diff --git a/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRootExpand.java b/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRootExpand.java new file mode 100644 index 0000000..f88ad19 --- /dev/null +++ b/src/test/test/atriasoft/archidata/dataAccess/model/TypeManyToManyLocalOIDRootExpand.java @@ -0,0 +1,20 @@ +package test.atriasoft.archidata.dataAccess.model; + +import java.util.List; + +import org.atriasoft.archidata.annotation.ManyToManyLocal; +import org.atriasoft.archidata.model.OIDGenericData; + +import dev.morphia.annotations.Entity; +import jakarta.persistence.Table; + +@Table(name = "TypeManyToManyLocalOIDRoot") +// for Mongo +@Entity(value = "TypeManyToManyLocalOIDRoot") +public class TypeManyToManyLocalOIDRootExpand extends OIDGenericData { + + public String otherData; + + @ManyToManyLocal(targetEntity = TypeManyToManyLocalOIDRemote.class, remoteField = "remoteToParent") + public List remote; +}