[FEAT] configure back compatibility with mongo

This commit is contained in:
Edouard DUPIN 2025-03-29 20:21:07 +01:00
parent f0cf1acf8a
commit 969bf78576
8 changed files with 175 additions and 381 deletions

View File

@ -18,6 +18,7 @@ import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.dataAccess.addOnMongo.AddOnManyToOne;
@ -27,6 +28,7 @@ import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.OrderBy;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.db.DbIoMorphia;
@ -128,7 +130,7 @@ public class DBAccessMorphia extends DBAccess {
return groups;
}
protected <T> void setValuedb(
protected <T> void setValueToDb(
final Class<?> type,
final T data,
final Field field,
@ -136,7 +138,9 @@ public class DBAccessMorphia extends DBAccess {
final Document docSet,
final Document docUnSet) throws Exception {
if (field.get(data) == null) {
if (docUnSet != null) {
docUnSet.append(fieldName, "");
}
return;
}
if (type == long.class) {
@ -151,7 +155,7 @@ public class DBAccessMorphia extends DBAccess {
docSet.append(fieldName, field.getFloat(data));
return;
}
if (type == Double.class) {
if (type == double.class) {
docSet.append(fieldName, field.getDouble(data));
return;
}
@ -196,56 +200,40 @@ public class DBAccessMorphia extends DBAccess {
docSet.append(fieldName, tmp);
return;
}
if (type == ObjectId.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == UUID.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Date.class) {
// TODO ...
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant());
ps.setTimestamp(iii.value, sqlDate);
}*/
*/
}
if (type == Instant.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final String sqlDate = ((Instant) tmp).toString();
ps.setString(iii.value, sqlDate);
}
*/
}
if (type == LocalDate.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Date sqlDate = java.sql.Date.valueOf((LocalDate) tmp);
ps.setDate(iii.value, sqlDate);
}
*/
}
if (type == LocalTime.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Time sqlDate = java.sql.Time.valueOf((LocalTime) tmp);
ps.setTime(iii.value, sqlDate);
}
*/
}
throw new DataAccessException("Unknown Field Type");
docSet.append(fieldName, tmp);
//throw new DataAccessException("Unknown Field Type");
}
public <T> void setValueFromDoc(
@ -265,6 +253,11 @@ public class DBAccessMorphia extends DBAccess {
field.set(data, value);
return;
}
if (type == ObjectId.class) {
final ObjectId value = doc.get(fieldName, ObjectId.class);
field.set(data, value);
return;
}
if (type == Long.class || type == long.class) {
final Long value = doc.getLong(fieldName);
field.set(data, value);
@ -349,8 +342,8 @@ public class DBAccessMorphia extends DBAccess {
final Object value = doc.get(fieldName, field.getType());
field.set(data, value);
} else {
final Object value = createObjectFromDocument(doc.get(fieldName, Document.class), field.getType(), null,
lazyCall);
final Object value = createObjectFromDocument(doc.get(fieldName, Document.class), field.getType(),
new QueryOptions(), lazyCall);
field.set(data, value);
}
@ -459,32 +452,45 @@ public class DBAccessMorphia extends DBAccess {
Object uniqueId = null;
// real add in the BDD:
ObjectId insertedId = null;
final List<OptionSpecifyType> specificTypes = options.get(OptionSpecifyType.class);
try {
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase()
.getCollection(collectionName);
final Document doc = new Document();
final Document docSet = new Document();
final Document docUnSet = new Document();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
final String tableFieldName = AnnotationTools.getFieldName(field, options).inTable();
final FieldName tableFieldName = AnnotationTools.getFieldName(field, options);
Object currentInsertValue = field.get(data);
if (AnnotationTools.isPrimaryKey(field)) {
primaryKeyField = field;
if (primaryKeyField.getType() == UUID.class) {
final UUID uuid = UuidUtils.nextUUID();
uniqueId = uuid;
doc.append(tableFieldName, uuid);
docSet.append(tableFieldName.inTable(), uuid);
continue;
} else if (primaryKeyField.getType() == Long.class || primaryKeyField.getType() == long.class) {
// By default the MongoDB does not manage the
final long id = getNextSequenceLongValue(collectionName, tableFieldName);
final long id = getNextSequenceLongValue(collectionName, tableFieldName.inTable());
uniqueId = id;
doc.append(tableFieldName, id);
docSet.append(tableFieldName.inTable(), id);
continue;
}
LOGGER.error("TODO: Manage the ID primary key for type: ");
LOGGER.error("TODO: Manage the ID primary key for type: {}=>{}", clazz.getCanonicalName(),
primaryKeyField.getType());
continue;
}
final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
if (createTime) {
docSet.append(tableFieldName.inTable(), Date.from(Instant.now()));
continue;
}
final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime) {
docSet.append(tableFieldName.inTable(), Date.from(Instant.now()));
continue;
}
final DataAccessAddOn addOn = findAddOnforField(field);
@ -495,19 +501,8 @@ public class DBAccessMorphia extends DBAccess {
}
continue;
}
final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
if (createTime) {
doc.append(tableFieldName, Date.from(Instant.now()));
continue;
}
final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime) {
doc.append(tableFieldName, Date.from(Instant.now()));
continue;
}
if (currentInsertValue == null && !field.getClass().isPrimitive()) {
final DefaultValue[] defaultValue = field.getDeclaredAnnotationsByType(DefaultValue.class);
LOGGER.error("TODO: convert default value in the correct value for the DB...");
if (defaultValue.length == 0) {
continue;
} else {
@ -518,9 +513,24 @@ public class DBAccessMorphia extends DBAccess {
currentInsertValue = convertDefaultField(value, field);
}
}
doc.append(tableFieldName, currentInsertValue);
// conversion table ...
//doc.append(tableFieldName, currentInsertValue);
if (addOn != null) {
addOn.insertData(this, field, data, options, docSet, docUnSet);
} else {
final Class<?> type = field.getType();
if (!type.isPrimitive()) {
if (field.get(data) == null) {
if (currentInsertValue != null) {
docSet.append(tableFieldName.inTable(), currentInsertValue);
}
final InsertOneResult result = collection.insertOne(doc);
continue;
}
}
setValueToDb(type, data, field, tableFieldName.inTable(), docSet, null);
}
}
final InsertOneResult result = collection.insertOne(docSet);
// Get the Object of inserted object:
insertedId = result.getInsertedId().asObjectId().getValue();
LOGGER.info("Document inserted with ID: " + insertedId);
@ -587,14 +597,14 @@ public class DBAccessMorphia extends DBAccess {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
final String fieldName = AnnotationTools.getFieldName(field, options).inTable();
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
// update field is not conditioned by filter:
final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime) {
docSet.append(fieldName, Date.from(Instant.now()));
docSet.append(fieldName.inTable(), Date.from(Instant.now()));
continue;
}
if (!filterKey.getValues().contains(fieldName)) {
if (!filterKey.getValues().contains(fieldName.inStruct())) {
continue;
} else if (AnnotationTools.isGenericField(field)) {
continue;
@ -624,12 +634,10 @@ public class DBAccessMorphia extends DBAccess {
continue;
}
}
setValuedb(type, data, field, fieldName, docSet, docUnSet);
setValueToDb(type, data, field, fieldName.inTable(), docSet, docUnSet);
}
}
// Do the query ...
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase()
.getCollection(collectionName);
final Document actions = new Document();
@ -652,7 +660,6 @@ public class DBAccessMorphia extends DBAccess {
}
public List<String> generateSelectField(final Class<?> clazz, final QueryOptions options) throws Exception {
// TODO: list of user select fields.
final boolean readAllfields = QueryOptions.readAllColomn(options);
final List<String> fieldsName = new ArrayList<>();
@ -776,6 +783,8 @@ public class DBAccessMorphia extends DBAccess {
final Class<?> clazz,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final List<OptionSpecifyType> specificTypes = options.get(OptionSpecifyType.class);
LOGGER.info("createObjectFromDocument: {}", clazz.getCanonicalName());
final boolean readAllfields = QueryOptions.readAllColomn(options);
// TODO: manage class that is defined inside a class ==> Not manage for now...
Object data = null;
@ -790,23 +799,37 @@ public class DBAccessMorphia extends DBAccess {
"Can not find the default constructor for the class: " + clazz.getCanonicalName());
}
for (final Field elem : clazz.getFields()) {
LOGGER.info(" Inspect field: name='{}' type='{}'", elem.getName(), elem.getType().getCanonicalName());
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
LOGGER.info(" ==> static");
continue;
}
final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canRetrieve(elem)) {
LOGGER.info(" ==> Can not retreive this field");
continue;
}
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
LOGGER.info(" ==> Not read this element");
continue;
}
if (addOn != null) {
LOGGER.error("TODO: Add on not managed .6. ");
addOn.fillFromDoc(this, doc, elem, data, options, lazyCall);
} else {
setValueFromDoc(elem.getType(), data, elem, doc, lazyCall, options);
Class<?> type = elem.getType();
if (type == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(elem.getName())) {
type = specify.clazz;
LOGGER.info("Detect overwrite of typing var={} ... '{}' => '{}'", elem.getName(),
elem.getType().getCanonicalName(), specify.clazz.getCanonicalName());
break;
}
}
}
setValueFromDoc(type, data, elem, doc, lazyCall, options);
}
}
return data;

