diff --git a/src/org/kar/archidata/dataAccess/DataAccessMorphia.java b/src/org/kar/archidata/dataAccess/DataAccessMorphia.java index 4b1dff5..8255a4d 100644 --- a/src/org/kar/archidata/dataAccess/DataAccessMorphia.java +++ b/src/org/kar/archidata/dataAccess/DataAccessMorphia.java @@ -23,6 +23,11 @@ import org.bson.types.ObjectId; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.CreationTimestamp; import org.kar.archidata.annotation.UpdateTimestamp; +import org.kar.archidata.dataAccess.addOnMongo.AddOnDataJson; +import org.kar.archidata.dataAccess.addOnMongo.AddOnManyToMany; +import org.kar.archidata.dataAccess.addOnMongo.AddOnManyToOne; +import org.kar.archidata.dataAccess.addOnMongo.AddOnOneToMany; +import org.kar.archidata.dataAccess.addOnMongo.DataAccessAddOn; import org.kar.archidata.dataAccess.options.CheckFunction; import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.FilterValue; @@ -60,13 +65,12 @@ public class DataAccessMorphia extends DataAccess { // by default we manage some add-on that permit to manage non-native model (like json serialization, List of external key as String list...) static final List addOn = new ArrayList<>(); - /*static { + static { addOn.add(new AddOnManyToMany()); addOn.add(new AddOnManyToOne()); addOn.add(new AddOnOneToMany()); addOn.add(new AddOnDataJson()); } - */ /** Add a new add-on on the current management. * @param addOn instantiate object on the Add-on diff --git a/src/org/kar/archidata/dataAccess/DataAccessSQL.java b/src/org/kar/archidata/dataAccess/DataAccessSQL.java index cc3e558..9d15090 100644 --- a/src/org/kar/archidata/dataAccess/DataAccessSQL.java +++ b/src/org/kar/archidata/dataAccess/DataAccessSQL.java @@ -23,10 +23,11 @@ import java.util.UUID; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.CreationTimestamp; import org.kar.archidata.annotation.UpdateTimestamp; -import org.kar.archidata.dataAccess.addOn.AddOnDataJson; -import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; -import org.kar.archidata.dataAccess.addOn.AddOnManyToOne; -import org.kar.archidata.dataAccess.addOn.AddOnOneToMany; +import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson; +import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToMany; +import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToOne; +import org.kar.archidata.dataAccess.addOnSQL.AddOnOneToMany; +import org.kar.archidata.dataAccess.addOnSQL.DataAccessAddOn; import org.kar.archidata.dataAccess.options.CheckFunction; import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.DBInterfaceRoot; diff --git a/src/org/kar/archidata/dataAccess/DataFactory.java b/src/org/kar/archidata/dataAccess/DataFactory.java index 4a398d3..cc9d702 100644 --- a/src/org/kar/archidata/dataAccess/DataFactory.java +++ b/src/org/kar/archidata/dataAccess/DataFactory.java @@ -14,6 +14,7 @@ import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.CreationTimestamp; import org.kar.archidata.annotation.DataIfNotExists; import org.kar.archidata.annotation.UpdateTimestamp; +import org.kar.archidata.dataAccess.addOnSQL.DataAccessAddOn; import org.kar.archidata.dataAccess.options.CreateDropTable; import org.kar.archidata.exception.DataAccessException; import org.kar.archidata.tools.ConfigBaseVariable; diff --git a/src/org/kar/archidata/dataAccess/addOnMongo/AddOnDataJson.java b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnDataJson.java new file mode 100644 index 0000000..160e679 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnDataJson.java @@ -0,0 +1,459 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +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.List; +import java.util.UUID; + +import org.bson.Document; +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.annotation.DataJson; +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DataAccessMorphia; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryOptions; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversLongLong; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversLongUUID; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversUUIDLong; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversUUIDUUID; +import org.kar.archidata.dataAccess.options.OverrideTableName; +import org.kar.archidata.exception.DataAccessException; +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 com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; + +import jakarta.validation.constraints.NotNull; + +public class AddOnDataJson implements DataAccessAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnDataJson.class); + + @Override + public Class getAnnotationClass() { + return DataJson.class; + } + + @Override + public String getSQLFieldType(final Field elem) throws DataAccessException { + final String fieldName = AnnotationTools.getFieldName(elem); + return DataFactory.convertTypeInSQL(String.class, fieldName); + } + + @Override + public boolean isCompatibleField(final Field elem) { + final DataJson decorators = elem.getDeclaredAnnotation(DataJson.class); + return decorators != null; + } + + @Override + public void insertData( + final DataAccessMorphia ioDb, + final PreparedStatement ps, + final Field field, + final Object rootObject, + final CountInOut iii) + throws IllegalArgumentException, IllegalAccessException, SQLException, JsonProcessingException { + final Object data = field.get(rootObject); + if (data == null) { + ps.setNull(iii.value, Types.VARCHAR); + } + final ObjectMapper objectMapper = new ObjectMapper(); + final String dataString = objectMapper.writeValueAsString(data); + ps.setString(iii.value, dataString); + iii.inc(); + } + + @Override + public boolean canInsert(final Field field) { + return true; + } + + @Override + public boolean isInsertAsync(final Field field) { + return false; + } + + @Override + public boolean canRetrieve(final Field field) { + return true; + } + + @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(); + return; + } + + @Override + public void fillFromQuery( + final DataAccessMorphia ioDb, + final ResultSet rs, + final Field field, + final Object data, + final CountInOut count, + final QueryOptions options, + final List lazyCall) throws Exception { + final String jsonData = rs.getString(count.value); + count.inc(); + if (!rs.wasNull()) { + final ObjectMapper objectMapper = new ObjectMapper(); + if (field.getType() == List.class) { + final ParameterizedType listType = (ParameterizedType) field.getGenericType(); + final Class listClass = (Class) listType.getActualTypeArguments()[0]; + if (listClass == Long.class) { + final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {});// field.getType()); + field.set(data, dataParsed); + return; + } + if (listClass == Float.class) { + final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {});// field.getType()); + field.set(data, dataParsed); + return; + } + if (listClass == Double.class) { + final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {});// field.getType()); + field.set(data, dataParsed); + return; + } + if (listClass == Integer.class) { + final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {});// field.getType()); + field.set(data, dataParsed); + return; + } + if (listClass == Short.class) { + final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {});// field.getType()); + field.set(data, dataParsed); + return; + } + if (listClass == String.class) { + final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {});// field.getType()); + field.set(data, dataParsed); + return; + } + if (listClass == UUID.class) { + final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference>() {});// field.getType()); + field.set(data, dataParsed); + return; + } + LOGGER.warn("Maybe fail to translate Model in datajson list: List<{}>", listClass.getCanonicalName()); + } + final Object dataParsed = objectMapper.readValue(jsonData, field.getType()); + field.set(data, dataParsed); + } + } + + @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) throws Exception { + DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList, + postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class); + } + + public static void addLink( + final DataAccess ioDb, + final Class clazz, + final Long id, + final String column, + final Long remoteKey) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + final TableCoversLongLong data = ioDb.get(TableCoversLongLong.class, id, new OverrideTableName(tableName)); + if (data.covers == null) { + data.covers = new ArrayList<>(); + } + for (final Long elem : data.covers) { + if (elem.equals(remoteKey)) { + return; + } + } + data.covers.add(remoteKey); + ioDb.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); + } + + /** + * Adds a remoteKey to the covers list of a data entry identified by the given class type and ID. + * If the covers list is null, it initializes it. If the remoteKey already exists in the list, + * the method returns without making any changes. + * + * @param clazz The class type to retrieve the table name from. + * @param id The ID of the data object to fetch. + * @param column The name of the column (currently not used, but may be used for specifying a field name). + * @param remoteKey The UUID to add to the covers list. + * @throws Exception If an error occurs during data retrieval or update. + */ + public static void addLink( + final DataAccess ioDb, + final Class clazz, + final Long id, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + // TODO: Get primary key name + final TableCoversLongUUID data = ioDb.get(TableCoversLongUUID.class, id, new OverrideTableName(tableName)); + if (data.covers == null) { + data.covers = new ArrayList<>(); + } + for (final UUID elem : data.covers) { + if (elem.equals(remoteKey)) { + return; + } + } + data.covers.add(remoteKey); + ioDb.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));// TODO: ,new OverrideFieldName("covers", column)); + } else if (ioDb instanceof final DataAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + /** + * Adds a remoteKey to the covers list of a data entry identified by the given class type and ID. + * If the covers list is null, it initializes it. If the remoteKey already exists in the list, + * the method returns without making any changes. + * + * @param clazz The class type to retrieve the table name from. + * @param id The ID of the data object to fetch. + * @param column The name of the column (currently not used, but may be used for specifying a field name). + * @param remoteKey The UUID to add to the covers list. + * @throws Exception If an error occurs during data retrieval or update. + */ + public static void addLink( + final DataAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final TableCoversUUIDUUID data = ioDb.get(TableCoversUUIDUUID.class, uuid, + new OverrideTableName(tableName)); + if (data.covers == null) { + data.covers = new ArrayList<>(); + } + for (final UUID elem : data.covers) { + if (elem.equals(remoteKey)) { + return; + } + } + data.covers.add(remoteKey); + ioDb.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); + } else if (ioDb instanceof final DataAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void addLink( + final DataAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final TableCoversUUIDLong data = ioDb.get(TableCoversUUIDLong.class, uuid, + new OverrideTableName(tableName)); + if (data.covers == null) { + data.covers = new ArrayList<>(); + } + for (final Long elem : data.covers) { + if (elem.equals(remoteKey)) { + return; + } + } + data.covers.add(remoteKey); + ioDb.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); + } else if (ioDb instanceof final DataAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DataAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final TableCoversUUIDLong data = ioDb.get(TableCoversUUIDLong.class, uuid, + new OverrideTableName(tableName)); + if (data.covers == null) { + return; + } + final List newList = new ArrayList<>(); + for (final Long elem : data.covers) { + if (elem.equals(remoteKey)) { + continue; + } + newList.add(elem); + } + data.covers = newList; + ioDb.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); + } else if (ioDb instanceof final DataAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DataAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final TableCoversUUIDUUID data = ioDb.get(TableCoversUUIDUUID.class, uuid, + new OverrideTableName(tableName)); + if (data.covers == null) { + return; + } + final List newList = new ArrayList<>(); + for (final UUID elem : data.covers) { + if (elem.equals(remoteKey)) { + continue; + } + newList.add(elem); + } + data.covers = newList; + ioDb.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); + } else if (ioDb instanceof final DataAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DataAccess ioDb, + final Class clazz, + final Long id, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final TableCoversLongLong data = ioDb.get(TableCoversLongLong.class, id, new OverrideTableName(tableName)); + if (data.covers == null) { + return; + } + final List newList = new ArrayList<>(); + for (final Long elem : data.covers) { + if (elem.equals(remoteKey)) { + continue; + } + newList.add(elem); + } + data.covers = newList; + ioDb.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); + } else if (ioDb instanceof final DataAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DataAccess ioDb, + final Class clazz, + final Long id, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final TableCoversLongUUID data = ioDb.get(TableCoversLongUUID.class, id, new OverrideTableName(tableName)); + if (data.covers == null) { + return; + } + final List newList = new ArrayList<>(); + for (final UUID elem : data.covers) { + if (elem.equals(remoteKey)) { + continue; + } + newList.add(elem); + } + data.covers = newList; + } else if (ioDb instanceof final DataAccessMorphia dam) { + final String collectionName = AnnotationTools.getCollectionName(clazz); + final Field primaryfield = AnnotationTools.getPrimaryKeyField(clazz); + final String primaryFieldName = AnnotationTools.getFieldName(primaryfield); + + final MongoCollection collection = dam.getInterface().getDatastore().getDatabase() + .getCollection(collectionName); + // retrieve previous value: + final Document ret = collection.find(Filters.eq(primaryFieldName, id)).first(); + if (ret == null) { + throw new DataAccessException("Element does not exist ..."); + } + final List newList = new ArrayList<>(); + final List listValues = ret.get(remoteKey, newList.getClass()); + /* + final Document actions = new Document(); + + // update value: + final Document actions = new Document(); + if (!docSet.isEmpty()) { + actions.append("$set", docSet); + } + if (!docUnSet.isEmpty()) { + actions.append("$unset", docUnSet); + } + LOGGER.info("update some values: {}", actions.toJson()); + final UpdateResult ret = collection.updateMany(filters, actions); + return ret.getModifiedCount(); + + final TableCoversLongUUID data = ioDb.getDocument(tableName, id); + if (data.covers == null) { + return; + } + final List newList = new ArrayList<>(); + for (final UUID elem : data.covers) { + if (elem.equals(remoteKey)) { + continue; + } + newList.add(elem); + } + data.covers = newList; + */ + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } +} diff --git a/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToMany.java b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToMany.java new file mode 100644 index 0000000..19abe25 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToMany.java @@ -0,0 +1,593 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DataAccessMorphia; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryAnd; +import org.kar.archidata.dataAccess.QueryCondition; +import org.kar.archidata.dataAccess.QueryInList; +import org.kar.archidata.dataAccess.QueryOptions; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableLongLong; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableLongUUID; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableUUIDLong; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableUUIDUUID; +import org.kar.archidata.dataAccess.options.Condition; +import org.kar.archidata.dataAccess.options.OverrideTableName; +import org.kar.archidata.exception.DataAccessException; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToMany; +import jakarta.validation.constraints.NotNull; + +public class AddOnManyToMany implements DataAccessAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); + static final String SEPARATOR_LONG = "-"; + static final String SEPARATOR_UUID = "_"; + + @Override + public Class getAnnotationClass() { + return ManyToMany.class; + } + + @Override + public String getSQLFieldType(final Field elem) { + return null; + } + + @Override + public boolean isCompatibleField(final Field elem) { + final ManyToMany decorators = elem.getDeclaredAnnotation(ManyToMany.class); + return decorators != null; + } + + @Override + public void insertData( + final DataAccessMorphia ioDb, + final PreparedStatement ps, + final Field field, + final Object rootObject, + final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException { + + } + + @Override + public boolean canInsert(final Field field) { + return false; + } + + @Override + public boolean canRetrieve(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) { + return true; + } + final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class); + if (decorators == null) { + return false; + } + if (decorators.targetEntity() == objectClass) { + return true; + } + return false; + } + + public static String generateLinkTableNameField(final String tableName, final Field field) throws Exception { + final String name = AnnotationTools.getFieldName(field); + return generateLinkTableName(tableName, name); + } + + public static String generateLinkTableName(final String tableName, final String name) { + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length() - 1); + } + return tableName + "_link_" + localName; + } + + public void generateConcatQuery( + @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 { + final ManyToMany manyToMany = AnnotationTools.getManyToMany(field); + String linkTableName = generateLinkTableName(tableName, name); + if (manyToMany.mappedBy() != null && manyToMany.mappedBy().length() != 0) { + // TODO: get the remote table name ..... + final String remoteTableName = AnnotationTools.getTableName(manyToMany.targetEntity()); + linkTableName = generateLinkTableName(remoteTableName, manyToMany.mappedBy()); + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + final String tmpVariable = "tmp_" + Integer.toString(count.value); + querySelect.append(" (SELECT GROUP_CONCAT("); + querySelect.append(tmpVariable); + if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) { + querySelect.append(".object2Id "); + } else { + querySelect.append(".object1Id "); + } + if ("sqlite".equals(ConfigBaseVariable.getDBType())) { + querySelect.append(", "); + } else { + querySelect.append("SEPARATOR "); + } + querySelect.append("'"); + if (objectClass == Long.class) { + querySelect.append(SEPARATOR_LONG); + } else if (objectClass == UUID.class) {} else { + final Class foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType(); + if (foreignKeyType == Long.class) { + querySelect.append(SEPARATOR_LONG); + } + } + querySelect.append("') FROM "); + querySelect.append(linkTableName); + querySelect.append(" "); + querySelect.append(tmpVariable); + querySelect.append(" WHERE "); + querySelect.append(tmpVariable); + querySelect.append(".deleted = false"); + querySelect.append(" AND "); + querySelect.append(tableName); + querySelect.append("."); + querySelect.append(primaryKey); + querySelect.append(" = "); + querySelect.append(tmpVariable); + querySelect.append("."); + if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) { + querySelect.append("object1Id "); + } else { + querySelect.append("object2Id "); + } + if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { + querySelect.append(" GROUP BY "); + querySelect.append(tmpVariable); + if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) { + querySelect.append(".object1Id"); + } else { + querySelect.append(".object2Id"); + } + } + querySelect.append(") AS "); + querySelect.append(name); + querySelect.append(" "); + /* " (SELECT GROUP_CONCAT(tmp.data_id SEPARATOR '-')" + " FROM cover_link_node tmp" + " WHERE tmp.deleted = false" + + * " AND node.id = tmp.node_id" + " GROUP BY tmp.node_id) AS covers" + */ + count.inc(); + } + + @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 { + if (field.getType() != List.class) { + return; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + // TODO: manage better the eager and lazy !! + if (objectClass == Long.class || objectClass == UUID.class) { + generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options); + } + final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class); + if (decorators == null) { + return; + } + if (objectClass == decorators.targetEntity()) { + if (decorators.fetch() == FetchType.EAGER) { + throw new DataAccessException("EAGER is not supported for list of element..."); + } else { + generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options); + } + } + } + + @Override + public void fillFromQuery( + final DataAccessMorphia 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) { + LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); + return; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass == Long.class) { + final List idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG); + field.set(data, idList); + count.inc(); + return; + } else if (objectClass == UUID.class) { + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); + field.set(data, idList); + count.inc(); + return; + } + final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class); + if (decorators == null) { + return; + } + if (objectClass == decorators.targetEntity()) { + final Class foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType(); + if (decorators.fetch() == FetchType.EAGER) { + throw new DataAccessException("EAGER is not supported for list of element..."); + } else if (foreignKeyType == Long.class) { + final List idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG); + // field.set(data, idList); + count.inc(); + if (idList != null && idList.size() > 0) { + final String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass)); + // 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 .... + @SuppressWarnings("unchecked") + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), + new Condition(new QueryInList<>(idField, childs))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } else if (foreignKeyType == UUID.class) { + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); + // field.set(data, idList); + count.inc(); + if (idList != null && idList.size() > 0) { + final String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass)); + // 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 .... + @SuppressWarnings("unchecked") + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), + new Condition(new QueryInList<>(idField, childs))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } + } + } + + @Override + public boolean isUpdateAsync(final Field field) { + return true; + } + + @Override + public void asyncUpdate( + final DataAccessMorphia ioDb, + final String tableName, + final Object localKey, + final Field field, + final Object data, + final List actions) throws Exception { + if (field.getType() != List.class) { + LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); + return; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + + objectClass.getCanonicalName() + ">"); + } + final String columnName = AnnotationTools.getFieldName(field); + final String linkTableName = generateLinkTableName(tableName, columnName); + + if (localKey instanceof final Long localKeyLong) { + if (objectClass == Long.class) { + actions.add(() -> { + ioDb.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), + new Condition(new QueryCondition("object1Id", "=", localKeyLong))); + }); + asyncInsert(ioDb, tableName, localKey, field, data, actions); + } else { + actions.add(() -> { + ioDb.deleteWhere(LinkTableLongUUID.class, new OverrideTableName(linkTableName), + new Condition(new QueryCondition("object1Id", "=", localKeyLong))); + }); + asyncInsert(ioDb, tableName, localKey, field, data, actions); + } + } else if (localKey instanceof final UUID localKeyUUID) { + if (objectClass == Long.class) { + actions.add(() -> { + ioDb.deleteWhere(LinkTableUUIDLong.class, new OverrideTableName(linkTableName), + new Condition(new QueryCondition("object1Id", "=", localKeyUUID))); + }); + asyncInsert(ioDb, tableName, localKey, field, data, actions); + } else { + actions.add(() -> { + ioDb.deleteWhere(LinkTableUUIDUUID.class, new OverrideTableName(linkTableName), + new Condition(new QueryCondition("object1Id", "=", localKeyUUID))); + }); + asyncInsert(ioDb, tableName, localKey, field, data, actions); + } + } + } + + @Override + public boolean isInsertAsync(final Field field) { + return true; + } + + @Override + public void asyncInsert( + final DataAccessMorphia ioDb, + final String tableName, + final Object localKey, + final Field field, + final Object data, + final List actions) throws Exception { + if (data == null) { + return; + } + if (field.getType() != List.class) { + LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); + return; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + + objectClass.getCanonicalName() + ">"); + } + final String columnName = AnnotationTools.getFieldName(field); + final String linkTableName = generateLinkTableName(tableName, columnName); + if (localKey instanceof final Long localKeyLong) { + if (objectClass == Long.class) { + // ======================================================== + // == Link a "Long" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final Long remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableLongLong(localKeyLong, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); + } else { + // ======================================================== + // == Link a "Long" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final UUID remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableLongUUID(localKeyLong, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); + } + } else if (localKey instanceof final UUID localKeyUUID) { + if (objectClass == Long.class) { + // ======================================================== + // == Link a "UUID" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final Long remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableUUIDLong(localKeyUUID, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); + } else { + // ======================================================== + // == Link a "UUID" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final UUID remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableUUIDUUID(localKeyUUID, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); + } + } else { + throw new DataAccessException("Not manage access of remte key like ManyToMany other than Long or UUID: " + + localKey.getClass().getCanonicalName()); + } + + } + + @Override + public void drop(final DataAccessMorphia ioDb, final String tableName, final Field field) throws Exception { + final String columnName = AnnotationTools.getFieldName(field); + final String linkTableName = generateLinkTableName(tableName, columnName); + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + + objectClass.getCanonicalName() + ">"); + } + ioDb.drop(LinkTableLongLong.class, new OverrideTableName(linkTableName)); + } + + @Override + public void cleanAll(final DataAccessMorphia ioDb, final String tableName, final Field field) throws Exception { + final String columnName = AnnotationTools.getFieldName(field); + final String linkTableName = generateLinkTableName(tableName, columnName); + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + + objectClass.getCanonicalName() + ">"); + } + ioDb.cleanAll(LinkTableLongLong.class, new OverrideTableName(linkTableName)); + } + + public static void addLink( + final DataAccess ioDb, + final Class clazz, + final long localKey, + final String column, + final long remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final String linkTableName = generateLinkTableName(tableName, column); + /* final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; if (objectClass != Long.class && objectClass != UUID.class) { throw new + * DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); } */ + final LinkTableLongLong insertElement = new LinkTableLongLong(localKey, remoteKey); + daSQL.insert(insertElement, new OverrideTableName(linkTableName)); + } else if (ioDb instanceof final DataAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + + } + + public static long removeLink( + final DataAccess ioDb, + final Class clazz, + final long localKey, + final String column, + final long remoteKey) throws Exception { + if (ioDb instanceof final DataAccessMorphia daSQL) { + final String tableName = AnnotationTools.getTableName(clazz); + final String linkTableName = generateLinkTableName(tableName, column); + return daSQL.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), + new Condition(new QueryAnd(new QueryCondition("object1Id", "=", localKey), + new QueryCondition("object2Id", "=", remoteKey)))); + } else if (ioDb instanceof final DataAccessMorphia dam) { + return 0L; + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + @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) throws Exception { + + final ManyToMany manyToMany = AnnotationTools.getManyToMany(field); + if (manyToMany.mappedBy() != null && manyToMany.mappedBy().length() != 0) { + // not the reference model to create base: + return; + } + final String linkTableName = generateLinkTableNameField(tableName, field); + final QueryOptions options = new QueryOptions(new OverrideTableName(linkTableName)); + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + + objectClass.getCanonicalName() + ">"); + } + final Class primaryType = primaryField.getType(); + if (primaryType == Long.class) { + if (objectClass == Long.class) { + final List sqlCommand = DataFactory.createTable(LinkTableLongLong.class, options); + postActionList.addAll(sqlCommand); + } else { + final List sqlCommand = DataFactory.createTable(LinkTableLongUUID.class, options); + postActionList.addAll(sqlCommand); + } + } else if (primaryType == UUID.class) { + if (objectClass == Long.class) { + final List sqlCommand = DataFactory.createTable(LinkTableUUIDLong.class, options); + postActionList.addAll(sqlCommand); + } else { + final List sqlCommand = DataFactory.createTable(LinkTableUUIDUUID.class, options); + postActionList.addAll(sqlCommand); + } + } else { + throw new DataAccessException("Can not ManyToMany with other than primary key type Long or UUID Model: " + + primaryType.getCanonicalName()); + } + } +} diff --git a/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToOne.java b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToOne.java new file mode 100644 index 0000000..5fe6d07 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToOne.java @@ -0,0 +1,308 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Types; +import java.util.List; +import java.util.UUID; + +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DataAccessMorphia; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryOptions; +import org.kar.archidata.exception.DataAccessException; +import org.kar.archidata.tools.UuidUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToOne; +import jakarta.validation.constraints.NotNull; + +public class AddOnManyToOne implements DataAccessAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); + + @Override + public Class getAnnotationClass() { + return ManyToOne.class; + } + + @Override + public String getSQLFieldType(final Field field) throws Exception { + final String fieldName = AnnotationTools.getFieldName(field); + try { + return DataFactory.convertTypeInSQL(field.getType(), fieldName); + } catch (final Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public boolean isCompatibleField(final Field elem) { + return elem.getDeclaredAnnotation(ManyToOne.class) != null; + } + + @Override + public void insertData( + final DataAccessMorphia ioDb, + final PreparedStatement ps, + final Field field, + final Object rootObject, + final CountInOut iii) throws Exception { + final Object data = field.get(rootObject); + if (data == null) { + if (field.getType() == Long.class) { + ps.setNull(iii.value, Types.BIGINT); + } else if (field.getType() == Integer.class) { + ps.setNull(iii.value, Types.INTEGER); + } else if (field.getType() == Short.class) { + ps.setNull(iii.value, Types.INTEGER); + } else if (field.getType() == String.class) { + ps.setNull(iii.value, Types.VARCHAR); + } else if (field.getType() == UUID.class) { + ps.setNull(iii.value, Types.BINARY); + } + } else if (field.getType() == Long.class) { + final Long dataTyped = (Long) data; + ps.setLong(iii.value, dataTyped); + } else if (field.getType() == Integer.class) { + final Integer dataTyped = (Integer) data; + ps.setInt(iii.value, dataTyped); + } else if (field.getType() == Short.class) { + final Short dataTyped = (Short) data; + ps.setShort(iii.value, dataTyped); + } else if (field.getType() == String.class) { + final String dataTyped = (String) data; + ps.setString(iii.value, dataTyped); + } else if (field.getType() == UUID.class) { + final UUID dataTyped = (UUID) data; + LOGGER.info("Generate UUTD for DB: {}", dataTyped); + final byte[] dataByte = UuidUtils.asBytes(dataTyped); + ps.setBytes(iii.value, dataByte); + } else { + final Field idField = AnnotationTools.getFieldOfId(field.getType()); + final Object uid = idField.get(data); + if (uid == null) { + ps.setNull(iii.value, Types.BIGINT); + throw new DataAccessException("Not implemented adding subClasses ==> add it manualy before..."); + } else { + final Long dataLong = (Long) uid; + ps.setLong(iii.value, dataLong); + } + } + iii.inc(); + } + + @Override + public boolean canInsert(final Field field) { + if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class + || field.getType() == String.class || field.getType() == UUID.class) { + return true; + } + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (field.getType() == decorators.targetEntity()) { + return true; + } + return false; + } + + @Override + public boolean isInsertAsync(final Field field) throws Exception { + return false; + } + + @Override + public boolean canRetrieve(final Field field) { + final Class classType = field.getType(); + if (classType == Long.class || classType == Integer.class || classType == Short.class + || classType == String.class || classType == UUID.class) { + return true; + } + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (field.getType() == decorators.targetEntity()) { + return true; + } + return false; + } + + @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 { + if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class + || field.getType() == String.class || field.getType() == UUID.class) { + querySelect.append(" "); + querySelect.append(tableName); + querySelect.append("."); + querySelect.append(name); + count.inc(); + return; + } + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (field.getType() == decorators.targetEntity()) { + if (decorators.fetch() == FetchType.EAGER) { + // TODO: rework this to have a lazy mode ... + DataAccessMorphia.generateSelectField(querySelect, query, field.getType(), options, count); + final Class subType = field.getType(); + final String subTableName = AnnotationTools.getTableName(subType); + final Field idField = AnnotationTools.getFieldOfId(subType); + query.append("LEFT OUTER JOIN `"); + query.append(subTableName); + query.append("` ON "); + query.append(subTableName); + query.append("."); + query.append(AnnotationTools.getFieldName(idField)); + query.append(" = "); + query.append(tableName); + query.append("."); + query.append(AnnotationTools.getFieldName(field)); + } else { + querySelect.append(" "); + querySelect.append(tableName); + querySelect.append("."); + querySelect.append(name); + count.inc(); + return; + } + } + + /* SELECT k.id, r.id FROM `right` k LEFT OUTER JOIN `rightDescription` r ON k.rightDescriptionId=r.id */ + } + + @Override + public void fillFromQuery( + final DataAccessMorphia ioDb, + final ResultSet rs, + final Field field, + final Object data, + final CountInOut count, + final QueryOptions options, + final List lazyCall) throws Exception { + if (field.getType() == Long.class) { + final Long foreignKey = rs.getLong(count.value); + count.inc(); + if (!rs.wasNull()) { + field.set(data, foreignKey); + } + return; + } + if (field.getType() == Integer.class) { + final Integer foreignKey = rs.getInt(count.value); + count.inc(); + if (!rs.wasNull()) { + field.set(data, foreignKey); + } + return; + } + if (field.getType() == Short.class) { + final Short foreignKey = rs.getShort(count.value); + count.inc(); + if (!rs.wasNull()) { + field.set(data, foreignKey); + } + return; + } + if (field.getType() == String.class) { + final String foreignKey = rs.getString(count.value); + count.inc(); + if (!rs.wasNull()) { + field.set(data, foreignKey); + } + return; + } + if (field.getType() == UUID.class) { + final byte[] tmp = rs.getBytes(count.value); + count.inc(); + if (!rs.wasNull()) { + final UUID foreignKey = UuidUtils.asUuid(tmp); + field.set(data, foreignKey); + } + return; + } + final Class objectClass = field.getType(); + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (decorators == null) { + return; + } + if (objectClass == decorators.targetEntity()) { + if (decorators.fetch() == FetchType.EAGER) { + final CountInOut countNotNull = new CountInOut(0); + final Object dataNew = ioDb.createObjectFromSQLRequest(rs, objectClass, count, countNotNull, options, + lazyCall); + if (dataNew != null && countNotNull.value != 0) { + field.set(data, dataNew); + } + return; + } + final Field remotePrimaryKeyField = AnnotationTools.getFieldOfId(objectClass); + final Class remotePrimaryKeyType = remotePrimaryKeyField.getType(); + if (remotePrimaryKeyType == Long.class) { + // here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ... + final Long foreignKey = rs.getLong(count.value); + count.inc(); + if (!rs.wasNull()) { + // 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.get(decorators.targetEntity(), foreignKey); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } else if (remotePrimaryKeyType == UUID.class) { + // here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ... + final UUID foreignKey = ioDb.getListOfRawUUID(rs, count.value); + count.inc(); + if (foreignKey != null) { + // 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.get(decorators.targetEntity(), foreignKey); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } + } + } + + // TODO : refacto this table to manage a generic table with dynamic name to be serialisable with the default system + @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) throws Exception { + final Class classType = field.getType(); + if (classType == Long.class || classType == Integer.class || classType == Short.class + || classType == String.class || classType == UUID.class) { + DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList, + postActionList, createIfNotExist, createDrop, fieldId, classType); + } else { + LOGGER.error("Support only the Long remote field of ecternal primary keys..."); + DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList, + postActionList, createIfNotExist, createDrop, fieldId, Long.class); + } + } +} diff --git a/src/org/kar/archidata/dataAccess/addOnMongo/AddOnOneToMany.java b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnOneToMany.java new file mode 100644 index 0000000..147920d --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnOneToMany.java @@ -0,0 +1,324 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DataAccessMorphia; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryCondition; +import org.kar.archidata.dataAccess.QueryOptions; +import org.kar.archidata.dataAccess.options.Condition; +import org.kar.archidata.exception.DataAccessException; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import jakarta.validation.constraints.NotNull; + +public class AddOnOneToMany implements DataAccessAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnOneToMany.class); + static final String SEPARATOR_LONG = "-"; + + /** Convert the list if external id in a string '-' separated + * @param ids List of value (null are removed) + * @return '-' string separated */ + protected static String getStringOfIds(final List ids) { + final List tmp = new ArrayList<>(ids); + return tmp.stream().map(String::valueOf).collect(Collectors.joining("-")); + } + + /** extract a list of "-" separated element from a SQL input data. + * @param rs Result Set of the BDD + * @param iii Id in the result set + * @return The list of Long value + * @throws SQLException if an error is generated in the sql request. */ + protected static List getListOfIds(final ResultSet rs, final int iii) throws SQLException { + final String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + final List out = new ArrayList<>(); + final String[] elements = trackString.split("-"); + for (final String elem : elements) { + final Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + + @Override + public Class getAnnotationClass() { + return OneToMany.class; + } + + @Override + public String getSQLFieldType(final Field field) throws Exception { + final String fieldName = AnnotationTools.getFieldName(field); + try { + return DataFactory.convertTypeInSQL(Long.class, fieldName); + } catch (final Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + @Override + public boolean isCompatibleField(final Field field) { + final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class); + return decorators != null; + } + + @Override + public void insertData( + final DataAccessMorphia ioDb, + final PreparedStatement ps, + final Field field, + final Object rootObject, + final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException { + throw new IllegalAccessException("Can not generate an inset of @OneToMany"); + } + + @Override + public boolean canInsert(final Field field) { + return false; + } + + @Override + public boolean isInsertAsync(final Field field) throws Exception { + // TODO: can be implemented later... + return false; + } + + @Override + public boolean canRetrieve(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) { + return true; + } + final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class); + if (decorators == null) { + return false; + } + if (decorators.targetEntity() == objectClass) { + return true; + } + return false; + } + + public void generateConcatQuery( + @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, + final Class targetEntity, + final String mappedBy) throws Exception { + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + final String remoteTableName = AnnotationTools.getTableName(targetEntity); + final String remoteTablePrimaryKeyName = AnnotationTools + .getFieldName(AnnotationTools.getPrimaryKeyField(targetEntity)); + final String tmpRemoteVariable = "tmp_" + Integer.toString(count.value); + final String remoteDeletedFieldName = AnnotationTools.getDeletedFieldName(targetEntity); + + querySelect.append(" (SELECT GROUP_CONCAT("); + querySelect.append(tmpRemoteVariable); + querySelect.append("."); + querySelect.append(remoteTablePrimaryKeyName); + querySelect.append(" "); + if ("sqlite".equals(ConfigBaseVariable.getDBType())) { + querySelect.append(", "); + } else { + querySelect.append("SEPARATOR "); + } + querySelect.append("'"); + if (objectClass == Long.class) { + querySelect.append(SEPARATOR_LONG); + } + querySelect.append("') FROM "); + querySelect.append(remoteTableName); + querySelect.append(" "); + querySelect.append(tmpRemoteVariable); + querySelect.append(" WHERE "); + if (remoteDeletedFieldName != null) { + querySelect.append(tmpRemoteVariable); + querySelect.append("."); + querySelect.append(remoteDeletedFieldName); + querySelect.append(" = false"); + querySelect.append(" AND "); + } + querySelect.append(tableName); + querySelect.append("."); + querySelect.append(primaryKey); + querySelect.append(" = "); + querySelect.append(tmpRemoteVariable); + querySelect.append("."); + querySelect.append(mappedBy); + querySelect.append(" "); + querySelect.append(") AS "); + querySelect.append(name); + querySelect.append(" "); + } + + @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 { + if (field.getType() != List.class) { + return; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class); + if (decorators == null) { + return; + } + // TODO: manage better the eager and lazy !! + if (objectClass == Long.class || objectClass == UUID.class) { + generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options, + decorators.targetEntity(), decorators.mappedBy()); + return; + } + if (objectClass == decorators.targetEntity()) { + if (decorators.fetch() == FetchType.EAGER) { + throw new DataAccessException("EAGER is not supported for list of element..."); + } else { + // Force a copy of the primaryKey to permit the async retrieve of the data + querySelect.append(" "); + querySelect.append(tableName); + querySelect.append("."); + querySelect.append(primaryKey); + querySelect.append(" AS tmp_"); + querySelect.append(Integer.toString(count.value)); + } + } + } + + @Override + public void fillFromQuery( + final DataAccessMorphia 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) { + LOGGER.error("Can not OneToMany with other than List Model: {}", field.getType().getCanonicalName()); + return; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class); + if (decorators == null) { + return; + } + if (objectClass == Long.class) { + final List idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG); + field.set(data, idList); + count.inc(); + return; + } else if (objectClass == UUID.class) { + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); + field.set(data, idList); + count.inc(); + return; + } + if (objectClass == decorators.targetEntity()) { + + Long parentIdTmp = null; + UUID parendUuidTmp = null; + try { + final String modelData = rs.getString(count.value); + parentIdTmp = Long.valueOf(modelData); + count.inc(); + } catch (final NumberFormatException ex) { + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); + parendUuidTmp = idList.get(0); + count.inc(); + } + final Long parentId = parentIdTmp; + final UUID parendUuid = parendUuidTmp; + final String mappingKey = decorators.mappedBy(); + // We get the parent ID ... ==> need to request the list of elements + if (objectClass == Long.class) { + LOGGER.error("Need to retreive all primary key of all elements"); + //field.set(data, idList); + return; + } else if (objectClass == UUID.class) { + LOGGER.error("Need to retreive all primary key of all elements"); + //field.set(data, idList); + return; + } + if (objectClass == decorators.targetEntity()) { + if (decorators.fetch() == FetchType.EAGER) { + throw new DataAccessException("EAGER is not supported for list of element..."); + } else if (parentId != null) { + // In the lazy mode, the request is done in asynchronous mode, they will be done after... + final LazyGetter lambda = () -> { + @SuppressWarnings("unchecked") + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), + new Condition(new QueryCondition(mappingKey, "=", parentId))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } else if (parendUuid != null) { + final LazyGetter lambda = () -> { + @SuppressWarnings("unchecked") + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), + new Condition(new QueryCondition(mappingKey, "=", parendUuid))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } + } + } + } + + // TODO : refacto this table to manage a generic table with dynamic name to be serialize with the default system + @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) throws Exception { + // This is a remote field ==> nothing to generate (it is stored in the remote object + } +} diff --git a/src/org/kar/archidata/dataAccess/addOnMongo/DataAccessAddOn.java b/src/org/kar/archidata/dataAccess/addOnMongo/DataAccessAddOn.java new file mode 100644 index 0000000..ba0cfac --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/DataAccessAddOn.java @@ -0,0 +1,149 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DataAccessMorphia; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryOptions; + +import jakarta.validation.constraints.NotNull; + +public interface DataAccessAddOn { + /** Get the Class of the declaration annotation + * @return The annotation class */ + Class getAnnotationClass(); + + /** Get the SQL type that is needed to declare for the specific Field Type. + * @param elem Field to declare. + * @return SQL type to create. */ + String getSQLFieldType(Field elem) throws Exception; + + /** Check if the field is manage by the local add-on + * @param elem Field to inspect. + * @return True of the field is manage by the current Add-on. */ + boolean isCompatibleField(Field elem); + + /** Insert data in the specific field (the field must be in the current db, otherwiise it does not work at all. + * @param ps DB statement interface. + * @param data The date to inject. + * @param iii The index of injection + * @return the new index of injection in case of multiple value management + * @throws SQLException */ + void insertData(final DataAccessMorphia ioDb, PreparedStatement ps, final Field field, Object data, CountInOut iii) + throws Exception, SQLException, IllegalArgumentException, IllegalAccessException; + + /** Element can insert in the single request + * @param field + * @return */ + default boolean canInsert(final Field field) { + return false; + } + + /** Element can be retrieve with the specific mode + * @param field + * @return */ + default boolean canRetrieve(final Field field) { + return false; + } + + void generateQuery( + @NotNull String tableName, + @NotNull final String primaryKey, + @NotNull Field field, + @NotNull final StringBuilder querySelect, + @NotNull final StringBuilder query, + @NotNull String name, + @NotNull CountInOut count, + QueryOptions options) throws Exception; + + // Return the number of colomn read + void fillFromQuery( + final DataAccessMorphia ioDb, + ResultSet rs, + Field field, + Object data, + CountInOut count, + QueryOptions options, + final List lazyCall) + throws Exception, SQLException, IllegalArgumentException, IllegalAccessException; + + /** Create associated table of the specific element. + * @param tableName + * @param elem + * @param mainTableBuilder + * @param ListOtherTables + * @param createIfNotExist + * @param createDrop + * @param fieldId + * @throws Exception */ + void createTables( + String tableName, + final Field primaryField, + Field field, + StringBuilder mainTableBuilder, + List preActionList, + List postActionList, + boolean createIfNotExist, + boolean createDrop, + int fieldId) throws Exception; + + /** Some action must be done asynchronously for update or remove element + * @param field + * @return */ + default boolean isInsertAsync(final Field field) throws Exception { + return false; + } + + /** 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. */ + default void asyncInsert( + final DataAccessMorphia ioDb, + final String tableName, + final Object localId, + final Field field, + final Object data, + final List actions) throws Exception { + + } + + /** Some action must be done asynchronously for update or remove element + * @param field + * @return */ + default boolean isUpdateAsync(final Field field) throws Exception { + return false; + } + + /** 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. */ + default void asyncUpdate( + final DataAccessMorphia ioDb, + final String tableName, + final Object localId, + final Field field, + final Object data, + final List actions) throws Exception { + + } + + default void drop(final DataAccessMorphia ioDb, final String tableName, final Field field) throws Exception { + + } + + default void cleanAll(final DataAccessMorphia ioDb, final String tableName, final Field field) throws Exception { + + } + +} diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnDataJson.java similarity index 97% rename from src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java rename to src/org/kar/archidata/dataAccess/addOnSQL/AddOnDataJson.java index 36788e8..2656bf3 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnDataJson.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn; +package org.kar.archidata.dataAccess.addOnSQL; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; @@ -15,16 +15,15 @@ import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.DataJson; import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DataAccessMorphia; import org.kar.archidata.dataAccess.DataAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.LazyGetter; import org.kar.archidata.dataAccess.QueryOptions; -import org.kar.archidata.dataAccess.addOn.model.TableCoversLongLong; -import org.kar.archidata.dataAccess.addOn.model.TableCoversLongUUID; -import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDLong; -import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDUUID; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversLongLong; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversLongUUID; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversUUIDLong; +import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversUUIDUUID; import org.kar.archidata.dataAccess.options.OverrideTableName; import org.kar.archidata.exception.DataAccessException; import org.slf4j.Logger; diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToMany.java similarity index 98% rename from src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java rename to src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToMany.java index 88ea507..4491ba6 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToMany.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn; +package org.kar.archidata.dataAccess.addOnSQL; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; @@ -12,7 +12,6 @@ import java.util.UUID; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DataAccessMorphia; import org.kar.archidata.dataAccess.DataAccessSQL; import org.kar.archidata.dataAccess.DataFactory; @@ -21,10 +20,10 @@ import org.kar.archidata.dataAccess.QueryAnd; import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryInList; import org.kar.archidata.dataAccess.QueryOptions; -import org.kar.archidata.dataAccess.addOn.model.LinkTableLongLong; -import org.kar.archidata.dataAccess.addOn.model.LinkTableLongUUID; -import org.kar.archidata.dataAccess.addOn.model.LinkTableUUIDLong; -import org.kar.archidata.dataAccess.addOn.model.LinkTableUUIDUUID; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableLongLong; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableLongUUID; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableUUIDLong; +import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableUUIDUUID; import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.OverrideTableName; import org.kar.archidata.exception.DataAccessException; diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToOne.java similarity index 99% rename from src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java rename to src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToOne.java index 41e5fe9..171ca48 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToOne.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn; +package org.kar.archidata.dataAccess.addOnSQL; import java.lang.reflect.Field; import java.sql.PreparedStatement; @@ -9,7 +9,6 @@ import java.util.UUID; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.dataAccess.CountInOut; -import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DataAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.LazyGetter; diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnOneToMany.java similarity index 99% rename from src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java rename to src/org/kar/archidata/dataAccess/addOnSQL/AddOnOneToMany.java index 34f502a..a5d88fc 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnOneToMany.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn; +package org.kar.archidata.dataAccess.addOnSQL; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; @@ -12,7 +12,6 @@ import java.util.stream.Collectors; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.dataAccess.CountInOut; -import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DataAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.LazyGetter; diff --git a/src/org/kar/archidata/dataAccess/DataAccessAddOn.java b/src/org/kar/archidata/dataAccess/addOnSQL/DataAccessAddOn.java similarity index 94% rename from src/org/kar/archidata/dataAccess/DataAccessAddOn.java rename to src/org/kar/archidata/dataAccess/addOnSQL/DataAccessAddOn.java index d426260..4eb434a 100644 --- a/src/org/kar/archidata/dataAccess/DataAccessAddOn.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/DataAccessAddOn.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess; +package org.kar.archidata.dataAccess.addOnSQL; import java.lang.reflect.Field; import java.sql.PreparedStatement; @@ -6,6 +6,11 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DataAccessSQL; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryOptions; + import jakarta.validation.constraints.NotNull; public interface DataAccessAddOn { diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongLong.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableLongLong.java similarity index 91% rename from src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongLong.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableLongLong.java index 4b458b5..e7c002e 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongLong.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableLongLong.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import org.kar.archidata.model.UUIDGenericDataSoftDelete; diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongUUID.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableLongUUID.java similarity index 92% rename from src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongUUID.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableLongUUID.java index 91cf667..8db1ecd 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongUUID.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableLongUUID.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import java.util.UUID; diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDLong.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableUUIDLong.java similarity index 92% rename from src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDLong.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableUUIDLong.java index 3da8c2f..1314b4b 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDLong.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableUUIDLong.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import java.util.UUID; diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDUUID.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableUUIDUUID.java similarity index 92% rename from src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDUUID.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableUUIDUUID.java index 81173e4..0316d6b 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDUUID.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/LinkTableUUIDUUID.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import java.util.UUID; diff --git a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversLongLong.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversLongLong.java similarity index 87% rename from src/org/kar/archidata/dataAccess/addOn/model/TableCoversLongLong.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversLongLong.java index b4b3485..522c958 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversLongLong.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversLongLong.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import java.util.List; diff --git a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversLongUUID.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversLongUUID.java similarity index 89% rename from src/org/kar/archidata/dataAccess/addOn/model/TableCoversLongUUID.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversLongUUID.java index a00f325..4ab6a5c 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversLongUUID.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversLongUUID.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import java.util.ArrayList; import java.util.List; diff --git a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversUUIDLong.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversUUIDLong.java similarity index 89% rename from src/org/kar/archidata/dataAccess/addOn/model/TableCoversUUIDLong.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversUUIDLong.java index c8adbde..7aa6b79 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversUUIDLong.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversUUIDLong.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import java.util.ArrayList; import java.util.List; diff --git a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversUUIDUUID.java b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversUUIDUUID.java similarity index 88% rename from src/org/kar/archidata/dataAccess/addOn/model/TableCoversUUIDUUID.java rename to src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversUUIDUUID.java index ae3dc43..a5a73a5 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/TableCoversUUIDUUID.java +++ b/src/org/kar/archidata/dataAccess/addOnSQL/model/TableCoversUUIDUUID.java @@ -1,4 +1,4 @@ -package org.kar.archidata.dataAccess.addOn.model; +package org.kar.archidata.dataAccess.addOnSQL.model; import java.util.List; import java.util.UUID;