View File

@ -6,7 +6,6 @@ import java.util.List;
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.DBAccessMorphia;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
@ -17,8 +16,6 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.validation.constraints.NotNull;
public class AddOnDataJson implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnDataJson.class);
@ -74,24 +71,6 @@ public class AddOnDataJson implements DataAccessAddOn {
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 fillFromDoc(
final DBAccessMorphia ioDb,

View File

@ -173,34 +173,6 @@ public class AddOnManyToMany implements DataAccessAddOn {
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];
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()) {
generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options);
}
}
@Override
public void fillFromDoc(
final DBAccessMorphia ioDb,

View File

@ -5,9 +5,9 @@ import java.util.List;
import java.util.UUID;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
@ -16,7 +16,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.NotNull;
public class AddOnManyToOne implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class);
@ -52,7 +51,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
final Document docUnSet) throws Exception {
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
final Object data = field.get(rootObject);
if (field.get(data) == null) {
if (data == null) {
docUnSet.append(fieldName.inTable(), "");
return;
} else if (field.getType() == Long.class) {
@ -70,6 +69,9 @@ public class AddOnManyToOne implements DataAccessAddOn {
} else if (field.getType() == UUID.class) {
final UUID dataTyped = (UUID) data;
docSet.append(fieldName.inTable(), dataTyped);
} else if (field.getType() == ObjectId.class) {
final ObjectId dataTyped = (ObjectId) data;
docSet.append(fieldName.inTable(), dataTyped);
} else {
final Field idField = AnnotationTools.getFieldOfId(field.getType());
final Object uid = idField.get(data);
@ -84,7 +86,8 @@ public class AddOnManyToOne implements DataAccessAddOn {
@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) {
|| field.getType() == String.class || field.getType() == UUID.class
|| field.getType() == ObjectId.class) {
return true;
}
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
@ -103,7 +106,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
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) {
|| classType == String.class || classType == UUID.class || classType == ObjectId.class) {
return true;
}
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
@ -113,36 +116,6 @@ public class AddOnManyToOne implements DataAccessAddOn {
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()) {
// no eager possible for no sql
querySelect.append(" ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(name);
count.inc();
}
}
@Override
public void fillFromDoc(
final DBAccessMorphia ioDb,
@ -159,7 +132,8 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
// local field to manage no remote object to retrieve.
if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class
|| field.getType() == String.class || field.getType() == UUID.class) {
|| field.getType() == String.class || field.getType() == UUID.class
|| field.getType() == ObjectId.class) {
ioDb.setValueFromDoc(field.getType(), data, field, doc, lazyCall, options);
return;
}
@ -174,9 +148,8 @@ public class AddOnManyToOne implements DataAccessAddOn {
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 = doc.getLong(fieldName);
final Long foreignKey = doc.getLong(fieldName.inTable());
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);
@ -189,9 +162,22 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
} 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 = doc.get(fieldName, UUID.class);
final UUID foreignKey = doc.get(fieldName.inTable(), UUID.class);
if (foreignKey != null) {
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 == ObjectId.class) {
// here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ...
final ObjectId foreignKey = doc.get(fieldName.inTable(), ObjectId.class);
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);
@ -221,7 +207,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
final QueryOptions options) throws Exception {
final Class<?> classType = field.getType();
if (classType == Long.class || classType == Integer.class || classType == Short.class
|| classType == String.class || classType == UUID.class) {
|| classType == String.class || classType == UUID.class || classType == ObjectId.class) {
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, classType, options);
} else {

View File

@ -2,62 +2,28 @@ package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
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.bson.Document;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessMorphia;
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<Long> ids) {
final List<Long> 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<Long> getListOfIds(final ResultSet rs, final int iii) throws SQLException {
final String trackString = rs.getString(iii);
if (rs.wasNull()) {
return null;
}
final List<Long> 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;
@ -98,7 +64,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (objectClass == Long.class || objectClass == UUID.class) {
if (objectClass == Long.class || objectClass == UUID.class || objectClass == ObjectId.class) {
return true;
}
final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class);
@ -111,104 +77,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
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 FieldName remoteTablePrimaryKeyName = AnnotationTools
.getFieldName(AnnotationTools.getPrimaryKeyField(targetEntity), options);
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.inTable());
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));
}
}
}
// in first implementation we did not keep the data in the 2 Objects, bun we will do it after to have a faster table interactions.
@Override
public void fillFromDoc(
final DBAccessMorphia ioDb,
@ -222,11 +91,12 @@ public class AddOnOneToMany implements DataAccessAddOn {
return;
}
final String fieldName = AnnotationTools.getFieldName(field, options).inTable();
if (!doc.containsKey(fieldName)) {
field.set(data, null);
return;
}
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
// in step 1 the fields are not stored in the local element
// if (!doc.containsKey(fieldName.inTable())) {
// field.set(data, null);
// return;
// }
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
@ -234,62 +104,46 @@ public class AddOnOneToMany implements DataAccessAddOn {
if (decorators == null) {
return;
}
if (objectClass == Long.class || objectClass == UUID.class) {
final Object value = doc.get(fieldName, field.getType());
if (objectClass == Long.class || objectClass == UUID.class || objectClass == ObjectId.class) {
if (true) {
// DEVELOPMENT step 1 we search all the element in the list:
// get the curentObject primary key
final Field primaryField = AnnotationTools.getPrimaryKeyField(data.getClass());
final String primaryKeyName = AnnotationTools.getFieldNameRaw(primaryField);
final Object primaryKey = doc.get(primaryKeyName, primaryField.getType());
// get the remotes objects
final List<?> returnValue = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(decorators.mappedBy(), "=", primaryKey)));
// extract the primary key of the remote objects
final Field remotePrimaryField = AnnotationTools.getPrimaryKeyField(decorators.targetEntity());
final String remotePrimaryKeyName = AnnotationTools.getFieldNameRaw(remotePrimaryField);
final List<Object> listOfRemoteKeys = new ArrayList<>();
for (final var item : returnValue) {
listOfRemoteKeys.add(remotePrimaryField.get(item));
}
// inject in the current data field
if (listOfRemoteKeys.size() != 0) {
field.set(data, listOfRemoteKeys);
}
} else {
// DEVELOPMENT In step 2 this will work well:
final Object value = doc.get(fieldName.inTable(), field.getType());
field.set(data, value);
}
return;
}
if (objectClass == decorators.targetEntity()) {
Long parentIdTmp = null;
UUID parendUuidTmp = null;
try {
final Object value = doc.get(fieldName);
if (value instanceof final Long valueCasted) {
parentIdTmp = valueCasted;
} else if (value instanceof final UUID valueCasted) {
parendUuidTmp = valueCasted;
}
} catch (final Exception ex) {
LOGGER.error("fail to find the correct type... {}", ex.getMessage());
}
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 (parentId != null) {
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);
}
// Maybe in a second step we do not like this but this way is efficient too.
// get the curentObject primary key
final Field primaryField = AnnotationTools.getPrimaryKeyField(data.getClass());
final String primaryKeyName = AnnotationTools.getFieldNameRaw(primaryField);
final Object primaryKey = doc.get(primaryKeyName, primaryField.getType());
// get the remotes objects
final List<?> returnValue = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(decorators.mappedBy(), "=", primaryKey)));
// inject in the current data field
if (returnValue.size() != 0) {
field.set(data, returnValue);
}
}
}

View File

@ -5,13 +5,10 @@ import java.sql.SQLException;
import java.util.List;
import org.bson.Document;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessMorphia;
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 */
@ -57,16 +54,6 @@ public interface DataAccessAddOn {
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 fillFromDoc(
final DBAccessMorphia ioDb,

View File

@ -16,7 +16,6 @@ import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
@ -254,7 +253,6 @@ public class AddOnDataJson implements DataAccessAddOn {
final Object id,
final String columnList,
final Object remoteKey) throws Exception {
if (ioDb instanceof final DBAccessSQL daSQL) {
final String tableName = AnnotationTools.getTableName(clazz);
final QueryOptions options = new QueryOptions(new OverrideTableName(tableName),
new OptionSpecifyType("id", id.getClass()),
@ -278,10 +276,5 @@ public class AddOnDataJson implements DataAccessAddOn {
}
data.covers = newList;
ioDb.update(data, data.id, List.of("covers"), options.getAllArray());
} else if (ioDb instanceof final DBAccessMorphia dam) {
} else {
throw new DataAccessException("DataAccess Not managed");
}
}
}

View File

@ -9,7 +9,7 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@Table(name = "TypeManyToOneLongRoot")
//for Mongo
//for Morphia
@Entity(value = "TypeManyToOneLongRoot")
public class TypeManyToOneLongRootExpand extends GenericData {