diff --git a/src/org/kar/archidata/GlobalConfiguration.java b/src/org/kar/archidata/GlobalConfiguration.java deleted file mode 100644 index 321c7c9c..0000000 --- a/src/org/kar/archidata/GlobalConfiguration.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.kar.archidata; - -import org.kar.archidata.db.DBConfig; -import org.kar.archidata.tools.ConfigBaseVariable; - -public class GlobalConfiguration { - public static final DBConfig dbConfig; - - static { - dbConfig = new DBConfig(ConfigBaseVariable.getDBType(), ConfigBaseVariable.getDBHost(), - Integer.parseInt(ConfigBaseVariable.getDBPort()), ConfigBaseVariable.getDBLogin(), - ConfigBaseVariable.getDBPassword(), ConfigBaseVariable.getDBName(), - ConfigBaseVariable.getDBKeepConnected()); - } -} diff --git a/src/org/kar/archidata/UserDB.java b/src/org/kar/archidata/UserDB.java deleted file mode 100755 index c7d2e73..0000000 --- a/src/org/kar/archidata/UserDB.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.kar.archidata; - -import java.io.IOException; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.dataAccess.QueryOptions; -import org.kar.archidata.dataAccess.options.DBInterfaceOption; -import org.kar.archidata.dataAccess.options.QueryOption; -import org.kar.archidata.db.DBEntry; -import org.kar.archidata.model.User; - -public class UserDB { - - public UserDB() {} - - public static User getUsers(final long userId, QueryOption... option) throws Exception { - return DataAccess.get(User.class, userId, option); - } - - public static User getUserOrCreate(final long userId, final String userLogin, QueryOption... option) - throws Exception { - final User user = getUsers(userId); - if (user != null) { - return user; - } - createUsersInfoFromOAuth(userId, userLogin, option); - return getUsers(userId); - } - - private static void createUsersInfoFromOAuth(final long userId, final String login, QueryOption... option) - throws IOException { - QueryOptions options = new QueryOptions(option); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')"; - try { - final PreparedStatement ps = entry.connection.prepareStatement(query); - ps.setLong(1, userId); - ps.setString(2, login); - ps.executeUpdate(); - } catch (final SQLException throwables) { - throwables.printStackTrace(); - } finally { - entry.close(); - } - } -} diff --git a/src/org/kar/archidata/annotation/DataComment.java b/src/org/kar/archidata/annotation/DataComment.java deleted file mode 100644 index 711f782..0000000 --- a/src/org/kar/archidata/annotation/DataComment.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.kar.archidata.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ ElementType.TYPE, ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -@Deprecated(since = "0.5.2") -public @interface DataComment { - String value(); -} diff --git a/src/org/kar/archidata/converter/morphia/SqlTimestampCodec.java b/src/org/kar/archidata/converter/morphia/SqlTimestampCodec.java new file mode 100644 index 0000000..e45e364 --- /dev/null +++ b/src/org/kar/archidata/converter/morphia/SqlTimestampCodec.java @@ -0,0 +1,34 @@ +package org.kar.archidata.converter.morphia; + +import java.sql.Timestamp; + +import org.bson.BsonReader; +import org.bson.BsonType; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; + +public class SqlTimestampCodec implements Codec { + + @Override + public void encode( + final BsonWriter writer, + final Timestamp value, + final org.bson.codecs.EncoderContext encoderContext) { + writer.writeDateTime(value.getTime()); + } + + @Override + public Timestamp decode(final BsonReader reader, final org.bson.codecs.DecoderContext decoderContext) { + final BsonType bsonType = reader.getCurrentBsonType(); + if (bsonType == BsonType.DATE_TIME) { + return new Timestamp(reader.readDateTime()); + } else { + throw new IllegalArgumentException("Expected a DATE_TIME but found " + bsonType); + } + } + + @Override + public Class getEncoderClass() { + return Timestamp.class; + } +} diff --git a/src/org/kar/archidata/dataAccess/DBAccess.java b/src/org/kar/archidata/dataAccess/DBAccess.java new file mode 100644 index 0000000..5de1b57 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/DBAccess.java @@ -0,0 +1,333 @@ +package org.kar.archidata.dataAccess; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import org.kar.archidata.annotation.AnnotationTools; +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.QueryOption; +import org.kar.archidata.dataAccess.options.TransmitKey; +import org.kar.archidata.db.DbConfig; +import org.kar.archidata.db.DbIo; +import org.kar.archidata.db.DbIoFactory; +import org.kar.archidata.db.DbIoMorphia; +import org.kar.archidata.db.DbIoSql; +import org.kar.archidata.exception.DataAccessException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import jakarta.ws.rs.InternalServerErrorException; + +/* TODO list: + - Manage to group of SQL action to permit to commit only at the end. + */ + +/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite + * back-end. */ +public abstract class DBAccess implements Closeable { + final static Logger LOGGER = LoggerFactory.getLogger(DBAccess.class); + + public static final DBAccess createInterface() + throws InternalServerErrorException, IOException, DataAccessException { + return DBAccess.createInterface(DbIoFactory.create()); + } + + public static final DBAccess createInterface(final DbConfig config) + throws InternalServerErrorException, IOException { + return DBAccess.createInterface(DbIoFactory.create(config)); + } + + public static final DBAccess createInterface(final DbIo io) throws InternalServerErrorException { + if (io instanceof final DbIoMorphia ioMorphia) { + try { + return new DBAccessMorphia(ioMorphia); + } catch (final IOException e) { + e.printStackTrace(); + throw new InternalServerErrorException("Fail to create DB interface."); + } + } else if (io instanceof final DbIoSql ioSQL) { + try { + return new DBAccessSQL(ioSQL); + } catch (final IOException e) { + e.printStackTrace(); + throw new InternalServerErrorException("Fail to create DB interface."); + } + } + throw new InternalServerErrorException("unknow DB interface ... "); + } + + public boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException { + throw new InternalServerErrorException("Can Not manage the DB-access"); + } + + public boolean createDB(final String name) { + throw new InternalServerErrorException("Can Not manage the DB-access"); + } + + public boolean deleteDB(final String name) { + throw new InternalServerErrorException("Can Not manage the DB-access"); + } + + public boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException { + throw new InternalServerErrorException("Can Not manage the DB-access"); + } + + public QueryCondition getTableIdCondition(final Class clazz, final ID_TYPE idKey) + throws DataAccessException { + // Find the ID field type .... + final Field idField = AnnotationTools.getIdField(clazz); + if (idField == null) { + throw new DataAccessException( + "The class have no annotation @Id ==> can not determine the default type searching"); + } + // check the compatibility of the id and the declared ID + final Class typeClass = idField.getType(); + if (idKey == null) { + throw new DataAccessException("Try to identify the ID type and object was null."); + } + if (idKey.getClass() != typeClass) { + if (idKey.getClass() == Condition.class) { + throw new DataAccessException( + "Try to identify the ID type on a condition 'close' internal API error use xxxWhere(...) instead."); + } + throw new DataAccessException("Request update with the wrong type ..."); + } + return new QueryCondition(AnnotationTools.getFieldName(idField), "=", idKey); + } + + // TODO: manage insert batch... + public List insertMultiple(final List data, final QueryOption... options) throws Exception { + final List out = new ArrayList<>(); + for (final T elem : data) { + final T tmp = insert(elem, options); + out.add(tmp); + } + return out; + } + + abstract public T insert(final T data, final QueryOption... option) throws Exception; + + // seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated... + public T insertWithJson(final Class clazz, final String jsonData) throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + final T data = mapper.readValue(jsonData, clazz); + return insert(data); + } + + /** Update an object with the inserted json data + * + * @param Type of the object to insert + * @param Master key on the object manage with @Id + * @param clazz Class reference of the insertion model + * @param id Key to insert data + * @param jsonData Json data (partial) values to update + * @return the number of object updated + * @throws Exception */ + public long updateWithJson( + final Class clazz, + final ID_TYPE id, + final String jsonData, + final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + options.add(new TransmitKey(id)); + return updateWhereWithJson(clazz, jsonData, options.getAllArray()); + } + + public long updateWhereWithJson(final Class clazz, final String jsonData, final QueryOption... option) + throws Exception { + final QueryOptions options = new QueryOptions(option); + if (options.get(Condition.class).size() == 0) { + throw new DataAccessException("request a updateWhereWithJson without any condition"); + } + final ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + final T data = mapper.readValue(jsonData, clazz); + // Read the tree to filter injection of data: + final JsonNode root = mapper.readTree(jsonData); + final List keys = new ArrayList<>(); + final var iterator = root.fieldNames(); + iterator.forEachRemaining(e -> keys.add(e)); + options.add(new FilterValue(keys)); + return updateWhere(data, options.getAllArray()); + } + + public long update(final T data, final ID_TYPE id) throws Exception { + return update(data, id, AnnotationTools.getFieldsNames(data.getClass())); + } + + /** @param + * @param data + * @param id + * @param filterValue + * @return the affected rows. + * @throws Exception */ + public long update( + final T data, + final ID_TYPE id, + final List updateColomn, + final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(data.getClass(), id))); + options.add(new FilterValue(updateColomn)); + options.add(new TransmitKey(id)); + return updateWhere(data, options); + } + + public long updateWhere(final T data, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + return updateWhere(data, options); + } + + public abstract long updateWhere(final T data, QueryOptions options) throws Exception; + + public T getWhere(final Class clazz, final QueryOptions options) throws Exception { + options.add(new Limit(1)); + final List values = getsWhere(clazz, options); + if (values.size() == 0) { + return null; + } + return values.get(0); + } + + public T getWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + return getWhere(clazz, options); + } + + public List getsWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + return getsWhere(clazz, options); + } + + public Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty) + throws DataAccessException { + if (options == null) { + return new Condition(); + } + final List conditions = options.get(Condition.class); + if (conditions.size() == 0) { + if (throwIfEmpty) { + throw new DataAccessException("request a gets without any condition"); + } else { + return new Condition(); + } + } + Condition condition = null; + if (conditions.size() == 1) { + condition = conditions.get(0); + } else { + final QueryAnd andCondition = new QueryAnd(); + for (final Condition cond : conditions) { + andCondition.add(cond.condition); + } + condition = new Condition(andCondition); + } + return condition; + } + + abstract public List getsWhere(final Class clazz, final QueryOptions options) + throws DataAccessException, IOException; + + public long count(final Class clazz, final ID_TYPE id, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return countWhere(clazz, options); + } + + public long countWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + return countWhere(clazz, options); + } + + public abstract long countWhere(final Class clazz, final QueryOptions options) throws Exception; + + public T get(final Class clazz, final ID_TYPE id, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return getWhere(clazz, options.getAllArray()); + } + + public List gets(final Class clazz) throws Exception { + return getsWhere(clazz); + } + + public List gets(final Class clazz, final QueryOption... option) throws Exception { + return getsWhere(clazz, option); + } + + /** Delete items with the specific Id (cf @Id) and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before). + * @param Type of the reference @Id + * @param clazz Data model that might remove element + * @param id Unique Id of the model + * @param options (Optional) Options of the request + * @return Number of element that is removed. */ + public long delete(final Class clazz, final ID_TYPE id, final QueryOption... options) + throws Exception { + final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + if (hasDeletedFieldName != null) { + return deleteSoft(clazz, id, options); + } else { + return deleteHard(clazz, id, options); + } + } + + /** Delete items with the specific condition and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before). + * @param clazz Data model that might remove element. + * @param condition Condition to remove elements. + * @param options (Optional) Options of the request. + * @return Number of element that is removed. */ + public long deleteWhere(final Class clazz, final QueryOption... option) throws Exception { + final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + if (hasDeletedFieldName != null) { + return deleteSoftWhere(clazz, option); + } else { + return deleteHardWhere(clazz, option); + } + } + + public long deleteHard(final Class clazz, final ID_TYPE id, final QueryOption... option) + throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return deleteHardWhere(clazz, options.getAllArray()); + } + + public abstract long deleteHardWhere(final Class clazz, final QueryOption... option) throws Exception; + + public long deleteSoft(final Class clazz, final ID_TYPE id, final QueryOption... option) + throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return deleteSoftWhere(clazz, options.getAllArray()); + } + + public abstract long deleteSoftWhere(final Class clazz, final QueryOption... option) throws Exception; + + public long unsetDelete(final Class clazz, final ID_TYPE id) throws DataAccessException { + return unsetDeleteWhere(clazz, new Condition(getTableIdCondition(clazz, id))); + } + + public long unsetDelete(final Class clazz, final ID_TYPE id, final QueryOption... option) + throws DataAccessException { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return unsetDeleteWhere(clazz, options.getAllArray()); + } + + public abstract long unsetDeleteWhere(final Class clazz, final QueryOption... option) throws DataAccessException; + + public abstract void drop(final Class clazz, final QueryOption... option) throws Exception; + + public abstract void cleanAll(final Class clazz, final QueryOption... option) throws Exception; + +} diff --git a/src/org/kar/archidata/dataAccess/DBAccessMorphia.java b/src/org/kar/archidata/dataAccess/DBAccessMorphia.java new file mode 100644 index 0000000..7dba8d8 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/DBAccessMorphia.java @@ -0,0 +1,946 @@ +package org.kar.archidata.dataAccess; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +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.CreationTimestamp; +import org.kar.archidata.annotation.UpdateTimestamp; +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; +import org.kar.archidata.dataAccess.options.Limit; +import org.kar.archidata.dataAccess.options.OrderBy; +import org.kar.archidata.dataAccess.options.QueryOption; +import org.kar.archidata.db.DbIoMorphia; +import org.kar.archidata.exception.DataAccessException; +import org.kar.archidata.tools.UuidUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.FindOneAndUpdateOptions; +import com.mongodb.client.model.Projections; +import com.mongodb.client.model.ReturnDocument; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.InsertOneResult; +import com.mongodb.client.result.UpdateResult; + +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.InternalServerErrorException; + +/* TODO list: + - Manage to group of SQL action to permit to commit only at the end. + */ + +/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite + * back-end. */ +public class DBAccessMorphia extends DBAccess { + static final Logger LOGGER = LoggerFactory.getLogger(DBAccessMorphia.class); + // 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 { + //addOn.add(new AddOnManyToMany()); + addOn.add(new AddOnManyToOne()); + addOn.add(new AddOnOneToMany()); + // no need, native support in mango .... addOn.add(new AddOnDataJson()); + } + + /** Add a new add-on on the current management. + * @param addOn instantiate object on the Add-on + */ + public static void addAddOn(final DataAccessAddOn addOn) { + DBAccessMorphia.addOn.add(addOn); + } + + private final DbIoMorphia db; + + public DBAccessMorphia(final DbIoMorphia db) throws IOException { + this.db = db; + db.open(); + } + + @Override + public void close() throws IOException { + this.db.close(); + } + + public DbIoMorphia getInterface() { + return this.db; + } + + @Override + public boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException { + // in Mongo DB we do not need to create a DB, then we have no need to check if it exist + return true; + } + + @Override + public boolean createDB(final String name) { + // in Mongo DB we do not need to create a DB + return true; + } + + @Override + public boolean deleteDB(final String name) { + final MongoDatabase database = this.db.getClient().getDatabase(name); + database.drop(); + return true; + } + + @Override + public boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException { + return true; + } + + public byte[][] splitIntoGroupsOf16Bytes(final byte[] input) { + final int inputLength = input.length; + final int numOfGroups = (inputLength + 15) / 16; // Calculate the number of groups needed + final byte[][] groups = new byte[numOfGroups][16]; + + for (int i = 0; i < numOfGroups; i++) { + final int startIndex = i * 16; + final int endIndex = Math.min(startIndex + 16, inputLength); + groups[i] = Arrays.copyOfRange(input, startIndex, endIndex); + } + + return groups; + } + + protected void setValuedb( + final Class type, + final T data, + final Field field, + final String fieldName, + final Document docSet, + final Document docUnSet) throws Exception { + if (field.get(data) == null) { + docUnSet.append(fieldName, ""); + return; + } + if (type == long.class) { + docSet.append(fieldName, field.getLong(data)); + return; + } + if (type == int.class) { + docSet.append(fieldName, field.getInt(data)); + return; + } + if (type == float.class) { + docSet.append(fieldName, field.getFloat(data)); + return; + } + if (type == Double.class) { + docSet.append(fieldName, field.getDouble(data)); + return; + } + if (type == boolean.class) { + docSet.append(fieldName, field.getBoolean(data)); + return; + } + final Object tmp = field.get(data); + if (tmp == null) { + docUnSet.append(fieldName, ""); + return; + } + if (type.isEnum()) { + docSet.append(fieldName, tmp.toString()); + return; + } + if (type == Long.class) { + docSet.append(fieldName, tmp); + return; + } + if (type == Integer.class) { + docSet.append(fieldName, tmp); + return; + } + if (type == Float.class) { + docSet.append(fieldName, tmp); + return; + } + if (type == Double.class) { + docSet.append(fieldName, tmp); + return; + } + if (type == Boolean.class) { + docSet.append(fieldName, tmp); + return; + } + if (type == String.class) { + docSet.append(fieldName, tmp); + return; + } + if (type == Timestamp.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"); + + } + + public void setValueFromDoc( + final Class type, + final Object data, + final Field field, + final Document doc, + final List lazyCall) throws Exception { + final String fieldName = AnnotationTools.getFieldName(field); + if (!doc.containsKey(fieldName)) { + field.set(data, null); + return; + } + if (type == UUID.class) { + final UUID value = doc.get(fieldName, UUID.class); + field.set(data, value); + return; + } + if (type == Long.class || type == long.class) { + final Long value = doc.getLong(fieldName); + field.set(data, value); + return; + } + if (type == Integer.class || type == int.class) { + final Integer value = doc.getInteger(fieldName); + field.set(data, value); + return; + } + if (type == Float.class || type == float.class) { + final Double value = doc.getDouble(fieldName); + field.set(data, (float) ((double) value)); + return; + } + if (type == Double.class || type == double.class) { + final Double value = doc.getDouble(fieldName); + field.set(data, value); + return; + } + if (type == Boolean.class || type == boolean.class) { + final Boolean value = doc.getBoolean(fieldName); + field.set(data, value); + return; + } + if (type == Timestamp.class) { + final Date value = doc.get(fieldName, Date.class); + final Timestamp newData = new Timestamp(value.getTime()); + field.set(data, newData); + return; + } + if (type == Date.class) { + final Date value = doc.get(fieldName, Date.class); + field.set(data, value); + return; + } + if (type == Instant.class) { + final Date value = doc.get(fieldName, Date.class); + final Instant newData = value.toInstant(); + field.set(data, newData); + return; + } + if (type == LocalDate.class) { + final Date value = doc.get(fieldName, Date.class); + final LocalDate newData = value.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + field.set(data, newData); + return; + } + if (type == LocalTime.class) { + final Long value = doc.getLong(fieldName); + final LocalTime newData = LocalTime.ofNanoOfDay(value); + field.set(data, newData); + return; + } + if (type == String.class) { + final String value = doc.getString(fieldName); + field.set(data, value); + return; + } + if (type == UUID.class) { + final Object value = doc.get(fieldName, field.getType()); + field.set(data, value); + return; + } + if (type.isEnum()) { + final String value = doc.getString(fieldName); + boolean find = false; + final Object[] arr = type.getEnumConstants(); + for (final Object elem : arr) { + if (elem.toString().equals(value)) { + field.set(data, elem); + find = true; + break; + } + } + if (!find) { + throw new DataAccessException("Enum value does not exist in the Model: '" + value + "'"); + } + return; + } + if (List.class == field.getType()) { + 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); + field.set(data, value); + } + + return; + //throw new ArchiveException("wrong type of field [" + fieldName + "]: " + doc.toJson()); + } + + protected Object convertDefaultField(String data, final Field field) throws Exception { + if (data.startsWith("'") && data.endsWith("'")) { + data = data.substring(1, data.length() - 1); + } + final Class type = field.getType(); + if (type == UUID.class) { + + } + if (type == Long.class || type == long.class) { + return Long.parseLong(data); + } + if (type == Integer.class || type == int.class) { + return Integer.parseInt(data); + } + if (type == Float.class || type == float.class) { + return Float.parseFloat(data); + } + if (type == Double.class || type == double.class) { + return Double.parseDouble(data); + } + if (type == Boolean.class || type == boolean.class) { + return Boolean.parseBoolean(data); + } + if (type == Timestamp.class) {} + if (type == Date.class) {} + if (type == Instant.class) {} + if (type == LocalDate.class) {} + if (type == LocalTime.class) {} + if (type == String.class) {} + if (type.isEnum()) { + final boolean find = false; + final Object[] arr = type.getEnumConstants(); + for (final Object elem : arr) { + if (elem.toString().equals(data)) { + return elem; + } + } + if (!find) { + throw new DataAccessException("Enum value does not exist in the Model: '" + data + "'"); + } + } + LOGGER.warn("Request default of unknow native type {} => {}", type.getCanonicalName(), data); + return null; + } + + public boolean isAddOnField(final Field field) { + return findAddOnforField(field) != null; + } + + public DataAccessAddOn findAddOnforField(final Field field) { + for (final DataAccessAddOn elem : addOn) { + if (elem.isCompatibleField(field)) { + return elem; + } + } + return null; + } + + public long getNextSequenceLongValue(final String collectionName, String fieldName) { + if (fieldName == null || fieldName.isEmpty()) { + fieldName = "sequence_id"; + } + // Collection "counters" to store the sequences if Ids + final MongoCollection countersCollection = this.db.getDatastore().getDatabase() + .getCollection("counters"); + + // Filter to find the specific counter for the collections + final Document filter = new Document("_id", collectionName); + + // Update the field of 1 + final Document update = new Document("$inc", new Document(fieldName, 1L)); + + // get the value after updated it + final FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER) + .upsert(true); // create field if not exist + + // Real creation of the unique counter. + final Document updatedCounter = countersCollection.findOneAndUpdate(filter, update, options); + + // Return the new sequence value... + return updatedCounter.getLong(fieldName); + } + + @Override + @SuppressWarnings("unchecked") + public T insert(final T data, final QueryOption... option) throws Exception { + final Class clazz = data.getClass(); + final QueryOptions options = new QueryOptions(option); + + // External checker of data: + final List checks = options.get(CheckFunction.class); + for (final CheckFunction check : checks) { + check.getChecker().check(this, "", data, AnnotationTools.getFieldsNames(clazz), options); + } + + final List asyncFieldUpdate = new ArrayList<>(); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + Field primaryKeyField = null; + Object uniqueId = null; + // real add in the BDD: + ObjectId insertedId = null; + try { + final MongoCollection collection = this.db.getDatastore().getDatabase() + .getCollection(collectionName); + final Document doc = 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); + 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); + 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); + uniqueId = id; + doc.append(tableFieldName, id); + continue; + } + LOGGER.error("TODO: Manage the ID primary key for type: "); + continue; + } + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { + if (addOn.isInsertAsync(field)) { + LOGGER.error("TODO: add async objects ..."); + //asyncFieldUpdate.add(field); + } + 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 { + final String value = defaultValue[0].value(); + if (value == null) { + continue; + } + currentInsertValue = convertDefaultField(value, field); + } + } + doc.append(tableFieldName, currentInsertValue); + } + final InsertOneResult result = collection.insertOne(doc); + // Get the Object of inserted object: + insertedId = result.getInsertedId().asObjectId().getValue(); + LOGGER.info("Document inserted with ID: " + insertedId); + + // Rechercher et récupérer le document inséré à partir de son ObjectId + final Document insertedDocument = collection.find(new Document("_id", insertedId)).first(); + + // Afficher le document récupéré + System.out.println("Inserted document: " + insertedDocument); + + } catch (final Exception ex) { + LOGGER.error("Fail SQL request: {}", ex.getMessage()); + ex.printStackTrace(); + throw new DataAccessException("Fail to Insert data in DB : " + ex.getMessage()); + } + final List asyncActions = new ArrayList<>(); + for (final Field field : asyncFieldUpdate) { + final DataAccessAddOn addOn = findAddOnforField(field); + if (uniqueId instanceof final Long id) { + LOGGER.error("TODO: Add on not managed .1. "); + //addOn.asyncInsert(tableName, id, field, field.get(data), asyncActions); + } else if (uniqueId instanceof final UUID uuid) { + LOGGER.error("TODO: Add on not managed .2. "); + //addOn.asyncInsert(tableName, uuid, field, field.get(data), asyncActions); + } + } + for (final LazyGetter action : asyncActions) { + action.doRequest(); + } + return (T) getWhere(clazz, new Condition(new QueryCondition("_id", "=", insertedId))); + } + + @Override + public long updateWhere(final T data, QueryOptions options) throws Exception { + final Class clazz = data.getClass(); + if (options == null) { + options = new QueryOptions(); + } + final Condition condition = conditionFusionOrEmpty(options, true); + final List filterKeys = options != null ? options.get(FilterValue.class) : new ArrayList<>(); + if (filterKeys.size() != 1) { + throw new DataAccessException("request a gets without/or with more 1 filter of values"); + } + final FilterValue filterKey = filterKeys.get(0); + // External checker of data: + if (options != null) { + final List checks = options.get(CheckFunction.class); + for (final CheckFunction check : checks) { + check.getChecker().check(this, "", data, filterKey.getValues(), options); + } + } + final List asyncActions = new ArrayList<>(); + + // real add in the BDD: + try { + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + final Bson filters = condition.getFilter(collectionName, options, deletedFieldName); + 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 fieldName = AnnotationTools.getFieldName(field); + // 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())); + continue; + } + if (!filterKey.getValues().contains(fieldName)) { + continue; + } else if (AnnotationTools.isGenericField(field)) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { + if (addOn.isInsertAsync(field)) { + LOGGER.error("TODO: Add on not managed .3. "); + /* + final List transmitKey = options.get(TransmitKey.class); + if (transmitKey.size() != 1) { + throw new DataAccessException( + "Fail to transmit Key to update the async update... (must have only 1)"); + } + addOn.asyncUpdate(tableName, transmitKey.get(0).getKey(), field, field.get(data), asyncActions); + */ + } + continue; + } + if (addOn != null) { + addOn.insertData(this, field, data, docSet, docUnSet); + } else { + final Class type = field.getType(); + if (!type.isPrimitive()) { + final Object tmp = field.get(data); + if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { + continue; + } + } + setValuedb(type, data, field, fieldName, docSet, docUnSet); + } + + } + // Do the query ... + + final MongoCollection collection = this.db.getDatastore().getDatabase() + .getCollection(collectionName); + final Document actions = new Document(); + if (!docSet.isEmpty()) { + actions.append("$set", docSet); + } + if (!docUnSet.isEmpty()) { + actions.append("$unset", docUnSet); + } + LOGGER.info("updateWhere with value: {}", actions.toJson()); + final UpdateResult ret = collection.updateMany(filters, actions); + return ret.getModifiedCount(); + } catch (final Exception ex) { + ex.printStackTrace(); + } + for (final LazyGetter action : asyncActions) { + action.doRequest(); + } + return 0; + } + + public List generateSelectField(final Class clazz, final QueryOptions options) throws Exception { + // TODO: list of user select fields. + final boolean readAllfields = QueryOptions.readAllColomn(options); + final List fieldsName = new ArrayList<>(); + + for (final Field elem : clazz.getFields()) { + // static field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(elem); + if (addOn != null && !addOn.canRetrieve(elem)) { + continue; + } + final boolean notRead = AnnotationTools.isdefaultNotRead(elem); + if (!readAllfields && notRead) { + continue; + } + final String name = AnnotationTools.getFieldName(elem); + fieldsName.add(name); + } + return fieldsName; + } + + @Override + public Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty) + throws DataAccessException { + if (options == null) { + return new Condition(); + } + final List conditions = options.get(Condition.class); + if (conditions.size() == 0) { + if (throwIfEmpty) { + throw new DataAccessException("request a gets without any condition"); + } else { + return new Condition(); + } + } + Condition condition = null; + if (conditions.size() == 1) { + condition = conditions.get(0); + } else { + final QueryAnd andCondition = new QueryAnd(); + for (final Condition cond : conditions) { + andCondition.add(cond.condition); + } + condition = new Condition(andCondition); + } + return condition; + } + + @Override + @SuppressWarnings("unchecked") + public List getsWhere(final Class clazz, final QueryOptions options) + throws DataAccessException, IOException { + + final Condition condition = conditionFusionOrEmpty(options, false); + final List lazyCall = new ArrayList<>(); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + final List outs = new ArrayList<>(); + final MongoCollection collection = this.db.getDatastore().getDatabase().getCollection(collectionName); + try { + // Generate the filtering of the data: + final Bson filters = condition.getFilter(collectionName, options, deletedFieldName); + FindIterable retFind = null; + if (filters != null) { + //LOGGER.info("getsWhere Find filter: {}", filters.toBsonDocument().toJson()); + retFind = collection.find(filters); + } else { + retFind = collection.find(); + } + /* Not manage right now ... + final List groups = options.get(GroupBy.class); + for (final GroupBy group : groups) { + group.generateQuery(query, tableName); + } + */ + final List orders = options.get(OrderBy.class); + if (orders.size() != 0) { + final Document sorts = new Document(); + for (final OrderBy order : orders) { + order.generateSort(sorts); + } + retFind = retFind.sort(sorts); + } + + final List limits = options.get(Limit.class); + if (limits.size() == 1) { + retFind = retFind.limit((int) limits.get(0).getValue()); + } else if (limits.size() > 1) { + throw new DataAccessException("Request with multiple 'limit'..."); + } + // Select values to read + final List listFields = generateSelectField(clazz, options); + listFields.add("_id"); + retFind = retFind.projection(Projections.include(listFields.toArray(new String[0]))); + + LOGGER.info("GetsWhere ..."); + final MongoCursor cursor = retFind.iterator(); + try (cursor) { + while (cursor.hasNext()) { + final Document doc = cursor.next(); + LOGGER.info(" - getWhere value: {}", doc.toJson()); + final Object data = createObjectFromDocument(doc, clazz, options, lazyCall); + final T out = (T) data; + outs.add(out); + } + LOGGER.info("Async calls: {}", lazyCall.size()); + for (final LazyGetter elem : lazyCall) { + elem.doRequest(); + } + } + } catch (final Exception ex) { + ex.printStackTrace(); + throw new DataAccessException("Catch an Exception: " + ex.getMessage()); + } + return outs; + } + + public Object createObjectFromDocument( + final Document doc, + final Class clazz, + final QueryOptions options, + final List lazyCall) throws Exception { + final boolean readAllfields = QueryOptions.readAllColomn(options); + // TODO: manage class that is defined inside a class ==> Not manage for now... + Object data = null; + for (final Constructor contructor : clazz.getConstructors()) { + if (contructor.getParameterCount() == 0) { + data = contructor.newInstance(); + break; + } + } + if (data == null) { + throw new DataAccessException( + "Can not find the default constructor for the class: " + clazz.getCanonicalName()); + } + for (final Field elem : clazz.getFields()) { + // static field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(elem); + if (addOn != null && !addOn.canRetrieve(elem)) { + continue; + } + final boolean notRead = AnnotationTools.isdefaultNotRead(elem); + if (!readAllfields && notRead) { + 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); + } + } + return data; + } + + @Override + public long count(final Class clazz, final ID_TYPE id, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return this.countWhere(clazz, options); + } + + @Override + public long countWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + return countWhere(clazz, options); + } + + @Override + public long countWhere(final Class clazz, final QueryOptions options) throws Exception { + final Condition condition = conditionFusionOrEmpty(options, false); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + final MongoCollection collection = this.db.getDatastore().getDatabase().getCollection(collectionName); + try { + // Generate the filtering of the data: + final Bson filters = condition.getFilter(collectionName, options, deletedFieldName); + if (filters != null) { + return collection.countDocuments(filters); + } + return collection.countDocuments(); + } catch (final Exception ex) { + ex.printStackTrace(); + throw new DataAccessException("Catch an Exception: " + ex.getMessage()); + } + } + + @Override + public T get(final Class clazz, final ID_TYPE id, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return this.getWhere(clazz, options.getAllArray()); + } + + @Override + public long deleteHard(final Class clazz, final ID_TYPE id, final QueryOption... option) + throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return deleteHardWhere(clazz, options.getAllArray()); + } + + @Override + public long deleteHardWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final Condition condition = conditionFusionOrEmpty(options, true); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + final MongoCollection collection = this.db.getDatastore().getDatabase().getCollection(collectionName); + final Bson filters = condition.getFilter(collectionName, options, deletedFieldName); + DeleteResult retFind; + if (filters != null) { + retFind = collection.deleteMany(filters); + } else { + throw new DataAccessException("Too dangerout to delete element with no filter values !!!"); + } + return retFind.getDeletedCount(); + } + + @Override + public long deleteSoft(final Class clazz, final ID_TYPE id, final QueryOption... option) + throws Exception { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return deleteSoftWhere(clazz, options.getAllArray()); + } + + @Override + public long deleteSoftWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final Condition condition = conditionFusionOrEmpty(options, true); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + final MongoCollection collection = this.db.getDatastore().getDatabase().getCollection(collectionName); + final Bson filters = condition.getFilter(collectionName, options, deletedFieldName); + final Document actions = new Document("$set", new Document(deletedFieldName, true)); + LOGGER.info("update some values: {}", actions.toJson()); + final UpdateResult ret = collection.updateMany(filters, actions); + return ret.getModifiedCount(); + } + + @Override + public long unsetDelete(final Class clazz, final ID_TYPE id) throws DataAccessException { + return unsetDeleteWhere(clazz, new Condition(getTableIdCondition(clazz, id))); + } + + @Override + public long unsetDelete(final Class clazz, final ID_TYPE id, final QueryOption... option) + throws DataAccessException { + final QueryOptions options = new QueryOptions(option); + options.add(new Condition(getTableIdCondition(clazz, id))); + return unsetDeleteWhere(clazz, options.getAllArray()); + } + + @Override + public long unsetDeleteWhere(final Class clazz, final QueryOption... option) throws DataAccessException { + final QueryOptions options = new QueryOptions(option); + final Condition condition = conditionFusionOrEmpty(options, true); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + if (deletedFieldName == null) { + throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field"); + } + final MongoCollection collection = this.db.getDatastore().getDatabase().getCollection(collectionName); + final Bson filters = condition.getFilter(collectionName, options, deletedFieldName); + final Document actions = new Document("$set", new Document(deletedFieldName, false)); + LOGGER.info("update some values: {}", actions.toJson()); + final UpdateResult ret = collection.updateMany(filters, actions); + return ret.getModifiedCount(); + } + + @Override + public void drop(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + final MongoCollection collection = this.db.getDatastore().getDatabase().getCollection(collectionName); + collection.drop(); + } + + @Override + public void cleanAll(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final String collectionName = AnnotationTools.getCollectionName(clazz, options); + final MongoCollection collection = this.db.getDatastore().getDatabase().getCollection(collectionName); + collection.deleteMany(new Document()); + } + +} diff --git a/src/org/kar/archidata/dataAccess/DBAccessSQL.java b/src/org/kar/archidata/dataAccess/DBAccessSQL.java new file mode 100644 index 0000000..98d4f61 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/DBAccessSQL.java @@ -0,0 +1,1639 @@ +package org.kar.archidata.dataAccess; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +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.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; +import org.kar.archidata.dataAccess.options.FilterValue; +import org.kar.archidata.dataAccess.options.GroupBy; +import org.kar.archidata.dataAccess.options.Limit; +import org.kar.archidata.dataAccess.options.OrderBy; +import org.kar.archidata.dataAccess.options.QueryOption; +import org.kar.archidata.dataAccess.options.TransmitKey; +import org.kar.archidata.db.DbIoSql; +import org.kar.archidata.exception.DataAccessException; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.kar.archidata.tools.DateTools; +import org.kar.archidata.tools.UuidUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.InternalServerErrorException; + +/* TODO list: + - Manage to group of SQL action to permit to commit only at the end. + */ + +/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite + * back-end. */ +public class DBAccessSQL extends DBAccess { + final static Logger LOGGER = LoggerFactory.getLogger(DBAccessSQL.class); + // by default we manage some add-on that permit to manage non-native model (like json serialization, List of external key as String list...) + final static List addOn = new ArrayList<>(); + + { + 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 */ + public static void addAddOn(final DataAccessAddOn addOn) { + DBAccessSQL.addOn.add(addOn); + } + + private final DbIoSql db; + + public DBAccessSQL(final DbIoSql db) throws IOException { + this.db = db; + db.open(); + } + + @Override + public void close() throws IOException { + this.db.close(); + } + + public Connection getConnection() { + return this.db.getConnection(); + } + + @Override + public boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException { + final QueryOptions options = new QueryOptions(option); + if ("sqlite".equals(ConfigBaseVariable.getDBType())) { + // no base manage in sqLite ... + // TODO: check if the file exist or not ... + return true; + } + try (final PreparedStatement ps = getConnection().prepareStatement("show databases")) { + // TODO : Maybe connect with a temporary not specified connection interface to a db ... + final ResultSet rs = ps.executeQuery(); + // LOGGER.info("List all tables: equals? '{}'", name); + while (rs.next()) { + final String data = rs.getString(1); + // LOGGER.info(" - '{}'", data); + if (name.equals(data)) { + return true; + } + } + return false; + } catch (final SQLException ex) { + LOGGER.error("Can not check if the DB exist SQL-error !!! {}", ex.getMessage()); + } + throw new InternalServerErrorException("Can Not manage the DB-access"); + } + + @Override + public boolean createDB(final String name) { + if ("sqlite".equals(ConfigBaseVariable.getDBType())) { + // no base manage in sqLite ... + // TODO: check if the file exist or not ... + return true; + } + try { + return 1 == executeSimpleQuery("CREATE DATABASE `" + name + "`;", new DBInterfaceRoot(true)); + } catch (final SQLException | IOException ex) { + ex.printStackTrace(); + LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); + return false; + } + } + + @Override + public boolean deleteDB(final String name) { + if ("sqlite".equals(ConfigBaseVariable.getDBType())) { + // no base manage in sqLite ... + // TODO: check if the file exist or not ... + return true; + } + try { + return 1 == executeSimpleQuery("DROP DATABASE `" + name + "`;", new DBInterfaceRoot(true)); + } catch (final SQLException | IOException ex) { + //ex.printStackTrace(); + LOGGER.error("Can not drop the DB!!! {}", ex.getMessage()); + } + return false; + } + + @Override + public boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException { + final QueryOptions options = new QueryOptions(option); + try { + String request = ""; + if ("sqlite".equals(ConfigBaseVariable.getDBType())) { + request = """ + SELECT COUNT(*) AS total + FROM sqlite_master + WHERE type = 'table' + AND name = ?; + """; + final PreparedStatement ps = this.db.getConnection().prepareStatement(request); + ps.setString(1, name); + final ResultSet ret = ps.executeQuery(); + final int count = ret.getInt("total"); + return count == 1; + } else { + // TODO : Maybe connect with a temporary not specified connection interface to a db ... + final PreparedStatement ps = this.db.getConnection() + .prepareStatement("SHOW TABLES IN `" + this.db.getCongig().getDbName() + "`"); + final ResultSet rs = ps.executeQuery(); + // LOGGER.info("List all tables: equals? '{}'", name); + while (rs.next()) { + final String data = rs.getString(1); + // LOGGER.info(" - '{}'", data); + if (name.equals(data)) { + return true; + } + } + return false; + } + } catch (final SQLException ex) { + LOGGER.error("Can not check if the table exist SQL-error !!! {}", ex.getMessage()); + } + throw new InternalServerErrorException("Can Not manage the DB-access"); + } + + /** Extract a list of Long with "-" 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. */ + public List getListOfIds(final ResultSet rs, final int iii, final String separator) throws SQLException { + final String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + final List out = new ArrayList<>(); + final String[] elements = trackString.split(separator); + for (final String elem : elements) { + final Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + + /** Extract a list of UUID with "-" 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. */ + public List getListOfUUIDs(final ResultSet rs, final int iii, final String separator) throws SQLException { + final String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + final List out = new ArrayList<>(); + final String[] elements = trackString.split(separator); + for (final String elem : elements) { + final UUID tmp = UUID.fromString(elem); + out.add(tmp); + } + return out; + } + + public byte[][] splitIntoGroupsOf16Bytes(final byte[] input) { + final int inputLength = input.length; + final int numOfGroups = (inputLength + 15) / 16; // Calculate the number of groups needed + final byte[][] groups = new byte[numOfGroups][16]; + + for (int i = 0; i < numOfGroups; i++) { + final int startIndex = i * 16; + final int endIndex = Math.min(startIndex + 16, inputLength); + groups[i] = Arrays.copyOfRange(input, startIndex, endIndex); + } + + return groups; + } + + public List getListOfRawUUIDs(final ResultSet rs, final int iii) throws SQLException, DataAccessException { + final byte[] trackString = rs.getBytes(iii); + if (rs.wasNull()) { + return null; + } + final byte[][] elements = splitIntoGroupsOf16Bytes(trackString); + final List out = new ArrayList<>(); + for (final byte[] elem : elements) { + final UUID tmp = UuidUtils.asUuid(elem); + out.add(tmp); + } + return out; + } + + public UUID getListOfRawUUID(final ResultSet rs, final int iii) throws SQLException, DataAccessException { + final byte[] elem = rs.getBytes(iii); + if (rs.wasNull()) { + return null; + } + return UuidUtils.asUuid(elem); + } + + protected void setValuedb( + final Class type, + final T data, + final CountInOut iii, + final Field field, + final PreparedStatement ps) throws Exception { + if (type == UUID.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.BINARY); + } else { + final byte[] dataByte = UuidUtils.asBytes((UUID) tmp); + ps.setBytes(iii.value, dataByte); + } + } else if (type == Long.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.BIGINT); + } else { + ps.setLong(iii.value, (Long) tmp); + } + } else if (type == long.class) { + ps.setLong(iii.value, field.getLong(data)); + } else if (type == Integer.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.INTEGER); + } else { + ps.setInt(iii.value, (Integer) tmp); + } + } else if (type == int.class) { + ps.setInt(iii.value, field.getInt(data)); + } else if (type == Float.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.FLOAT); + } else { + ps.setFloat(iii.value, (Float) tmp); + } + } else if (type == float.class) { + ps.setFloat(iii.value, field.getFloat(data)); + } else if (type == Double.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.DOUBLE); + } else { + ps.setDouble(iii.value, (Double) tmp); + } + } else if (type == Double.class) { + ps.setDouble(iii.value, field.getDouble(data)); + } else if (type == Boolean.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.INTEGER); + } else { + ps.setBoolean(iii.value, (Boolean) tmp); + } + } else if (type == boolean.class) { + ps.setBoolean(iii.value, field.getBoolean(data)); + } else if (type == Timestamp.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.INTEGER); + } else { + ps.setTimestamp(iii.value, (Timestamp) tmp); + } + } else if (type == Date.class) { + 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); + } + } else 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); + } + } else 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); + } + } else 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); + } + } else if (type == String.class) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.VARCHAR); + } else { + ps.setString(iii.value, (String) tmp); + } + } else if (type.isEnum()) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(iii.value, Types.VARCHAR); + } else { + ps.setString(iii.value, tmp.toString()); + } + } else { + throw new DataAccessException("Unknown Field Type"); + } + iii.inc(); + } + + protected void setValueFromDb( + final Class type, + final Object data, + final CountInOut count, + final Field field, + final ResultSet rs, + final CountInOut countNotNull) throws Exception { + if (type == UUID.class) { + final byte[] tmp = rs.getBytes(count.value); + // final UUID tmp = rs.getObject(count.value, UUID.class); + if (rs.wasNull()) { + field.set(data, null); + } else { + // field.set(data, tmp); + final UUID uuid = UuidUtils.asUuid(tmp); + field.set(data, uuid); + countNotNull.inc(); + } + } else if (type == Long.class) { + final Long tmp = rs.getLong(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + countNotNull.inc(); + } + } else if (type == long.class) { + final Long tmp = rs.getLong(count.value); + if (rs.wasNull()) { + // field.set(data, null); + } else { + field.setLong(data, tmp); + countNotNull.inc(); + } + } else if (type == Integer.class) { + final Integer tmp = rs.getInt(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + countNotNull.inc(); + } + } else if (type == int.class) { + final Integer tmp = rs.getInt(count.value); + if (rs.wasNull()) { + // field.set(data, null); + } else { + field.setInt(data, tmp); + countNotNull.inc(); + } + } else if (type == Float.class) { + final Float tmp = rs.getFloat(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + countNotNull.inc(); + } + } else if (type == float.class) { + final Float tmp = rs.getFloat(count.value); + if (rs.wasNull()) { + // field.set(data, null); + } else { + field.setFloat(data, tmp); + countNotNull.inc(); + } + } else if (type == Double.class) { + final Double tmp = rs.getDouble(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + countNotNull.inc(); + } + } else if (type == double.class) { + final Double tmp = rs.getDouble(count.value); + if (rs.wasNull()) { + // field.set(data, null); + } else { + field.setDouble(data, tmp); + countNotNull.inc(); + } + } else if (type == Boolean.class) { + final Boolean tmp = rs.getBoolean(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + countNotNull.inc(); + } + } else if (type == boolean.class) { + final Boolean tmp = rs.getBoolean(count.value); + if (rs.wasNull()) { + // field.set(data, null); + } else { + field.setBoolean(data, tmp); + countNotNull.inc(); + } + } else if (type == Timestamp.class) { + final Timestamp tmp = rs.getTimestamp(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + countNotNull.inc(); + } + } else if (type == Date.class) { + try { + final Timestamp tmp = rs.getTimestamp(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, Date.from(tmp.toInstant())); + countNotNull.inc(); + } + } catch (final SQLException ex) { + final String tmp = rs.getString(count.value); + LOGGER.error("Fail to parse the SQL time !!! {}", tmp); + if (rs.wasNull()) { + field.set(data, null); + } else { + final Date date = DateTools.parseDate(tmp); + LOGGER.error("Fail to parse the SQL time !!! {}", date); + field.set(data, date); + countNotNull.inc(); + } + } + } else if (type == Instant.class) { + final String tmp = rs.getString(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, Instant.parse(tmp)); + countNotNull.inc(); + } + } else if (type == LocalDate.class) { + final java.sql.Date tmp = rs.getDate(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp.toLocalDate()); + countNotNull.inc(); + } + } else if (type == LocalTime.class) { + final java.sql.Time tmp = rs.getTime(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp.toLocalTime()); + countNotNull.inc(); + } + } else if (type == String.class) { + final String tmp = rs.getString(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + countNotNull.inc(); + } + } else if (type.isEnum()) { + final String tmp = rs.getString(count.value); + if (rs.wasNull()) { + field.set(data, null); + } else { + boolean find = false; + final Object[] arr = type.getEnumConstants(); + for (final Object elem : arr) { + if (elem.toString().equals(tmp)) { + field.set(data, elem); + countNotNull.inc(); + find = true; + break; + } + } + if (!find) { + throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'"); + } + } + } else { + throw new DataAccessException("Unknown Field Type"); + } + count.inc(); + } + + // TODO: this function will replace the previous one !!! + protected RetreiveFromDB createSetValueFromDbCallback(final int count, final Field field) throws Exception { + final Class type = field.getType(); + if (type == UUID.class) { + return (final ResultSet rs, final Object obj) -> { + + final byte[] tmp = rs.getBytes(count); + // final UUID tmp = rs.getObject(count, UUID.class); + if (rs.wasNull()) { + field.set(obj, null); + } else { + // field.set(obj, tmp); + final UUID uuid = UuidUtils.asUuid(tmp); + field.set(obj, uuid); + } + }; + } + if (type == Long.class) { + return (final ResultSet rs, final Object obj) -> { + final Long tmp = rs.getLong(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp); + } + }; + } + if (type == long.class) { + return (final ResultSet rs, final Object obj) -> { + final Long tmp = rs.getLong(count); + if (rs.wasNull()) { + // field.set(data, null); + } else { + field.setLong(obj, tmp); + } + }; + } + if (type == Integer.class) { + return (final ResultSet rs, final Object obj) -> { + final Integer tmp = rs.getInt(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp); + } + }; + } + if (type == int.class) { + return (final ResultSet rs, final Object obj) -> { + final Integer tmp = rs.getInt(count); + if (rs.wasNull()) { + // field.set(obj, null); + } else { + field.setInt(obj, tmp); + } + }; + } + if (type == Float.class) { + return (final ResultSet rs, final Object obj) -> { + final Float tmp = rs.getFloat(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp); + } + }; + } + if (type == float.class) { + return (final ResultSet rs, final Object obj) -> { + final Float tmp = rs.getFloat(count); + if (rs.wasNull()) { + // field.set(obj, null); + } else { + field.setFloat(obj, tmp); + } + }; + } + if (type == Double.class) { + return (final ResultSet rs, final Object obj) -> { + final Double tmp = rs.getDouble(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp); + } + }; + } + if (type == double.class) { + return (final ResultSet rs, final Object obj) -> { + final Double tmp = rs.getDouble(count); + if (rs.wasNull()) { + // field.set(obj, null); + } else { + field.setDouble(obj, tmp); + } + }; + } + if (type == Boolean.class) { + return (final ResultSet rs, final Object obj) -> { + final Boolean tmp = rs.getBoolean(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp); + } + }; + } + if (type == boolean.class) { + return (final ResultSet rs, final Object obj) -> { + final Boolean tmp = rs.getBoolean(count); + if (rs.wasNull()) { + // field.set(obj, null); + } else { + field.setBoolean(obj, tmp); + } + }; + } + if (type == Timestamp.class) { + return (final ResultSet rs, final Object obj) -> { + final Timestamp tmp = rs.getTimestamp(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp); + } + }; + } + if (type == Date.class) { + return (final ResultSet rs, final Object obj) -> { + try { + final Timestamp tmp = rs.getTimestamp(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, Date.from(tmp.toInstant())); + } + } catch (final SQLException ex) { + final String tmp = rs.getString(count); + LOGGER.error("Fail to parse the SQL time !!! {}", tmp); + if (rs.wasNull()) { + field.set(obj, null); + } else { + final Date date = DateTools.parseDate(tmp); + LOGGER.error("Fail to parse the SQL time !!! {}", date); + field.set(obj, date); + } + } + }; + } + if (type == Instant.class) { + return (final ResultSet rs, final Object obj) -> { + final String tmp = rs.getString(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, Instant.parse(tmp)); + } + }; + } + if (type == LocalDate.class) { + return (final ResultSet rs, final Object obj) -> { + final java.sql.Date tmp = rs.getDate(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp.toLocalDate()); + } + }; + } + if (type == LocalTime.class) { + return (final ResultSet rs, final Object obj) -> { + final java.sql.Time tmp = rs.getTime(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp.toLocalTime()); + } + }; + } + if (type == String.class) { + return (final ResultSet rs, final Object obj) -> { + final String tmp = rs.getString(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + field.set(obj, tmp); + } + }; + } + if (type.isEnum()) { + return (final ResultSet rs, final Object obj) -> { + final String tmp = rs.getString(count); + if (rs.wasNull()) { + field.set(obj, null); + } else { + boolean find = false; + final Object[] arr = type.getEnumConstants(); + for (final Object elem : arr) { + if (elem.toString().equals(tmp)) { + field.set(obj, elem); + find = true; + break; + } + } + if (!find) { + throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'"); + } + } + }; + } + throw new DataAccessException("Unknown Field Type"); + + } + + public static boolean isAddOnField(final Field field) { + return findAddOnforField(field) != null; + } + + public static DataAccessAddOn findAddOnforField(final Field field) { + for (final DataAccessAddOn elem : addOn) { + if (elem.isCompatibleField(field)) { + return elem; + } + } + return null; + } + + @Override + @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") + public T insert(final T data, final QueryOption... option) throws Exception { + final Class clazz = data.getClass(); + final QueryOptions options = new QueryOptions(option); + + // External checker of data: + final List checks = options.get(CheckFunction.class); + for (final CheckFunction check : checks) { + check.getChecker().check(this, "", data, AnnotationTools.getFieldsNames(clazz), options); + } + final List asyncFieldUpdate = new ArrayList<>(); + Long uniqueSQLID = null; + UUID uniqueSQLUUID = null; + final String tableName = AnnotationTools.getTableName(clazz, options); + Field primaryKeyField = null; + boolean generateUUID = false; + // real add in the BDD: + try { + // boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + final StringBuilder query = new StringBuilder(); + query.append("INSERT INTO `"); + query.append(tableName); + query.append("` ("); + + boolean firstField = true; + int count = 0; + for (final Field field : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + continue; + } + if (AnnotationTools.isPrimaryKey(field)) { + primaryKeyField = field; + if (primaryKeyField.getType() != UUID.class) { + break; + } + generateUUID = true; + count++; + final String name = AnnotationTools.getFieldName(field); + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" `"); + query.append(name); + query.append("`"); + break; + } + } + for (final Field field : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + continue; + } + if (AnnotationTools.isPrimaryKey(field)) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { + if (addOn.isInsertAsync(field)) { + asyncFieldUpdate.add(field); + } + continue; + } + final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; + if (createTime) { + continue; + } + final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; + if (updateTime) { + continue; + } + if (!field.getClass().isPrimitive()) { + final Object tmp = field.get(data); + if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { + continue; + } + } + count++; + final String name = AnnotationTools.getFieldName(field); + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" `"); + query.append(name); + query.append("`"); + } + firstField = true; + query.append(") VALUES ("); + for (int iii = 0; iii < count; iii++) { + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append("?"); + } + query.append(")"); + final List orders = options.get(OrderBy.class); + for (final OrderBy order : orders) { + order.generateQuery(query, tableName); + } + LOGGER.debug("generate the query: '{}'", query.toString()); + // prepare the request: + final PreparedStatement ps = getConnection().prepareStatement(query.toString(), + Statement.RETURN_GENERATED_KEYS); + + final CountInOut iii = new CountInOut(1); + UUID uuid = null; + if (generateUUID) { + firstField = false; + // uuid = UUID.randomUUID(); + uuid = UuidUtils.nextUUID(); + addElement(ps, uuid, iii); + iii.inc(); + } + for (final Field elem : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; + } + if (AnnotationTools.isPrimaryKey(elem)) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(elem); + if (addOn != null && !addOn.canInsert(elem)) { + continue; + } + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; + if (createTime) { + continue; + } + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; + if (updateTime) { + continue; + } + if (addOn != null) { + // Add-on specific insertion. + addOn.insertData(this, ps, elem, data, iii); + } else { + // Generic class insertion... + final Class type = elem.getType(); + if (!type.isPrimitive()) { + final Object tmp = elem.get(data); + if (tmp == null && elem.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { + continue; + } + } + setValuedb(type, data, iii, elem, ps); + } + count++; + } + // execute the request + final int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating node failed, no rows affected."); + } + // Retrieve uid inserted + if (generateUUID) { + // we generate the UUID, otherwise we can not retrieve it + uniqueSQLUUID = uuid; + } else { + try (ResultSet generatedKeys = ps.getGeneratedKeys()) { + if (generatedKeys.next()) { + if (primaryKeyField.getType() == UUID.class) { + // uniqueSQLUUID = generatedKeys.getObject(1, UUID.class); + /* final Object obj = generatedKeys.getObject(1); final BigInteger bigint = (BigInteger) generatedKeys.getObject(1); uniqueSQLUUID = UuidUtils.asUuid(bigint); final UUID + * generatedUUID = (UUID) generatedKeys.getObject(1); System.out.println("UUID généré: " + generatedUUID); */ + //final Object obj = generatedKeys.getObject(1); + final byte[] tmpid = generatedKeys.getBytes(1); + uniqueSQLUUID = UuidUtils.asUuid(tmpid); + } else { + uniqueSQLID = generatedKeys.getLong(1); + } + } else { + throw new SQLException("Creating node failed, no ID obtained (1)."); + } + } catch (final Exception ex) { + LOGGER.error("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating node failed, no ID obtained (2)."); + } + } + ps.close(); + if (primaryKeyField != null) { + if (primaryKeyField.getType() == Long.class) { + primaryKeyField.set(data, uniqueSQLID); + } else if (primaryKeyField.getType() == long.class) { + primaryKeyField.setLong(data, uniqueSQLID); + } else if (primaryKeyField.getType() == UUID.class) { + primaryKeyField.set(data, uniqueSQLUUID); + } else { + LOGGER.error("Can not manage the primary filed !!!"); + } + } + // ps.execute(); + } catch (final SQLException ex) { + LOGGER.error("Fail SQL request: {}", ex.getMessage()); + ex.printStackTrace(); + throw new DataAccessException("Fail to Insert data in DB : " + ex.getMessage()); + } + final List asyncActions = new ArrayList<>(); + for (final Field field : asyncFieldUpdate) { + final DataAccessAddOn addOn = findAddOnforField(field); + if (uniqueSQLID != null) { + addOn.asyncInsert(this, tableName, uniqueSQLID, field, field.get(data), asyncActions); + } else if (uniqueSQLUUID != null) { + addOn.asyncInsert(this, tableName, uniqueSQLUUID, field, field.get(data), asyncActions); + } + } + for (final LazyGetter action : asyncActions) { + action.doRequest(); + } + return data; + } + + @Override + @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") + public long updateWhere(final T data, QueryOptions options) throws Exception { + final Class clazz = data.getClass(); + if (options == null) { + options = new QueryOptions(); + } + final Condition condition = conditionFusionOrEmpty(options, true); + final List filters = options != null ? options.get(FilterValue.class) : new ArrayList<>(); + if (filters.size() != 1) { + throw new DataAccessException("request a gets without/or with more 1 filter of values"); + } + final FilterValue filter = filters.get(0); + // External checker of data: + if (options != null) { + final List checks = options.get(CheckFunction.class); + for (final CheckFunction check : checks) { + check.getChecker().check(this, "", data, filter.getValues(), options); + } + } + final List asyncActions = new ArrayList<>(); + // real add in the BDD: + try { + final String tableName = AnnotationTools.getTableName(clazz, options); + // boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + final StringBuilder query = new StringBuilder(); + query.append("UPDATE `"); + query.append(tableName); + query.append("` SET "); + + boolean firstField = true; + for (final Field field : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + continue; + } + final String name = AnnotationTools.getFieldName(field); + if (!filter.getValues().contains(name)) { + continue; + } else if (AnnotationTools.isGenericField(field)) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { + if (addOn.isInsertAsync(field)) { + final List transmitKey = options.get(TransmitKey.class); + if (transmitKey.size() != 1) { + throw new DataAccessException( + "Fail to transmit Key to update the async update... (must have only 1)"); + } + addOn.asyncUpdate(this, tableName, transmitKey.get(0).getKey(), field, field.get(data), + asyncActions); + } + continue; + } + if (!field.getClass().isPrimitive()) { + final Object tmp = field.get(data); + if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { + continue; + } + } + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" `"); + query.append(name); + query.append("` = ? "); + } + query.append(" "); + final List orders = options.get(OrderBy.class); + for (final OrderBy order : orders) { + order.generateQuery(query, tableName); + } + query.append(" "); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + condition.whereAppendQuery(query, tableName, null, deletedFieldName); + + // If the first field is not set, then nothing to update n the main base: + if (!firstField) { + LOGGER.debug("generate update query: '{}'", query.toString()); + // prepare the request: + try (final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString(), + Statement.RETURN_GENERATED_KEYS)) { + final CountInOut iii = new CountInOut(1); + for (final Field field : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + continue; + } + final String name = AnnotationTools.getFieldName(field); + if (!filter.getValues().contains(name)) { + continue; + } else if (AnnotationTools.isGenericField(field)) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { + continue; + } + if (addOn == null) { + final Class type = field.getType(); + if (!type.isPrimitive()) { + final Object tmp = field.get(data); + if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { + continue; + } + } + setValuedb(type, data, iii, field, ps); + } else { + addOn.insertData(this, ps, field, data, iii); + } + } + condition.injectQuery(this, ps, iii); + final int out = ps.executeUpdate(); + return out; + } + } + } catch (final SQLException ex) { + ex.printStackTrace(); + } + for (final LazyGetter action : asyncActions) { + action.doRequest(); + } + return 0L; + } + + public void addElement(final PreparedStatement ps, final Object value, final CountInOut iii) throws Exception { + if (value == null) { + ps.setNull(iii.value, Types.INTEGER); + return; + } + if (value instanceof final UUID tmp) { + final byte[] dataByte = UuidUtils.asBytes(tmp); + ps.setBytes(iii.value, dataByte); + } else if (value instanceof final Long tmp) { + LOGGER.debug("Inject Long => {}", tmp); + ps.setLong(iii.value, tmp); + } else if (value instanceof final Integer tmp) { + LOGGER.debug("Inject Integer => {}", tmp); + ps.setInt(iii.value, tmp); + } else if (value instanceof final String tmp) { + LOGGER.debug("Inject String => {}", tmp); + ps.setString(iii.value, tmp); + } else if (value instanceof final Short tmp) { + LOGGER.debug("Inject Short => {}", tmp); + ps.setShort(iii.value, tmp); + } else if (value instanceof final Byte tmp) { + LOGGER.debug("Inject Byte => {}", tmp); + ps.setByte(iii.value, tmp); + } else if (value instanceof final Float tmp) { + LOGGER.debug("Inject Float => {}", tmp); + ps.setFloat(iii.value, tmp); + } else if (value instanceof final Double tmp) { + LOGGER.debug("Inject Double => {}", tmp); + ps.setDouble(iii.value, tmp); + } else if (value instanceof final Boolean tmp) { + LOGGER.debug("Inject Boolean => {}", tmp); + ps.setBoolean(iii.value, tmp); + } else if (value instanceof final Timestamp tmp) { + LOGGER.debug("Inject Timestamp => {}", tmp); + ps.setTimestamp(iii.value, tmp); + } else if (value instanceof final Date tmp) { + LOGGER.debug("Inject Date => {}", tmp); + ps.setTimestamp(iii.value, java.sql.Timestamp.from((tmp).toInstant())); + } else if (value instanceof final LocalDate tmp) { + LOGGER.debug("Inject LocalDate => {}", tmp); + ps.setDate(iii.value, java.sql.Date.valueOf(tmp)); + } else if (value instanceof final LocalTime tmp) { + LOGGER.debug("Inject LocalTime => {}", tmp); + ps.setTime(iii.value, java.sql.Time.valueOf(tmp)); + } else if (value.getClass().isEnum()) { + LOGGER.debug("Inject ENUM => {}", value.toString()); + ps.setString(iii.value, value.toString()); + } else { + throw new DataAccessException("Not manage type ==> need to add it ..."); + } + } + + public long executeSimpleQuery(final String query, final QueryOption... option) throws SQLException, IOException { + LOGGER.info("Query : '{}'", query); + try (final Statement stmt = this.db.getConnection().createStatement()) { + return stmt.executeUpdate(query); + } + } + + public boolean executeQuery(final String query, final QueryOption... option) throws SQLException, IOException { + try (final Statement stmt = this.db.getConnection().createStatement()) { + return stmt.execute(query); + } + } + + public static void generateSelectField(// + final StringBuilder querySelect, // + final StringBuilder query, // + final Class clazz, // + final QueryOptions options, // + final CountInOut count// + ) throws Exception { + final boolean readAllfields = QueryOptions.readAllColomn(options); + final String tableName = AnnotationTools.getTableName(clazz, options); + final String primaryKey = AnnotationTools.getPrimaryKeyField(clazz).getName(); + boolean firstField = true; + + for (final Field elem : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(elem); + if (addOn != null && !addOn.canRetrieve(elem)) { + continue; + } + final boolean notRead = AnnotationTools.isdefaultNotRead(elem); + if (!readAllfields && notRead) { + continue; + } + final String name = AnnotationTools.getFieldName(elem); + if (firstField) { + firstField = false; + } else { + querySelect.append(","); + } + querySelect.append(" "); + if (addOn != null) { + addOn.generateQuery(tableName, primaryKey, elem, querySelect, query, name, count, options); + } else { + querySelect.append(tableName); + querySelect.append("."); + querySelect.append(name); + count.inc(); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public List getsWhere(final Class clazz, final QueryOptions options) + throws DataAccessException, IOException { + final Condition condition = conditionFusionOrEmpty(options, false); + final List lazyCall = new ArrayList<>(); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + final List outs = new ArrayList<>(); + try { + final CountInOut count = new CountInOut(); + final StringBuilder querySelect = new StringBuilder(); + StringBuilder query = new StringBuilder(); + final String tableName = AnnotationTools.getTableName(clazz, options); + querySelect.append("SELECT "); + query.append(" FROM `"); + query.append(tableName); + query.append("` "); + + generateSelectField(querySelect, query, clazz, options, count); + querySelect.append(query.toString()); + query = querySelect; + condition.whereAppendQuery(query, tableName, options, deletedFieldName); + final List groups = options.get(GroupBy.class); + for (final GroupBy group : groups) { + group.generateQuery(query, tableName); + } + final List orders = options.get(OrderBy.class); + for (final OrderBy order : orders) { + order.generateQuery(query, tableName); + } + final List limits = options.get(Limit.class); + if (limits.size() == 1) { + limits.get(0).generateQuery(query, tableName); + } else if (limits.size() > 1) { + throw new DataAccessException("Request with multiple 'limit'..."); + } + LOGGER.debug("generate the query: '{}'", query.toString()); + // prepare the request: + try (final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString(), + Statement.RETURN_GENERATED_KEYS)) { + final CountInOut iii = new CountInOut(1); + condition.injectQuery(this, ps, iii); + if (limits.size() == 1) { + limits.get(0).injectQuery(this, ps, iii); + } + // execute the request + final ResultSet rs = ps.executeQuery(); + while (rs.next()) { + count.value = 1; + final CountInOut countNotNull = new CountInOut(0); + final Object data = createObjectFromSQLRequest(rs, clazz, count, countNotNull, options, lazyCall); + final T out = (T) data; + outs.add(out); + } + LOGGER.info("Async calls: {}", lazyCall.size()); + for (final LazyGetter elem : lazyCall) { + elem.doRequest(); + } + } + } catch (final SQLException ex) { + ex.printStackTrace(); + throw new DataAccessException("Catch a SQL Exception: " + ex.getMessage()); + } catch (final Exception ex) { + ex.printStackTrace(); + throw new DataAccessException("Catch an Exception: " + ex.getMessage()); + } + return outs; + } + + public Object createObjectFromSQLRequest( + final ResultSet rs, + final Class clazz, + final CountInOut count, + final CountInOut countNotNull, + final QueryOptions options, + final List lazyCall) throws Exception { + final boolean readAllfields = QueryOptions.readAllColomn(options); + // TODO: manage class that is defined inside a class ==> Not manage for now... + Object data = null; + for (final Constructor contructor : clazz.getConstructors()) { + if (contructor.getParameterCount() == 0) { + data = contructor.newInstance(); + } + } + if (data == null) { + throw new DataAccessException( + "Can not find the default constructor for the class: " + clazz.getCanonicalName()); + } + for (final Field elem : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(elem); + if (addOn != null && !addOn.canRetrieve(elem)) { + continue; + } + final boolean notRead = AnnotationTools.isdefaultNotRead(elem); + if (!readAllfields && notRead) { + continue; + } + if (addOn != null) { + addOn.fillFromQuery(this, rs, elem, data, count, options, lazyCall); + } else { + setValueFromDb(elem.getType(), data, count, elem, rs, countNotNull); + } + } + return data; + } + + @Override + public long countWhere(final Class clazz, final QueryOptions options) throws Exception { + final Condition condition = conditionFusionOrEmpty(options, false); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + long count = 0; + // real add in the BDD: + try { + final StringBuilder query = new StringBuilder(); + final String tableName = AnnotationTools.getTableName(clazz, options); + query.append("SELECT COUNT(*) AS count FROM `"); + query.append(tableName); + query.append("` "); + condition.whereAppendQuery(query, tableName, options, deletedFieldName); + final List limits = options.get(Limit.class); + if (limits.size() == 1) { + limits.get(0).generateQuery(query, tableName); + } else if (limits.size() > 1) { + throw new DataAccessException("Request with multiple 'limit'..."); + } + LOGGER.debug("generate the query: '{}'", query.toString()); + // prepare the request: + final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString(), + Statement.RETURN_GENERATED_KEYS); + final CountInOut iii = new CountInOut(1); + condition.injectQuery(this, ps, iii); + if (limits.size() == 1) { + limits.get(0).injectQuery(this, ps, iii); + } + // execute the request + final ResultSet rs = ps.executeQuery(); + if (rs.next()) { + count = rs.getLong("count"); + } + } catch (final SQLException ex) { + ex.printStackTrace(); + throw ex; + } catch (final Exception ex) { + ex.printStackTrace(); + } + return count; + } + + @Override + public long deleteHardWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final Condition condition = conditionFusionOrEmpty(options, true); + final String tableName = AnnotationTools.getTableName(clazz, options); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + // find the deleted field + final StringBuilder query = new StringBuilder(); + query.append("DELETE FROM `"); + query.append(tableName); + query.append("` "); + condition.whereAppendQuery(query, tableName, null, deletedFieldName); + LOGGER.debug("APPLY: {}", query.toString()); + final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString()); + final CountInOut iii = new CountInOut(1); + condition.injectQuery(this, ps, iii); + return ps.executeUpdate(); + } + + @Override + public long deleteSoftWhere(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final Condition condition = conditionFusionOrEmpty(options, true); + final String tableName = AnnotationTools.getTableName(clazz, options); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + /* String updateFieldName = null; if ("sqlite".equalsIgnoreCase(ConfigBaseVariable.getDBType())) { updateFieldName = AnnotationTools.getUpdatedFieldName(clazz); } */ + // find the deleted field + final StringBuilder query = new StringBuilder(); + query.append("UPDATE `"); + query.append(tableName); + query.append("` SET `"); + query.append(deletedFieldName); + query.append("`=true "); + /* The trigger work well, but the timestamp is store @ seconds... if (updateFieldName != null) { // done only in SQLite (the trigger does not work... query.append(", `"); + * query.append(updateFieldName); query.append("`=DATE()"); } */ + condition.whereAppendQuery(query, tableName, null, deletedFieldName); + + LOGGER.debug("APPLY UPDATE: {}", query.toString()); + final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString()); + final CountInOut iii = new CountInOut(1); + condition.injectQuery(this, ps, iii); + return ps.executeUpdate(); + + } + + @Override + public long unsetDeleteWhere(final Class clazz, final QueryOption... option) throws DataAccessException { + final QueryOptions options = new QueryOptions(option); + final Condition condition = conditionFusionOrEmpty(options, true); + final String tableName = AnnotationTools.getTableName(clazz, options); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); + if (deletedFieldName == null) { + throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field"); + } + final StringBuilder query = new StringBuilder(); + query.append("UPDATE `"); + query.append(tableName); + query.append("` SET `"); + query.append(deletedFieldName); + query.append("`=false "); + // need to disable the deleted false because the model must be unselected to be updated. + options.add(QueryOptions.ACCESS_DELETED_ITEMS); + condition.whereAppendQuery(query, tableName, options, deletedFieldName); + try (final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString())) { + final CountInOut iii = new CountInOut(1); + condition.injectQuery(this, ps, iii); + return ps.executeUpdate(); + } catch (final SQLException ex) { + throw new DataAccessException("Catch SQL error:" + ex.getMessage()); + } catch (final Exception ex) { + throw new DataAccessException("Fail to excute the SQL query:" + ex.getMessage()); + } + } + + @Override + public void drop(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final String tableName = AnnotationTools.getTableName(clazz, options); + final StringBuilder query = new StringBuilder(); + query.append("DROP TABLE IF EXISTS `"); + query.append(tableName); + query.append("`"); + LOGGER.trace("Execute Query: {}", query.toString()); + // Remove main table + final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString()); + ps.executeUpdate(); + // search subTable: + for (final Field field : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + continue; + } + if (AnnotationTools.isGenericField(field)) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { + addOn.drop(this, tableName, field); + } + } + } + + @Override + public void cleanAll(final Class clazz, final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + final String tableName = AnnotationTools.getTableName(clazz, options); + final StringBuilder query = new StringBuilder(); + query.append("DELETE FROM `"); + query.append(tableName); + query.append("`"); + LOGGER.trace("Execute Query: {}", query.toString()); + // Remove main table + final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString()); + ps.executeUpdate(); + // search subTable: + for (final Field field : clazz.getFields()) { + // field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + continue; + } + if (AnnotationTools.isGenericField(field)) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { + addOn.cleanAll(this, tableName, field); + } + } + } + + /** Execute a simple query with external property. + * @param Type of the data generate. + * @param clazz Class that might be analyze. + * @param query Base of the query. + * @param parameters "?" parameter of the query. + * @param option Optional parameters + * @return The list of element requested + * @throws Exception */ + public List query( + final Class clazz, + final String query, + final List parameters, + final QueryOption... option) throws Exception { + final QueryOptions options = new QueryOptions(option); + return query(clazz, query, parameters, options); + } + + public List query( + final Class clazz, + final String queryBase, + final List parameters, + final QueryOptions options) throws Exception { + final List lazyCall = new ArrayList<>(); + final Condition condition = conditionFusionOrEmpty(options, false); + final StringBuilder query = new StringBuilder(queryBase); + final List outs = new ArrayList<>(); + // real add in the BDD: + try { + final CountInOut count = new CountInOut(); + condition.whereAppendQuery(query, null, options, null); + + final List groups = options.get(GroupBy.class); + for (final GroupBy group : groups) { + group.generateQuery(query, null); + } + final List orders = options.get(OrderBy.class); + for (final OrderBy order : orders) { + order.generateQuery(query, null); + } + final List limits = options.get(Limit.class); + if (limits.size() == 1) { + limits.get(0).generateQuery(query, null); + } else if (limits.size() > 1) { + throw new DataAccessException("Request with multiple 'limit'..."); + } + LOGGER.debug("generate the query: '{}'", query.toString()); + // prepare the request: + final PreparedStatement ps = this.db.getConnection().prepareStatement(query.toString(), + Statement.RETURN_GENERATED_KEYS); + final CountInOut iii = new CountInOut(1); + if (parameters != null) { + for (final Object elem : parameters) { + addElement(ps, elem, iii); + } + iii.inc(); + } + condition.injectQuery(this, ps, iii); + if (limits.size() == 1) { + limits.get(0).injectQuery(this, ps, iii); + } + // execute the request + final ResultSet rs = ps.executeQuery(); + final ResultSetMetaData rsmd = rs.getMetaData(); + final List actionToRetreive = new ArrayList<>(); + LOGGER.info("Field:"); + for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) { + final String label = rsmd.getColumnLabel(jjj + 1); + LOGGER.info(" - {}:{}", jjj, label); + // find field name ... + final Field field = AnnotationTools.getFieldNamed(clazz, label); + if (field == null) { + throw new DataAccessException("Query with unknown field: '" + label + "'"); + } + // create the callback... + final RetreiveFromDB element = createSetValueFromDbCallback(jjj + 1, field); + actionToRetreive.add(element); + } + + while (rs.next()) { + count.value = 1; + Object data = null; + for (final Constructor contructor : clazz.getConstructors()) { + if (contructor.getParameterCount() == 0) { + data = contructor.newInstance(); + } + } + if (data == null) { + // TODO... + } else { + for (final RetreiveFromDB action : actionToRetreive) { + action.doRequest(rs, data); + } + } + @SuppressWarnings("unchecked") + final TYPE out = (TYPE) data; + outs.add(out); + } + LOGGER.info("Async calls: {}", lazyCall.size()); + for (final LazyGetter elem : lazyCall) { + elem.doRequest(); + } + } catch (final SQLException ex) { + ex.printStackTrace(); + throw ex; + } catch (final Exception ex) { + ex.printStackTrace(); + } + return outs; + } + +} diff --git a/src/org/kar/archidata/dataAccess/DataAccess.java b/src/org/kar/archidata/dataAccess/DataAccess.java index 169827f..363f0ed 100644 --- a/src/org/kar/archidata/dataAccess/DataAccess.java +++ b/src/org/kar/archidata/dataAccess/DataAccess.java @@ -1,54 +1,15 @@ package org.kar.archidata.dataAccess; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.sql.Types; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; import java.util.List; -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.options.CheckFunction; import org.kar.archidata.dataAccess.options.Condition; -import org.kar.archidata.dataAccess.options.DBInterfaceOption; -import org.kar.archidata.dataAccess.options.DBInterfaceRoot; -import org.kar.archidata.dataAccess.options.FilterValue; -import org.kar.archidata.dataAccess.options.GroupBy; -import org.kar.archidata.dataAccess.options.Limit; -import org.kar.archidata.dataAccess.options.OrderBy; import org.kar.archidata.dataAccess.options.QueryOption; -import org.kar.archidata.dataAccess.options.TransmitKey; -import org.kar.archidata.db.DBEntry; import org.kar.archidata.exception.DataAccessException; -import org.kar.archidata.tools.ConfigBaseVariable; -import org.kar.archidata.tools.DateTools; -import org.kar.archidata.tools.UuidUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.InternalServerErrorException; /* TODO list: @@ -58,998 +19,59 @@ import jakarta.ws.rs.InternalServerErrorException; /** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite * back-end. */ public class DataAccess { - static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.class); - // 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 { - 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 */ - public static void addAddOn(final DataAccessAddOn addOn) { - DataAccess.addOn.add(addOn); - } + private static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.class); public DataAccess() { } - public static boolean isDBExist(final String name, final QueryOption... option) - throws InternalServerErrorException { - final QueryOptions options = new QueryOptions(option); - if ("sqlite".equals(ConfigBaseVariable.getDBType())) { - // no base manage in sqLite ... - // TODO: check if the file exist or not ... - return true; - } - DBEntry entry; - try { - entry = DBInterfaceOption.getAutoEntry(options); - } catch (final IOException ex) { - ex.printStackTrace(); - LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); - - // TODO: TO test - - return false; - } - try { - // TODO : Maybe connect with a temporary not specified connection interface to a db ... - final PreparedStatement ps = entry.connection.prepareStatement("show databases"); - final ResultSet rs = ps.executeQuery(); - // LOGGER.info("List all tables: equals? '{}'", name); - while (rs.next()) { - final String data = rs.getString(1); - // LOGGER.info(" - '{}'", data); - if (name.equals(data)) { - return true; - } - } - return false; - } catch (final SQLException ex) { - LOGGER.error("Can not check if the DB exist SQL-error !!! {}", ex.getMessage()); - } finally { - try { - entry.close(); - } catch (final IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - entry = null; - } - throw new InternalServerErrorException("Can Not manage the DB-access"); - } - - public static boolean createDB(final String name) { - if ("sqlite".equals(ConfigBaseVariable.getDBType())) { - // no base manage in sqLite ... - // TODO: check if the file exist or not ... - return true; - } - try { - return 1 == DataAccess.executeSimpleQuery("CREATE DATABASE `" + name + "`;", new DBInterfaceRoot(true)); - } catch (final SQLException | IOException ex) { - ex.printStackTrace(); - LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); - return false; + public static boolean isDBExist(final String name, final QueryOption... options) + throws InternalServerErrorException, IOException, DataAccessException { + try (DBAccess db = DBAccess.createInterface()) { + return db.isDBExist(name, options); } } - public static boolean isTableExist(final String name, final QueryOption... option) - throws InternalServerErrorException { - final QueryOptions options = new QueryOptions(option); - try { - String request = ""; - if ("sqlite".equals(ConfigBaseVariable.getDBType())) { - request = """ - SELECT COUNT(*) AS total - FROM sqlite_master - WHERE type = 'table' - AND name = ?; - """; - // PreparedStatement ps = entry.connection.prepareStatement("show tables"); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final PreparedStatement ps = entry.connection.prepareStatement(request); - ps.setString(1, name); - final ResultSet ret = ps.executeQuery(); - final int count = ret.getInt("total"); - return count == 1; - } else { - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - // TODO : Maybe connect with a temporary not specified connection interface to a db ... - final PreparedStatement ps = entry.connection.prepareStatement("show tables"); - final ResultSet rs = ps.executeQuery(); - // LOGGER.info("List all tables: equals? '{}'", name); - while (rs.next()) { - final String data = rs.getString(1); - // LOGGER.info(" - '{}'", data); - if (name.equals(data)) { - return true; - } - } - return false; - } - } catch (final SQLException ex) { - LOGGER.error("Can not check if the table exist SQL-error !!! {}", ex.getMessage()); - } catch (final IOException ex) { - LOGGER.error("Can not check if the table exist!!! {}", ex.getMessage()); + public static boolean createDB(final String name) + throws IOException, InternalServerErrorException, DataAccessException { + try (DBAccess db = DBAccess.createInterface()) { + return db.createDB(name); } - throw new InternalServerErrorException("Can Not manage the DB-access"); } - /** Extract a list of Long with "-" 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. */ - public static List getListOfIds(final ResultSet rs, final int iii, final String separator) - throws SQLException { - final String trackString = rs.getString(iii); - if (rs.wasNull()) { - return null; + public static boolean isTableExist(final String name, final QueryOption... options) + throws InternalServerErrorException, IOException, DataAccessException { + try (DBAccess db = DBAccess.createInterface()) { + return db.isTableExist(name, options); } - final List out = new ArrayList<>(); - final String[] elements = trackString.split(separator); - for (final String elem : elements) { - final Long tmp = Long.parseLong(elem); - out.add(tmp); - } - return out; - } - - /** Extract a list of UUID with "-" 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. */ - public static List getListOfUUIDs(final ResultSet rs, final int iii, final String separator) - throws SQLException { - final String trackString = rs.getString(iii); - if (rs.wasNull()) { - return null; - } - final List out = new ArrayList<>(); - final String[] elements = trackString.split(separator); - for (final String elem : elements) { - final UUID tmp = UUID.fromString(elem); - out.add(tmp); - } - return out; - } - - public static byte[][] splitIntoGroupsOf16Bytes(final byte[] input) { - final int inputLength = input.length; - final int numOfGroups = (inputLength + 15) / 16; // Calculate the number of groups needed - final byte[][] groups = new byte[numOfGroups][16]; - - for (int i = 0; i < numOfGroups; i++) { - final int startIndex = i * 16; - final int endIndex = Math.min(startIndex + 16, inputLength); - groups[i] = Arrays.copyOfRange(input, startIndex, endIndex); - } - - return groups; - } - - public static List getListOfRawUUIDs(final ResultSet rs, final int iii) - throws SQLException, DataAccessException { - final byte[] trackString = rs.getBytes(iii); - if (rs.wasNull()) { - return null; - } - final byte[][] elements = splitIntoGroupsOf16Bytes(trackString); - final List out = new ArrayList<>(); - for (final byte[] elem : elements) { - final UUID tmp = UuidUtils.asUuid(elem); - out.add(tmp); - } - return out; - } - - public static UUID getListOfRawUUID(final ResultSet rs, final int iii) throws SQLException, DataAccessException { - final byte[] elem = rs.getBytes(iii); - if (rs.wasNull()) { - return null; - } - return UuidUtils.asUuid(elem); - } - - protected static void setValuedb( - final Class type, - final T data, - final CountInOut iii, - final Field field, - final PreparedStatement ps) throws Exception { - if (type == UUID.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.BINARY); - } else { - final byte[] dataByte = UuidUtils.asBytes((UUID) tmp); - ps.setBytes(iii.value, dataByte); - } - } else if (type == Long.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.BIGINT); - } else { - ps.setLong(iii.value, (Long) tmp); - } - } else if (type == long.class) { - ps.setLong(iii.value, field.getLong(data)); - } else if (type == Integer.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.INTEGER); - } else { - ps.setInt(iii.value, (Integer) tmp); - } - } else if (type == int.class) { - ps.setInt(iii.value, field.getInt(data)); - } else if (type == Float.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.FLOAT); - } else { - ps.setFloat(iii.value, (Float) tmp); - } - } else if (type == float.class) { - ps.setFloat(iii.value, field.getFloat(data)); - } else if (type == Double.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.DOUBLE); - } else { - ps.setDouble(iii.value, (Double) tmp); - } - } else if (type == Double.class) { - ps.setDouble(iii.value, field.getDouble(data)); - } else if (type == Boolean.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.INTEGER); - } else { - ps.setBoolean(iii.value, (Boolean) tmp); - } - } else if (type == boolean.class) { - ps.setBoolean(iii.value, field.getBoolean(data)); - } else if (type == Timestamp.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.INTEGER); - } else { - ps.setTimestamp(iii.value, (Timestamp) tmp); - } - } else if (type == Date.class) { - 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); - } - } else 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); - } - } else 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); - } - } else 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); - } - } else if (type == String.class) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.VARCHAR); - } else { - ps.setString(iii.value, (String) tmp); - } - } else if (type.isEnum()) { - final Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(iii.value, Types.VARCHAR); - } else { - ps.setString(iii.value, tmp.toString()); - } - } else { - throw new DataAccessException("Unknown Field Type"); - } - iii.inc(); - } - - protected static void setValueFromDb( - final Class type, - final Object data, - final CountInOut count, - final Field field, - final ResultSet rs, - final CountInOut countNotNull) throws Exception { - if (type == UUID.class) { - final byte[] tmp = rs.getBytes(count.value); - // final UUID tmp = rs.getObject(count.value, UUID.class); - if (rs.wasNull()) { - field.set(data, null); - } else { - // field.set(data, tmp); - final UUID uuid = UuidUtils.asUuid(tmp); - field.set(data, uuid); - countNotNull.inc(); - } - } else if (type == Long.class) { - final Long tmp = rs.getLong(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); - countNotNull.inc(); - } - } else if (type == long.class) { - final Long tmp = rs.getLong(count.value); - if (rs.wasNull()) { - // field.set(data, null); - } else { - field.setLong(data, tmp); - countNotNull.inc(); - } - } else if (type == Integer.class) { - final Integer tmp = rs.getInt(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); - countNotNull.inc(); - } - } else if (type == int.class) { - final Integer tmp = rs.getInt(count.value); - if (rs.wasNull()) { - // field.set(data, null); - } else { - field.setInt(data, tmp); - countNotNull.inc(); - } - } else if (type == Float.class) { - final Float tmp = rs.getFloat(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); - countNotNull.inc(); - } - } else if (type == float.class) { - final Float tmp = rs.getFloat(count.value); - if (rs.wasNull()) { - // field.set(data, null); - } else { - field.setFloat(data, tmp); - countNotNull.inc(); - } - } else if (type == Double.class) { - final Double tmp = rs.getDouble(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); - countNotNull.inc(); - } - } else if (type == double.class) { - final Double tmp = rs.getDouble(count.value); - if (rs.wasNull()) { - // field.set(data, null); - } else { - field.setDouble(data, tmp); - countNotNull.inc(); - } - } else if (type == Boolean.class) { - final Boolean tmp = rs.getBoolean(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); - countNotNull.inc(); - } - } else if (type == boolean.class) { - final Boolean tmp = rs.getBoolean(count.value); - if (rs.wasNull()) { - // field.set(data, null); - } else { - field.setBoolean(data, tmp); - countNotNull.inc(); - } - } else if (type == Timestamp.class) { - final Timestamp tmp = rs.getTimestamp(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); - countNotNull.inc(); - } - } else if (type == Date.class) { - try { - final Timestamp tmp = rs.getTimestamp(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, Date.from(tmp.toInstant())); - countNotNull.inc(); - } - } catch (final SQLException ex) { - final String tmp = rs.getString(count.value); - LOGGER.error("Fail to parse the SQL time !!! {}", tmp); - if (rs.wasNull()) { - field.set(data, null); - } else { - final Date date = DateTools.parseDate(tmp); - LOGGER.error("Fail to parse the SQL time !!! {}", date); - field.set(data, date); - countNotNull.inc(); - } - } - } else if (type == Instant.class) { - final String tmp = rs.getString(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, Instant.parse(tmp)); - countNotNull.inc(); - } - } else if (type == LocalDate.class) { - final java.sql.Date tmp = rs.getDate(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp.toLocalDate()); - countNotNull.inc(); - } - } else if (type == LocalTime.class) { - final java.sql.Time tmp = rs.getTime(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp.toLocalTime()); - countNotNull.inc(); - } - } else if (type == String.class) { - final String tmp = rs.getString(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); - countNotNull.inc(); - } - } else if (type.isEnum()) { - final String tmp = rs.getString(count.value); - if (rs.wasNull()) { - field.set(data, null); - } else { - boolean find = false; - final Object[] arr = type.getEnumConstants(); - for (final Object elem : arr) { - if (elem.toString().equals(tmp)) { - field.set(data, elem); - countNotNull.inc(); - find = true; - break; - } - } - if (!find) { - throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'"); - } - } - } else { - throw new DataAccessException("Unknown Field Type"); - } - count.inc(); - } - - // TODO: this function will replace the previous one !!! - protected static RetreiveFromDB createSetValueFromDbCallback(final int count, final Field field) throws Exception { - final Class type = field.getType(); - if (type == UUID.class) { - return (final ResultSet rs, final Object obj) -> { - - final byte[] tmp = rs.getBytes(count); - // final UUID tmp = rs.getObject(count, UUID.class); - if (rs.wasNull()) { - field.set(obj, null); - } else { - // field.set(obj, tmp); - final UUID uuid = UuidUtils.asUuid(tmp); - field.set(obj, uuid); - } - }; - } - if (type == Long.class) { - return (final ResultSet rs, final Object obj) -> { - final Long tmp = rs.getLong(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp); - } - }; - } - if (type == long.class) { - return (final ResultSet rs, final Object obj) -> { - final Long tmp = rs.getLong(count); - if (rs.wasNull()) { - // field.set(data, null); - } else { - field.setLong(obj, tmp); - } - }; - } - if (type == Integer.class) { - return (final ResultSet rs, final Object obj) -> { - final Integer tmp = rs.getInt(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp); - } - }; - } - if (type == int.class) { - return (final ResultSet rs, final Object obj) -> { - final Integer tmp = rs.getInt(count); - if (rs.wasNull()) { - // field.set(obj, null); - } else { - field.setInt(obj, tmp); - } - }; - } - if (type == Float.class) { - return (final ResultSet rs, final Object obj) -> { - final Float tmp = rs.getFloat(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp); - } - }; - } - if (type == float.class) { - return (final ResultSet rs, final Object obj) -> { - final Float tmp = rs.getFloat(count); - if (rs.wasNull()) { - // field.set(obj, null); - } else { - field.setFloat(obj, tmp); - } - }; - } - if (type == Double.class) { - return (final ResultSet rs, final Object obj) -> { - final Double tmp = rs.getDouble(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp); - } - }; - } - if (type == double.class) { - return (final ResultSet rs, final Object obj) -> { - final Double tmp = rs.getDouble(count); - if (rs.wasNull()) { - // field.set(obj, null); - } else { - field.setDouble(obj, tmp); - } - }; - } - if (type == Boolean.class) { - return (final ResultSet rs, final Object obj) -> { - final Boolean tmp = rs.getBoolean(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp); - } - }; - } - if (type == boolean.class) { - return (final ResultSet rs, final Object obj) -> { - final Boolean tmp = rs.getBoolean(count); - if (rs.wasNull()) { - // field.set(obj, null); - } else { - field.setBoolean(obj, tmp); - } - }; - } - if (type == Timestamp.class) { - return (final ResultSet rs, final Object obj) -> { - final Timestamp tmp = rs.getTimestamp(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp); - } - }; - } - if (type == Date.class) { - return (final ResultSet rs, final Object obj) -> { - try { - final Timestamp tmp = rs.getTimestamp(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, Date.from(tmp.toInstant())); - } - } catch (final SQLException ex) { - final String tmp = rs.getString(count); - LOGGER.error("Fail to parse the SQL time !!! {}", tmp); - if (rs.wasNull()) { - field.set(obj, null); - } else { - final Date date = DateTools.parseDate(tmp); - LOGGER.error("Fail to parse the SQL time !!! {}", date); - field.set(obj, date); - } - } - }; - } - if (type == Instant.class) { - return (final ResultSet rs, final Object obj) -> { - final String tmp = rs.getString(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, Instant.parse(tmp)); - } - }; - } - if (type == LocalDate.class) { - return (final ResultSet rs, final Object obj) -> { - final java.sql.Date tmp = rs.getDate(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp.toLocalDate()); - } - }; - } - if (type == LocalTime.class) { - return (final ResultSet rs, final Object obj) -> { - final java.sql.Time tmp = rs.getTime(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp.toLocalTime()); - } - }; - } - if (type == String.class) { - return (final ResultSet rs, final Object obj) -> { - final String tmp = rs.getString(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - field.set(obj, tmp); - } - }; - } - if (type.isEnum()) { - return (final ResultSet rs, final Object obj) -> { - final String tmp = rs.getString(count); - if (rs.wasNull()) { - field.set(obj, null); - } else { - boolean find = false; - final Object[] arr = type.getEnumConstants(); - for (final Object elem : arr) { - if (elem.toString().equals(tmp)) { - field.set(obj, elem); - find = true; - break; - } - } - if (!find) { - throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'"); - } - } - }; - } - throw new DataAccessException("Unknown Field Type"); - - } - - public static boolean isAddOnField(final Field field) { - return findAddOnforField(field) != null; - } - - public static DataAccessAddOn findAddOnforField(final Field field) { - for (final DataAccessAddOn elem : addOn) { - if (elem.isCompatibleField(field)) { - return elem; - } - } - return null; } // TODO: manage insert batch... public static List insertMultiple(final List data, final QueryOption... options) throws Exception { - final List out = new ArrayList<>(); - for (final T elem : data) { - final T tmp = insert(elem, options); - out.add(tmp); + try (DBAccess db = DBAccess.createInterface()) { + return db.insertMultiple(data, options); } - return out; } @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") - public static T insert(final T data, final QueryOption... option) throws Exception { - final Class clazz = data.getClass(); - final QueryOptions options = new QueryOptions(option); - - // External checker of data: - final List checks = options.get(CheckFunction.class); - for (final CheckFunction check : checks) { - check.getChecker().check("", data, AnnotationTools.getFieldsNames(clazz), options); + public static T insert(final T data, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.insert(data, options); } - - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final List asyncFieldUpdate = new ArrayList<>(); - Long uniqueSQLID = null; - UUID uniqueSQLUUID = null; - final String tableName = AnnotationTools.getTableName(clazz, options); - Field primaryKeyField = null; - boolean generateUUID = false; - // real add in the BDD: - try { - // boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - final StringBuilder query = new StringBuilder(); - query.append("INSERT INTO `"); - query.append(tableName); - query.append("` ("); - - boolean firstField = true; - int count = 0; - 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; - } - if (AnnotationTools.isPrimaryKey(field)) { - primaryKeyField = field; - if (primaryKeyField.getType() != UUID.class) { - break; - } - generateUUID = true; - count++; - final String name = AnnotationTools.getFieldName(field); - if (firstField) { - firstField = false; - } else { - query.append(","); - } - query.append(" `"); - query.append(name); - query.append("`"); - break; - } - } - 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; - } - if (AnnotationTools.isPrimaryKey(field)) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(field); - if (addOn != null && !addOn.canInsert(field)) { - if (addOn.isInsertAsync(field)) { - asyncFieldUpdate.add(field); - } - continue; - } - final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; - if (createTime) { - continue; - } - final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; - if (updateTime) { - continue; - } - if (!field.getClass().isPrimitive()) { - final Object tmp = field.get(data); - if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { - continue; - } - } - count++; - final String name = AnnotationTools.getFieldName(field); - if (firstField) { - firstField = false; - } else { - query.append(","); - } - query.append(" `"); - query.append(name); - query.append("`"); - } - firstField = true; - query.append(") VALUES ("); - for (int iii = 0; iii < count; iii++) { - if (firstField) { - firstField = false; - } else { - query.append(","); - } - query.append("?"); - } - query.append(")"); - final List orders = options.get(OrderBy.class); - for (final OrderBy order : orders) { - order.generateQuery(query, tableName); - } - LOGGER.debug("generate the query: '{}'", query.toString()); - // prepare the request: - final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), - Statement.RETURN_GENERATED_KEYS); - - final CountInOut iii = new CountInOut(1); - UUID uuid = null; - if (generateUUID) { - firstField = false; - // uuid = UUID.randomUUID(); - uuid = UuidUtils.nextUUID(); - addElement(ps, uuid, iii); - iii.inc(); - } - for (final Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - if (AnnotationTools.isPrimaryKey(elem)) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canInsert(elem)) { - continue; - } - final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; - if (createTime) { - continue; - } - final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; - if (updateTime) { - continue; - } - if (addOn != null) { - // Add-on specific insertion. - addOn.insertData(ps, elem, data, iii); - } else { - // Generic class insertion... - final Class type = elem.getType(); - if (!type.isPrimitive()) { - final Object tmp = elem.get(data); - if (tmp == null && elem.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { - continue; - } - } - setValuedb(type, data, iii, elem, ps); - } - count++; - } - // execute the request - final int affectedRows = ps.executeUpdate(); - if (affectedRows == 0) { - throw new SQLException("Creating node failed, no rows affected."); - } - // Retrieve uid inserted - if (generateUUID) { - // we generate the UUID, otherwise we can not retrieve it - uniqueSQLUUID = uuid; - } else { - try (ResultSet generatedKeys = ps.getGeneratedKeys()) { - if (generatedKeys.next()) { - if (primaryKeyField.getType() == UUID.class) { - // uniqueSQLUUID = generatedKeys.getObject(1, UUID.class); - /* final Object obj = generatedKeys.getObject(1); final BigInteger bigint = (BigInteger) generatedKeys.getObject(1); uniqueSQLUUID = UuidUtils.asUuid(bigint); final UUID - * generatedUUID = (UUID) generatedKeys.getObject(1); System.out.println("UUID généré: " + generatedUUID); */ - //final Object obj = generatedKeys.getObject(1); - final byte[] tmpid = generatedKeys.getBytes(1); - uniqueSQLUUID = UuidUtils.asUuid(tmpid); - } else { - uniqueSQLID = generatedKeys.getLong(1); - } - } else { - throw new SQLException("Creating node failed, no ID obtained (1)."); - } - } catch (final Exception ex) { - LOGGER.error("Can not get the UID key inserted ... "); - ex.printStackTrace(); - throw new SQLException("Creating node failed, no ID obtained (2)."); - } - } - ps.close(); - if (primaryKeyField != null) { - if (primaryKeyField.getType() == Long.class) { - primaryKeyField.set(data, uniqueSQLID); - } else if (primaryKeyField.getType() == long.class) { - primaryKeyField.setLong(data, uniqueSQLID); - } else if (primaryKeyField.getType() == UUID.class) { - primaryKeyField.set(data, uniqueSQLUUID); - } else { - LOGGER.error("Can not manage the primary filed !!!"); - } - } - // ps.execute(); - } catch (final SQLException ex) { - LOGGER.error("Fail SQL request: {}", ex.getMessage()); - ex.printStackTrace(); - throw new DataAccessException("Fail to Insert data in DB : " + ex.getMessage()); - } finally { - entry.close(); - } - final List asyncActions = new ArrayList<>(); - for (final Field field : asyncFieldUpdate) { - final DataAccessAddOn addOn = findAddOnforField(field); - if (uniqueSQLID != null) { - addOn.asyncInsert(tableName, uniqueSQLID, field, field.get(data), asyncActions); - } else if (uniqueSQLUUID != null) { - addOn.asyncInsert(tableName, uniqueSQLUUID, field, field.get(data), asyncActions); - } - } - for (final LazyGetter action : asyncActions) { - action.doRequest(); - } - return data; } // seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated... public static T insertWithJson(final Class clazz, final String jsonData) throws Exception { - final ObjectMapper mapper = new ObjectMapper(); - // parse the object to be sure the data are valid: - final T data = mapper.readValue(jsonData, clazz); - return insert(data); + try (DBAccess db = DBAccess.createInterface()) { + return db.insertWithJson(clazz, jsonData); + } } public static QueryCondition getTableIdCondition(final Class clazz, final ID_TYPE idKey) - throws DataAccessException { - // Find the ID field type .... - final Field idField = AnnotationTools.getIdField(clazz); - if (idField == null) { - throw new DataAccessException( - "The class have no annotation @Id ==> can not determine the default type searching"); + throws DataAccessException, IOException { + try (DBAccess db = DBAccess.createInterface()) { + return db.getTableIdCondition(clazz, idKey); } - // check the compatibility of the id and the declared ID - final Class typeClass = idField.getType(); - if (idKey == null) { - throw new DataAccessException("Try to identify the ID type and object wa null."); - } - if (idKey.getClass() != typeClass) { - if (idKey.getClass() == Condition.class) { - throw new DataAccessException( - "Try to identify the ID type on a condition 'close' internal API error use xxxWhere(...) instead."); - } - throw new DataAccessException("Request update with the wrong type ..."); - } - return new QueryCondition(AnnotationTools.getFieldName(idField), "=", idKey); } /** Update an object with the inserted json data @@ -1061,37 +83,29 @@ public class DataAccess { * @param jsonData Json data (partial) values to update * @return the number of object updated * @throws Exception */ - public static int updateWithJson( + public static long updateWithJson( final Class clazz, final ID_TYPE id, final String jsonData, - final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - options.add(new Condition(getTableIdCondition(clazz, id))); - options.add(new TransmitKey(id)); - return updateWhereWithJson(clazz, jsonData, options.getAllArray()); - } - - public static int updateWhereWithJson(final Class clazz, final String jsonData, final QueryOption... option) - throws Exception { - final QueryOptions options = new QueryOptions(option); - if (options.get(Condition.class).size() == 0) { - throw new DataAccessException("request a updateWhereWithJson without any condition"); + final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.updateWithJson(clazz, id, jsonData, options); } - final ObjectMapper mapper = new ObjectMapper(); - // parse the object to be sure the data are valid: - final T data = mapper.readValue(jsonData, clazz); - // Read the tree to filter injection of data: - final JsonNode root = mapper.readTree(jsonData); - final List keys = new ArrayList<>(); - final var iterator = root.fieldNames(); - iterator.forEachRemaining(e -> keys.add(e)); - options.add(new FilterValue(keys)); - return updateWhere(data, options.getAllArray()); } - public static int update(final T data, final ID_TYPE id) throws Exception { - return update(data, id, AnnotationTools.getFieldsNames(data.getClass())); + public static long updateWhereWithJson( + final Class clazz, + final String jsonData, + final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.updateWhereWithJson(clazz, jsonData, options); + } + } + + public static long update(final T data, final ID_TYPE id) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.update(data, id); + } } /** @param @@ -1100,489 +114,96 @@ public class DataAccess { * @param filterValue * @return the affected rows. * @throws Exception */ - public static int update( + public static long update( final T data, final ID_TYPE id, final List updateColomn, - final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - options.add(new Condition(getTableIdCondition(data.getClass(), id))); - options.add(new FilterValue(updateColomn)); - options.add(new TransmitKey(id)); - return updateWhere(data, options); - } - - public static int updateWhere(final T data, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - return updateWhere(data, options); - } - - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") - public static int updateWhere(final T data, QueryOptions options) throws Exception { - final Class clazz = data.getClass(); - if (options == null) { - options = new QueryOptions(); - } - final Condition condition = conditionFusionOrEmpty(options, true); - final List filters = options != null ? options.get(FilterValue.class) : new ArrayList<>(); - if (filters.size() != 1) { - throw new DataAccessException("request a gets without/or with more 1 filter of values"); - } - final FilterValue filter = filters.get(0); - // External checker of data: - if (options != null) { - final List checks = options.get(CheckFunction.class); - for (final CheckFunction check : checks) { - check.getChecker().check("", data, filter.getValues(), options); - } - } - final List asyncActions = new ArrayList<>(); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - // real add in the BDD: - try (entry) { - final String tableName = AnnotationTools.getTableName(clazz, options); - // boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - final StringBuilder query = new StringBuilder(); - query.append("UPDATE `"); - query.append(tableName); - query.append("` SET "); - - boolean firstField = true; - 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 name = AnnotationTools.getFieldName(field); - if (!filter.getValues().contains(name)) { - continue; - } else if (AnnotationTools.isGenericField(field)) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(field); - if (addOn != null && !addOn.canInsert(field)) { - if (addOn.isInsertAsync(field)) { - final List transmitKey = options.get(TransmitKey.class); - if (transmitKey.size() != 1) { - throw new DataAccessException( - "Fail to transmit Key to update the async update... (must have only 1)"); - } - addOn.asyncUpdate(tableName, transmitKey.get(0).getKey(), field, field.get(data), asyncActions); - } - continue; - } - if (!field.getClass().isPrimitive()) { - final Object tmp = field.get(data); - if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { - continue; - } - } - if (firstField) { - firstField = false; - } else { - query.append(","); - } - query.append(" `"); - query.append(name); - query.append("` = ? "); - } - query.append(" "); - final List orders = options.get(OrderBy.class); - for (final OrderBy order : orders) { - order.generateQuery(query, tableName); - } - query.append(" "); - final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - condition.whereAppendQuery(query, tableName, null, deletedFieldName); - - // If the first field is not set, then nothing to update n the main base: - if (!firstField) { - LOGGER.debug("generate update query: '{}'", query.toString()); - // prepare the request: - try (final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), - Statement.RETURN_GENERATED_KEYS)) { - final CountInOut iii = new CountInOut(1); - 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 name = AnnotationTools.getFieldName(field); - if (!filter.getValues().contains(name)) { - continue; - } else if (AnnotationTools.isGenericField(field)) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(field); - if (addOn != null && !addOn.canInsert(field)) { - continue; - } - if (addOn == null) { - final Class type = field.getType(); - if (!type.isPrimitive()) { - final Object tmp = field.get(data); - if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { - continue; - } - } - setValuedb(type, data, iii, field, ps); - } else { - addOn.insertData(ps, field, data, iii); - } - } - condition.injectQuery(ps, iii); - final int out = ps.executeUpdate(); - return out; - } - } - } catch (final SQLException ex) { - ex.printStackTrace(); - } - for (final LazyGetter action : asyncActions) { - action.doRequest(); - } - return 0; - } - - public static void addElement(final PreparedStatement ps, final Object value, final CountInOut iii) - throws Exception { - if (value == null) { - ps.setNull(iii.value, Types.INTEGER); - return; - } - if (value instanceof final UUID tmp) { - final byte[] dataByte = UuidUtils.asBytes(tmp); - ps.setBytes(iii.value, dataByte); - } else if (value instanceof final Long tmp) { - LOGGER.debug("Inject Long => {}", tmp); - ps.setLong(iii.value, tmp); - } else if (value instanceof final Integer tmp) { - LOGGER.debug("Inject Integer => {}", tmp); - ps.setInt(iii.value, tmp); - } else if (value instanceof final String tmp) { - LOGGER.debug("Inject String => {}", tmp); - ps.setString(iii.value, tmp); - } else if (value instanceof final Short tmp) { - LOGGER.debug("Inject Short => {}", tmp); - ps.setShort(iii.value, tmp); - } else if (value instanceof final Byte tmp) { - LOGGER.debug("Inject Byte => {}", tmp); - ps.setByte(iii.value, tmp); - } else if (value instanceof final Float tmp) { - LOGGER.debug("Inject Float => {}", tmp); - ps.setFloat(iii.value, tmp); - } else if (value instanceof final Double tmp) { - LOGGER.debug("Inject Double => {}", tmp); - ps.setDouble(iii.value, tmp); - } else if (value instanceof final Boolean tmp) { - LOGGER.debug("Inject Boolean => {}", tmp); - ps.setBoolean(iii.value, tmp); - } else if (value instanceof final Timestamp tmp) { - LOGGER.debug("Inject Timestamp => {}", tmp); - ps.setTimestamp(iii.value, tmp); - } else if (value instanceof final Date tmp) { - LOGGER.debug("Inject Date => {}", tmp); - ps.setTimestamp(iii.value, java.sql.Timestamp.from((tmp).toInstant())); - } else if (value instanceof final LocalDate tmp) { - LOGGER.debug("Inject LocalDate => {}", tmp); - ps.setDate(iii.value, java.sql.Date.valueOf(tmp)); - } else if (value instanceof final LocalTime tmp) { - LOGGER.debug("Inject LocalTime => {}", tmp); - ps.setTime(iii.value, java.sql.Time.valueOf(tmp)); - } else if (value.getClass().isEnum()) { - LOGGER.debug("Inject ENUM => {}", value.toString()); - ps.setString(iii.value, value.toString()); - } else { - throw new DataAccessException("Not manage type ==> need to add it ..."); + final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.update(data, id, updateColomn, options); } } - public static int executeSimpleQuery(final String query, final QueryOption... option) - throws SQLException, IOException { - final QueryOptions options = new QueryOptions(option); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - LOGGER.info("Query : '{}'", query); - try (final Statement stmt = entry.connection.createStatement()) { - return stmt.executeUpdate(query); + public static long updateWhere(final T data, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.updateWhere(data, options); } } - public static boolean executeQuery(final String query, final QueryOption... option) - throws SQLException, IOException { - final QueryOptions options = new QueryOptions(option); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - try (final Statement stmt = entry.connection.createStatement()) { - return stmt.execute(query); + public static long updateWhere(final T data, final QueryOptions options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.updateWhere(data, options); } } public static T getWhere(final Class clazz, final QueryOptions options) throws Exception { - options.add(new Limit(1)); - final List values = getsWhere(clazz, options); - if (values.size() == 0) { - return null; - } - return values.get(0); - } - - public static T getWhere(final Class clazz, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - return getWhere(clazz, options); - } - - public static void generateSelectField(// - final StringBuilder querySelect, // - final StringBuilder query, // - final Class clazz, // - final QueryOptions options, // - final CountInOut count// - ) throws Exception { - final boolean readAllfields = QueryOptions.readAllColomn(options); - final String tableName = AnnotationTools.getTableName(clazz, options); - final String primaryKey = AnnotationTools.getPrimaryKeyField(clazz).getName(); - boolean firstField = true; - - for (final Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canRetrieve(elem)) { - continue; - } - final boolean notRead = AnnotationTools.isdefaultNotRead(elem); - if (!readAllfields && notRead) { - continue; - } - final String name = AnnotationTools.getFieldName(elem); - if (firstField) { - firstField = false; - } else { - querySelect.append(","); - } - querySelect.append(" "); - if (addOn != null) { - addOn.generateQuery(tableName, primaryKey, elem, querySelect, query, name, count, options); - } else { - querySelect.append(tableName); - querySelect.append("."); - querySelect.append(name); - count.inc(); - } + try (DBAccess db = DBAccess.createInterface()) { + return db.getWhere(clazz, options); } } - public static List getsWhere(final Class clazz, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - return getsWhere(clazz, options); + public static T getWhere(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.getWhere(clazz, options); + } + } + + public static List getsWhere(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.getsWhere(clazz, options); + } } public static Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty) - throws DataAccessException { - if (options == null) { - return new Condition(); + throws DataAccessException, IOException { + try (DBAccess db = DBAccess.createInterface()) { + return db.conditionFusionOrEmpty(options, throwIfEmpty); } - final List conditions = options.get(Condition.class); - if (conditions.size() == 0) { - if (throwIfEmpty) { - throw new DataAccessException("request a gets without any condition"); - } else { - return new Condition(); - } - } - Condition condition = null; - if (conditions.size() == 1) { - condition = conditions.get(0); - } else { - final QueryAnd andCondition = new QueryAnd(); - for (final Condition cond : conditions) { - andCondition.add(cond.condition); - } - condition = new Condition(andCondition); - } - return condition; } - @SuppressWarnings("unchecked") public static List getsWhere(final Class clazz, final QueryOptions options) throws DataAccessException, IOException { - final Condition condition = conditionFusionOrEmpty(options, false); - final List lazyCall = new ArrayList<>(); - final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - final List outs = new ArrayList<>(); - try (final DBEntry entry = DBInterfaceOption.getAutoEntry(options)) { - final CountInOut count = new CountInOut(); - final StringBuilder querySelect = new StringBuilder(); - StringBuilder query = new StringBuilder(); - final String tableName = AnnotationTools.getTableName(clazz, options); - querySelect.append("SELECT "); - query.append(" FROM `"); - query.append(tableName); - query.append("` "); - - generateSelectField(querySelect, query, clazz, options, count); - querySelect.append(query.toString()); - query = querySelect; - condition.whereAppendQuery(query, tableName, options, deletedFieldName); - final List groups = options.get(GroupBy.class); - for (final GroupBy group : groups) { - group.generateQuery(query, tableName); - } - final List orders = options.get(OrderBy.class); - for (final OrderBy order : orders) { - order.generateQuery(query, tableName); - } - final List limits = options.get(Limit.class); - if (limits.size() == 1) { - limits.get(0).generateQuery(query, tableName); - } else if (limits.size() > 1) { - throw new DataAccessException("Request with multiple 'limit'..."); - } - LOGGER.debug("generate the query: '{}'", query.toString()); - // prepare the request: - try (final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), - Statement.RETURN_GENERATED_KEYS)) { - final CountInOut iii = new CountInOut(1); - condition.injectQuery(ps, iii); - if (limits.size() == 1) { - limits.get(0).injectQuery(ps, iii); - } - // execute the request - final ResultSet rs = ps.executeQuery(); - while (rs.next()) { - count.value = 1; - final CountInOut countNotNull = new CountInOut(0); - final Object data = createObjectFromSQLRequest(rs, clazz, count, countNotNull, options, lazyCall); - final T out = (T) data; - outs.add(out); - } - LOGGER.info("Async calls: {}", lazyCall.size()); - for (final LazyGetter elem : lazyCall) { - elem.doRequest(); - } - } - } catch (final SQLException ex) { - ex.printStackTrace(); - throw new DataAccessException("Catch a SQL Exception: " + ex.getMessage()); - } catch (final Exception ex) { - ex.printStackTrace(); - throw new DataAccessException("Catch an Exception: " + ex.getMessage()); + try (DBAccess db = DBAccess.createInterface()) { + return db.getsWhere(clazz, options); } - return outs; } - public static Object createObjectFromSQLRequest( - final ResultSet rs, - final Class clazz, - final CountInOut count, - final CountInOut countNotNull, - final QueryOptions options, - final List lazyCall) throws Exception { - final boolean readAllfields = QueryOptions.readAllColomn(options); - // TODO: manage class that is defined inside a class ==> Not manage for now... - Object data = null; - for (final Constructor contructor : clazz.getConstructors()) { - if (contructor.getParameterCount() == 0) { - data = contructor.newInstance(); - } - } - if (data == null) { - throw new DataAccessException( - "Can not find the default constructor for the class: " + clazz.getCanonicalName()); - } - for (final Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canRetrieve(elem)) { - continue; - } - final boolean notRead = AnnotationTools.isdefaultNotRead(elem); - if (!readAllfields && notRead) { - continue; - } - if (addOn != null) { - addOn.fillFromQuery(rs, elem, data, count, options, lazyCall); - } else { - setValueFromDb(elem.getType(), data, count, elem, rs, countNotNull); - } - } - return data; - } - - public static long count(final Class clazz, final ID_TYPE id, final QueryOption... option) + public static long count(final Class clazz, final ID_TYPE id, final QueryOption... options) throws Exception { - final QueryOptions options = new QueryOptions(option); - options.add(new Condition(getTableIdCondition(clazz, id))); - return DataAccess.countWhere(clazz, options); + try (DBAccess db = DBAccess.createInterface()) { + return db.count(clazz, id, options); + } } - public static long countWhere(final Class clazz, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - return countWhere(clazz, options); + public static long countWhere(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.countWhere(clazz, options); + } } public static long countWhere(final Class clazz, final QueryOptions options) throws Exception { - final Condition condition = conditionFusionOrEmpty(options, false); - final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - DBEntry entry = DBInterfaceOption.getAutoEntry(options); - long count = 0; - // real add in the BDD: - try { - final StringBuilder query = new StringBuilder(); - final String tableName = AnnotationTools.getTableName(clazz, options); - query.append("SELECT COUNT(*) AS count FROM `"); - query.append(tableName); - query.append("` "); - condition.whereAppendQuery(query, tableName, options, deletedFieldName); - final List limits = options.get(Limit.class); - if (limits.size() == 1) { - limits.get(0).generateQuery(query, tableName); - } else if (limits.size() > 1) { - throw new DataAccessException("Request with multiple 'limit'..."); - } - LOGGER.debug("generate the query: '{}'", query.toString()); - // prepare the request: - final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), - Statement.RETURN_GENERATED_KEYS); - final CountInOut iii = new CountInOut(1); - condition.injectQuery(ps, iii); - if (limits.size() == 1) { - limits.get(0).injectQuery(ps, iii); - } - // execute the request - final ResultSet rs = ps.executeQuery(); - if (rs.next()) { - count = rs.getLong("count"); - } - } catch (final SQLException ex) { - ex.printStackTrace(); - throw ex; - } catch (final Exception ex) { - ex.printStackTrace(); - } finally { - entry.close(); - entry = null; + try (DBAccess db = DBAccess.createInterface()) { + return db.countWhere(clazz, options); } - return count; } - public static T get(final Class clazz, final ID_TYPE id, final QueryOption... option) + public static T get(final Class clazz, final ID_TYPE id, final QueryOption... options) throws Exception { - final QueryOptions options = new QueryOptions(option); - options.add(new Condition(getTableIdCondition(clazz, id))); - return DataAccess.getWhere(clazz, options.getAllArray()); + try (DBAccess db = DBAccess.createInterface()) { + return db.get(clazz, id, options); + } } public static List gets(final Class clazz) throws Exception { - return getsWhere(clazz); + try (DBAccess db = DBAccess.createInterface()) { + return db.gets(clazz); + } } - public static List gets(final Class clazz, final QueryOption... option) throws Exception { - return getsWhere(clazz, option); + public static List gets(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.gets(clazz, options); + } } /** Delete items with the specific Id (cf @Id) and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before). @@ -1591,13 +212,10 @@ public class DataAccess { * @param id Unique Id of the model * @param options (Optional) Options of the request * @return Number of element that is removed. */ - public static int delete(final Class clazz, final ID_TYPE id, final QueryOption... options) + public static long delete(final Class clazz, final ID_TYPE id, final QueryOption... options) throws Exception { - final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - if (hasDeletedFieldName != null) { - return deleteSoft(clazz, id, options); - } else { - return deleteHard(clazz, id, options); + try (DBAccess db = DBAccess.createInterface()) { + return db.delete(clazz, id, options); } } @@ -1606,303 +224,69 @@ public class DataAccess { * @param condition Condition to remove elements. * @param options (Optional) Options of the request. * @return Number of element that is removed. */ - public static int deleteWhere(final Class clazz, final QueryOption... option) throws Exception { - - final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - if (hasDeletedFieldName != null) { - return deleteSoftWhere(clazz, option); - } else { - return deleteHardWhere(clazz, option); + public static long deleteWhere(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.deleteWhere(clazz, options); } } - public static int deleteHard(final Class clazz, final ID_TYPE id, final QueryOption... option) + public static long deleteHard(final Class clazz, final ID_TYPE id, final QueryOption... options) throws Exception { - final QueryOptions options = new QueryOptions(option); - options.add(new Condition(getTableIdCondition(clazz, id))); - return deleteHardWhere(clazz, options.getAllArray()); - } - - public static int deleteHardWhere(final Class clazz, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - final Condition condition = conditionFusionOrEmpty(options, true); - final String tableName = AnnotationTools.getTableName(clazz, options); - final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - // find the deleted field - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final StringBuilder query = new StringBuilder(); - query.append("DELETE FROM `"); - query.append(tableName); - query.append("` "); - condition.whereAppendQuery(query, tableName, null, deletedFieldName); - try { - LOGGER.debug("APPLY: {}", query.toString()); - final PreparedStatement ps = entry.connection.prepareStatement(query.toString()); - final CountInOut iii = new CountInOut(1); - condition.injectQuery(ps, iii); - return ps.executeUpdate(); - } finally { - entry.close(); + try (DBAccess db = DBAccess.createInterface()) { + return db.deleteHard(clazz, id, options); } } - private static int deleteSoft(final Class clazz, final ID_TYPE id, final QueryOption... option) + public static long deleteHardWhere(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.deleteHardWhere(clazz, options); + } + } + + public static long deleteSoft(final Class clazz, final ID_TYPE id, final QueryOption... options) throws Exception { - final QueryOptions options = new QueryOptions(option); - options.add(new Condition(getTableIdCondition(clazz, id))); - return deleteSoftWhere(clazz, options.getAllArray()); - } - - public static int deleteSoftWhere(final Class clazz, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - final Condition condition = conditionFusionOrEmpty(options, true); - final String tableName = AnnotationTools.getTableName(clazz, options); - final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - /* String updateFieldName = null; if ("sqlite".equalsIgnoreCase(ConfigBaseVariable.getDBType())) { updateFieldName = AnnotationTools.getUpdatedFieldName(clazz); } */ - // find the deleted field - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final StringBuilder query = new StringBuilder(); - query.append("UPDATE `"); - query.append(tableName); - query.append("` SET `"); - query.append(deletedFieldName); - query.append("`=true "); - /* The trigger work well, but the timestamp is store @ seconds... if (updateFieldName != null) { // done only in SQLite (the trigger does not work... query.append(", `"); - * query.append(updateFieldName); query.append("`=DATE()"); } */ - condition.whereAppendQuery(query, tableName, null, deletedFieldName); - try { - LOGGER.debug("APPLY UPDATE: {}", query.toString()); - final PreparedStatement ps = entry.connection.prepareStatement(query.toString()); - final CountInOut iii = new CountInOut(1); - condition.injectQuery(ps, iii); - return ps.executeUpdate(); - } finally { - entry.close(); + try (DBAccess db = DBAccess.createInterface()) { + return db.deleteSoft(clazz, id, options); } } - public static int unsetDelete(final Class clazz, final ID_TYPE id) throws DataAccessException { - return unsetDeleteWhere(clazz, new Condition(getTableIdCondition(clazz, id))); - } - - public static int unsetDelete(final Class clazz, final ID_TYPE id, final QueryOption... option) - throws DataAccessException { - final QueryOptions options = new QueryOptions(option); - options.add(new Condition(getTableIdCondition(clazz, id))); - return unsetDeleteWhere(clazz, options.getAllArray()); - } - - public static int unsetDeleteWhere(final Class clazz, final QueryOption... option) throws DataAccessException { - final QueryOptions options = new QueryOptions(option); - final Condition condition = conditionFusionOrEmpty(options, true); - final String tableName = AnnotationTools.getTableName(clazz, options); - final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - if (deletedFieldName == null) { - throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field"); - } - DBEntry entry; - try { - entry = DBInterfaceOption.getAutoEntry(options); - } catch (final IOException ex) { - throw new DataAccessException("Fail to connect the DB: " + ex.getMessage()); - } - final StringBuilder query = new StringBuilder(); - query.append("UPDATE `"); - query.append(tableName); - query.append("` SET `"); - query.append(deletedFieldName); - query.append("`=false "); - // need to disable the deleted false because the model must be unselected to be updated. - options.add(QueryOptions.ACCESS_DELETED_ITEMS); - condition.whereAppendQuery(query, tableName, options, deletedFieldName); - try (final PreparedStatement ps = entry.connection.prepareStatement(query.toString())) { - final CountInOut iii = new CountInOut(1); - condition.injectQuery(ps, iii); - return ps.executeUpdate(); - } catch (final SQLException ex) { - throw new DataAccessException("Catch SQL error:" + ex.getMessage()); - } catch (final Exception ex) { - throw new DataAccessException("Fail to excute the SQL query:" + ex.getMessage()); + public static long deleteSoftWhere(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + return db.deleteSoftWhere(clazz, options); } } - public static void drop(final Class clazz, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - final String tableName = AnnotationTools.getTableName(clazz, options); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final StringBuilder query = new StringBuilder(); - query.append("DROP TABLE IF EXISTS `"); - query.append(tableName); - query.append("`"); - try { - LOGGER.trace("Execute Query: {}", query.toString()); - // Remove main table - final PreparedStatement ps = entry.connection.prepareStatement(query.toString()); - ps.executeUpdate(); - // search subTable: - 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; - } - if (AnnotationTools.isGenericField(field)) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(field); - if (addOn != null && !addOn.canInsert(field)) { - addOn.drop(tableName, field); - } - } - } finally { - entry.close(); + public static long unsetDelete(final Class clazz, final ID_TYPE id) + throws DataAccessException, IOException { + try (DBAccess db = DBAccess.createInterface()) { + return db.unsetDelete(clazz, id); } } - public static void cleanAll(final Class clazz, final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - final String tableName = AnnotationTools.getTableName(clazz, options); - DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final StringBuilder query = new StringBuilder(); - query.append("DELETE FROM `"); - query.append(tableName); - query.append("`"); - try { - LOGGER.trace("Execute Query: {}", query.toString()); - // Remove main table - final PreparedStatement ps = entry.connection.prepareStatement(query.toString()); - ps.executeUpdate(); - // search subTable: - 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; - } - if (AnnotationTools.isGenericField(field)) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(field); - if (addOn != null && !addOn.canInsert(field)) { - addOn.cleanAll(tableName, field); - } - } - } finally { - entry.close(); - entry = null; + public static long unsetDelete(final Class clazz, final ID_TYPE id, final QueryOption... options) + throws DataAccessException, IOException { + try (DBAccess db = DBAccess.createInterface()) { + return db.unsetDelete(clazz, id, options); } } - /** Execute a simple query with external property. - * @param Type of the data generate. - * @param clazz Class that might be analyze. - * @param query Base of the query. - * @param parameters "?" parameter of the query. - * @param option Optional parameters - * @return The list of element requested - * @throws Exception */ - public static List query( - final Class clazz, - final String query, - final List parameters, - final QueryOption... option) throws Exception { - final QueryOptions options = new QueryOptions(option); - return query(clazz, query, parameters, options); - } - - public static List query( - final Class clazz, - final String queryBase, - final List parameters, - final QueryOptions options) throws Exception { - final List lazyCall = new ArrayList<>(); - // TODO ... final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - - final Condition condition = conditionFusionOrEmpty(options, false); - final StringBuilder query = new StringBuilder(queryBase); - final List outs = new ArrayList<>(); - // real add in the BDD: - try { - final CountInOut count = new CountInOut(); - condition.whereAppendQuery(query, null, options, null); - - final List groups = options.get(GroupBy.class); - for (final GroupBy group : groups) { - group.generateQuery(query, null); - } - final List orders = options.get(OrderBy.class); - for (final OrderBy order : orders) { - order.generateQuery(query, null); - } - final List limits = options.get(Limit.class); - if (limits.size() == 1) { - limits.get(0).generateQuery(query, null); - } else if (limits.size() > 1) { - throw new DataAccessException("Request with multiple 'limit'..."); - } - LOGGER.debug("generate the query: '{}'", query.toString()); - // prepare the request: - final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), - Statement.RETURN_GENERATED_KEYS); - final CountInOut iii = new CountInOut(1); - if (parameters != null) { - for (final Object elem : parameters) { - DataAccess.addElement(ps, elem, iii); - } - iii.inc(); - } - condition.injectQuery(ps, iii); - if (limits.size() == 1) { - limits.get(0).injectQuery(ps, iii); - } - // execute the request - final ResultSet rs = ps.executeQuery(); - final ResultSetMetaData rsmd = rs.getMetaData(); - final List actionToRetreive = new ArrayList<>(); - LOGGER.info("Field:"); - for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) { - final String label = rsmd.getColumnLabel(jjj + 1); - LOGGER.info(" - {}:{}", jjj, label); - // find field name ... - final Field field = AnnotationTools.getFieldNamed(clazz, label); - if (field == null) { - throw new DataAccessException("Query with unknown field: '" + label + "'"); - } - // create the callback... - final RetreiveFromDB element = createSetValueFromDbCallback(jjj + 1, field); - actionToRetreive.add(element); - } - - while (rs.next()) { - count.value = 1; - Object data = null; - for (final Constructor contructor : clazz.getConstructors()) { - if (contructor.getParameterCount() == 0) { - data = contructor.newInstance(); - } - } - if (data == null) { - // TODO... - } else { - for (final RetreiveFromDB action : actionToRetreive) { - action.doRequest(rs, data); - } - } - @SuppressWarnings("unchecked") - final TYPE out = (TYPE) data; - outs.add(out); - } - LOGGER.info("Async calls: {}", lazyCall.size()); - for (final LazyGetter elem : lazyCall) { - elem.doRequest(); - } - } catch (final SQLException ex) { - ex.printStackTrace(); - throw ex; - } catch (final Exception ex) { - ex.printStackTrace(); - } finally { - entry.close(); + public static long unsetDeleteWhere(final Class clazz, final QueryOption... options) + throws DataAccessException, IOException { + try (DBAccess db = DBAccess.createInterface()) { + return db.unsetDeleteWhere(clazz, options); } - return outs; } + + public static void drop(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + db.drop(clazz, options); + } + } + + public static void cleanAll(final Class clazz, final QueryOption... options) throws Exception { + try (DBAccess db = DBAccess.createInterface()) { + db.cleanAll(clazz, options); + } + } + } diff --git a/src/org/kar/archidata/dataAccess/DataExport.java b/src/org/kar/archidata/dataAccess/DataExport.java index bb0c150..3e1eba3 100644 --- a/src/org/kar/archidata/dataAccess/DataExport.java +++ b/src/org/kar/archidata/dataAccess/DataExport.java @@ -19,12 +19,10 @@ import java.util.UUID; import org.kar.archidata.dataAccess.exportTools.TableQuery; import org.kar.archidata.dataAccess.exportTools.TableQueryTypes; import org.kar.archidata.dataAccess.options.Condition; -import org.kar.archidata.dataAccess.options.DBInterfaceOption; import org.kar.archidata.dataAccess.options.GroupBy; import org.kar.archidata.dataAccess.options.Limit; import org.kar.archidata.dataAccess.options.OrderBy; import org.kar.archidata.dataAccess.options.QueryOption; -import org.kar.archidata.db.DBEntry; import org.kar.archidata.exception.DataAccessException; import org.kar.archidata.tools.DateTools; import org.slf4j.Logger; @@ -246,24 +244,24 @@ public class DataExport { } public static TableQuery queryTable( + final DBAccessSQL ioDb, final List headers, final String query, final List parameters, final QueryOption... option) throws Exception { final QueryOptions options = new QueryOptions(option); - return queryTable(headers, query, parameters, options); + return queryTable(ioDb, headers, query, parameters, options); } public static TableQuery queryTable( + final DBAccessSQL ioDb, final List headers, final String queryBase, final List parameters, final QueryOptions options) throws Exception { final List lazyCall = new ArrayList<>(); - // TODO ... final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - final DBEntry entry = DBInterfaceOption.getAutoEntry(options); - final Condition condition = DataAccess.conditionFusionOrEmpty(options, false); + final Condition condition = ioDb.conditionFusionOrEmpty(options, false); final StringBuilder query = new StringBuilder(queryBase); final TableQuery out = new TableQuery(headers); // real add in the BDD: @@ -286,18 +284,18 @@ public class DataExport { } LOGGER.warn("generate the query: '{}'", query.toString()); // prepare the request: - final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), + final PreparedStatement ps = ioDb.getConnection().prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); final CountInOut iii = new CountInOut(1); if (parameters != null) { for (final Object elem : parameters) { - DataAccess.addElement(ps, elem, iii); + ioDb.addElement(ps, elem, iii); } iii.inc(); } - condition.injectQuery(ps, iii); + condition.injectQuery(ioDb, ps, iii); if (limits.size() == 1) { - limits.get(0).injectQuery(ps, iii); + limits.get(0).injectQuery(ioDb, ps, iii); } // execute the request final ResultSet rs = ps.executeQuery(); @@ -332,8 +330,6 @@ public class DataExport { throw ex; } catch (final Exception ex) { ex.printStackTrace(); - } finally { - entry.close(); } return out; } diff --git a/src/org/kar/archidata/dataAccess/DataFactory.java b/src/org/kar/archidata/dataAccess/DataFactory.java index 89e39f4..fc9db8e 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; @@ -25,10 +26,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.GenerationType; public class DataFactory { - static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class); public static String convertTypeInSQL(final Class type, final String fieldName) throws DataAccessException { - if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { + final String typelocal = ConfigBaseVariable.getDBType(); + if ("mysql".equals(typelocal)) { if (type == UUID.class) { return "binary(16)"; } @@ -82,7 +84,7 @@ public class DataFactory { out.append(")"); return out.toString(); } - } else { + } else if ("sqlite".equals(typelocal)) { if (type == UUID.class) { return "BINARY(16)"; } @@ -138,6 +140,9 @@ public class DataFactory { out.append(" ) )"); return out.toString(); } + } else if ("mongo".equals(typelocal)) { + // no importance for mango ... + return "text"; } throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName()); } @@ -162,7 +167,7 @@ public class DataFactory { final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; - final String comment = AnnotationTools.getComment(elem); + final String comment = AnnotationTools.getSchemaDescription(elem); final String defaultValue = AnnotationTools.getDefault(elem); if (mainTableBuilder.toString().length() == 0) { @@ -383,8 +388,8 @@ public class DataFactory { } alreadyAdded.add(dataName); LOGGER.trace(" + '{}'", elem.getName()); - if (DataAccess.isAddOnField(elem)) { - final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem); + if (DBAccessSQL.isAddOnField(elem)) { + final DataAccessAddOn addOn = DBAccessSQL.findAddOnforField(elem); LOGGER.trace("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType()); if (addOn != null) { @@ -439,4 +444,4 @@ public class DataFactory { return preActionList; } -} \ No newline at end of file +} diff --git a/src/org/kar/archidata/dataAccess/QueryAnd.java b/src/org/kar/archidata/dataAccess/QueryAnd.java index 55f7f4a..738bcff 100644 --- a/src/org/kar/archidata/dataAccess/QueryAnd.java +++ b/src/org/kar/archidata/dataAccess/QueryAnd.java @@ -5,6 +5,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.bson.conversions.Bson; + +import com.mongodb.client.model.Filters; + public class QueryAnd implements QueryItem { protected final List childs; @@ -41,14 +45,22 @@ public class QueryAnd implements QueryItem { } @Override - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { - + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception { for (final QueryItem elem : this.childs) { - elem.injectQuery(ps, iii); + elem.injectQuery(ioDb, ps, iii); } } public int size() { return this.childs.size(); } + + @Override + public void generateFilter(final List filters) { + final List filtersLocal = new ArrayList<>(); + for (final QueryItem elem : this.childs) { + elem.generateFilter(filtersLocal); + } + filters.add(Filters.and(filtersLocal.toArray(new Bson[0]))); + } } diff --git a/src/org/kar/archidata/dataAccess/QueryCondition.java b/src/org/kar/archidata/dataAccess/QueryCondition.java index c399d3f..f356dc0 100644 --- a/src/org/kar/archidata/dataAccess/QueryCondition.java +++ b/src/org/kar/archidata/dataAccess/QueryCondition.java @@ -1,8 +1,16 @@ package org.kar.archidata.dataAccess; import java.sql.PreparedStatement; +import java.util.List; + +import org.bson.conversions.Bson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mongodb.client.model.Filters; public class QueryCondition implements QueryItem { + static final Logger LOGGER = LoggerFactory.getLogger(DBAccess.class); private final String key; private final String comparator; private final Object value; @@ -32,8 +40,28 @@ public class QueryCondition implements QueryItem { } @Override - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { - DataAccess.addElement(ps, this.value, iii); + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception { + ioDb.addElement(ps, this.value, iii); iii.inc(); } + + @Override + public void generateFilter(final List filters) { + if ("=".equals(this.comparator)) { + filters.add(Filters.eq(this.key, this.value)); + } else if ("!=".equals(this.comparator)) { + filters.add(Filters.ne(this.key, this.value)); + } else if (">".equals(this.comparator)) { + filters.add(Filters.gt(this.key, this.value)); + } else if (">=".equals(this.comparator)) { + filters.add(Filters.gte(this.key, this.value)); + } else if ("<".equals(this.comparator)) { + filters.add(Filters.lt(this.key, this.value)); + } else if ("<=".equals(this.comparator)) { + filters.add(Filters.lte(this.key, this.value)); + } else { + LOGGER.error("Not manage comparison: '{}'", this.key); + } + + } } diff --git a/src/org/kar/archidata/dataAccess/QueryInList.java b/src/org/kar/archidata/dataAccess/QueryInList.java index bfacf9f..e3b0205 100644 --- a/src/org/kar/archidata/dataAccess/QueryInList.java +++ b/src/org/kar/archidata/dataAccess/QueryInList.java @@ -3,6 +3,10 @@ package org.kar.archidata.dataAccess; import java.sql.PreparedStatement; import java.util.List; +import org.bson.conversions.Bson; + +import com.mongodb.client.model.Filters; + public class QueryInList implements QueryItem { protected final String key; protected final String comparator; @@ -44,10 +48,15 @@ public class QueryInList implements QueryItem { } @Override - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception { for (final Object elem : this.value) { - DataAccess.addElement(ps, elem, iii); + ioDb.addElement(ps, elem, iii); iii.inc(); } } + + @Override + public void generateFilter(final List filters) { + filters.add(Filters.in(this.key, this.value)); + } } diff --git a/src/org/kar/archidata/dataAccess/QueryItem.java b/src/org/kar/archidata/dataAccess/QueryItem.java index 20498b7..5cda519 100644 --- a/src/org/kar/archidata/dataAccess/QueryItem.java +++ b/src/org/kar/archidata/dataAccess/QueryItem.java @@ -1,9 +1,17 @@ package org.kar.archidata.dataAccess; import java.sql.PreparedStatement; +import java.util.List; + +import org.bson.conversions.Bson; public interface QueryItem { + // For SQL mode query construction void generateQuery(StringBuilder query, String tableName); - void injectQuery(PreparedStatement ps, CountInOut iii) throws Exception; + // For SQL mode query injection + void injectQuery(DBAccessSQL ioDb, PreparedStatement ps, CountInOut iii) throws Exception; + + // For No-SQL mode filter creation + void generateFilter(List filters); } diff --git a/src/org/kar/archidata/dataAccess/QueryNotNull.java b/src/org/kar/archidata/dataAccess/QueryNotNull.java index 3bcef4e..05aa0bd 100644 --- a/src/org/kar/archidata/dataAccess/QueryNotNull.java +++ b/src/org/kar/archidata/dataAccess/QueryNotNull.java @@ -1,6 +1,11 @@ package org.kar.archidata.dataAccess; import java.sql.PreparedStatement; +import java.util.List; + +import org.bson.conversions.Bson; + +import com.mongodb.client.model.Filters; public class QueryNotNull implements QueryItem { private final String key; @@ -20,5 +25,11 @@ public class QueryNotNull implements QueryItem { } @Override - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {} + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) + throws Exception {} + + @Override + public void generateFilter(final List filters) { + filters.add(Filters.exists(this.key)); + } } diff --git a/src/org/kar/archidata/dataAccess/QueryNull.java b/src/org/kar/archidata/dataAccess/QueryNull.java index dfc70d4..11aec2d 100644 --- a/src/org/kar/archidata/dataAccess/QueryNull.java +++ b/src/org/kar/archidata/dataAccess/QueryNull.java @@ -1,6 +1,11 @@ package org.kar.archidata.dataAccess; import java.sql.PreparedStatement; +import java.util.List; + +import org.bson.conversions.Bson; + +import com.mongodb.client.model.Filters; public class QueryNull implements QueryItem { private final String key; @@ -20,5 +25,12 @@ public class QueryNull implements QueryItem { } @Override - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {} + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) + throws Exception {} + + @Override + public void generateFilter(final List filters) { + // Not sure of the result ... maybe check it ... + filters.add(Filters.eq(this.key, null)); + } } diff --git a/src/org/kar/archidata/dataAccess/QueryOr.java b/src/org/kar/archidata/dataAccess/QueryOr.java index 18e28aa..ecede52 100644 --- a/src/org/kar/archidata/dataAccess/QueryOr.java +++ b/src/org/kar/archidata/dataAccess/QueryOr.java @@ -1,8 +1,13 @@ package org.kar.archidata.dataAccess; import java.sql.PreparedStatement; +import java.util.ArrayList; import java.util.List; +import org.bson.conversions.Bson; + +import com.mongodb.client.model.Filters; + public class QueryOr implements QueryItem { protected final List childs; @@ -34,9 +39,18 @@ public class QueryOr implements QueryItem { } @Override - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception { for (final QueryItem elem : this.childs) { - elem.injectQuery(ps, iii); + elem.injectQuery(ioDb, ps, iii); } } + + @Override + public void generateFilter(final List filters) { + final List filtersLocal = new ArrayList<>(); + for (final QueryItem elem : this.childs) { + elem.generateFilter(filtersLocal); + } + filters.add(Filters.or(filtersLocal.toArray(new Bson[0]))); + } } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java b/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java deleted file mode 100644 index 7393115..0000000 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java +++ /dev/null @@ -1,346 +0,0 @@ -package org.kar.archidata.dataAccess.addOn; - -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.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.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.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.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.type.TypeFactory; - -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 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 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 TypeFactory typeFactory = objectMapper.getTypeFactory(); - final JavaType fieldType = typeFactory.constructType(field.getGenericType()); - final Object dataParsed = objectMapper.readValue(jsonData, fieldType); - //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 Class clazz, final Long id, final String column, final Long remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final TableCoversLongLong data = DataAccess.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); - DataAccess.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 Class clazz, final Long id, final String column, final UUID remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - // TODO: Get primary key name - final TableCoversLongUUID data = DataAccess.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); - DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));// TODO: ,new OverrideFieldName("covers", column)); - } - - /** - * 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 Class clazz, final UUID uuid, final String column, final UUID remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final TableCoversUUIDUUID data = DataAccess.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); - DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); - } - - public static void addLink(final Class clazz, final UUID uuid, final String column, final Long remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final TableCoversUUIDLong data = DataAccess.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); - DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); - } - - public static void removeLink(final Class clazz, final UUID uuid, final String column, final Long remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final TableCoversUUIDLong data = DataAccess.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; - DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); - } - - public static void removeLink(final Class clazz, final UUID uuid, final String column, final UUID remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final TableCoversUUIDUUID data = DataAccess.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; - DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName)); - } - - public static void removeLink(final Class clazz, final Long id, final String column, final Long remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final TableCoversLongLong data = DataAccess.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; - DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); - } - - public static void removeLink(final Class clazz, final Long id, final String column, final UUID remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final TableCoversLongUUID data = DataAccess.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; - DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); - } -} 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..f1fd1fe --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnDataJson.java @@ -0,0 +1,457 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +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.DBAccess; +import org.kar.archidata.dataAccess.DBAccessMorphia; +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.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 DBAccessMorphia ioDb, + final Field field, + final Object rootObject, + final Document docSet, + final Document docUnSet) throws Exception { + /* + 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 fillFromDoc( + final DBAccessMorphia ioDb, + final Document doc, + final Field field, + final Object data, + final QueryOptions options, + final List lazyCall) throws Exception { + /* + final String fieldName = AnnotationTools.getFieldName(field); + if (!doc.containsKey(fieldName)) { + field.set(data, null); + return; + } + final String jsonData = rs.getString(count.value); + 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 DBAccess 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 DBAccess ioDb, + final Class clazz, + final Long id, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia 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 DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void addLink( + final DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final Long id, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final Long id, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia 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..3050be2 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToMany.java @@ -0,0 +1,590 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +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.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DBAccess; +import org.kar.archidata.dataAccess.DBAccessMorphia; +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.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.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 DBAccessMorphia ioDb, + final Field field, + final Object rootObject, + final Document docSet, + final Document docUnSet) throws Exception { + + } + + @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]; + 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, + final Document doc, + final Field field, + final Object data, + 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 String fieldName = AnnotationTools.getFieldName(field); + if (!doc.containsKey(fieldName)) { + field.set(data, null); + 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 (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 DBAccessMorphia 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 DBAccessMorphia 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 DBAccessMorphia 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 DBAccessMorphia 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 DBAccess ioDb, + final Class clazz, + final long localKey, + final String column, + final long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + + } + + public static long removeLink( + final DBAccess ioDb, + final Class clazz, + final long localKey, + final String column, + final long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessMorphia 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 DBAccessMorphia 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..484e032 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnManyToOne.java @@ -0,0 +1,230 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.UUID; + +import org.bson.Document; +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DBAccessMorphia; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryOptions; +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); + + @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 DBAccessMorphia ioDb, + final Field field, + final Object rootObject, + final Document docSet, + final Document docUnSet) throws Exception { + final String fieldName = AnnotationTools.getFieldName(field); + final Object data = field.get(rootObject); + if (field.get(data) == null) { + docUnSet.append(fieldName, ""); + return; + } else if (field.getType() == Long.class) { + final Long dataTyped = (Long) data; + docSet.append(fieldName, dataTyped); + } else if (field.getType() == Integer.class) { + final Integer dataTyped = (Integer) data; + docSet.append(fieldName, dataTyped); + } else if (field.getType() == Short.class) { + final Short dataTyped = (Short) data; + docSet.append(fieldName, dataTyped); + } else if (field.getType() == String.class) { + final String dataTyped = (String) data; + docSet.append(fieldName, dataTyped); + } else if (field.getType() == UUID.class) { + final UUID dataTyped = (UUID) data; + docSet.append(fieldName, dataTyped); + } else { + final Field idField = AnnotationTools.getFieldOfId(field.getType()); + final Object uid = idField.get(data); + if (uid == null) { + docUnSet.append(fieldName, ""); + } else { + docSet.append(fieldName, uid); + } + } + } + + @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()) { + // 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, + final Document doc, + final Field field, + final Object data, + final QueryOptions options, + final List lazyCall) throws Exception { + + final String fieldName = AnnotationTools.getFieldName(field); + if (!doc.containsKey(fieldName)) { + field.set(data, null); + return; + } + // 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) { + ioDb.setValueFromDoc(field.getType(), data, field, doc, lazyCall); + return; + } + final Class objectClass = field.getType(); + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (decorators == null) { + return; + } + if (objectClass == decorators.targetEntity()) { + + 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 = doc.getLong(fieldName); + 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); + } + } 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); + 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..fae4d7a --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/AddOnOneToMany.java @@ -0,0 +1,322 @@ +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.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DBAccessMorphia; +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 DBAccessMorphia ioDb, + final Field field, + final Object rootObject, + final Document docSet, + final Document docUnSet) throws Exception { + 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 fillFromDoc( + final DBAccessMorphia ioDb, + final Document doc, + final Field field, + final Object data, + 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 String fieldName = AnnotationTools.getFieldName(field); + if (!doc.containsKey(fieldName)) { + field.set(data, null); + 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 || objectClass == UUID.class) { + final Object value = doc.get(fieldName, 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); + } + } + } + } + + // 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..52ca5e6 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnMongo/DataAccessAddOn.java @@ -0,0 +1,151 @@ +package org.kar.archidata.dataAccess.addOnMongo; + +import java.lang.reflect.Field; +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 */ + 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 DBAccessMorphia ioDb, + final Field field, + final Object rootObject, + final Document docSet, + final Document docUnSet) throws Exception; + + /** 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 fillFromDoc( + final DBAccessMorphia ioDb, + Document doc, + Field field, + Object data, + 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 DBAccessMorphia 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 DBAccessMorphia ioDb, + final String tableName, + final Object localId, + final Field field, + final Object data, + final List actions) throws Exception { + + } + + default void drop(final DBAccessMorphia ioDb, final String tableName, final Field field) throws Exception { + + } + + default void cleanAll(final DBAccessMorphia ioDb, final String tableName, final Field field) throws Exception { + + } + +} diff --git a/src/org/kar/archidata/dataAccess/addOnSQL/AddOnDataJson.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnDataJson.java new file mode 100644 index 0000000..7860e5d --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnDataJson.java @@ -0,0 +1,464 @@ +package org.kar.archidata.dataAccess.addOnSQL; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.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.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; +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.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +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 DBAccessSQL 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 DBAccessSQL 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 TypeFactory typeFactory = objectMapper.getTypeFactory(); + final JavaType fieldType = typeFactory.constructType(field.getGenericType()); + final Object dataParsed = objectMapper.readValue(jsonData, fieldType); + 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 DBAccess 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 DBAccess ioDb, + final Class clazz, + final Long id, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia 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 DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void addLink( + final DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final UUID uuid, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final Long id, + final String column, + final Long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } + } + + public static void removeLink( + final DBAccess ioDb, + final Class clazz, + final Long id, + final String column, + final UUID remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia 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/addOn/AddOnManyToMany.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToMany.java similarity index 80% rename from src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java rename to src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToMany.java index c525376..2f5b51d 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; @@ -11,18 +11,19 @@ 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.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; 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; @@ -56,8 +57,12 @@ public class AddOnManyToMany implements DataAccessAddOn { } @Override - public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) - throws SQLException, IllegalArgumentException, IllegalAccessException { + public void insertData( + final DBAccessSQL ioDb, + final PreparedStatement ps, + final Field field, + final Object rootObject, + final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException { } @@ -120,8 +125,7 @@ public class AddOnManyToMany implements DataAccessAddOn { final String tmpVariable = "tmp_" + Integer.toString(count.value); querySelect.append(" (SELECT GROUP_CONCAT("); querySelect.append(tmpVariable); - final boolean mode = manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0; - if (mode) { + if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) { querySelect.append(".object2Id "); } else { querySelect.append(".object1Id "); @@ -129,7 +133,6 @@ public class AddOnManyToMany implements DataAccessAddOn { if ("sqlite".equals(ConfigBaseVariable.getDBType())) { querySelect.append(", "); } else { - querySelect.append("ORDER BY uuid ASC "); querySelect.append("SEPARATOR "); } querySelect.append("'"); @@ -155,7 +158,7 @@ public class AddOnManyToMany implements DataAccessAddOn { querySelect.append(" = "); querySelect.append(tmpVariable); querySelect.append("."); - if (mode) { + if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) { querySelect.append("object1Id "); } else { querySelect.append("object2Id "); @@ -163,7 +166,7 @@ public class AddOnManyToMany implements DataAccessAddOn { if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { querySelect.append(" GROUP BY "); querySelect.append(tmpVariable); - if (mode) { + if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) { querySelect.append(".object1Id"); } else { querySelect.append(".object2Id"); @@ -211,6 +214,7 @@ public class AddOnManyToMany implements DataAccessAddOn { @Override public void fillFromQuery( + final DBAccessSQL ioDb, final ResultSet rs, final Field field, final Object data, @@ -224,12 +228,12 @@ public class AddOnManyToMany implements DataAccessAddOn { final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) .getActualTypeArguments()[0]; if (objectClass == Long.class) { - final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG); + 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 = DataAccess.getListOfRawUUIDs(rs, count.value); + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); field.set(data, idList); count.inc(); return; @@ -243,7 +247,7 @@ public class AddOnManyToMany implements DataAccessAddOn { if (decorators.fetch() == FetchType.EAGER) { throw new DataAccessException("EAGER is not supported for list of element..."); } else if (foreignKeyType == Long.class) { - final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG); + final List idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG); // field.set(data, idList); count.inc(); if (idList != null && idList.size() > 0) { @@ -253,7 +257,7 @@ public class AddOnManyToMany implements DataAccessAddOn { final List childs = new ArrayList<>(idList); // TODO: update to have get with abstract types .... @SuppressWarnings("unchecked") - final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), new Condition(new QueryInList<>(idField, childs))); if (foreignData == null) { return; @@ -263,7 +267,7 @@ public class AddOnManyToMany implements DataAccessAddOn { lazyCall.add(lambda); } } else if (foreignKeyType == UUID.class) { - final List idList = DataAccess.getListOfRawUUIDs(rs, count.value); + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); // field.set(data, idList); count.inc(); if (idList != null && idList.size() > 0) { @@ -273,7 +277,7 @@ public class AddOnManyToMany implements DataAccessAddOn { final List childs = new ArrayList<>(idList); // TODO: update to have get with abstract types .... @SuppressWarnings("unchecked") - final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), new Condition(new QueryInList<>(idField, childs))); if (foreignData == null) { return; @@ -293,6 +297,7 @@ public class AddOnManyToMany implements DataAccessAddOn { @Override public void asyncUpdate( + final DBAccessSQL ioDb, final String tableName, final Object localKey, final Field field, @@ -314,30 +319,30 @@ public class AddOnManyToMany implements DataAccessAddOn { if (localKey instanceof final Long localKeyLong) { if (objectClass == Long.class) { actions.add(() -> { - DataAccess.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), + ioDb.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyLong))); }); - asyncInsert(tableName, localKey, field, data, actions); + asyncInsert(ioDb, tableName, localKey, field, data, actions); } else { actions.add(() -> { - DataAccess.deleteWhere(LinkTableLongUUID.class, new OverrideTableName(linkTableName), + ioDb.deleteWhere(LinkTableLongUUID.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyLong))); }); - asyncInsert(tableName, localKey, field, data, actions); + asyncInsert(ioDb, tableName, localKey, field, data, actions); } } else if (localKey instanceof final UUID localKeyUUID) { if (objectClass == Long.class) { actions.add(() -> { - DataAccess.deleteWhere(LinkTableUUIDLong.class, new OverrideTableName(linkTableName), + ioDb.deleteWhere(LinkTableUUIDLong.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyUUID))); }); - asyncInsert(tableName, localKey, field, data, actions); + asyncInsert(ioDb, tableName, localKey, field, data, actions); } else { actions.add(() -> { - DataAccess.deleteWhere(LinkTableUUIDUUID.class, new OverrideTableName(linkTableName), + ioDb.deleteWhere(LinkTableUUIDUUID.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyUUID))); }); - asyncInsert(tableName, localKey, field, data, actions); + asyncInsert(ioDb, tableName, localKey, field, data, actions); } } } @@ -349,6 +354,7 @@ public class AddOnManyToMany implements DataAccessAddOn { @Override public void asyncInsert( + final DBAccessSQL ioDb, final String tableName, final Object localKey, final Field field, @@ -391,7 +397,7 @@ public class AddOnManyToMany implements DataAccessAddOn { return; } actions.add(() -> { - DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); }); } else { // ======================================================== @@ -414,7 +420,7 @@ public class AddOnManyToMany implements DataAccessAddOn { return; } actions.add(() -> { - DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); }); } } else if (localKey instanceof final UUID localKeyUUID) { @@ -439,7 +445,7 @@ public class AddOnManyToMany implements DataAccessAddOn { return; } actions.add(() -> { - DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); }); } else { // ======================================================== @@ -462,7 +468,7 @@ public class AddOnManyToMany implements DataAccessAddOn { return; } actions.add(() -> { - DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName)); }); } } else { @@ -473,7 +479,7 @@ public class AddOnManyToMany implements DataAccessAddOn { } @Override - public void drop(final String tableName, final Field field) throws Exception { + public void drop(final DBAccessSQL 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()) @@ -482,11 +488,11 @@ public class AddOnManyToMany implements DataAccessAddOn { throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); } - DataAccess.drop(LinkTableLongLong.class, new OverrideTableName(linkTableName)); + ioDb.drop(LinkTableLongLong.class, new OverrideTableName(linkTableName)); } @Override - public void cleanAll(final String tableName, final Field field) throws Exception { + public void cleanAll(final DBAccessSQL 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()) @@ -495,27 +501,47 @@ public class AddOnManyToMany implements DataAccessAddOn { throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); } - DataAccess.cleanAll(LinkTableLongLong.class, new OverrideTableName(linkTableName)); + ioDb.cleanAll(LinkTableLongLong.class, new OverrideTableName(linkTableName)); } - public static void addLink(final Class clazz, final long localKey, final String column, final long remoteKey) - throws Exception { - 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); - DataAccess.insert(insertElement, new OverrideTableName(linkTableName)); + public static void addLink( + final DBAccess ioDb, + final Class clazz, + final long localKey, + final String column, + final long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia dam) { + + } else { + throw new DataAccessException("DataAccess Not managed"); + } } - public static int removeLink(final Class clazz, final long localKey, final String column, final long remoteKey) - throws Exception { - final String tableName = AnnotationTools.getTableName(clazz); - final String linkTableName = generateLinkTableName(tableName, column); - return DataAccess.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), - new Condition(new QueryAnd(new QueryCondition("object1Id", "=", localKey), - new QueryCondition("object2Id", "=", remoteKey)))); + public static long removeLink( + final DBAccess ioDb, + final Class clazz, + final long localKey, + final String column, + final long remoteKey) throws Exception { + if (ioDb instanceof final DBAccessSQL 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 DBAccessMorphia dam) { + return 0L; + } else { + throw new DataAccessException("DataAccess Not managed"); + } } @Override diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToOne.java similarity index 92% rename from src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java rename to src/org/kar/archidata/dataAccess/addOnSQL/AddOnManyToOne.java index 6881e4b..f2543d4 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,8 +9,7 @@ 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.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.LazyGetter; import org.kar.archidata.dataAccess.QueryOptions; @@ -48,8 +47,12 @@ public class AddOnManyToOne implements DataAccessAddOn { } @Override - public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) - throws Exception { + public void insertData( + final DBAccessSQL 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) { @@ -149,7 +152,7 @@ public class AddOnManyToOne implements DataAccessAddOn { if (field.getType() == decorators.targetEntity()) { if (decorators.fetch() == FetchType.EAGER) { // TODO: rework this to have a lazy mode ... - DataAccess.generateSelectField(querySelect, query, field.getType(), options, count); + DBAccessSQL.generateSelectField(querySelect, query, field.getType(), options, count); final Class subType = field.getType(); final String subTableName = AnnotationTools.getTableName(subType); final Field idField = AnnotationTools.getFieldOfId(subType); @@ -178,6 +181,7 @@ public class AddOnManyToOne implements DataAccessAddOn { @Override public void fillFromQuery( + final DBAccessSQL ioDb, final ResultSet rs, final Field field, final Object data, @@ -233,8 +237,8 @@ public class AddOnManyToOne implements DataAccessAddOn { if (objectClass == decorators.targetEntity()) { if (decorators.fetch() == FetchType.EAGER) { final CountInOut countNotNull = new CountInOut(0); - final Object dataNew = DataAccess.createObjectFromSQLRequest(rs, objectClass, count, countNotNull, - options, lazyCall); + final Object dataNew = ioDb.createObjectFromSQLRequest(rs, objectClass, count, countNotNull, options, + lazyCall); if (dataNew != null && countNotNull.value != 0) { field.set(data, dataNew); } @@ -250,7 +254,7 @@ public class AddOnManyToOne implements DataAccessAddOn { // 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 = DataAccess.get(decorators.targetEntity(), foreignKey); + final Object foreignData = ioDb.get(decorators.targetEntity(), foreignKey); if (foreignData == null) { return; } @@ -260,13 +264,13 @@ 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 = DataAccess.getListOfRawUUID(rs, count.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 = DataAccess.get(decorators.targetEntity(), foreignKey); + final Object foreignData = ioDb.get(decorators.targetEntity(), foreignKey); if (foreignData == null) { return; } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java b/src/org/kar/archidata/dataAccess/addOnSQL/AddOnOneToMany.java similarity index 93% rename from src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java rename to src/org/kar/archidata/dataAccess/addOnSQL/AddOnOneToMany.java index c73666c..4b1a384 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,8 +12,7 @@ import java.util.stream.Collectors; 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.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.LazyGetter; import org.kar.archidata.dataAccess.QueryCondition; @@ -83,8 +82,12 @@ public class AddOnOneToMany implements DataAccessAddOn { } @Override - public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) - throws SQLException, IllegalArgumentException, IllegalAccessException { + public void insertData( + final DBAccessSQL 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"); } @@ -219,6 +222,7 @@ public class AddOnOneToMany implements DataAccessAddOn { @Override public void fillFromQuery( + final DBAccessSQL ioDb, final ResultSet rs, final Field field, final Object data, @@ -236,12 +240,12 @@ public class AddOnOneToMany implements DataAccessAddOn { return; } if (objectClass == Long.class) { - final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG); + 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 = DataAccess.getListOfRawUUIDs(rs, count.value); + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); field.set(data, idList); count.inc(); return; @@ -255,7 +259,7 @@ public class AddOnOneToMany implements DataAccessAddOn { parentIdTmp = Long.valueOf(modelData); count.inc(); } catch (final NumberFormatException ex) { - final List idList = DataAccess.getListOfRawUUIDs(rs, count.value); + final List idList = ioDb.getListOfRawUUIDs(rs, count.value); parendUuidTmp = idList.get(0); count.inc(); } @@ -279,7 +283,7 @@ public class AddOnOneToMany implements DataAccessAddOn { // In the lazy mode, the request is done in asynchronous mode, they will be done after... final LazyGetter lambda = () -> { @SuppressWarnings("unchecked") - final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), new Condition(new QueryCondition(mappingKey, "=", parentId))); if (foreignData == null) { return; @@ -290,7 +294,7 @@ public class AddOnOneToMany implements DataAccessAddOn { } else if (parendUuid != null) { final LazyGetter lambda = () -> { @SuppressWarnings("unchecked") - final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), + final Object foreignData = ioDb.getsWhere(decorators.targetEntity(), new Condition(new QueryCondition(mappingKey, "=", parendUuid))); if (foreignData == null) { return; diff --git a/src/org/kar/archidata/dataAccess/DataAccessAddOn.java b/src/org/kar/archidata/dataAccess/addOnSQL/DataAccessAddOn.java similarity index 85% rename from src/org/kar/archidata/dataAccess/DataAccessAddOn.java rename to src/org/kar/archidata/dataAccess/addOnSQL/DataAccessAddOn.java index 1ae46cf..35b764a 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.DBAccessSQL; +import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryOptions; + import jakarta.validation.constraints.NotNull; public interface DataAccessAddOn { @@ -29,7 +34,7 @@ public interface DataAccessAddOn { * @param iii The index of injection * @return the new index of injection in case of multiple value management * @throws SQLException */ - void insertData(PreparedStatement ps, final Field field, Object data, CountInOut iii) + void insertData(final DBAccessSQL ioDb, PreparedStatement ps, final Field field, Object data, CountInOut iii) throws Exception, SQLException, IllegalArgumentException, IllegalAccessException; /** Element can insert in the single request @@ -58,6 +63,7 @@ public interface DataAccessAddOn { // Return the number of colomn read void fillFromQuery( + final DBAccessSQL ioDb, ResultSet rs, Field field, Object data, @@ -100,6 +106,7 @@ public interface DataAccessAddOn { * @param data Data that might be inserted. * @param actions Asynchronous action to do after main request. */ default void asyncInsert( + final DBAccessSQL ioDb, final String tableName, final Object localId, final Field field, @@ -122,6 +129,7 @@ public interface DataAccessAddOn { * @param data Data that might be inserted. * @param actions Asynchronous action to do after main request. */ default void asyncUpdate( + final DBAccessSQL ioDb, final String tableName, final Object localId, final Field field, @@ -130,11 +138,11 @@ public interface DataAccessAddOn { } - default void drop(final String tableName, final Field field) throws Exception { + default void drop(final DBAccessSQL ioDb, final String tableName, final Field field) throws Exception { } - default void cleanAll(final String tableName, final Field field) throws Exception { + default void cleanAll(final DBAccessSQL ioDb, final String tableName, final Field field) throws Exception { } 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; diff --git a/src/org/kar/archidata/dataAccess/options/CheckFunctionInterface.java b/src/org/kar/archidata/dataAccess/options/CheckFunctionInterface.java index 4f2685c..06e3881 100644 --- a/src/org/kar/archidata/dataAccess/options/CheckFunctionInterface.java +++ b/src/org/kar/archidata/dataAccess/options/CheckFunctionInterface.java @@ -3,6 +3,7 @@ package org.kar.archidata.dataAccess.options; import java.util.List; import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.DBAccess; import org.kar.archidata.dataAccess.QueryOptions; /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ @@ -12,11 +13,16 @@ public interface CheckFunctionInterface { * @param data The object that might be injected. * @param modifiedValue List of fields that might be check. If null, then all column must be checked. * @throws Exception Exception is generate if the data are incorrect. */ - void check(final String baseName, Object data, List modifiedValue, final QueryOptions options) - throws Exception; + void check( + final DBAccess ioDb, + final String baseName, + Object data, + List modifiedValue, + final QueryOptions options) throws Exception; - default void checkAll(final String baseName, final Object data, final QueryOptions options) throws Exception { - check(baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()), options); + default void checkAll(final DBAccess ioDb, final String baseName, final Object data, final QueryOptions options) + throws Exception { + check(ioDb, baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()), options); } } diff --git a/src/org/kar/archidata/dataAccess/options/CheckFunctionVoid.java b/src/org/kar/archidata/dataAccess/options/CheckFunctionVoid.java index f98fda7..cf2dcec 100644 --- a/src/org/kar/archidata/dataAccess/options/CheckFunctionVoid.java +++ b/src/org/kar/archidata/dataAccess/options/CheckFunctionVoid.java @@ -2,12 +2,14 @@ package org.kar.archidata.dataAccess.options; import java.util.List; +import org.kar.archidata.dataAccess.DBAccess; import org.kar.archidata.dataAccess.QueryOptions; /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ public class CheckFunctionVoid implements CheckFunctionInterface { @Override public void check( + final DBAccess ioDb, final String baseName, final Object data, final List filterValue, diff --git a/src/org/kar/archidata/dataAccess/options/CheckJPA.java b/src/org/kar/archidata/dataAccess/options/CheckJPA.java index 60a056f..5363175 100644 --- a/src/org/kar/archidata/dataAccess/options/CheckJPA.java +++ b/src/org/kar/archidata/dataAccess/options/CheckJPA.java @@ -14,6 +14,7 @@ import java.util.regex.Pattern; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.DataJson; +import org.kar.archidata.dataAccess.DBAccess; import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryOptions; @@ -35,13 +36,18 @@ public class CheckJPA implements CheckFunctionInterface { /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ public interface CheckInterface { /** This function implementation is design to check if the updated class is valid of not for insertion + * @param ioDb Access on the Data-Base * @param baseName Base of the name input that is displayed in exception generated. * @param data The object that might be injected. * @param modifiedValue List of fields that modification is requested. * @param options Some query option that the checker can need to generate basic check. * @throws Exception Exception is generate if the data are incorrect. */ - void check(final String baseName, final K data, List modifiedValue, final QueryOptions options) - throws Exception; + void check( + final DBAccess ioDb, + final String baseName, + final K data, + List modifiedValue, + final QueryOptions options) throws Exception; } protected Map>> checking = null; @@ -72,6 +78,7 @@ public class CheckJPA implements CheckFunctionInterface { if (AnnotationTools.isPrimaryKey(field)) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -83,6 +90,7 @@ public class CheckJPA implements CheckFunctionInterface { if (AnnotationTools.getConstraintsNotNull(field)) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -95,6 +103,7 @@ public class CheckJPA implements CheckFunctionInterface { if (AnnotationTools.isCreatedAtField(field) || AnnotationTools.isUpdateAtField(field)) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -109,6 +118,7 @@ public class CheckJPA implements CheckFunctionInterface { if (maxValue != null) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -128,6 +138,7 @@ public class CheckJPA implements CheckFunctionInterface { if (minValue != null) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -147,6 +158,7 @@ public class CheckJPA implements CheckFunctionInterface { if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -173,6 +185,7 @@ public class CheckJPA implements CheckFunctionInterface { final int maxValue = maxValueRoot.intValue(); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -193,6 +206,7 @@ public class CheckJPA implements CheckFunctionInterface { final int minValue = minValueRoot.intValue(); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -212,6 +226,7 @@ public class CheckJPA implements CheckFunctionInterface { if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -232,6 +247,7 @@ public class CheckJPA implements CheckFunctionInterface { if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -255,6 +271,7 @@ public class CheckJPA implements CheckFunctionInterface { final float maxValue = maxValueRoot.floatValue(); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -275,6 +292,7 @@ public class CheckJPA implements CheckFunctionInterface { final float minValue = minValueRoot.floatValue(); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -296,6 +314,7 @@ public class CheckJPA implements CheckFunctionInterface { final double maxValue = maxValueRoot.doubleValue(); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -316,6 +335,7 @@ public class CheckJPA implements CheckFunctionInterface { final double minValue = minValueRoot.doubleValue(); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -342,6 +362,7 @@ public class CheckJPA implements CheckFunctionInterface { if (maxSizeString > 0) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -361,6 +382,7 @@ public class CheckJPA implements CheckFunctionInterface { if (limitSize != null) { add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -385,6 +407,7 @@ public class CheckJPA implements CheckFunctionInterface { final Pattern pattern = Pattern.compile(patternString); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -406,6 +429,7 @@ public class CheckJPA implements CheckFunctionInterface { final Pattern pattern = Pattern.compile(emailPattern); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -430,11 +454,12 @@ public class CheckJPA implements CheckFunctionInterface { .newInstance(); add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, final QueryOptions options) -> { - instance.checkAll(baseName + fieldName + ".", field.get(data), options); + instance.checkAll(ioDb, baseName + fieldName + ".", field.get(data), options); }); } } else if (type.isEnum()) { @@ -445,6 +470,7 @@ public class CheckJPA implements CheckFunctionInterface { // Create the request ... add(fieldName, ( + final DBAccess ioDb, final String baseName, final T data, final List modifiedValue, @@ -472,8 +498,18 @@ public class CheckJPA implements CheckFunctionInterface { } } + public void check(final DBAccess ioDb, final String baseName, final Object data) throws Exception { + check(ioDb, baseName, data, null, null); + } + + public void check(final DBAccess ioDb, final String baseName, final Object data, final List filterValue) + throws Exception { + check(ioDb, baseName, data, filterValue, null); + } + @Override public void check( + final DBAccess ioDb, final String baseName, final Object data, final List modifiedValue, @@ -492,7 +528,7 @@ public class CheckJPA implements CheckFunctionInterface { continue; } for (final CheckInterface action : actions) { - action.check(baseName, dataCasted, modifiedValue, options); + action.check(ioDb, baseName, dataCasted, modifiedValue, options); } } checkTyped(dataCasted, modifiedValue, options); @@ -502,4 +538,5 @@ public class CheckJPA implements CheckFunctionInterface { throws Exception { // nothing to do ... } + } diff --git a/src/org/kar/archidata/dataAccess/options/Condition.java b/src/org/kar/archidata/dataAccess/options/Condition.java index 7831a80..23e7ab6 100644 --- a/src/org/kar/archidata/dataAccess/options/Condition.java +++ b/src/org/kar/archidata/dataAccess/options/Condition.java @@ -1,11 +1,17 @@ package org.kar.archidata.dataAccess.options; import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.List; +import org.bson.conversions.Bson; import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.QueryItem; import org.kar.archidata.dataAccess.QueryOptions; +import com.mongodb.client.model.Filters; + /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ public class Condition extends QueryOption { public final QueryItem condition; @@ -24,9 +30,9 @@ public class Condition extends QueryOption { } } - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception { if (this.condition != null) { - this.condition.injectQuery(ps, iii); + this.condition.injectQuery(ioDb, ps, iii); } } @@ -62,4 +68,26 @@ public class Condition extends QueryOption { } query.append("\n"); } + + public Bson getFilter(final String collectionName, final QueryOptions options, final String deletedFieldName) { + boolean exclude_deleted = true; + if (options != null) { + exclude_deleted = !options.exist(AccessDeletedItems.class); + } + final List filter = new ArrayList<>(); + if (exclude_deleted && deletedFieldName != null) { + filter.add(Filters.eq(deletedFieldName, false)); + } + // Check if we have a condition to generate + if (this.condition != null) { + this.condition.generateFilter(filter); + } + if (filter.size() == 0) { + return null; + } + if (filter.size() == 1) { + return filter.get(0); + } + return Filters.and(filter.toArray(new Bson[0])); + } } diff --git a/src/org/kar/archidata/dataAccess/options/DBInterfaceOption.java b/src/org/kar/archidata/dataAccess/options/DBInterfaceOption.java deleted file mode 100644 index a740c0d..0000000 --- a/src/org/kar/archidata/dataAccess/options/DBInterfaceOption.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.kar.archidata.dataAccess.options; - -import java.io.IOException; -import java.util.List; - -import org.kar.archidata.GlobalConfiguration; -import org.kar.archidata.dataAccess.QueryOptions; -import org.kar.archidata.db.DBConfig; -import org.kar.archidata.db.DBEntry; - -public class DBInterfaceOption extends QueryOption { - private DBEntry entry = null; - private final DBConfig config; - private final boolean root; - - public DBInterfaceOption(final DBConfig config) { - this.config = config; - this.root = false; - } - - public DBInterfaceOption(final DBConfig config, final boolean root) { - this.config = config; - this.root = root; - } - - public DBEntry getEntry(final QueryOptions options) throws IOException { - if (this.entry == null) { - final List isRoot = options.get(DBInterfaceRoot.class); - this.entry = DBEntry.createInterface(this.config, isRoot.size() == 1 && isRoot.get(0).getRoot()); - } - return this.entry; - } - - public boolean getRoot() { - return this.root; - } - - public static DBEntry getAutoEntry(final QueryOptions options) throws IOException { - if (options == null) { - return DBEntry.createInterface(GlobalConfiguration.dbConfig, false); - } - final List dbOption = options.get(DBInterfaceOption.class); - if (dbOption.size() == 0) { - final List isRoot = options.get(DBInterfaceRoot.class); - return DBEntry.createInterface(GlobalConfiguration.dbConfig, isRoot.size() == 1 && isRoot.get(0).getRoot()); - } else { - return dbOption.get(0).getEntry(options); - } - } - -} diff --git a/src/org/kar/archidata/dataAccess/options/Limit.java b/src/org/kar/archidata/dataAccess/options/Limit.java index fbabb21..a469d57 100644 --- a/src/org/kar/archidata/dataAccess/options/Limit.java +++ b/src/org/kar/archidata/dataAccess/options/Limit.java @@ -3,7 +3,7 @@ package org.kar.archidata.dataAccess.options; import java.sql.PreparedStatement; import org.kar.archidata.dataAccess.CountInOut; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; public class Limit extends QueryOption { protected final long limit; @@ -16,8 +16,12 @@ public class Limit extends QueryOption { query.append(" LIMIT ? \n"); } - public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { - DataAccess.addElement(ps, this.limit, iii); + public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception { + ioDb.addElement(ps, this.limit, iii); iii.inc(); } + + public long getValue() { + return this.limit; + } } diff --git a/src/org/kar/archidata/dataAccess/options/OrderBy.java b/src/org/kar/archidata/dataAccess/options/OrderBy.java index be0a10e..9416b3f 100644 --- a/src/org/kar/archidata/dataAccess/options/OrderBy.java +++ b/src/org/kar/archidata/dataAccess/options/OrderBy.java @@ -3,7 +3,9 @@ package org.kar.archidata.dataAccess.options; import java.sql.PreparedStatement; import java.util.List; +import org.bson.Document; import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.options.OrderItem.Order; public class OrderBy extends QueryOption { protected final List childs; @@ -40,4 +42,10 @@ public class OrderBy extends QueryOption { public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { // nothing to add. } + + public void generateSort(final Document data) { + for (final OrderItem elem : this.childs) { + data.append(elem.value, elem.order == Order.ASC ? 1 : -1); + } + } } diff --git a/src/org/kar/archidata/db/DBConfig.java b/src/org/kar/archidata/db/DBConfig.java deleted file mode 100644 index 46c7a52..0000000 --- a/src/org/kar/archidata/db/DBConfig.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.kar.archidata.db; - -import org.kar.archidata.dataAccess.DataAccess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DBConfig { - static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.class); - private final String type; - private final String hostname; - private final int port; - private final String login; - private final String password; - private final String dbName; - private final boolean keepConnected; - - public DBConfig(final String type, final String hostname, final Integer port, final String login, - final String password, final String dbName, final boolean keepConnected) { - if (type == null) { - this.type = "mysql"; - } else { - this.type = type; - } - if (hostname == null) { - this.hostname = "localhost"; - } else { - this.hostname = hostname; - } - if (port == null) { - this.port = 3306; - } else { - this.port = port; - } - this.login = login; - this.password = password; - this.dbName = dbName; - this.keepConnected = keepConnected; - } - - @Override - public String toString() { - return "DBConfig{type='" + this.type + '\'' + ", hostname='" + this.hostname + '\'' + ", port=" + this.port - + ", login='" + this.login + '\'' + ", password='" + this.password + '\'' + ", dbName='" + this.dbName - + "' }"; - } - - public String getHostname() { - return this.hostname; - } - - public int getPort() { - return this.port; - } - - public String getLogin() { - return this.login; - } - - public String getPassword() { - return this.password; - } - - public String getDbName() { - return this.dbName; - } - - public boolean getKeepConnected() { - return this.keepConnected; - } - - public String getUrl() { - return getUrl(false); - } - - public String getUrl(final boolean isRoot) { - if (this.type.equals("sqlite")) { - if (isRoot) { - LOGGER.error("Can not manage root connection on SQLite..."); - } - if (this.hostname.equals("memory")) { - return "jdbc:sqlite::memory:"; - } - return "jdbc:sqlite:" + this.hostname + ".db"; - } - if (isRoot) { - return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port - + "/?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; - } - return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/" + this.dbName - + "?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; - } -} diff --git a/src/org/kar/archidata/db/DBEntry.java b/src/org/kar/archidata/db/DBEntry.java deleted file mode 100644 index c24f620..0000000 --- a/src/org/kar/archidata/db/DBEntry.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.kar.archidata.db; - -import java.io.Closeable; -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DBEntry implements Closeable { - final static Logger LOGGER = LoggerFactory.getLogger(DBEntry.class); - public DBConfig config; - public Connection connection; - private static List stored = new ArrayList<>(); - - private DBEntry(final DBConfig config, final boolean root) throws IOException { - this.config = config; - if (root) { - connectRoot(); - } else { - connect(); - } - } - - public static DBEntry createInterface(final DBConfig config) throws IOException { - return createInterface(config, false); - } - - public static DBEntry createInterface(final DBConfig config, final boolean root) throws IOException { - if (config.getKeepConnected()) { - for (final DBEntry elem : stored) { - if (elem == null) { - continue; - } - if (elem.config.getUrl().equals(config.getUrl())) { - return elem; - } - } - final DBEntry tmp = new DBEntry(config, root); - stored.add(tmp); - return tmp; - } else { - return new DBEntry(config, root); - } - } - - public void connectRoot() throws IOException { - try { - this.connection = DriverManager.getConnection(this.config.getUrl(true), this.config.getLogin(), - this.config.getPassword()); - } catch (final SQLException ex) { - throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true)); - } - - } - - public void connect() throws IOException { - try { - this.connection = DriverManager.getConnection(this.config.getUrl(), this.config.getLogin(), - this.config.getPassword()); - } catch (final SQLException ex) { - LOGGER.error("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true)); - throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true)); - } - - } - - @Override - public void close() throws IOException { - if (this.config.getKeepConnected()) { - return; - } - closeForce(); - } - - public void closeForce() throws IOException { - try { - // connection.commit(); - this.connection.close(); - } catch (final SQLException ex) { - throw new IOException("Dis-connection db fail: " + ex.getMessage()); - } - } - - public static void closeAllForceMode() throws IOException { - for (final DBEntry entry : stored) { - entry.closeForce(); - } - stored = new ArrayList<>(); - } -} diff --git a/src/org/kar/archidata/db/DbConfig.java b/src/org/kar/archidata/db/DbConfig.java new file mode 100644 index 0000000..aafc7a5 --- /dev/null +++ b/src/org/kar/archidata/db/DbConfig.java @@ -0,0 +1,165 @@ +package org.kar.archidata.db; + +import java.util.List; +import java.util.Objects; + +import org.kar.archidata.dataAccess.DBAccess; +import org.kar.archidata.exception.DataAccessException; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbConfig { + static final Logger LOGGER = LoggerFactory.getLogger(DBAccess.class); + private final String type; + private final String hostname; + private final Short port; + private final String login; + private final String password; + private String dbName; + private final boolean keepConnected; + private final List> classes; + + public DbConfig() throws DataAccessException { + this(ConfigBaseVariable.getDBType(), ConfigBaseVariable.getDBHost(), ConfigBaseVariable.getDBPort(), + ConfigBaseVariable.getDBLogin(), ConfigBaseVariable.getDBPassword(), ConfigBaseVariable.getDBName(), + ConfigBaseVariable.getDBKeepConnected(), List.of(ConfigBaseVariable.getBbInterfacesClasses())); + } + + public DbConfig(final String type, final String hostname, final Short port, final String login, + final String password, final String dbName, final boolean keepConnected, final List> classes) + throws DataAccessException { + if (type == null) { + this.type = "mysql"; + } else { + if (!"mysql".equals(type) && !"sqlite".equals(type) && !"mongo".equals(type)) { + throw new DataAccessException("unexpected DB type: '" + type + "'"); + } + this.type = type; + } + if (hostname == null) { + this.hostname = "localhost"; + } else { + this.hostname = hostname; + } + if (port == null) { + if ("mysql".equals(this.type)) { + this.port = 3306; + } else { + this.port = 27017; + } + } else { + this.port = port; + } + this.login = login; + this.password = password; + this.dbName = dbName; + this.keepConnected = keepConnected; + this.classes = classes; + + } + + @Override + public String toString() { + return "DBConfig{type='" + this.type + '\'' + ", hostname='" + this.hostname + '\'' + ", port=" + this.port + + ", login='" + this.login + '\'' + ", password='" + this.password + '\'' + ", dbName='" + this.dbName + + "' }"; + } + + public String getHostname() { + return this.hostname; + } + + public String getType() { + return this.type; + } + + public int getPort() { + return this.port; + } + + public String getLogin() { + return this.login; + } + + public String getPassword() { + return this.password; + } + + public String getDbName() { + return this.dbName; + } + + public void setDbName(final String dbName) { + this.dbName = dbName; + } + + public boolean getKeepConnected() { + return this.keepConnected; + } + + public List> getClasses() { + return this.classes; + } + + public String getUrl() { + if (this.type.equals("sqlite")) { + if (this.hostname.equals("memory")) { + return "jdbc:sqlite::memory:"; + } + return "jdbc:sqlite:" + this.hostname + ".db"; + } + if ("mongo".equals(this.type)) { + return "mongodb://" + getLogin() + ":" + getPassword() + "@" + this.hostname + ":" + this.port; + } + if ("mysql".equals(this.type)) { + if (this.dbName == null || this.dbName.isEmpty()) { + LOGGER.warn("Request log on SQL: root"); + return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + + "/?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; + } + return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/" + this.dbName + + "?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; + } + return "dead_code"; + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + if (other instanceof final DbConfig dbConfig) { + return Objects.equals(this.port, dbConfig.port) // + && this.keepConnected == dbConfig.keepConnected // + && Objects.equals(this.type, dbConfig.type) // + && Objects.equals(this.hostname, dbConfig.hostname) // + && Objects.equals(this.login, dbConfig.login) // + && Objects.equals(this.password, dbConfig.password) // + && Objects.equals(this.dbName, dbConfig.dbName) // + && Objects.equals(this.classes, dbConfig.classes); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(this.type, this.hostname, this.port, this.login, this.password, this.dbName, + this.keepConnected, this.classes); + } + + @Override + public DbConfig clone() { + try { + return new DbConfig(this.type, this.hostname, this.port, this.login, this.password, this.dbName, + this.keepConnected, this.classes); + } catch (final DataAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } +} diff --git a/src/org/kar/archidata/db/DbIo.java b/src/org/kar/archidata/db/DbIo.java new file mode 100644 index 0000000..3234f3c --- /dev/null +++ b/src/org/kar/archidata/db/DbIo.java @@ -0,0 +1,82 @@ +package org.kar.archidata.db; + +import java.io.Closeable; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class DbIo implements Closeable { + private final static Logger LOGGER = LoggerFactory.getLogger(DbIo.class); + + // we count the number of connection in the system to prevent disconnection in a middle of a stream. + private int count = 0; + + private static int idCount = 0; + protected final int id; + protected final DbConfig config; + + protected DbIo(final DbConfig config) throws IOException { + this.id = idCount; + idCount += 10; + this.config = config; + } + + @Override + public synchronized final void close() throws IOException { + LOGGER.trace("[{}] Request close count={}", this.id, this.count); + if (this.count <= 0) { + LOGGER.error("[{}] Request one more close", this.id); + return; + } + this.count--; + if (this.count == 0) { + LOGGER.trace("[{}] close", this.id); + closeImplement(); + } else { + LOGGER.trace("[{}] postponed close", this.id); + } + } + + public synchronized final void closeForce() throws IOException { + LOGGER.trace("[{}] Request Force close count={}", this.id, this.count); + if (this.count == 0) { + LOGGER.trace("[{}] Nothing to do in force close, DB is already closed", this.id); + return; + } + if (this.config.getKeepConnected()) { + if (this.count >= 2) { + LOGGER.error("[{}] Force close: with {} connection on it", this.id, this.count - 1); + } + } else if (this.count >= 1) { + LOGGER.error("[{}] Force close: with {} connection on it", this.id, this.count); + } + this.count = 0; + LOGGER.trace("[{}] Force close", this.id); + closeImplement(); + } + + public synchronized final void open() throws IOException { + LOGGER.trace("[{}] Request open count={}", this.id, this.count); + if (this.count == 0) { + LOGGER.trace("[{}] open", this.id); + openImplement(); + } else { + LOGGER.trace("[{}] open: already done", this.id); + } + this.count++; + + } + + protected abstract void closeImplement() throws IOException; + + protected abstract void openImplement() throws IOException; + + public boolean compatible(final DbConfig config) { + return this.config.equals(config); + } + + public DbConfig getCongig() { + return this.config; + } +} diff --git a/src/org/kar/archidata/db/DbIoFactory.java b/src/org/kar/archidata/db/DbIoFactory.java new file mode 100644 index 0000000..12841c7 --- /dev/null +++ b/src/org/kar/archidata/db/DbIoFactory.java @@ -0,0 +1,65 @@ +package org.kar.archidata.db; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.kar.archidata.exception.DataAccessException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbIoFactory { + final static Logger LOGGER = LoggerFactory.getLogger(DbIoFactory.class); + private static List dbIoStored = new ArrayList<>(); + + private DbIoFactory() throws IOException {} + + public static DbIo create() throws IOException, DataAccessException { + // Find the global configuration of the system. + return create(new DbConfig()); + } + + public static DbIo create(final DbConfig config) throws IOException { + for (final DbIo dbIo : dbIoStored) { + if (dbIo == null) { + continue; + } + if (dbIo.compatible(config)) { + dbIo.open(); + return dbIo; + } + } + final DbIo dbIo = createInstance(config); + if (config.getKeepConnected()) { + dbIo.open(); + dbIoStored.add(dbIo); + } + return dbIo; + } + + private static DbIo createInstance(final DbConfig config) throws IOException { + switch (config.getType()) { + case "mysql": + return new DbIoSql(config); + case "sqlite": + return new DbIoSql(config); + case "mongo": + return new DbIoMorphia(config); + } + throw new IOException("DB type: '" + config.getType() + "'is not managed"); + + } + + public static void close() throws IOException { + for (final DbIo dbIo : dbIoStored) { + dbIo.close(); + } + } + + public static void closeAllForceMode() throws IOException { + for (final DbIo entry : dbIoStored) { + entry.closeForce(); + } + dbIoStored = new ArrayList<>(); + } +} diff --git a/src/org/kar/archidata/db/DbIoMorphia.java b/src/org/kar/archidata/db/DbIoMorphia.java new file mode 100644 index 0000000..6da68c2 --- /dev/null +++ b/src/org/kar/archidata/db/DbIoMorphia.java @@ -0,0 +1,83 @@ +package org.kar.archidata.db; + +import java.io.Closeable; +import java.io.IOException; + +import org.bson.UuidRepresentation; +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; +import org.kar.archidata.converter.morphia.SqlTimestampCodec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; + +import dev.morphia.Datastore; +import dev.morphia.Morphia; + +public class DbIoMorphia extends DbIo implements Closeable { + private final static Logger LOGGER = LoggerFactory.getLogger(DbIoMorphia.class); + private MongoClient mongoClient = null; + private Datastore datastore = null; + + public DbIoMorphia(final DbConfig config) throws IOException { + super(config); + } + + public Datastore getDatastore() { + return this.datastore; + } + + public MongoClient getClient() { + return this.mongoClient; + } + + @Override + synchronized public void closeImplement() throws IOException { + this.mongoClient.close(); + this.mongoClient = null; + this.datastore = null; + } + + @Override + synchronized public void openImplement() throws IOException { + final Class[] classes = this.config.getClasses().toArray(new Class[0]); + final String dbUrl = this.config.getUrl(); + final String dbName = this.config.getDbName(); + // Connect to MongoDB (simple form): + // final MongoClient mongoClient = MongoClients.create(dbUrl); + LOGGER.info("Connect on the DB: {}", dbUrl); + // Connect to MongoDB (complex form): + final ConnectionString connectionString = new ConnectionString(dbUrl); + // Créer un CodecRegistry pour UUID + //final CodecRegistry uuidCodecRegistry = CodecRegistries.fromCodecs(new UUIDCodec()); + final CodecRegistry SqlTimestampCodecRegistry = CodecRegistries.fromCodecs(new SqlTimestampCodec()); + // Créer un CodecRegistry pour POJOs + final CodecRegistry pojoCodecRegistry = CodecRegistries + .fromProviders(PojoCodecProvider.builder().automatic(true).build()); + // Ajouter le CodecRegistry par défaut, le codec UUID et celui pour POJOs + //final CodecRegistry codecRegistry = CodecRegistries.fromRegistries( + // MongoClientSettings.getDefaultCodecRegistry(), /*uuidCodecRegistry, */ pojoCodecRegistry); + + final CodecRegistry codecRegistry = CodecRegistries.fromRegistries( + MongoClientSettings.getDefaultCodecRegistry(), + CodecRegistries.fromCodecs(new org.bson.codecs.UuidCodec(UuidRepresentation.STANDARD)), + pojoCodecRegistry, SqlTimestampCodecRegistry); + // Configurer MongoClientSettings + final MongoClientSettings clientSettings = MongoClientSettings.builder() // + .applyConnectionString(connectionString)// + .codecRegistry(codecRegistry) // + .uuidRepresentation(UuidRepresentation.STANDARD)// + .build(); + this.mongoClient = MongoClients.create(clientSettings); + this.datastore = Morphia.createDatastore(this.mongoClient, dbName); + // Map entities + this.datastore.getMapper().map(classes); + // Ensure indexes + this.datastore.ensureIndexes(); + } +} diff --git a/src/org/kar/archidata/db/DbIoSql.java b/src/org/kar/archidata/db/DbIoSql.java new file mode 100644 index 0000000..f5fa030 --- /dev/null +++ b/src/org/kar/archidata/db/DbIoSql.java @@ -0,0 +1,56 @@ +package org.kar.archidata.db; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbIoSql extends DbIo { + final static Logger LOGGER = LoggerFactory.getLogger(DbIoSql.class); + + private Connection connection = null; + + public DbIoSql(final DbConfig config) throws IOException { + super(config); + } + + public Connection getConnection() { + if (this.connection == null) { + LOGGER.error("[{}] Retrieve a closed connection !!!", this.id); + } + return this.connection; + } + + @Override + synchronized public void openImplement() throws IOException { + final String dbUrl = this.config.getUrl(); + final String login = this.config.getLogin(); + final String password = this.config.getPassword(); + try { + this.connection = DriverManager.getConnection(dbUrl, login, password); + } catch (final SQLException ex) { + LOGGER.error("Connection db fail: " + ex.getMessage() + " On URL: " + dbUrl); + throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + dbUrl); + } + if (this.connection == null) { + throw new IOException("Connection db fail: NULL On URL: " + dbUrl); + } + } + + @Override + synchronized public void closeImplement() throws IOException { + if (this.connection == null) { + LOGGER.error("Request close of un-open connection !!!"); + return; + } + try { + this.connection.close(); + this.connection = null; + } catch (final SQLException ex) { + throw new IOException("Dis-connection db fail: " + ex.getMessage()); + } + } +} diff --git a/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java b/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java index eee0361..7b78ff0 100644 --- a/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java @@ -136,7 +136,7 @@ public class ClassObjectModel extends ClassModel { this(field.getName(), // ClassModel.getModel(field.getGenericType(), previous), // getSubModelIfExist(field, previous), // - AnnotationTools.getComment(field), // + AnnotationTools.getSchemaDescription(field), // getStringMinSize(field), // getStringMaxSize(field), // AnnotationTools.getConstraintsMin(field), // diff --git a/src/org/kar/archidata/migration/AsyncCall.java b/src/org/kar/archidata/migration/AsyncCall.java index 0ea56b6..eac7cc9 100644 --- a/src/org/kar/archidata/migration/AsyncCall.java +++ b/src/org/kar/archidata/migration/AsyncCall.java @@ -1,5 +1,7 @@ package org.kar.archidata.migration; +import org.kar.archidata.dataAccess.DBAccess; + public interface AsyncCall { - void doRequest() throws Exception; + void doRequest(DBAccess da) throws Exception; } diff --git a/src/org/kar/archidata/migration/MigrationEngine.java b/src/org/kar/archidata/migration/MigrationEngine.java index 53d93e8..8b30a00 100644 --- a/src/org/kar/archidata/migration/MigrationEngine.java +++ b/src/org/kar/archidata/migration/MigrationEngine.java @@ -5,16 +5,17 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.QueryOptions; -import org.kar.archidata.db.DBConfig; -import org.kar.archidata.db.DBEntry; +import org.kar.archidata.db.DbConfig; import org.kar.archidata.migration.model.Migration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.ws.rs.InternalServerErrorException; public class MigrationEngine { final static Logger LOGGER = LoggerFactory.getLogger(MigrationEngine.class); @@ -52,17 +53,17 @@ public class MigrationEngine { /** Get the current version/migration name * @return Model represent the last migration. If null then no migration has been done. * @throws MigrationException */ - public Migration getCurrentVersion() throws MigrationException { - if (!DataAccess.isTableExist("KAR_migration")) { + public Migration getCurrentVersion(final DBAccess da) throws MigrationException { + if (!da.isTableExist("KAR_migration")) { return null; } try { List data = null; try { - data = DataAccess.gets(Migration.class, QueryOptions.READ_ALL_COLOMN); + data = da.gets(Migration.class, QueryOptions.READ_ALL_COLOMN); } catch (final Exception e) { // Previous version does not have the same timeCode... - data = DataAccess.gets(Migration.class); + data = da.gets(Migration.class); } if (data == null) { LOGGER.error("Can not collect the migration table in the DB:{}"); @@ -87,7 +88,7 @@ public class MigrationEngine { /** Process the automatic migration of the system The function wait the Administrator intervention to correct the bug. * @param config SQL connection for the migration. * @throws InterruptedException user interrupt the migration */ - public void migrateWaitAdmin(final DBConfig config) throws InterruptedException { + public void migrateWaitAdmin(final DbConfig config) throws InterruptedException { try { migrateErrorThrow(config); } catch (final Exception ex) { @@ -102,13 +103,7 @@ public class MigrationEngine { } } - /** Process the automatic migration of the system - * @param config SQL connection for the migration - * @throws IOException Error if access on the DB */ - @SuppressFBWarnings({ "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING", - "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" }) - public void migrateErrorThrow(final DBConfig config) throws MigrationException { - LOGGER.info("Execute migration ... [BEGIN]"); + private void listAvailableMigration() throws MigrationException { // check the integrity of the migrations: LOGGER.info("List of availlable Migration: "); for (final MigrationInterface elem : this.datas) { @@ -132,129 +127,154 @@ public class MigrationEngine { } } } + } - // STEP 1: Check the DB exist: - LOGGER.info("Verify existance of '{}'", config.getDbName()); - boolean exist = DataAccess.isDBExist(config.getDbName()); - if (!exist) { - LOGGER.warn("DB: '{}' DOES NOT EXIST ==> create one", config.getDbName()); - // create the local DB: - DataAccess.createDB(config.getDbName()); - } - exist = DataAccess.isDBExist(config.getDbName()); - while (!exist) { - LOGGER.error("DB: '{}' DOES NOT EXIST after trying to create one ", config.getDbName()); - LOGGER.error("Waiting administrator create a new one, we check after 30 seconds..."); - try { - Thread.sleep(30000); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + private void createTableIfAbleOrWaitAdmin(final DbConfig configInput) throws MigrationException { + final DbConfig config = configInput.clone(); + config.setDbName(null); + final String dbName = configInput.getDbName(); + LOGGER.info("Verify existance of '{}'", dbName); + try (final DBAccess da = DBAccess.createInterface(config)) { + boolean exist = da.isDBExist(dbName); + if (!exist) { + LOGGER.warn("DB: '{}' DOES NOT EXIST ==> create one", dbName); + // create the local DB: + da.createDB(dbName); } - exist = DataAccess.isDBExist(config.getDbName()); - } - LOGGER.info("DB '{}' exist.", config.getDbName()); - // STEP 2: Check migration table exist: - LOGGER.info("Verify existance of migration table '{}'", "KAR_migration"); - // TODO: set the class in parameters instead of string... - exist = DataAccess.isTableExist("KAR_migration"); - if (!exist) { - LOGGER.info("'{}' Does not exist create a new one...", "KAR_migration"); - // create the table: - List sqlQuery; - try { - sqlQuery = DataFactory.createTable(Migration.class); - } catch (final Exception ex) { - ex.printStackTrace(); - throw new MigrationException( - "Fail to create the local DB SQL model for migaration ==> wait administrator interventions"); - } - LOGGER.info("Create Table with : {}", sqlQuery.get(0)); - try { - DataAccess.executeQuery(sqlQuery.get(0)); - } catch (SQLException | IOException ex) { - ex.printStackTrace(); - throw new MigrationException( - "Fail to create the local DB model for migaration ==> wait administrator interventions"); - } - } - final Migration currentVersion = getCurrentVersion(); - List toApply = new ArrayList<>(); - boolean needPlaceholder = false; - if (currentVersion == null) { - // This is a first migration - LOGGER.info("First installation of the system ==> Create the DB"); - if (this.init == null) { - // No initialization class ==> manage a historical creation mode... - toApply = this.datas; - } else { - // Select Initialization class if it exist - toApply.add(this.init); - needPlaceholder = true; - } - } else { - if (!currentVersion.terminated) { - throw new MigrationException("An error occured in the last migration: '" + currentVersion.name - + "' defect @" + currentVersion.stepId + "/" + currentVersion.count); - } - LOGGER.info("Upgrade the system Current version: {}", currentVersion.name); - boolean find = this.init != null && this.init.getName().equals(currentVersion.name); - if (find) { - toApply = this.datas; - } else { - LOGGER.info(" ===> Check what must be apply:"); - for (final MigrationInterface elem : this.datas) { - LOGGER.info(" - {}", elem.getName()); - if (!find) { - if (currentVersion.name.equals(elem.getName())) { - LOGGER.info(" == current version"); - find = true; - } - continue; - } - LOGGER.info(" ++ add "); - toApply.add(elem); - } - } - } - DBEntry entry; - try { - entry = DBEntry.createInterface(config); - final int id = 0; - final int count = toApply.size(); - for (final MigrationInterface elem : toApply) { - migrateSingle(entry, elem, id, count); - } - } catch (final IOException e) { - e.printStackTrace(); - throw new MigrationException("An error occured in the migration (can not access to the DB): '" - + currentVersion.name + "' defect @" + currentVersion.stepId + "/" + currentVersion.count); - } - if (needPlaceholder) { - if (this.datas.size() == 0) { - // No placeholder needed, the model have no migration in the current version... - } else { - // we insert a placeholder to simulate the last migration is well done. - final String placeholderName = this.datas.get(this.datas.size() - 1).getName(); - Migration migrationResult = new Migration(); - migrationResult.id = 1000L; - migrationResult.name = placeholderName; - migrationResult.stepId = 0; - migrationResult.terminated = true; - migrationResult.count = 0; - migrationResult.log = "Place-holder for first initialization"; + exist = da.isDBExist(dbName); + while (!exist) { + LOGGER.error("DB: '{}' DOES NOT EXIST after trying to create one ", dbName); + LOGGER.error("Waiting administrator create a new one, we check after 30 seconds..."); try { - migrationResult = DataAccess.insert(migrationResult); - } catch (final Exception e) { + Thread.sleep(30000); + } catch (final InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } + exist = da.isDBExist(dbName); } + } catch (final InternalServerErrorException e) { + e.printStackTrace(); + throw new MigrationException("TODO ..."); + } catch (final IOException e) { + e.printStackTrace(); + throw new MigrationException("TODO ..."); } - LOGGER.info("Execute migration ... [ END ]"); } - public void migrateSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) + /** Process the automatic migration of the system + * @param config SQL connection for the migration + * @throws IOException Error if access on the DB */ + @SuppressFBWarnings({ "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING", + "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" }) + public void migrateErrorThrow(final DbConfig config) throws MigrationException { + LOGGER.info("Execute migration ... [BEGIN]"); + listAvailableMigration(); + // STEP 1: Check the DB exist: + createTableIfAbleOrWaitAdmin(config); + LOGGER.info("DB '{}' exist.", config.getDbName()); + try (final DBAccess da = DBAccess.createInterface(config)) { + // STEP 2: Check migration table exist: + LOGGER.info("Verify existance of migration table '{}'", "KAR_migration"); + if (da instanceof final DBAccessSQL daSQL) { + final boolean exist = da.isTableExist("KAR_migration"); + if (!exist) { + LOGGER.info("'{}' Does not exist create a new one...", "KAR_migration"); + // create the table: + List sqlQuery; + try { + sqlQuery = DataFactory.createTable(Migration.class); + } catch (final Exception ex) { + ex.printStackTrace(); + throw new MigrationException( + "Fail to create the local DB SQL model for migaration ==> wait administrator interventions"); + } + LOGGER.info("Create Table with : {}", sqlQuery.get(0)); + try { + daSQL.executeQuery(sqlQuery.get(0)); + } catch (SQLException | IOException ex) { + ex.printStackTrace(); + throw new MigrationException( + "Fail to create the local DB model for migaration ==> wait administrator interventions"); + } + } + } + final Migration currentVersion = getCurrentVersion(da); + List toApply = new ArrayList<>(); + boolean needPlaceholder = false; + if (currentVersion == null) { + // This is a first migration + LOGGER.info("First installation of the system ==> Create the DB"); + if (this.init == null) { + // No initialization class ==> manage a historical creation mode... + toApply = this.datas; + } else { + // Select Initialization class if it exist + toApply.add(this.init); + needPlaceholder = true; + } + } else { + if (!currentVersion.terminated) { + throw new MigrationException("An error occured in the last migration: '" + currentVersion.name + + "' defect @" + currentVersion.stepId + "/" + currentVersion.count); + } + LOGGER.info("Upgrade the system Current version: {}", currentVersion.name); + boolean find = this.init != null && this.init.getName().equals(currentVersion.name); + if (find) { + toApply = this.datas; + } else { + LOGGER.info(" ===> Check what must be apply:"); + for (final MigrationInterface elem : this.datas) { + LOGGER.info(" - {}", elem.getName()); + if (!find) { + if (currentVersion.name.equals(elem.getName())) { + LOGGER.info(" == current version"); + find = true; + } + continue; + } + LOGGER.info(" ++ add "); + toApply.add(elem); + } + } + } + final int id = 0; + final int count = toApply.size(); + for (final MigrationInterface elem : toApply) { + migrateSingle(da, elem, id, count); + } + if (needPlaceholder) { + if (this.datas.size() == 0) { + // No placeholder needed, the model have no migration in the current version... + } else { + // we insert a placeholder to simulate the last migration is well done. + final String placeholderName = this.datas.get(this.datas.size() - 1).getName(); + Migration migrationResult = new Migration(); + migrationResult.id = 1000L; + migrationResult.name = placeholderName; + migrationResult.stepId = 0; + migrationResult.terminated = true; + migrationResult.count = 0; + migrationResult.log = "Place-holder for first initialization"; + try { + migrationResult = da.insert(migrationResult); + } catch (final Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + LOGGER.info("Execute migration ... [ END ]"); + } catch (final InternalServerErrorException e) { + e.printStackTrace(); + throw new MigrationException("TODO ..."); + } catch (final IOException e) { + e.printStackTrace(); + throw new MigrationException("TODO ..."); + } + } + + public void migrateSingle(final DBAccess da, final MigrationInterface elem, final int id, final int count) throws MigrationException { LOGGER.info("---------------------------------------------------------"); LOGGER.info("-- Migrate: [{}/{}] {} [BEGIN]", id, count, elem.getName()); @@ -274,7 +294,7 @@ public class MigrationEngine { } migrationResult.log = log.toString(); try { - migrationResult = DataAccess.insert(migrationResult); + migrationResult = da.insert(migrationResult); } catch (final Exception e) { e.printStackTrace(); throw new MigrationException( @@ -282,7 +302,7 @@ public class MigrationEngine { } boolean ret = true; try { - ret = elem.applyMigration(entry, log, migrationResult); + ret = elem.applyMigration(da, log, migrationResult); } catch (final Exception e) { log.append("\nFail in the migration apply "); log.append(e.getLocalizedMessage()); @@ -293,7 +313,7 @@ public class MigrationEngine { if (ret) { migrationResult.terminated = true; try { - DataAccess.update(migrationResult, migrationResult.id, List.of("terminated")); + da.update(migrationResult, migrationResult.id, List.of("terminated")); } catch (final Exception e) { e.printStackTrace(); throw new MigrationException( @@ -303,7 +323,7 @@ public class MigrationEngine { try { log.append("Fail in the migration engine..."); migrationResult.log = log.toString(); - DataAccess.update(migrationResult, migrationResult.id, List.of("log")); + da.update(migrationResult, migrationResult.id, List.of("log")); } catch (final Exception e) { e.printStackTrace(); throw new MigrationException("Fail to update migration Log in the migration table: " @@ -316,8 +336,8 @@ public class MigrationEngine { LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName()); } - public void revertTo(final DBEntry entry, final String migrationName) throws MigrationException { - final Migration currentVersion = getCurrentVersion(); + public void revertTo(final DBAccess da, final String migrationName) throws MigrationException { + final Migration currentVersion = getCurrentVersion(da); final List toApply = new ArrayList<>(); boolean find = false; for (int iii = this.datas.size() - 1; iii >= 0; iii--) { @@ -335,11 +355,11 @@ public class MigrationEngine { final int id = 0; final int count = toApply.size(); for (final MigrationInterface elem : toApply) { - revertSingle(entry, elem, id, count); + revertSingle(da, elem, id, count); } } - public void revertSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) { + public void revertSingle(final DBAccess da, final MigrationInterface elem, final int id, final int count) { LOGGER.info("Revert migration: {} [BEGIN]", elem.getName()); LOGGER.info("Revert migration: {} [ END ]", elem.getName()); diff --git a/src/org/kar/archidata/migration/MigrationInterface.java b/src/org/kar/archidata/migration/MigrationInterface.java index f98cd35..1243f38 100644 --- a/src/org/kar/archidata/migration/MigrationInterface.java +++ b/src/org/kar/archidata/migration/MigrationInterface.java @@ -1,6 +1,6 @@ package org.kar.archidata.migration; -import org.kar.archidata.db.DBEntry; +import org.kar.archidata.dataAccess.DBAccess; import org.kar.archidata.migration.model.Migration; public interface MigrationInterface { @@ -13,13 +13,13 @@ public interface MigrationInterface { * @param log Stored data in the BDD for the migration progression. * @param migration Migration post data on each step... * @return true if migration is finished. */ - boolean applyMigration(DBEntry entry, StringBuilder log, Migration model) throws Exception; + boolean applyMigration(DBAccess entry, StringBuilder log, Migration model) throws Exception; /** Remove a migration the system to the previous version. * @param entry DB interface for the migration. * @param log Stored data in the BDD for the migration progression. * @return true if migration is finished. */ - boolean revertMigration(DBEntry entry, StringBuilder log) throws Exception; + boolean revertMigration(DBAccess entry, StringBuilder log) throws Exception; /** Get the number of step in the migration process. * @return count of SQL access. */ diff --git a/src/org/kar/archidata/migration/MigrationSqlStep.java b/src/org/kar/archidata/migration/MigrationSqlStep.java index af63f7d..fb74703 100644 --- a/src/org/kar/archidata/migration/MigrationSqlStep.java +++ b/src/org/kar/archidata/migration/MigrationSqlStep.java @@ -5,9 +5,9 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; -import org.kar.archidata.db.DBEntry; import org.kar.archidata.migration.model.Migration; import org.kar.archidata.tools.ConfigBaseVariable; import org.slf4j.Logger; @@ -70,8 +70,7 @@ public class MigrationSqlStep implements MigrationInterface { } @Override - public boolean applyMigration(final DBEntry entry, final StringBuilder log, final Migration model) - throws Exception { + public boolean applyMigration(final DBAccess da, final StringBuilder log, final Migration model) throws Exception { if (!this.isGenerated) { this.isGenerated = true; generateStep(); @@ -106,9 +105,11 @@ public class MigrationSqlStep implements MigrationInterface { } try { if (action.action() != null) { - DataAccess.executeQuery(action.action()); + if (da instanceof final DBAccessSQL ioDBSQL) { + ioDBSQL.executeQuery(action.action()); + } } else { - action.async().doRequest(); + action.async().doRequest(da); } } catch (SQLException | IOException ex) { ex.printStackTrace(); @@ -117,7 +118,7 @@ public class MigrationSqlStep implements MigrationInterface { model.stepId = iii + 1; model.log = log.toString(); try { - DataAccess.update(model, model.id, List.of("stepId", "log")); + da.update(model, model.id, List.of("stepId", "log")); } catch (final Exception e) { e.printStackTrace(); } @@ -128,7 +129,7 @@ public class MigrationSqlStep implements MigrationInterface { model.stepId = iii + 1; model.log = log.toString(); try { - DataAccess.update(model, model.id, List.of("stepId", "log")); + da.update(model, model.id, List.of("stepId", "log")); } catch (final Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -143,7 +144,7 @@ public class MigrationSqlStep implements MigrationInterface { } @Override - public boolean revertMigration(final DBEntry entry, final StringBuilder log) throws Exception { + public boolean revertMigration(final DBAccess da, final StringBuilder log) throws Exception { generateRevertStep(); return false; } diff --git a/src/org/kar/archidata/migration/model/Migration.java b/src/org/kar/archidata/migration/model/Migration.java index a2aef7e..a3c85d5 100644 --- a/src/org/kar/archidata/migration/model/Migration.java +++ b/src/org/kar/archidata/migration/model/Migration.java @@ -6,6 +6,7 @@ import org.kar.archidata.model.GenericDataSoftDelete; import com.fasterxml.jackson.annotation.JsonInclude; +import dev.morphia.annotations.Entity; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; import jakarta.persistence.Table; @@ -16,6 +17,7 @@ import jakarta.ws.rs.DefaultValue; // TODO: Add a migration Hash to be sure that the current migration init is correct and has not change... @Table(name = "KAR_migration") +@Entity("KAR_migration") @DataIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class Migration extends GenericDataSoftDelete { diff --git a/src/org/kar/archidata/model/GenericData.java b/src/org/kar/archidata/model/GenericData.java index dacedb0..4749023 100644 --- a/src/org/kar/archidata/model/GenericData.java +++ b/src/org/kar/archidata/model/GenericData.java @@ -1,5 +1,7 @@ package org.kar.archidata.model; +import org.bson.types.ObjectId; + import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; import jakarta.persistence.GeneratedValue; @@ -7,6 +9,8 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; public class GenericData extends GenericTiming { + @dev.morphia.annotations.Id + private ObjectId _id; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(nullable = false, unique = true) diff --git a/src/org/kar/archidata/tools/ConfigBaseVariable.java b/src/org/kar/archidata/tools/ConfigBaseVariable.java index b068e1c..cf04df3 100644 --- a/src/org/kar/archidata/tools/ConfigBaseVariable.java +++ b/src/org/kar/archidata/tools/ConfigBaseVariable.java @@ -17,6 +17,7 @@ public class ConfigBaseVariable { static public String eMailFrom; static public String eMailLogin; static public String eMailPassword; + static public Class[] dbInterfacesClasses; // For test only public static void clearAllValue() { @@ -36,6 +37,7 @@ public class ConfigBaseVariable { eMailFrom = System.getenv("EMAIL_FROM"); eMailLogin = System.getenv("EMAIL_LOGIN"); eMailPassword = System.getenv("EMAIL_PASSWORD"); + dbInterfacesClasses = new Class[0]; } static { @@ -70,11 +72,17 @@ public class ConfigBaseVariable { return dbHost; } - public static String getDBPort() { + public static Short getDBPort() { if (dbPort == null) { - return "3306"; + if (getDBType().equals("mongo")) { + return 27017; + } + return 3306; } - return dbPort; + if (dbPort == null) { + return null; + } + return Short.parseShort(dbPort); } public static String getDBLogin() { @@ -139,4 +147,11 @@ public class ConfigBaseVariable { return new EMailConfig(eMailFrom, eMailLogin, eMailPassword); } + public static Class[] getBbInterfacesClasses() { + return dbInterfacesClasses; + } + + public static void setBbInterfacesClasses(final Class[] data) { + dbInterfacesClasses = data; + } } diff --git a/src/org/kar/archidata/tools/DataTools.java b/src/org/kar/archidata/tools/DataTools.java index 60f7ce1..f440568 100644 --- a/src/org/kar/archidata/tools/DataTools.java +++ b/src/org/kar/archidata/tools/DataTools.java @@ -18,10 +18,10 @@ import java.util.UUID; import org.apache.tika.Tika; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.kar.archidata.api.DataResource; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccess; import org.kar.archidata.dataAccess.QueryAnd; import org.kar.archidata.dataAccess.QueryCondition; -import org.kar.archidata.dataAccess.addOn.AddOnDataJson; +import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson; import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.ReadAllColumn; import org.kar.archidata.exception.FailException; @@ -77,9 +77,9 @@ public class DataTools { return filePath; } - public static Data getWithSha512(final String sha512) { + public static Data getWithSha512(final DBAccess ioDb, final String sha512) { try { - return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)), + return ioDb.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)), new ReadAllColumn()); } catch (final Exception e) { // TODO Auto-generated catch block @@ -88,9 +88,9 @@ public class DataTools { return null; } - public static Data getWithId(final long id) { + public static Data getWithId(final DBAccess ioDb, final long id) { try { - return DataAccess.getWhere(Data.class, new Condition(new QueryAnd( + return ioDb.getWhere(Data.class, new Condition(new QueryAnd( List.of(new QueryCondition("deleted", "=", false), new QueryCondition("id", "=", id))))); } catch (final Exception e) { // TODO Auto-generated catch block @@ -100,6 +100,7 @@ public class DataTools { } public static Data createNewData( + final DBAccess ioDb, final long tmpUID, final String originalFileName, final String sha512, @@ -113,7 +114,7 @@ public class DataTools { out.sha512 = sha512; out.mimeType = mimeType; out.size = fileSize; - out = DataAccess.insert(out); + out = ioDb.insert(out); } catch (final Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -130,8 +131,11 @@ public class DataTools { return out; } - public static Data createNewData(final long tmpUID, final String originalFileName, final String sha512) - throws IOException, SQLException { + public static Data createNewData( + final DBAccess ioDb, + final long tmpUID, + final String originalFileName, + final String sha512) throws IOException, SQLException { // determine mime type: String mimeType = ""; final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); @@ -144,12 +148,12 @@ public class DataTools { case "webm" -> "video/webm"; default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'"); }; - return createNewData(tmpUID, originalFileName, sha512, mimeType); + return createNewData(ioDb, tmpUID, originalFileName, sha512, mimeType); } - public static void undelete(final UUID id) { + public static void undelete(final DBAccess ioDb, final UUID id) { try { - DataAccess.unsetDelete(Data.class, id); + ioDb.unsetDelete(Data.class, id); } catch (final Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -272,13 +276,14 @@ public class DataTools { } public static void uploadCoverFromUri( + final DBAccess ioDb, final Class clazz, final ID_TYPE id, final String url) throws Exception { LOGGER.info(" - id: {}", id); LOGGER.info(" - url: {} ", url); - final CLASS_TYPE media = DataAccess.get(clazz, id); + final CLASS_TYPE media = ioDb.get(clazz, id); if (media == null) { throw new InputException(clazz.getCanonicalName(), "[" + id.toString() + "] Id does not exist or removed..."); @@ -310,7 +315,7 @@ public class DataTools { final long tmpUID = getTmpDataId(); final String sha512 = saveTemporaryFile(dataResponse, tmpUID); - Data data = getWithSha512(sha512); + Data data = getWithSha512(ioDb, sha512); final String mimeType = getMimeType(dataResponse); if (!Arrays.asList(SUPPORTED_IMAGE_MIME_TYPE).contains(mimeType)) { throw new FailException(Response.Status.NOT_ACCEPTABLE, @@ -321,7 +326,7 @@ public class DataTools { if (data == null) { LOGGER.info("Need to add the data in the BDD ... "); try { - data = createNewData(tmpUID, url, sha512, mimeType); + data = createNewData(ioDb, tmpUID, url, sha512, mimeType); } catch (final IOException ex) { removeTemporaryFile(tmpUID); throw new FailException(Response.Status.NOT_MODIFIED, @@ -333,7 +338,7 @@ public class DataTools { } } else if (data.deleted) { LOGGER.error("Data already exist but deleted"); - undelete(data.uuid); + undelete(ioDb, data.uuid); data.deleted = false; } else { LOGGER.error("Data already exist ... all good"); @@ -341,15 +346,16 @@ public class DataTools { // Fist step: retrieve all the Id of each parents:... LOGGER.info("Find typeNode"); if (id instanceof final Long idLong) { - AddOnDataJson.addLink(clazz, idLong, "covers", data.uuid); + AddOnDataJson.addLink(ioDb, clazz, idLong, "covers", data.uuid); } else if (id instanceof final UUID idUUID) { - AddOnDataJson.addLink(clazz, idUUID, "covers", data.uuid); + AddOnDataJson.addLink(ioDb, clazz, idUUID, "covers", data.uuid); } else { throw new IOException("Fail to add Cover can not detect type..."); } } public static void uploadCover( + final DBAccess ioDb, final Class clazz, final ID_TYPE id, final InputStream fileInputStream, @@ -360,7 +366,7 @@ public class DataTools { LOGGER.info(" - file_name: {} ", fileMetaData.getFileName()); LOGGER.info(" - fileInputStream: {}", fileInputStream); LOGGER.info(" - fileMetaData: {}", fileMetaData); - final CLASS_TYPE media = DataAccess.get(clazz, id); + final CLASS_TYPE media = ioDb.get(clazz, id); if (media == null) { throw new InputException(clazz.getCanonicalName(), "[" + id.toString() + "] Id does not exist or removed..."); @@ -368,11 +374,11 @@ public class DataTools { final long tmpUID = getTmpDataId(); final String sha512 = saveTemporaryFile(fileInputStream, tmpUID); - Data data = getWithSha512(sha512); + Data data = getWithSha512(ioDb, sha512); if (data == null) { LOGGER.info("Need to add the data in the BDD ... "); try { - data = createNewData(tmpUID, fileMetaData.getFileName(), sha512); + data = createNewData(ioDb, tmpUID, fileMetaData.getFileName(), sha512); } catch (final IOException ex) { removeTemporaryFile(tmpUID); throw new FailException(Response.Status.NOT_MODIFIED, @@ -384,7 +390,7 @@ public class DataTools { } } else if (data.deleted) { LOGGER.error("Data already exist but deleted"); - undelete(data.uuid); + undelete(ioDb, data.uuid); data.deleted = false; } else { LOGGER.error("Data already exist ... all good"); @@ -392,9 +398,9 @@ public class DataTools { // Fist step: retrieve all the Id of each parents:... LOGGER.info("Find typeNode"); if (id instanceof final Long idLong) { - AddOnDataJson.addLink(clazz, idLong, "covers", data.uuid); + AddOnDataJson.addLink(ioDb, clazz, idLong, "covers", data.uuid); } else if (id instanceof final UUID idUUID) { - AddOnDataJson.addLink(clazz, idUUID, "covers", data.uuid); + AddOnDataJson.addLink(ioDb, clazz, idUUID, "covers", data.uuid); } else { throw new IOException("Fail to add Cover can not detect type..."); } diff --git a/test/src/test/kar/archidata/ConfigureDb.java b/test/src/test/kar/archidata/ConfigureDb.java index dc80bf4..9461023 100644 --- a/test/src/test/kar/archidata/ConfigureDb.java +++ b/test/src/test/kar/archidata/ConfigureDb.java @@ -1,40 +1,157 @@ package test.kar.archidata; import java.io.IOException; +import java.util.List; -import org.kar.archidata.GlobalConfiguration; -import org.kar.archidata.db.DBEntry; +import org.kar.archidata.dataAccess.DBAccess; +import org.kar.archidata.db.DbConfig; +import org.kar.archidata.db.DbIoFactory; +import org.kar.archidata.exception.DataAccessException; import org.kar.archidata.tools.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.InternalServerErrorException; +import test.kar.archidata.dataAccess.model.SerializeAsJson; +import test.kar.archidata.dataAccess.model.SerializeListAsJson; +import test.kar.archidata.dataAccess.model.SimpleTable; +import test.kar.archidata.dataAccess.model.SimpleTableSoftDelete; +import test.kar.archidata.dataAccess.model.TypeManyToManyRemote; +import test.kar.archidata.dataAccess.model.TypeManyToManyRoot; +import test.kar.archidata.dataAccess.model.TypeManyToManyRootExpand; +import test.kar.archidata.dataAccess.model.TypeManyToOneRemote; +import test.kar.archidata.dataAccess.model.TypeManyToOneRoot; +import test.kar.archidata.dataAccess.model.TypeManyToOneRootExpand; +import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRemote; +import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRoot; +import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRootExpand; +import test.kar.archidata.dataAccess.model.TypeOneToManyRemote; +import test.kar.archidata.dataAccess.model.TypeOneToManyRoot; +import test.kar.archidata.dataAccess.model.TypeOneToManyRootExpand; +import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRemote; +import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRoot; +import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRootExpand; +import test.kar.archidata.dataAccess.model.TypesEnum1; +import test.kar.archidata.dataAccess.model.TypesEnum2; +import test.kar.archidata.dataAccess.model.TypesTable; + public class ConfigureDb { final static private Logger LOGGER = LoggerFactory.getLogger(ConfigureDb.class); + final static private String modeTestForced = null;// "MONGO"; + public static DBAccess da = null; - public static void configure() throws IOException { - if (true) { - if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) { - ConfigBaseVariable.dbType = "sqlite"; - ConfigBaseVariable.dbHost = "memory"; - // for test we need to connect all time the DB - ConfigBaseVariable.dbKeepConnected = "true"; - } - } else { - // Enable this if you want to access to a local MySQL base to test with an adminer + public static void configure() throws IOException, InternalServerErrorException, DataAccessException { + String modeTest = System.getenv("TEST_E2E_MODE"); + if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) { + modeTest = "SQLITE-MEMORY"; + } else if ("true".equalsIgnoreCase(modeTest)) { + modeTest = "MY-SQL"; + } + // override the local test: + if (modeTestForced != null) { + modeTest = modeTestForced; + } + final List> listObject = List.of( // + SerializeAsJson.class, // + SerializeListAsJson.class, // + SimpleTable.class, // + SimpleTableSoftDelete.class, // + TypeManyToManyRemote.class, // + TypeManyToManyRoot.class, // + TypeManyToManyRootExpand.class, // + TypeManyToOneRemote.class, // + TypeManyToOneRoot.class, // + TypeManyToOneRootExpand.class, // + TypeManyToOneUUIDRemote.class, // + TypeManyToOneUUIDRoot.class, // + TypeManyToOneUUIDRootExpand.class, // + TypeOneToManyRemote.class, // + TypeOneToManyRoot.class, // + TypeOneToManyRootExpand.class, // + TypeOneToManyUUIDRemote.class, // + TypeOneToManyUUIDRoot.class, // + TypeOneToManyUUIDRootExpand.class, // + TypesEnum1.class, // + TypesEnum2.class, // + TypesTable.class); + if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) { + ConfigBaseVariable.dbType = "sqlite"; + ConfigBaseVariable.bdDatabase = null; + ConfigBaseVariable.dbHost = "memory"; + // for test we need to connect all time the DB + ConfigBaseVariable.dbKeepConnected = "true"; + } else if ("SQLITE".equalsIgnoreCase(modeTest)) { + ConfigBaseVariable.dbType = "sqlite"; + ConfigBaseVariable.bdDatabase = null; + ConfigBaseVariable.dbKeepConnected = "true"; + } else if ("MY-SQL".equalsIgnoreCase(modeTest)) { + ConfigBaseVariable.dbType = "mysql"; + ConfigBaseVariable.bdDatabase = "test_db"; + ConfigBaseVariable.dbPort = "3906"; + ConfigBaseVariable.dbUser = "root"; + } else if ("MONGO".equalsIgnoreCase(modeTest)) { + ConfigBaseVariable.dbType = "mongo"; + ConfigBaseVariable.bdDatabase = "test_db"; + } else { + // User local modification ... ConfigBaseVariable.bdDatabase = "test_db"; ConfigBaseVariable.dbPort = "3906"; ConfigBaseVariable.dbUser = "root"; - //ConfigBaseVariable.dbPassword = "password"; } + removeDB(); // Connect the dataBase... - final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - entry.connect(); + da = DBAccess.createInterface(); + } + + public static void removeDB() { + String modeTest = System.getenv("TEST_E2E_MODE"); + if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) { + modeTest = "SQLITE-MEMORY"; + } else if ("true".equalsIgnoreCase(modeTest)) { + modeTest = "MY-SQL"; + } + // override the local test: + if (modeTestForced != null) { + modeTest = modeTestForced; + } + DbConfig config = null; + try { + config = new DbConfig(); + } catch (final DataAccessException e) { + e.printStackTrace(); + LOGGER.error("Fail to clean the DB"); + return; + } + config.setDbName(null); + LOGGER.info("Remove the DB and create a new one '{}'", config.getDbName()); + try (final DBAccess daRoot = DBAccess.createInterface(config)) { + if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) { + // nothing to do ... + } else if ("SQLITE".equalsIgnoreCase(modeTest)) { + daRoot.deleteDB(ConfigBaseVariable.bdDatabase); + } else if ("MY-SQL".equalsIgnoreCase(modeTest)) { + daRoot.deleteDB(ConfigBaseVariable.bdDatabase); + } else if ("MONGO".equalsIgnoreCase(modeTest)) { + daRoot.deleteDB(ConfigBaseVariable.bdDatabase); + } + daRoot.createDB(ConfigBaseVariable.bdDatabase); + } catch (final InternalServerErrorException e) { + e.printStackTrace(); + LOGGER.error("Fail to clean the DB"); + return; + } catch (final IOException e) { + e.printStackTrace(); + LOGGER.error("Fail to clean the DB"); + return; + } } public static void clear() throws IOException { LOGGER.info("Remove the test db"); - DBEntry.closeAllForceMode(); + removeDB(); + // The connection is by default open ==> close it at the end of test: + da.close(); + DbIoFactory.closeAllForceMode(); ConfigBaseVariable.clearAllValue(); - } } diff --git a/test/src/test/kar/archidata/TestRawQuery.java b/test/src/test/kar/archidata/TestRawQuery.java deleted file mode 100644 index 21a41fd..0000000 --- a/test/src/test/kar/archidata/TestRawQuery.java +++ /dev/null @@ -1,108 +0,0 @@ -package test.kar.archidata; - -import java.io.IOException; -import java.util.List; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.dataAccess.DataFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import test.kar.archidata.model.TypesTable; - -@ExtendWith(StepwiseExtension.class) -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class TestRawQuery { - final static private Logger LOGGER = LoggerFactory.getLogger(TestTypes.class); - - @BeforeAll - public static void configureWebServer() throws Exception { - ConfigureDb.configure(); - } - - @AfterAll - public static void removeDataBase() throws IOException { - ConfigureDb.clear(); - } - - @Order(1) - @Test - public void testCreateTable() throws Exception { - final List sqlCommand = DataFactory.createTable(TypesTable.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); - } - } - - @Order(2) - @Test - public void testGet() throws Exception { - - final TypesTable test = new TypesTable(); - test.intData = 95; - test.floatData = 1.0F; - DataAccess.insert(test); - test.intData = 96; - test.floatData = 2.0F; - DataAccess.insert(test); - test.intData = 97; - test.floatData = 3.0F; - DataAccess.insert(test); - test.intData = 98; - test.floatData = 4.0F; - DataAccess.insert(test); - test.intData = 99; - test.floatData = 5.0F; - DataAccess.insert(test); - test.intData = 99; - test.floatData = 6.0F; - DataAccess.insert(test); - test.intData = 99; - test.floatData = 7.0F; - DataAccess.insert(test); - { - final String query = """ - SELECT * - FROM TypesTable - WHERE `intData` = ? - ORDER BY id DESC - """; - final List parameters = List.of(Integer.valueOf(99)); - // Try to retrieve all the data: - final List retrieve = DataAccess.query(TypesTable.class, query, parameters); - - Assertions.assertNotNull(retrieve); - Assertions.assertEquals(3, retrieve.size()); - Assertions.assertEquals(99, retrieve.get(0).intData); - Assertions.assertEquals(7.0F, retrieve.get(0).floatData); - Assertions.assertEquals(6.0F, retrieve.get(1).floatData); - Assertions.assertEquals(5.0F, retrieve.get(2).floatData); - } - { - - final String query = """ - SELECT DISTINCT intData - FROM TypesTable - WHERE `intData` = ? - ORDER BY id DESC - """; - final List parameters = List.of(Integer.valueOf(99)); - // Try to retrieve all the data: - final List retrieve = DataAccess.query(TypesTable.class, query, parameters); - - Assertions.assertNotNull(retrieve); - Assertions.assertEquals(1, retrieve.size()); - Assertions.assertEquals(99, retrieve.get(0).intData); - } - } - -} diff --git a/test/src/test/kar/archidata/apiExtern/Common.java b/test/src/test/kar/archidata/apiExtern/Common.java new file mode 100644 index 0000000..63fa05a --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/Common.java @@ -0,0 +1,34 @@ +package test.kar.archidata.apiExtern; + +import java.util.Map; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.kar.archidata.tools.JWTWrapper; + +public class Common { + public static final String USER_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_user_login", "KarAuth", + "farm.neo.back", // + Map.of("farm.neo.back", Map.of("USER", Boolean.TRUE))); + public static final String ADMIN_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_admin_login", "KarAuth", + "farm.neo.back", Map.of("farm.neo.back", Map.of("USER", Boolean.TRUE, "ADMIN", Boolean.TRUE))); + + public static String RandGeneratedStr(final int length) { + final String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz0123456789éàê_- '()"; + final StringBuilder out = new StringBuilder(length); + for (int iii = 0; iii < length; iii++) { + final int chId = (int) (base.length() * Math.random()); + out.append(base.charAt(chId)); + } + return out.toString(); + } + + public static void checkUUID(final UUID id) { + final String data = id.toString(); + Assertions.assertFalse(data.equals("00000000-0000-0000-0000-000000000000")); + final String[] elems = data.split("-"); + Assertions.assertEquals(elems.length, 5); + Assertions.assertTrue(elems[3].equals("0001")); + + } +} diff --git a/test/src/test/kar/archidata/apiExtern/TestAPI.java b/test/src/test/kar/archidata/apiExtern/TestAPI.java new file mode 100644 index 0000000..01e2827 --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/TestAPI.java @@ -0,0 +1,96 @@ +package test.kar.archidata.apiExtern; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.kar.archidata.tools.RESTApi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.apiExtern.model.SimpleArchiveTable; + +@ExtendWith(StepwiseExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestAPI { + private final static Logger LOGGER = LoggerFactory.getLogger(TestAPI.class); + public final static String ENDPOINT_NAME = "TestResource"; + + static WebLauncherTest webInterface = null; + static RESTApi api = null; + + private static Long idTest = 0L; + + @BeforeAll + public static void configureWebServer() throws Exception { + ConfigureDb.configure(); + LOGGER.info("configure server ..."); + webInterface = new WebLauncherTest(); + LOGGER.info("Clean previous table"); + + LOGGER.info("Start REST (BEGIN)"); + webInterface.process(); + LOGGER.info("Start REST (DONE)"); + api = new RESTApi(ConfigBaseVariable.apiAdress); + api.setToken(Common.ADMIN_TOKEN); + } + + @AfterAll + public static void stopWebServer() throws Exception { + LOGGER.info("Kill the web server"); + webInterface.stop(); + webInterface = null; + ConfigureDb.clear(); + } + + @Order(1) + @Test + public void insertValue() throws Exception { + + final SimpleArchiveTable data = new SimpleArchiveTable(); + data.name = "Test name"; + + final SimpleArchiveTable inserted = api.post(SimpleArchiveTable.class, TestAPI.ENDPOINT_NAME, data); + Assertions.assertNotNull(inserted); + Assertions.assertNotNull(inserted.id); + Assertions.assertNotNull(inserted.name); + Assertions.assertEquals(data.name, inserted.name); + + TestAPI.idTest = inserted.id; + final SimpleArchiveTable retrieve = api.get(SimpleArchiveTable.class, + TestAPI.ENDPOINT_NAME + "/" + TestAPI.idTest); + Assertions.assertNotNull(retrieve); + Assertions.assertEquals(TestAPI.idTest, retrieve.id); + Assertions.assertNotNull(retrieve.name); + Assertions.assertEquals(data.name, retrieve.name); + } + + @Order(2) + @Test + public void archiveValue() throws Exception { + final SimpleArchiveTable archivedData = api.archive(SimpleArchiveTable.class, + TestAPI.ENDPOINT_NAME + "/" + TestAPI.idTest); + Assertions.assertNotNull(archivedData); + Assertions.assertEquals(TestAPI.idTest, archivedData.id); + Assertions.assertNotNull(archivedData.name); + Assertions.assertNotNull(archivedData.archive); + } + + @Order(2) + @Test + public void restoreValue() throws Exception { + final SimpleArchiveTable archivedData = api.restore(SimpleArchiveTable.class, + TestAPI.ENDPOINT_NAME + "/" + TestAPI.idTest); + Assertions.assertNotNull(archivedData); + Assertions.assertEquals(TestAPI.idTest, archivedData.id); + Assertions.assertNotNull(archivedData.name); + Assertions.assertNull(archivedData.archive); + } +} diff --git a/test/src/test/kar/archidata/apiExtern/TestAuthenticationFilter.java b/test/src/test/kar/archidata/apiExtern/TestAuthenticationFilter.java new file mode 100644 index 0000000..93c7c47 --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/TestAuthenticationFilter.java @@ -0,0 +1,23 @@ +package test.kar.archidata.apiExtern; + +import org.kar.archidata.filter.AuthenticationFilter; + +import jakarta.ws.rs.Priorities; +import jakarta.ws.rs.ext.Provider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.annotation.Priority; + +//@PreMatching +@Provider +@Priority(Priorities.AUTHENTICATION) +public class TestAuthenticationFilter extends AuthenticationFilter { + final Logger logger = LoggerFactory.getLogger(TestAuthenticationFilter.class); + + public TestAuthenticationFilter() { + super("karusic"); + } + +} diff --git a/test/src/test/kar/archidata/apiExtern/WebLauncher.java b/test/src/test/kar/archidata/apiExtern/WebLauncher.java new file mode 100755 index 0000000..1551cea --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/WebLauncher.java @@ -0,0 +1,172 @@ +package test.kar.archidata.apiExtern; + +import java.net.URI; +import java.util.Iterator; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageWriter; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.kar.archidata.UpdateJwtPublicKey; +import org.kar.archidata.api.DataResource; +import org.kar.archidata.api.ProxyResource; +import org.kar.archidata.catcher.GenericCatcher; +import org.kar.archidata.db.DbConfig; +import org.kar.archidata.exception.DataAccessException; +import org.kar.archidata.filter.CORSFilter; +import org.kar.archidata.filter.OptionFilter; +import org.kar.archidata.migration.MigrationEngine; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.UriBuilder; +import test.kar.archidata.apiExtern.resource.TestResource; + +public class WebLauncher { + final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class); + protected UpdateJwtPublicKey keyUpdater = null; + protected HttpServer server = null; + + public WebLauncher() {} + + private static URI getBaseURI() { + return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build(); + } + + public void migrateDB() throws Exception { + WebLauncher.LOGGER.info("Create migration engine"); + final MigrationEngine migrationEngine = new MigrationEngine(); + WebLauncher.LOGGER.info("Add initialization"); + //migrationEngine.setInit(new Initialization()); + WebLauncher.LOGGER.info("Add migration since last version"); + //migrationEngine.add(new Migration20231126()); + WebLauncher.LOGGER.info("Migrate the DB [START]"); + migrationEngine.migrateWaitAdmin(new DbConfig()); + WebLauncher.LOGGER.info("Migrate the DB [STOP]"); + } + + public static void main(final String[] args) throws Exception { + WebLauncher.LOGGER.info("[START] application wake UP"); + final WebLauncher launcher = new WebLauncher(); + launcher.migrateDB(); + + launcher.process(); + WebLauncher.LOGGER.info("end-configure the server & wait finish process:"); + Thread.currentThread().join(); + WebLauncher.LOGGER.info("STOP Key updater"); + launcher.stopOther(); + WebLauncher.LOGGER.info("STOP the REST server:"); + } + + public void plop(final String aaa) { + // List available Image Readers + System.out.println("Available Image Readers:"); + final Iterator readers = ImageIO.getImageReadersByFormatName(aaa); + while (readers.hasNext()) { + final ImageReader reader = readers.next(); + System.out.println("Reader: " + reader.getOriginatingProvider().getDescription(null)); + System.out.println("Reader CN: " + reader.getOriginatingProvider().getPluginClassName()); + // ImageIO.deregisterServiceProvider(reader.getOriginatingProvider()); + } + + // List available Image Writers + System.out.println("\nAvailable Image Writers:"); + final Iterator writers = ImageIO.getImageWritersByFormatName(aaa); + while (writers.hasNext()) { + final ImageWriter writer = writers.next(); + System.out.println("Writer: " + writer.getOriginatingProvider().getDescription(null)); + System.out.println("Writer CN: " + writer.getOriginatingProvider().getPluginClassName()); + } + } + + public void process() throws InterruptedException, DataAccessException { + + ImageIO.scanForPlugins(); + plop("jpeg"); + plop("png"); + plop("webmp"); + plop("webp"); + // =================================================================== + // Configure resources + // =================================================================== + final ResourceConfig rc = new ResourceConfig(); + + // add multipart models .. + rc.register(MultiPartFeature.class); + // global authentication system + rc.register(OptionFilter.class); + // remove cors ==> all time called by an other system... + rc.register(CORSFilter.class); + // global authentication system + rc.register(TestAuthenticationFilter.class); + // register exception catcher + GenericCatcher.addAll(rc); + // add default resource: + rc.register(TestResource.class); + rc.register(DataResource.class); + rc.register(ProxyResource.class); + + // add jackson to be discover when we are ins standalone server + rc.register(JacksonFeature.class); + // enable this to show low level request + // rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName()); + + // System.out.println("Connect on the BDD:"); + // System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'"); + // System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'"); + // System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'"); + // System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'"); + // System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'"); + LOGGER.info(" ==> {}", new DbConfig()); + LOGGER.info("OAuth service {}", getBaseURI()); + this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc); + final HttpServer serverLink = this.server; + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Stopping server.."); + serverLink.shutdownNow(); + } + }, "shutdownHook")); + + // =================================================================== + // start periodic update of the token ... + // =================================================================== + this.keyUpdater = new UpdateJwtPublicKey(); + this.keyUpdater.start(); + + // =================================================================== + // run JERSEY + // =================================================================== + try { + this.server.start(); + LOGGER.info("Jersey app started at {}", getBaseURI()); + } catch (final Exception e) { + LOGGER.error("There was an error while starting Grizzly HTTP server."); + e.printStackTrace(); + } + } + + public void stop() { + if (this.server != null) { + this.server.shutdownNow(); + this.server = null; + } + } + + public void stopOther() { + this.keyUpdater.kill(); + try { + this.keyUpdater.join(4000, 0); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/test/src/test/kar/archidata/apiExtern/WebLauncherTest.java b/test/src/test/kar/archidata/apiExtern/WebLauncherTest.java new file mode 100755 index 0000000..1b323fd --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/WebLauncherTest.java @@ -0,0 +1,19 @@ + +package test.kar.archidata.apiExtern; + +import org.kar.archidata.tools.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebLauncherTest extends WebLauncher { + final private static Logger LOGGER = LoggerFactory.getLogger(WebLauncherTest.class); + + public WebLauncherTest() { + LOGGER.debug("Configure REST system"); + // for local test: + ConfigBaseVariable.apiAdress = "http://127.0.0.1:12345/test/api/"; + // Enable the test mode permit to access to the test token (never use it in production). + ConfigBaseVariable.testMode = "true"; + // ConfigBaseVariable.dbPort = "3306"; + } +} diff --git a/test/src/test/kar/archidata/apiExtern/model/SimpleArchiveTable.java b/test/src/test/kar/archidata/apiExtern/model/SimpleArchiveTable.java new file mode 100644 index 0000000..294206a --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/model/SimpleArchiveTable.java @@ -0,0 +1,14 @@ +package test.kar.archidata.apiExtern.model; + +import java.util.Date; + +import org.kar.archidata.model.GenericData; + +import com.fasterxml.jackson.annotation.JsonFormat; + +public class SimpleArchiveTable extends GenericData { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") + public Date archive; + public String name; + +} \ No newline at end of file diff --git a/test/src/test/kar/archidata/apiExtern/resource/TestResource.java b/test/src/test/kar/archidata/apiExtern/resource/TestResource.java new file mode 100644 index 0000000..51b1728 --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/resource/TestResource.java @@ -0,0 +1,121 @@ +package test.kar.archidata.apiExtern.resource; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.kar.archidata.annotation.ARCHIVE; +import org.kar.archidata.annotation.AsyncType; +import org.kar.archidata.annotation.RESTORE; +import org.kar.archidata.exception.NotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.annotation.security.PermitAll; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import test.kar.archidata.apiExtern.model.SimpleArchiveTable; + +@Path("/TestResource") +@Produces({ MediaType.APPLICATION_JSON }) +public class TestResource { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestResource.class); + private static final List data = new ArrayList<>(); + private static long uniqueId = 330; + + @GET + @PermitAll + public List gets() throws Exception { + return this.data; + } + + @GET + @Path("{id}") + @PermitAll + public SimpleArchiveTable get(@PathParam("id") final Long id) throws Exception { + LOGGER.info("get({})", id); + for (final SimpleArchiveTable elem : this.data) { + if (elem.id.equals(id)) { + return elem; + } + } + throw new NotFoundException("element does not exist: " + id); + } + + @ARCHIVE + @Path("{id}") + @PermitAll + public SimpleArchiveTable archive(@PathParam("id") final Long id) throws Exception { + LOGGER.info("archive({})", id); + for (final SimpleArchiveTable elem : this.data) { + if (elem.id.equals(id)) { + elem.archive = new Date(); + return elem; + } + } + throw new NotFoundException("element does not exist: " + id); + } + + @RESTORE + @Path("{id}") + @PermitAll + public SimpleArchiveTable restore(@PathParam("id") final Long id) throws Exception { + LOGGER.info("restore({})", id); + for (final SimpleArchiveTable elem : this.data) { + if (elem.id.equals(id)) { + elem.archive = null; + return elem; + } + } + throw new NotFoundException("element does not exist: " + id); + } + + @POST + @PermitAll + @Consumes(MediaType.APPLICATION_JSON) + public SimpleArchiveTable post(final SimpleArchiveTable data) throws Exception { + LOGGER.info("post(...)"); + data.id = this.uniqueId; + this.uniqueId += 5; + this.data.add(data); + return data; + } + + @PATCH + @Path("{id}") + @PermitAll + @Consumes(MediaType.APPLICATION_JSON) + public SimpleArchiveTable patch( + @PathParam("id") final Long id, + @AsyncType(SimpleArchiveTable.class) final String jsonRequest) throws Exception { + LOGGER.info("patch({})", id); + throw new NotFoundException("element does not exist: " + id); + } + + @PUT + @Path("{id}") + @PermitAll + @Consumes(MediaType.APPLICATION_JSON) + public SimpleArchiveTable put(@PathParam("id") final Long id, final SimpleArchiveTable data) throws Exception { + LOGGER.info("put({})", id); + throw new NotFoundException("element does not exist: " + id); + } + + @DELETE + @Path("{id}") + @PermitAll + public void remove(@PathParam("id") final Long id) throws Exception { + LOGGER.info("remove({})", id); + this.data.removeIf(e -> e.id.equals(id)); + } + +} diff --git a/test/src/test/kar/archidata/apiExtern/resource/TestResourceSample.java b/test/src/test/kar/archidata/apiExtern/resource/TestResourceSample.java new file mode 100644 index 0000000..08817a8 --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/resource/TestResourceSample.java @@ -0,0 +1,91 @@ +package test.kar.archidata.apiExtern.resource; + +import java.util.List; + +import org.kar.archidata.annotation.ARCHIVE; +import org.kar.archidata.annotation.AsyncType; +import org.kar.archidata.annotation.RESTORE; +import org.kar.archidata.dataAccess.DataAccess; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.annotation.security.PermitAll; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import test.kar.archidata.dataAccess.model.SimpleTable; + +@Path("/TestResourceSample") +@Produces({ MediaType.APPLICATION_JSON }) +public class TestResourceSample { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestResource.class); + + @GET + @PermitAll + public List gets() throws Exception { + return DataAccess.gets(SimpleTable.class); + } + + @GET + @Path("{id}") + @PermitAll + public SimpleTable get(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(SimpleTable.class, id); + } + + @ARCHIVE + @Path("{id}") + @PermitAll + public SimpleTable archive(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(SimpleTable.class, id); + } + + @RESTORE + @Path("{id}") + @PermitAll + public SimpleTable restore(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(SimpleTable.class, id); + } + + @POST + @PermitAll + @Consumes(MediaType.APPLICATION_JSON) + public SimpleTable post(final SimpleTable data) throws Exception { + return DataAccess.insert(data); + } + + @PATCH + @Path("{id}") + @PermitAll + @Consumes(MediaType.APPLICATION_JSON) + public SimpleTable patch(@PathParam("id") final Long id, @AsyncType(SimpleTable.class) final String jsonRequest) + throws Exception { + DataAccess.updateWithJson(SimpleTable.class, id, jsonRequest); + return DataAccess.get(SimpleTable.class, id); + } + + @PUT + @Path("{id}") + @PermitAll + @Consumes(MediaType.APPLICATION_JSON) + public SimpleTable put(@PathParam("id") final Long id, final SimpleTable data) throws Exception { + DataAccess.update(data, id); + return DataAccess.get(SimpleTable.class, id); + } + + @DELETE + @Path("{id}") + @PermitAll + public void remove(@PathParam("id") final Long id) throws Exception { + DataAccess.delete(SimpleTable.class, id); + } + +} diff --git a/test/src/test/kar/archidata/TestJson.java b/test/src/test/kar/archidata/dataAccess/TestJson.java similarity index 72% rename from test/src/test/kar/archidata/TestJson.java rename to test/src/test/kar/archidata/dataAccess/TestJson.java index 197bf50..ef356b6 100644 --- a/test/src/test/kar/archidata/TestJson.java +++ b/test/src/test/kar/archidata/dataAccess/TestJson.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.util.List; @@ -11,13 +11,15 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.SerializeAsJson; -import test.kar.archidata.model.SimpleTable; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.SerializeAsJson; +import test.kar.archidata.dataAccess.model.SimpleTable; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -36,11 +38,13 @@ public class TestJson { @Order(1) @Test - public void testTableInsertAndRetrieve() throws Exception { + public void testTableFactory() throws Exception { final List sqlCommand = DataFactory.createTable(SerializeAsJson.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -51,7 +55,7 @@ public class TestJson { test.data = new SimpleTable(); test.data.data = "plopppopql"; - final SerializeAsJson insertedData = DataAccess.insert(test); + final SerializeAsJson insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); @@ -61,7 +65,7 @@ public class TestJson { Assertions.assertEquals(test.data.data, insertedData.data.data); // Try to retrieve all the data: - final SerializeAsJson retrieve = DataAccess.get(SerializeAsJson.class, insertedData.id); + final SerializeAsJson retrieve = ConfigureDb.da.get(SerializeAsJson.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); diff --git a/test/src/test/kar/archidata/TestListJson.java b/test/src/test/kar/archidata/dataAccess/TestListJson.java similarity index 81% rename from test/src/test/kar/archidata/TestListJson.java rename to test/src/test/kar/archidata/dataAccess/TestListJson.java index d4b0262..47c2b1a 100644 --- a/test/src/test/kar/archidata/TestListJson.java +++ b/test/src/test/kar/archidata/dataAccess/TestListJson.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.util.ArrayList; @@ -12,12 +12,14 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.SerializeListAsJson; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.SerializeListAsJson; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -38,9 +40,11 @@ public class TestListJson { @Test public void testTableInsertAndRetrieve() throws Exception { final List sqlCommand = DataFactory.createTable(SerializeListAsJson.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -55,7 +59,7 @@ public class TestListJson { test.data.add(6); test.data.add(51); - final SerializeListAsJson insertedData = DataAccess.insert(test); + final SerializeListAsJson insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); @@ -69,7 +73,7 @@ public class TestListJson { Assertions.assertEquals(test.data.get(4), insertedData.data.get(4)); // Try to retrieve all the data: - final SerializeListAsJson retrieve = DataAccess.get(SerializeListAsJson.class, insertedData.id); + final SerializeListAsJson retrieve = ConfigureDb.da.get(SerializeListAsJson.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); diff --git a/test/src/test/kar/archidata/TestManyToMany.java b/test/src/test/kar/archidata/dataAccess/TestManyToMany.java similarity index 70% rename from test/src/test/kar/archidata/TestManyToMany.java rename to test/src/test/kar/archidata/dataAccess/TestManyToMany.java index 28c89a1..6e18b75 100644 --- a/test/src/test/kar/archidata/TestManyToMany.java +++ b/test/src/test/kar/archidata/dataAccess/TestManyToMany.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.util.List; @@ -11,15 +11,17 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; -import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; +import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToMany; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.TypeManyToManyRemote; -import test.kar.archidata.model.TypeManyToManyRoot; -import test.kar.archidata.model.TypeManyToManyRootExpand; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.TypeManyToManyRemote; +import test.kar.archidata.dataAccess.model.TypeManyToManyRoot; +import test.kar.archidata.dataAccess.model.TypeManyToManyRootExpand; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -42,9 +44,11 @@ public class TestManyToMany { final List sqlCommand2 = DataFactory.createTable(TypeManyToManyRoot.class); final List sqlCommand = DataFactory.createTable(TypeManyToManyRemote.class); sqlCommand.addAll(sqlCommand2); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -53,14 +57,14 @@ public class TestManyToMany { public void testSimpleInsertAndRetieve() throws Exception { final TypeManyToManyRoot test = new TypeManyToManyRoot(); test.otherData = "kjhlkjlkj"; - final TypeManyToManyRoot insertedData = DataAccess.insert(test); + final TypeManyToManyRoot insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); Assertions.assertNull(insertedData.remote); // Try to retrieve all the data: - final TypeManyToManyRoot retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + final TypeManyToManyRoot retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -69,7 +73,7 @@ public class TestManyToMany { Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertNull(retrieve.remote); - DataAccess.delete(TypeManyToManyRoot.class, insertedData.id); + ConfigureDb.da.delete(TypeManyToManyRoot.class, insertedData.id); } @Order(3) @@ -78,24 +82,24 @@ public class TestManyToMany { TypeManyToManyRemote remote = new TypeManyToManyRemote(); remote.data = "remote1"; - final TypeManyToManyRemote insertedRemote1 = DataAccess.insert(remote); + final TypeManyToManyRemote insertedRemote1 = ConfigureDb.da.insert(remote); Assertions.assertEquals(insertedRemote1.data, remote.data); remote = new TypeManyToManyRemote(); remote.data = "remote2"; - final TypeManyToManyRemote insertedRemote2 = DataAccess.insert(remote); + final TypeManyToManyRemote insertedRemote2 = ConfigureDb.da.insert(remote); Assertions.assertEquals(insertedRemote2.data, remote.data); final TypeManyToManyRoot test = new TypeManyToManyRoot(); test.otherData = "kjhlkjlkj"; - final TypeManyToManyRoot insertedData = DataAccess.insert(test); + final TypeManyToManyRoot insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); Assertions.assertNull(insertedData.remote); // Try to retrieve all the data: - TypeManyToManyRoot retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + TypeManyToManyRoot retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -105,10 +109,10 @@ public class TestManyToMany { Assertions.assertNull(retrieve.remote); // Add remote elements - AddOnManyToMany.addLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id); - AddOnManyToMany.addLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id); + AddOnManyToMany.addLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id); + AddOnManyToMany.addLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id); - retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -120,7 +124,8 @@ public class TestManyToMany { Assertions.assertEquals(retrieve.remote.get(0), insertedRemote1.id); Assertions.assertEquals(retrieve.remote.get(1), insertedRemote2.id); - final TypeManyToManyRootExpand retrieveExpand = DataAccess.get(TypeManyToManyRootExpand.class, insertedData.id); + final TypeManyToManyRootExpand retrieveExpand = ConfigureDb.da.get(TypeManyToManyRootExpand.class, + insertedData.id); Assertions.assertNotNull(retrieveExpand); Assertions.assertNotNull(retrieveExpand.id); @@ -133,10 +138,11 @@ public class TestManyToMany { Assertions.assertEquals(retrieveExpand.remote.get(1).id, insertedRemote2.id); // Remove an element - int count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id); + long count = AddOnManyToMany.removeLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote", + insertedRemote1.id); Assertions.assertEquals(1, count); - retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -148,10 +154,11 @@ public class TestManyToMany { Assertions.assertEquals(retrieve.remote.get(0), insertedRemote2.id); // Remove the second element - count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id); + count = AddOnManyToMany.removeLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote", + insertedRemote2.id); Assertions.assertEquals(1, count); - retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -160,9 +167,9 @@ public class TestManyToMany { Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertNull(retrieve.remote); - DataAccess.delete(TypeManyToManyRoot.class, insertedData.id); + ConfigureDb.da.delete(TypeManyToManyRoot.class, insertedData.id); } /* API TODO: - Replace list (permet de les ordonnées) - remove all links - delete en cascade .... (compliqué...) */ -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/TestManyToOne.java b/test/src/test/kar/archidata/dataAccess/TestManyToOne.java similarity index 70% rename from test/src/test/kar/archidata/TestManyToOne.java rename to test/src/test/kar/archidata/dataAccess/TestManyToOne.java index 2619191..e28f1a6 100644 --- a/test/src/test/kar/archidata/TestManyToOne.java +++ b/test/src/test/kar/archidata/dataAccess/TestManyToOne.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.util.List; @@ -11,17 +11,19 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.TypeManyToOneRemote; -import test.kar.archidata.model.TypeManyToOneRoot; -import test.kar.archidata.model.TypeManyToOneRootExpand; -import test.kar.archidata.model.TypeManyToOneUUIDRemote; -import test.kar.archidata.model.TypeManyToOneUUIDRoot; -import test.kar.archidata.model.TypeManyToOneUUIDRootExpand; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.TypeManyToOneRemote; +import test.kar.archidata.dataAccess.model.TypeManyToOneRoot; +import test.kar.archidata.dataAccess.model.TypeManyToOneRootExpand; +import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRemote; +import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRoot; +import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRootExpand; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -45,9 +47,11 @@ public class TestManyToOne { sqlCommand.addAll(DataFactory.createTable(TypeManyToOneRoot.class)); sqlCommand.addAll(DataFactory.createTable(TypeManyToOneUUIDRoot.class)); sqlCommand.addAll(DataFactory.createTable(TypeManyToOneUUIDRemote.class)); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -56,32 +60,32 @@ public class TestManyToOne { public void testRemoteLong() throws Exception { TypeManyToOneRemote remote = new TypeManyToOneRemote(); remote.data = "remote1"; - final TypeManyToOneRemote insertedRemote1 = DataAccess.insert(remote); + final TypeManyToOneRemote insertedRemote1 = ConfigureDb.da.insert(remote); Assertions.assertEquals(insertedRemote1.data, remote.data); remote = new TypeManyToOneRemote(); remote.data = "remote2"; - final TypeManyToOneRemote insertedRemote2 = DataAccess.insert(remote); + final TypeManyToOneRemote insertedRemote2 = ConfigureDb.da.insert(remote); Assertions.assertEquals(insertedRemote2.data, remote.data); final TypeManyToOneRoot test = new TypeManyToOneRoot(); test.otherData = "kjhlkjlkj"; test.remoteId = insertedRemote2.id; - final TypeManyToOneRoot insertedData = DataAccess.insert(test); + final TypeManyToOneRoot insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); Assertions.assertEquals(test.otherData, insertedData.otherData); Assertions.assertEquals(insertedRemote2.id, insertedData.remoteId); - TypeManyToOneRoot retrieve = DataAccess.get(TypeManyToOneRoot.class, insertedData.id); + TypeManyToOneRoot retrieve = ConfigureDb.da.get(TypeManyToOneRoot.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId); - TypeManyToOneRootExpand retrieve2 = DataAccess.get(TypeManyToOneRootExpand.class, insertedData.id); + TypeManyToOneRootExpand retrieve2 = ConfigureDb.da.get(TypeManyToOneRootExpand.class, insertedData.id); Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2.id); Assertions.assertEquals(insertedData.id, retrieve2.id); @@ -91,19 +95,22 @@ public class TestManyToOne { Assertions.assertEquals(insertedRemote2.data, retrieve2.remote.data); // remove values: - final int count = DataAccess.delete(TypeManyToOneRemote.class, remote.id); - Assertions.assertEquals(1, count); - + try { + final long count = ConfigureDb.da.delete(TypeManyToOneRemote.class, insertedRemote2.id); + Assertions.assertEquals(1L, count); + } catch (final Exception ex) { + ex.printStackTrace(); + } // check fail: - retrieve = DataAccess.get(TypeManyToOneRoot.class, insertedData.id); + retrieve = ConfigureDb.da.get(TypeManyToOneRoot.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId); - retrieve2 = DataAccess.get(TypeManyToOneRootExpand.class, insertedData.id); + retrieve2 = ConfigureDb.da.get(TypeManyToOneRootExpand.class, insertedData.id); Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2.id); Assertions.assertEquals(insertedData.id, retrieve2.id); @@ -116,31 +123,32 @@ public class TestManyToOne { public void testRemoteUUID() throws Exception { TypeManyToOneUUIDRemote remote = new TypeManyToOneUUIDRemote(); remote.data = "remote1"; - final TypeManyToOneUUIDRemote insertedRemote1 = DataAccess.insert(remote); + final TypeManyToOneUUIDRemote insertedRemote1 = ConfigureDb.da.insert(remote); Assertions.assertEquals(insertedRemote1.data, remote.data); remote = new TypeManyToOneUUIDRemote(); remote.data = "remote2"; - final TypeManyToOneUUIDRemote insertedRemote2 = DataAccess.insert(remote); + final TypeManyToOneUUIDRemote insertedRemote2 = ConfigureDb.da.insert(remote); Assertions.assertEquals(insertedRemote2.data, remote.data); final TypeManyToOneUUIDRoot test = new TypeManyToOneUUIDRoot(); test.otherData = "kjhlkjlkj"; test.remoteUuid = insertedRemote2.uuid; - final TypeManyToOneUUIDRoot insertedData = DataAccess.insert(test); + final TypeManyToOneUUIDRoot insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.uuid); Assertions.assertEquals(test.otherData, insertedData.otherData); Assertions.assertEquals(insertedRemote2.uuid, insertedData.remoteUuid); - TypeManyToOneUUIDRoot retrieve = DataAccess.get(TypeManyToOneUUIDRoot.class, insertedData.uuid); + TypeManyToOneUUIDRoot retrieve = ConfigureDb.da.get(TypeManyToOneUUIDRoot.class, insertedData.uuid); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.uuid); Assertions.assertEquals(insertedData.uuid, retrieve.uuid); Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedRemote2.uuid, retrieve.remoteUuid); - TypeManyToOneUUIDRootExpand retrieve2 = DataAccess.get(TypeManyToOneUUIDRootExpand.class, insertedData.uuid); + TypeManyToOneUUIDRootExpand retrieve2 = ConfigureDb.da.get(TypeManyToOneUUIDRootExpand.class, + insertedData.uuid); Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2.uuid); Assertions.assertEquals(insertedData.uuid, retrieve2.uuid); @@ -150,23 +158,23 @@ public class TestManyToOne { Assertions.assertEquals(insertedRemote2.data, retrieve2.remote.data); // remove values: - final int count = DataAccess.delete(TypeManyToOneUUIDRemote.class, remote.uuid); + final long count = ConfigureDb.da.delete(TypeManyToOneUUIDRemote.class, insertedRemote2.uuid); Assertions.assertEquals(1, count); // check fail: - retrieve = DataAccess.get(TypeManyToOneUUIDRoot.class, insertedData.uuid); + retrieve = ConfigureDb.da.get(TypeManyToOneUUIDRoot.class, insertedData.uuid); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.uuid); Assertions.assertEquals(insertedData.uuid, retrieve.uuid); Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedRemote2.uuid, retrieve.remoteUuid); - retrieve2 = DataAccess.get(TypeManyToOneUUIDRootExpand.class, insertedData.uuid); + retrieve2 = ConfigureDb.da.get(TypeManyToOneUUIDRootExpand.class, insertedData.uuid); Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2.uuid); Assertions.assertEquals(insertedData.uuid, retrieve2.uuid); Assertions.assertEquals(insertedData.otherData, retrieve2.otherData); Assertions.assertNull(retrieve2.remote); } -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/TestOneToMany.java b/test/src/test/kar/archidata/dataAccess/TestOneToMany.java similarity index 77% rename from test/src/test/kar/archidata/TestOneToMany.java rename to test/src/test/kar/archidata/dataAccess/TestOneToMany.java index e2b2e27..d639e23 100644 --- a/test/src/test/kar/archidata/TestOneToMany.java +++ b/test/src/test/kar/archidata/dataAccess/TestOneToMany.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.util.List; @@ -11,17 +11,19 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.TypeOneToManyRemote; -import test.kar.archidata.model.TypeOneToManyRoot; -import test.kar.archidata.model.TypeOneToManyRootExpand; -import test.kar.archidata.model.TypeOneToManyUUIDRemote; -import test.kar.archidata.model.TypeOneToManyUUIDRoot; -import test.kar.archidata.model.TypeOneToManyUUIDRootExpand; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.TypeOneToManyRemote; +import test.kar.archidata.dataAccess.model.TypeOneToManyRoot; +import test.kar.archidata.dataAccess.model.TypeOneToManyRootExpand; +import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRemote; +import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRoot; +import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRootExpand; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -45,9 +47,11 @@ public class TestOneToMany { sqlCommand.addAll(DataFactory.createTable(TypeOneToManyRoot.class)); sqlCommand.addAll(DataFactory.createTable(TypeOneToManyUUIDRemote.class)); sqlCommand.addAll(DataFactory.createTable(TypeOneToManyUUIDRoot.class)); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -58,13 +62,13 @@ public class TestOneToMany { final TypeOneToManyRoot root = new TypeOneToManyRoot(); root.otherData = "plouf"; - final TypeOneToManyRoot insertedRoot = DataAccess.insert(root); + final TypeOneToManyRoot insertedRoot = ConfigureDb.da.insert(root); Assertions.assertEquals(insertedRoot.otherData, root.otherData); Assertions.assertNull(insertedRoot.remoteIds); final TypeOneToManyRoot root2 = new TypeOneToManyRoot(); root2.otherData = "plouf 2"; - final TypeOneToManyRoot insertedRoot2 = DataAccess.insert(root2); + final TypeOneToManyRoot insertedRoot2 = ConfigureDb.da.insert(root2); Assertions.assertEquals(insertedRoot2.otherData, root2.otherData); Assertions.assertNull(insertedRoot2.remoteIds); @@ -73,34 +77,34 @@ public class TestOneToMany { final TypeOneToManyRemote remote10 = new TypeOneToManyRemote(); remote10.data = "remote10"; remote10.rootId = insertedRoot.id; - final TypeOneToManyRemote insertedRemote10 = DataAccess.insert(remote10); + final TypeOneToManyRemote insertedRemote10 = ConfigureDb.da.insert(remote10); Assertions.assertEquals(insertedRemote10.data, remote10.data); Assertions.assertEquals(insertedRemote10.rootId, remote10.rootId); final TypeOneToManyRemote remote11 = new TypeOneToManyRemote(); remote11.data = "remote11"; remote11.rootId = insertedRoot.id; - final TypeOneToManyRemote insertedRemote11 = DataAccess.insert(remote11); + final TypeOneToManyRemote insertedRemote11 = ConfigureDb.da.insert(remote11); Assertions.assertEquals(insertedRemote11.data, remote11.data); Assertions.assertEquals(insertedRemote11.rootId, remote11.rootId); final TypeOneToManyRemote remote20 = new TypeOneToManyRemote(); remote20.data = "remote20"; remote20.rootId = insertedRoot2.id; - final TypeOneToManyRemote insertedRemote20 = DataAccess.insert(remote20); + final TypeOneToManyRemote insertedRemote20 = ConfigureDb.da.insert(remote20); Assertions.assertEquals(insertedRemote20.data, remote20.data); Assertions.assertEquals(insertedRemote20.rootId, remote20.rootId); // Check remote are inserted - final TypeOneToManyRoot retreiveRoot1 = DataAccess.get(TypeOneToManyRoot.class, insertedRoot.id); + final TypeOneToManyRoot retreiveRoot1 = ConfigureDb.da.get(TypeOneToManyRoot.class, insertedRoot.id); Assertions.assertEquals(retreiveRoot1.otherData, insertedRoot.otherData); Assertions.assertNotNull(retreiveRoot1.remoteIds); Assertions.assertEquals(2, retreiveRoot1.remoteIds.size()); Assertions.assertEquals(insertedRemote10.id, retreiveRoot1.remoteIds.get(0)); Assertions.assertEquals(insertedRemote11.id, retreiveRoot1.remoteIds.get(1)); - final TypeOneToManyRoot retreiveRoot2 = DataAccess.get(TypeOneToManyRoot.class, insertedRoot2.id); + final TypeOneToManyRoot retreiveRoot2 = ConfigureDb.da.get(TypeOneToManyRoot.class, insertedRoot2.id); Assertions.assertEquals(retreiveRoot2.otherData, insertedRoot2.otherData); Assertions.assertNotNull(retreiveRoot2.remoteIds); Assertions.assertEquals(1, retreiveRoot2.remoteIds.size()); @@ -108,7 +112,7 @@ public class TestOneToMany { // Check remote are inserted and expandable - final TypeOneToManyRootExpand retreiveRootExpand1 = DataAccess.get(TypeOneToManyRootExpand.class, + final TypeOneToManyRootExpand retreiveRootExpand1 = ConfigureDb.da.get(TypeOneToManyRootExpand.class, insertedRoot.id); Assertions.assertEquals(retreiveRootExpand1.otherData, insertedRoot.otherData); Assertions.assertNotNull(retreiveRootExpand1.remotes); @@ -120,7 +124,7 @@ public class TestOneToMany { Assertions.assertEquals(insertedRemote11.rootId, retreiveRootExpand1.remotes.get(1).rootId); Assertions.assertEquals(insertedRemote11.data, retreiveRootExpand1.remotes.get(1).data); - final TypeOneToManyRootExpand retreiveRootExpand2 = DataAccess.get(TypeOneToManyRootExpand.class, + final TypeOneToManyRootExpand retreiveRootExpand2 = ConfigureDb.da.get(TypeOneToManyRootExpand.class, insertedRoot2.id); Assertions.assertEquals(retreiveRootExpand2.otherData, insertedRoot2.otherData); Assertions.assertNotNull(retreiveRootExpand2.remotes); @@ -138,13 +142,13 @@ public class TestOneToMany { final TypeOneToManyUUIDRoot root = new TypeOneToManyUUIDRoot(); root.otherData = "plouf"; - final TypeOneToManyUUIDRoot insertedRoot = DataAccess.insert(root); + final TypeOneToManyUUIDRoot insertedRoot = ConfigureDb.da.insert(root); Assertions.assertEquals(insertedRoot.otherData, root.otherData); Assertions.assertNull(insertedRoot.remoteIds); final TypeOneToManyUUIDRoot root2 = new TypeOneToManyUUIDRoot(); root2.otherData = "plouf 2"; - final TypeOneToManyUUIDRoot insertedRoot2 = DataAccess.insert(root2); + final TypeOneToManyUUIDRoot insertedRoot2 = ConfigureDb.da.insert(root2); Assertions.assertEquals(insertedRoot2.otherData, root2.otherData); Assertions.assertNull(insertedRoot2.remoteIds); @@ -153,34 +157,34 @@ public class TestOneToMany { final TypeOneToManyUUIDRemote remote10 = new TypeOneToManyUUIDRemote(); remote10.data = "remote10"; remote10.rootUuid = insertedRoot.uuid; - final TypeOneToManyUUIDRemote insertedRemote10 = DataAccess.insert(remote10); + final TypeOneToManyUUIDRemote insertedRemote10 = ConfigureDb.da.insert(remote10); Assertions.assertEquals(insertedRemote10.data, remote10.data); Assertions.assertEquals(insertedRemote10.rootUuid, remote10.rootUuid); final TypeOneToManyUUIDRemote remote11 = new TypeOneToManyUUIDRemote(); remote11.data = "remote11"; remote11.rootUuid = insertedRoot.uuid; - final TypeOneToManyUUIDRemote insertedRemote11 = DataAccess.insert(remote11); + final TypeOneToManyUUIDRemote insertedRemote11 = ConfigureDb.da.insert(remote11); Assertions.assertEquals(insertedRemote11.data, remote11.data); Assertions.assertEquals(insertedRemote11.rootUuid, remote11.rootUuid); final TypeOneToManyUUIDRemote remote20 = new TypeOneToManyUUIDRemote(); remote20.data = "remote20"; remote20.rootUuid = insertedRoot2.uuid; - final TypeOneToManyUUIDRemote insertedRemote20 = DataAccess.insert(remote20); + final TypeOneToManyUUIDRemote insertedRemote20 = ConfigureDb.da.insert(remote20); Assertions.assertEquals(insertedRemote20.data, remote20.data); Assertions.assertEquals(insertedRemote20.rootUuid, remote20.rootUuid); // Check remote are inserted - final TypeOneToManyUUIDRoot retreiveRoot1 = DataAccess.get(TypeOneToManyUUIDRoot.class, insertedRoot.uuid); + final TypeOneToManyUUIDRoot retreiveRoot1 = ConfigureDb.da.get(TypeOneToManyUUIDRoot.class, insertedRoot.uuid); Assertions.assertEquals(retreiveRoot1.otherData, insertedRoot.otherData); Assertions.assertNotNull(retreiveRoot1.remoteIds); Assertions.assertEquals(2, retreiveRoot1.remoteIds.size()); Assertions.assertEquals(insertedRemote10.uuid, retreiveRoot1.remoteIds.get(0)); Assertions.assertEquals(insertedRemote11.uuid, retreiveRoot1.remoteIds.get(1)); - final TypeOneToManyUUIDRoot retreiveRoot2 = DataAccess.get(TypeOneToManyUUIDRoot.class, insertedRoot2.uuid); + final TypeOneToManyUUIDRoot retreiveRoot2 = ConfigureDb.da.get(TypeOneToManyUUIDRoot.class, insertedRoot2.uuid); Assertions.assertEquals(retreiveRoot2.otherData, insertedRoot2.otherData); Assertions.assertNotNull(retreiveRoot2.remoteIds); Assertions.assertEquals(1, retreiveRoot2.remoteIds.size()); @@ -188,7 +192,7 @@ public class TestOneToMany { // Check remote are inserted and expandable - final TypeOneToManyUUIDRootExpand retreiveRootExpand1 = DataAccess.get(TypeOneToManyUUIDRootExpand.class, + final TypeOneToManyUUIDRootExpand retreiveRootExpand1 = ConfigureDb.da.get(TypeOneToManyUUIDRootExpand.class, insertedRoot.uuid); Assertions.assertEquals(retreiveRootExpand1.otherData, insertedRoot.otherData); Assertions.assertNotNull(retreiveRootExpand1.remotes); @@ -200,7 +204,7 @@ public class TestOneToMany { Assertions.assertEquals(insertedRemote11.rootUuid, retreiveRootExpand1.remotes.get(1).rootUuid); Assertions.assertEquals(insertedRemote11.data, retreiveRootExpand1.remotes.get(1).data); - final TypeOneToManyUUIDRootExpand retreiveRootExpand2 = DataAccess.get(TypeOneToManyUUIDRootExpand.class, + final TypeOneToManyUUIDRootExpand retreiveRootExpand2 = ConfigureDb.da.get(TypeOneToManyUUIDRootExpand.class, insertedRoot2.uuid); Assertions.assertEquals(retreiveRootExpand2.otherData, insertedRoot2.otherData); Assertions.assertNotNull(retreiveRootExpand2.remotes); @@ -210,4 +214,4 @@ public class TestOneToMany { Assertions.assertEquals(insertedRemote20.data, retreiveRootExpand2.remotes.get(0).data); } -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/dataAccess/TestRawQuery.java b/test/src/test/kar/archidata/dataAccess/TestRawQuery.java new file mode 100644 index 0000000..2786d8b --- /dev/null +++ b/test/src/test/kar/archidata/dataAccess/TestRawQuery.java @@ -0,0 +1,116 @@ +package test.kar.archidata.dataAccess; + +import java.io.IOException; +import java.util.List; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.kar.archidata.dataAccess.DBAccessSQL; +import org.kar.archidata.dataAccess.DataFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.TypesTable; + +@ExtendWith(StepwiseExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestRawQuery { + final static private Logger LOGGER = LoggerFactory.getLogger(TestTypes.class); + + @BeforeAll + public static void configureWebServer() throws Exception { + ConfigureDb.configure(); + } + + @AfterAll + public static void removeDataBase() throws IOException { + ConfigureDb.clear(); + } + + @Order(1) + @Test + public void testCreateTable() throws Exception { + final List sqlCommand = DataFactory.createTable(TypesTable.class); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } + } + } + + @Order(2) + @Test + public void testGet() throws Exception { + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + + final TypesTable test = new TypesTable(); + test.intData = 95; + test.floatData = 1.0F; + ConfigureDb.da.insert(test); + test.intData = 96; + test.floatData = 2.0F; + ConfigureDb.da.insert(test); + test.intData = 97; + test.floatData = 3.0F; + ConfigureDb.da.insert(test); + test.intData = 98; + test.floatData = 4.0F; + ConfigureDb.da.insert(test); + test.intData = 99; + test.floatData = 5.0F; + ConfigureDb.da.insert(test); + test.intData = 99; + test.floatData = 6.0F; + ConfigureDb.da.insert(test); + test.intData = 99; + test.floatData = 7.0F; + ConfigureDb.da.insert(test); + { + final String query = """ + SELECT * + FROM TypesTable + WHERE `intData` = ? + ORDER BY id DESC + """; + final List parameters = List.of(Integer.valueOf(99)); + // Try to retrieve all the data: + final List retrieve = daSQL.query(TypesTable.class, query, parameters); + + Assertions.assertNotNull(retrieve); + Assertions.assertEquals(3, retrieve.size()); + Assertions.assertEquals(99, retrieve.get(0).intData); + Assertions.assertEquals(7.0F, retrieve.get(0).floatData); + Assertions.assertEquals(6.0F, retrieve.get(1).floatData); + Assertions.assertEquals(5.0F, retrieve.get(2).floatData); + } + { + + final String query = """ + SELECT id, intData + FROM TypesTable + WHERE `intData` = ? + ORDER BY id DESC + """; + final List parameters = List.of(Integer.valueOf(99)); + // Try to retrieve all the data: + final List retrieve = daSQL.query(TypesTable.class, query, parameters); + + Assertions.assertNotNull(retrieve); + Assertions.assertEquals(3, retrieve.size()); + Assertions.assertEquals(99, retrieve.get(0).intData); + } + } else { + LOGGER.warn("Not a SQL DB ..."); + } + } + +} diff --git a/test/src/test/kar/archidata/TestSimpleTable.java b/test/src/test/kar/archidata/dataAccess/TestSimpleTable.java similarity index 79% rename from test/src/test/kar/archidata/TestSimpleTable.java rename to test/src/test/kar/archidata/dataAccess/TestSimpleTable.java index dce854f..78e4ac1 100644 --- a/test/src/test/kar/archidata/TestSimpleTable.java +++ b/test/src/test/kar/archidata/dataAccess/TestSimpleTable.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.sql.Timestamp; @@ -14,13 +14,15 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.QueryOptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.SimpleTable; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.SimpleTable; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -49,20 +51,22 @@ public class TestSimpleTable { public void testTableInsertAndRetrieve() throws Exception { TestSimpleTable.startAction = Timestamp.from(Instant.now()); final List sqlCommand = DataFactory.createTable(SimpleTable.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } final SimpleTable test = new SimpleTable(); test.data = TestSimpleTable.DATA_INJECTED; - final SimpleTable insertedData = DataAccess.insert(test); + final SimpleTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final SimpleTable retrieve = DataAccess.get(SimpleTable.class, insertedData.id); + final SimpleTable retrieve = ConfigureDb.da.get(SimpleTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -77,7 +81,7 @@ public class TestSimpleTable { @Test public void testReadAllValuesUnreadable() throws Exception { // check the full values - final SimpleTable retrieve = DataAccess.get(SimpleTable.class, TestSimpleTable.idOfTheObject, + final SimpleTable retrieve = ConfigureDb.da.get(SimpleTable.class, TestSimpleTable.idOfTheObject, QueryOptions.READ_ALL_COLOMN); Assertions.assertNotNull(retrieve); @@ -100,8 +104,8 @@ public class TestSimpleTable { // Delete the entry: final SimpleTable test = new SimpleTable(); test.data = TestSimpleTable.DATA_INJECTED_2; - DataAccess.update(test, TestSimpleTable.idOfTheObject, List.of("data")); - final SimpleTable retrieve = DataAccess.get(SimpleTable.class, TestSimpleTable.idOfTheObject, + ConfigureDb.da.update(test, TestSimpleTable.idOfTheObject, List.of("data")); + final SimpleTable retrieve = ConfigureDb.da.get(SimpleTable.class, TestSimpleTable.idOfTheObject, QueryOptions.READ_ALL_COLOMN); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -117,8 +121,8 @@ public class TestSimpleTable { @Test public void testDeleteTheObject() throws Exception { // Delete the entry: - DataAccess.delete(SimpleTable.class, TestSimpleTable.idOfTheObject); - final SimpleTable retrieve = DataAccess.get(SimpleTable.class, TestSimpleTable.idOfTheObject); + ConfigureDb.da.delete(SimpleTable.class, TestSimpleTable.idOfTheObject); + final SimpleTable retrieve = ConfigureDb.da.get(SimpleTable.class, TestSimpleTable.idOfTheObject); Assertions.assertNull(retrieve); } @@ -127,7 +131,7 @@ public class TestSimpleTable { public void testReadDeletedObject() throws Exception { // check if we set get deleted element - final SimpleTable retrieve = DataAccess.get(SimpleTable.class, TestSimpleTable.idOfTheObject, + final SimpleTable retrieve = ConfigureDb.da.get(SimpleTable.class, TestSimpleTable.idOfTheObject, QueryOptions.ACCESS_DELETED_ITEMS); Assertions.assertNull(retrieve); @@ -137,7 +141,7 @@ public class TestSimpleTable { @Test public void testReadAllValuesUnreadableOfDeletedObject() throws Exception { // check if we set get deleted element with all data - final SimpleTable retrieve = DataAccess.get(SimpleTable.class, TestSimpleTable.idOfTheObject, + final SimpleTable retrieve = ConfigureDb.da.get(SimpleTable.class, TestSimpleTable.idOfTheObject, QueryOptions.ACCESS_DELETED_ITEMS, QueryOptions.READ_ALL_COLOMN); Assertions.assertNull(retrieve); diff --git a/test/src/test/kar/archidata/TestSimpleTableSoftDelete.java b/test/src/test/kar/archidata/dataAccess/TestSimpleTableSoftDelete.java similarity index 84% rename from test/src/test/kar/archidata/TestSimpleTableSoftDelete.java rename to test/src/test/kar/archidata/dataAccess/TestSimpleTableSoftDelete.java index 3faccf2..01cf612 100644 --- a/test/src/test/kar/archidata/TestSimpleTableSoftDelete.java +++ b/test/src/test/kar/archidata/dataAccess/TestSimpleTableSoftDelete.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.sql.Timestamp; @@ -14,14 +14,16 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.tools.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.SimpleTableSoftDelete; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.SimpleTableSoftDelete; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -51,20 +53,22 @@ public class TestSimpleTableSoftDelete { public void testTableInsertAndRetrieve() throws Exception { TestSimpleTableSoftDelete.startAction = Timestamp.from(Instant.now()); final List sqlCommand = DataFactory.createTable(SimpleTableSoftDelete.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } final SimpleTableSoftDelete test = new SimpleTableSoftDelete(); test.data = TestSimpleTableSoftDelete.DATA_INJECTED; - final SimpleTableSoftDelete insertedData = DataAccess.insert(test); + final SimpleTableSoftDelete insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final SimpleTableSoftDelete retrieve = DataAccess.get(SimpleTableSoftDelete.class, insertedData.id); + final SimpleTableSoftDelete retrieve = ConfigureDb.da.get(SimpleTableSoftDelete.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -80,9 +84,8 @@ public class TestSimpleTableSoftDelete { @Test public void testReadAllValuesUnreadable() throws Exception { // check the full values - final SimpleTableSoftDelete retrieve = DataAccess.get(SimpleTableSoftDelete.class, + final SimpleTableSoftDelete retrieve = ConfigureDb.da.get(SimpleTableSoftDelete.class, TestSimpleTableSoftDelete.idOfTheObject, QueryOptions.READ_ALL_COLOMN); - Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(TestSimpleTableSoftDelete.idOfTheObject, retrieve.id); @@ -107,8 +110,8 @@ public class TestSimpleTableSoftDelete { // Delete the entry: final SimpleTableSoftDelete test = new SimpleTableSoftDelete(); test.data = TestSimpleTableSoftDelete.DATA_INJECTED_2; - DataAccess.update(test, TestSimpleTableSoftDelete.idOfTheObject, List.of("data")); - final SimpleTableSoftDelete retrieve = DataAccess.get(SimpleTableSoftDelete.class, + ConfigureDb.da.update(test, TestSimpleTableSoftDelete.idOfTheObject, List.of("data")); + final SimpleTableSoftDelete retrieve = ConfigureDb.da.get(SimpleTableSoftDelete.class, TestSimpleTableSoftDelete.idOfTheObject, QueryOptions.ACCESS_DELETED_ITEMS, QueryOptions.READ_ALL_COLOMN); Assertions.assertNotNull(retrieve); @@ -132,8 +135,8 @@ public class TestSimpleTableSoftDelete { Thread.sleep(Duration.ofMillis(15)); } // Delete the entry: - DataAccess.delete(SimpleTableSoftDelete.class, TestSimpleTableSoftDelete.idOfTheObject); - final SimpleTableSoftDelete retrieve = DataAccess.get(SimpleTableSoftDelete.class, + ConfigureDb.da.delete(SimpleTableSoftDelete.class, TestSimpleTableSoftDelete.idOfTheObject); + final SimpleTableSoftDelete retrieve = ConfigureDb.da.get(SimpleTableSoftDelete.class, TestSimpleTableSoftDelete.idOfTheObject); Assertions.assertNull(retrieve); } @@ -143,7 +146,7 @@ public class TestSimpleTableSoftDelete { public void testReadDeletedObject() throws Exception { // check if we set get deleted element - final SimpleTableSoftDelete retrieve = DataAccess.get(SimpleTableSoftDelete.class, + final SimpleTableSoftDelete retrieve = ConfigureDb.da.get(SimpleTableSoftDelete.class, TestSimpleTableSoftDelete.idOfTheObject, QueryOptions.ACCESS_DELETED_ITEMS); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -159,7 +162,7 @@ public class TestSimpleTableSoftDelete { @Test public void testReadAllValuesUnreadableOfDeletedObject() throws Exception { // check if we set get deleted element with all data - final SimpleTableSoftDelete retrieve = DataAccess.get(SimpleTableSoftDelete.class, + final SimpleTableSoftDelete retrieve = ConfigureDb.da.get(SimpleTableSoftDelete.class, TestSimpleTableSoftDelete.idOfTheObject, QueryOptions.ACCESS_DELETED_ITEMS, QueryOptions.READ_ALL_COLOMN); Assertions.assertNotNull(retrieve); diff --git a/test/src/test/kar/archidata/TestTypeEnum1.java b/test/src/test/kar/archidata/dataAccess/TestTypeEnum1.java similarity index 70% rename from test/src/test/kar/archidata/TestTypeEnum1.java rename to test/src/test/kar/archidata/dataAccess/TestTypeEnum1.java index 5e10264..3a1bf74 100644 --- a/test/src/test/kar/archidata/TestTypeEnum1.java +++ b/test/src/test/kar/archidata/dataAccess/TestTypeEnum1.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.util.List; @@ -11,13 +11,15 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.Enum1ForTest; -import test.kar.archidata.model.TypesEnum1; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.Enum1ForTest; +import test.kar.archidata.dataAccess.model.TypesEnum1; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -38,9 +40,11 @@ public class TestTypeEnum1 { @Test public void testCreateTable() throws Exception { final List sqlCommand = DataFactory.createTable(TypesEnum1.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -50,13 +54,13 @@ public class TestTypeEnum1 { final TypesEnum1 test = new TypesEnum1(); test.data = Enum1ForTest.ENUM_VALUE_3; - final TypesEnum1 insertedData = DataAccess.insert(test); + final TypesEnum1 insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesEnum1 retrieve = DataAccess.get(TypesEnum1.class, insertedData.id); + final TypesEnum1 retrieve = ConfigureDb.da.get(TypesEnum1.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -64,6 +68,6 @@ public class TestTypeEnum1 { Assertions.assertNotNull(retrieve.data); Assertions.assertEquals(insertedData.data, retrieve.data); - DataAccess.delete(TypesEnum1.class, insertedData.id); + ConfigureDb.da.delete(TypesEnum1.class, insertedData.id); } -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/TestTypeEnum2.java b/test/src/test/kar/archidata/dataAccess/TestTypeEnum2.java similarity index 67% rename from test/src/test/kar/archidata/TestTypeEnum2.java rename to test/src/test/kar/archidata/dataAccess/TestTypeEnum2.java index dc78878..f25e5d1 100644 --- a/test/src/test/kar/archidata/TestTypeEnum2.java +++ b/test/src/test/kar/archidata/dataAccess/TestTypeEnum2.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.util.List; @@ -11,13 +11,15 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.Enum2ForTest; -import test.kar.archidata.model.TypesEnum2; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.Enum2ForTest; +import test.kar.archidata.dataAccess.model.TypesEnum2; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -38,9 +40,11 @@ public class TestTypeEnum2 { @Test public void testCreateTable() throws Exception { final List sqlCommand = DataFactory.createTable(TypesEnum2.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -50,13 +54,13 @@ public class TestTypeEnum2 { final TypesEnum2 test = new TypesEnum2(); test.data = Enum2ForTest.ENUM_VALUE_4; - final TypesEnum2 insertedData = DataAccess.insert(test); + final TypesEnum2 insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - TypesEnum2 retrieve = DataAccess.get(TypesEnum2.class, insertedData.id); + TypesEnum2 retrieve = ConfigureDb.da.get(TypesEnum2.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); @@ -65,22 +69,22 @@ public class TestTypeEnum2 { // Update data to null retrieve.data = null; - int ret = DataAccess.update(retrieve, retrieve.id); - Assertions.assertEquals(1, ret); + long ret = ConfigureDb.da.update(retrieve, retrieve.id); + Assertions.assertEquals(1L, ret); // get new data - retrieve = DataAccess.get(TypesEnum2.class, insertedData.id); + retrieve = ConfigureDb.da.get(TypesEnum2.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertNull(retrieve.data); // Remove the data - ret = DataAccess.delete(TypesEnum2.class, insertedData.id); - Assertions.assertEquals(1, ret); + ret = ConfigureDb.da.delete(TypesEnum2.class, insertedData.id); + Assertions.assertEquals(1L, ret); // Get the removed data: - retrieve = DataAccess.get(TypesEnum2.class, insertedData.id); + retrieve = ConfigureDb.da.get(TypesEnum2.class, insertedData.id); Assertions.assertNull(retrieve); } @@ -90,19 +94,19 @@ public class TestTypeEnum2 { final TypesEnum2 test = new TypesEnum2(); test.data = null; - final TypesEnum2 insertedData = DataAccess.insert(test); + final TypesEnum2 insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesEnum2 retrieve = DataAccess.get(TypesEnum2.class, insertedData.id); + final TypesEnum2 retrieve = ConfigureDb.da.get(TypesEnum2.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertNull(retrieve.data); - DataAccess.delete(TypesEnum2.class, insertedData.id); + ConfigureDb.da.delete(TypesEnum2.class, insertedData.id); } -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/TestTypes.java b/test/src/test/kar/archidata/dataAccess/TestTypes.java similarity index 75% rename from test/src/test/kar/archidata/TestTypes.java rename to test/src/test/kar/archidata/dataAccess/TestTypes.java index b3f5405..e2732eb 100644 --- a/test/src/test/kar/archidata/TestTypes.java +++ b/test/src/test/kar/archidata/dataAccess/TestTypes.java @@ -1,4 +1,4 @@ -package test.kar.archidata; +package test.kar.archidata.dataAccess; import java.io.IOException; import java.sql.Timestamp; @@ -16,12 +16,14 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DBAccessSQL; import org.kar.archidata.dataAccess.DataFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import test.kar.archidata.model.TypesTable; +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.dataAccess.model.TypesTable; @ExtendWith(StepwiseExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -42,9 +44,11 @@ public class TestTypes { @Test public void testCreateTable() throws Exception { final List sqlCommand = DataFactory.createTable(TypesTable.class); - for (final String elem : sqlCommand) { - LOGGER.debug("request: '{}'", elem); - DataAccess.executeSimpleQuery(elem); + if (ConfigureDb.da instanceof final DBAccessSQL daSQL) { + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + daSQL.executeSimpleQuery(elem); + } } } @@ -54,13 +58,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.intData = 95; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -68,7 +72,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.intData); Assertions.assertEquals(insertedData.intData, retrieve.intData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(3) @@ -77,13 +81,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.longData = 541684354354L; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -91,7 +95,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.longData); Assertions.assertEquals(insertedData.longData, retrieve.longData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(4) @@ -100,13 +104,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.floatData = 153154.0f; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -114,7 +118,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.floatData); Assertions.assertEquals(insertedData.floatData, retrieve.floatData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(5) @@ -123,13 +127,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.doubleData = 153152654654.0; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -137,7 +141,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.doubleData); Assertions.assertEquals(insertedData.doubleData, retrieve.doubleData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(6) @@ -146,13 +150,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.textData = "lkjlkjlkjmlkqjsdùkljqsùmckljvùwxmckvmwlkdnfqmsjdvnmclkwsjdn;vbcm = 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -160,7 +164,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.textData); Assertions.assertEquals(insertedData.textData, retrieve.textData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(7) @@ -169,13 +173,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.varcharData = "123456789123456789"; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -183,7 +187,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.varcharData); Assertions.assertEquals(insertedData.varcharData, retrieve.varcharData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(8) @@ -192,13 +196,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.booleanData = true; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -206,7 +210,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.booleanData); Assertions.assertEquals(insertedData.booleanData, retrieve.booleanData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(9) @@ -215,13 +219,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.booleanData = false; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -229,7 +233,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.booleanData); Assertions.assertEquals(insertedData.booleanData, retrieve.booleanData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(10) @@ -239,13 +243,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.timeStampData = Timestamp.from(Instant.now()); LOGGER.debug("Timestamp = {}", test.timeStampData); - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -257,7 +261,7 @@ public class TestTypes { Assertions.assertEquals(insertedData.timeStampData.toInstant().toEpochMilli(), retrieve.timeStampData.toInstant().toEpochMilli()); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(11) @@ -267,13 +271,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.dateFullData = Date.from(Instant.now()); LOGGER.debug("Date = {}", test.dateFullData); - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -282,7 +286,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.dateFullData); Assertions.assertEquals(insertedData.dateFullData, retrieve.dateFullData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(12) @@ -292,13 +296,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.dateData = LocalDate.now(); LOGGER.debug("LocalDate = {}", test.dateData); - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -307,7 +311,7 @@ public class TestTypes { Assertions.assertNotNull(retrieve.dateData); Assertions.assertEquals(insertedData.dateData, retrieve.dateData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(13) @@ -317,13 +321,13 @@ public class TestTypes { final TypesTable test = new TypesTable(); test.timeData = LocalTime.now(); LOGGER.debug("LocalTime = {}", test.timeData); - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -334,7 +338,7 @@ public class TestTypes { Assertions.assertEquals(insertedData.timeData.getMinute(), retrieve.timeData.getMinute()); Assertions.assertEquals(insertedData.timeData.getSecond(), retrieve.timeData.getSecond()); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(14) @@ -345,13 +349,13 @@ public class TestTypes { test.textData = "test 1"; test.booleanData = null; test.varcharData = "plop"; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -366,11 +370,11 @@ public class TestTypes { retrieve.textData = "test 2"; retrieve.booleanData = true; retrieve.varcharData = null; - final int nbUpdate = DataAccess.update(retrieve, insertedData.id); - Assertions.assertEquals(1, nbUpdate); + final long nbUpdate = ConfigureDb.da.update(retrieve, insertedData.id); + Assertions.assertEquals(1L, nbUpdate); // Get new data - final TypesTable retrieve2 = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve2 = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2.id); @@ -385,11 +389,11 @@ public class TestTypes { retrieve.textData = "test 3"; retrieve.booleanData = false; retrieve.varcharData = "test3"; - final int nbUpdate2 = DataAccess.update(retrieve, insertedData.id, List.of("textData")); - Assertions.assertEquals(1, nbUpdate2); + final long nbUpdate2 = ConfigureDb.da.update(retrieve, insertedData.id, List.of("textData")); + Assertions.assertEquals(1L, nbUpdate2); // Get new data - final TypesTable retrieve3 = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve3 = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve3); Assertions.assertNotNull(retrieve3.id); @@ -401,7 +405,7 @@ public class TestTypes { Assertions.assertEquals(retrieve2.booleanData, retrieve3.booleanData); Assertions.assertNull(retrieve3.varcharData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } @Order(15) @@ -412,13 +416,13 @@ public class TestTypes { test.textData = "test 1"; test.booleanData = null; test.varcharData = "plop"; - final TypesTable insertedData = DataAccess.insert(test); + final TypesTable insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); // Try to retrieve all the data: - final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); @@ -437,11 +441,11 @@ public class TestTypes { "varcharData": null } """; - final int nbUpdate = DataAccess.updateWithJson(TypesTable.class, insertedData.id, jsonData); - Assertions.assertEquals(1, nbUpdate); + final long nbUpdate = ConfigureDb.da.updateWithJson(TypesTable.class, insertedData.id, jsonData); + Assertions.assertEquals(1L, nbUpdate); // Get new data - final TypesTable retrieve2 = DataAccess.get(TypesTable.class, insertedData.id); + final TypesTable retrieve2 = ConfigureDb.da.get(TypesTable.class, insertedData.id); Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2.id); @@ -452,7 +456,7 @@ public class TestTypes { Assertions.assertEquals(true, retrieve2.booleanData); Assertions.assertNull(retrieve2.varcharData); - DataAccess.delete(TypesTable.class, insertedData.id); + ConfigureDb.da.delete(TypesTable.class, insertedData.id); } } diff --git a/test/src/test/kar/archidata/model/Enum1ForTest.java b/test/src/test/kar/archidata/dataAccess/model/Enum1ForTest.java similarity index 69% rename from test/src/test/kar/archidata/model/Enum1ForTest.java rename to test/src/test/kar/archidata/dataAccess/model/Enum1ForTest.java index 074dc44..b8afb73 100644 --- a/test/src/test/kar/archidata/model/Enum1ForTest.java +++ b/test/src/test/kar/archidata/dataAccess/model/Enum1ForTest.java @@ -1,4 +1,4 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; public enum Enum1ForTest { ENUM_VALUE_1, ENUM_VALUE_2, ENUM_VALUE_3, ENUM_VALUE_4, ENUM_VALUE_5, diff --git a/test/src/test/kar/archidata/model/Enum2ForTest.java b/test/src/test/kar/archidata/dataAccess/model/Enum2ForTest.java similarity index 82% rename from test/src/test/kar/archidata/model/Enum2ForTest.java rename to test/src/test/kar/archidata/dataAccess/model/Enum2ForTest.java index aa51a95..ea1eac7 100644 --- a/test/src/test/kar/archidata/model/Enum2ForTest.java +++ b/test/src/test/kar/archidata/dataAccess/model/Enum2ForTest.java @@ -1,4 +1,4 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; public enum Enum2ForTest { ENUM_VALUE_1(5), ENUM_VALUE_2(6), ENUM_VALUE_3(55), ENUM_VALUE_4(84241), ENUM_VALUE_5(54546); diff --git a/test/src/test/kar/archidata/model/SerializeAsJson.java b/test/src/test/kar/archidata/dataAccess/model/SerializeAsJson.java similarity index 66% rename from test/src/test/kar/archidata/model/SerializeAsJson.java rename to test/src/test/kar/archidata/dataAccess/model/SerializeAsJson.java index ba5f8e9..589c565 100644 --- a/test/src/test/kar/archidata/model/SerializeAsJson.java +++ b/test/src/test/kar/archidata/dataAccess/model/SerializeAsJson.java @@ -1,8 +1,11 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import org.kar.archidata.annotation.DataJson; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; + +@Entity public class SerializeAsJson extends GenericData { @DataJson diff --git a/test/src/test/kar/archidata/model/SerializeListAsJson.java b/test/src/test/kar/archidata/dataAccess/model/SerializeListAsJson.java similarity index 69% rename from test/src/test/kar/archidata/model/SerializeListAsJson.java rename to test/src/test/kar/archidata/dataAccess/model/SerializeListAsJson.java index 7fbda65..5b4a7b9 100644 --- a/test/src/test/kar/archidata/model/SerializeListAsJson.java +++ b/test/src/test/kar/archidata/dataAccess/model/SerializeListAsJson.java @@ -1,10 +1,13 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; import org.kar.archidata.annotation.DataJson; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; + +@Entity public class SerializeListAsJson extends GenericData { @DataJson diff --git a/test/src/test/kar/archidata/dataAccess/model/SimpleTable.java b/test/src/test/kar/archidata/dataAccess/model/SimpleTable.java new file mode 100644 index 0000000..4ffcbcf --- /dev/null +++ b/test/src/test/kar/archidata/dataAccess/model/SimpleTable.java @@ -0,0 +1,13 @@ +package test.kar.archidata.dataAccess.model; + +import org.kar.archidata.model.GenericData; + +import dev.morphia.annotations.Entity; +import jakarta.persistence.Column; + +@Entity +public class SimpleTable extends GenericData { + @Column(length = 0) + public String data; + +} \ No newline at end of file diff --git a/test/src/test/kar/archidata/dataAccess/model/SimpleTableSoftDelete.java b/test/src/test/kar/archidata/dataAccess/model/SimpleTableSoftDelete.java new file mode 100644 index 0000000..e71d1fd --- /dev/null +++ b/test/src/test/kar/archidata/dataAccess/model/SimpleTableSoftDelete.java @@ -0,0 +1,12 @@ +package test.kar.archidata.dataAccess.model; + +import org.kar.archidata.model.GenericDataSoftDelete; + +import dev.morphia.annotations.Entity; +import jakarta.persistence.Column; + +@Entity +public class SimpleTableSoftDelete extends GenericDataSoftDelete { + @Column(length = 0) + public String data; +} \ No newline at end of file diff --git a/test/src/test/kar/archidata/model/TypeManyToManyRemote.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRemote.java similarity index 79% rename from test/src/test/kar/archidata/model/TypeManyToManyRemote.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRemote.java index 8e4f14e..9c26f9b 100644 --- a/test/src/test/kar/archidata/model/TypeManyToManyRemote.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRemote.java @@ -1,12 +1,14 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.ManyToMany; +@Entity public class TypeManyToManyRemote extends GenericData { @ManyToMany(fetch = FetchType.LAZY, targetEntity = TypeManyToManyRoot.class, mappedBy = "remote") public List remoteToParent; diff --git a/test/src/test/kar/archidata/model/TypeManyToManyRoot.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRoot.java similarity index 78% rename from test/src/test/kar/archidata/model/TypeManyToManyRoot.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRoot.java index 9338b97..8568bb2 100644 --- a/test/src/test/kar/archidata/model/TypeManyToManyRoot.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRoot.java @@ -1,12 +1,14 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.ManyToMany; +@Entity public class TypeManyToManyRoot extends GenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeManyToManyRootExpand.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRootExpand.java similarity index 76% rename from test/src/test/kar/archidata/model/TypeManyToManyRootExpand.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRootExpand.java index ee85481..b72116e 100644 --- a/test/src/test/kar/archidata/model/TypeManyToManyRootExpand.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToManyRootExpand.java @@ -1,14 +1,17 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.ManyToMany; import jakarta.persistence.Table; @Table(name = "TypeManyToManyRoot") +// for Mongo +@Entity(value = "TypeManyToManyRoot") public class TypeManyToManyRootExpand extends GenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeManyToOneRemote.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRemote.java similarity index 72% rename from test/src/test/kar/archidata/model/TypeManyToOneRemote.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRemote.java index 3e3036c..238c356 100644 --- a/test/src/test/kar/archidata/model/TypeManyToOneRemote.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRemote.java @@ -1,7 +1,10 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; + +@Entity public class TypeManyToOneRemote extends GenericData { public String data; diff --git a/test/src/test/kar/archidata/model/TypeManyToOneRoot.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRoot.java similarity index 83% rename from test/src/test/kar/archidata/model/TypeManyToOneRoot.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRoot.java index 92a5444..67a9e77 100644 --- a/test/src/test/kar/archidata/model/TypeManyToOneRoot.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRoot.java @@ -1,10 +1,12 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.ManyToOne; +@Entity public class TypeManyToOneRoot extends GenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeManyToOneRootExpand.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRootExpand.java similarity index 82% rename from test/src/test/kar/archidata/model/TypeManyToOneRootExpand.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRootExpand.java index 746fea1..0129caf 100644 --- a/test/src/test/kar/archidata/model/TypeManyToOneRootExpand.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneRootExpand.java @@ -1,13 +1,16 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.FetchType; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; @Table(name = "TypeManyToOneRoot") +//for Mongo +@Entity(value = "TypeManyToOneRoot") public class TypeManyToOneRootExpand extends GenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeManyToOneUUIDRemote.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRemote.java similarity index 59% rename from test/src/test/kar/archidata/model/TypeManyToOneUUIDRemote.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRemote.java index 9332827..c8ae524 100644 --- a/test/src/test/kar/archidata/model/TypeManyToOneUUIDRemote.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRemote.java @@ -1,7 +1,10 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import org.kar.archidata.model.UUIDGenericData; +import dev.morphia.annotations.Entity; + +@Entity public class TypeManyToOneUUIDRemote extends UUIDGenericData { public String data; diff --git a/test/src/test/kar/archidata/model/TypeManyToOneUUIDRoot.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRoot.java similarity index 79% rename from test/src/test/kar/archidata/model/TypeManyToOneUUIDRoot.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRoot.java index 1064d2d..960c33c 100644 --- a/test/src/test/kar/archidata/model/TypeManyToOneUUIDRoot.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRoot.java @@ -1,12 +1,14 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.UUID; import org.kar.archidata.model.UUIDGenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.ManyToOne; +@Entity public class TypeManyToOneUUIDRoot extends UUIDGenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeManyToOneUUIDRootExpand.java b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRootExpand.java similarity index 78% rename from test/src/test/kar/archidata/model/TypeManyToOneUUIDRootExpand.java rename to test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRootExpand.java index 56a0057..c0bf77d 100644 --- a/test/src/test/kar/archidata/model/TypeManyToOneUUIDRootExpand.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeManyToOneUUIDRootExpand.java @@ -1,13 +1,16 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import org.kar.archidata.model.UUIDGenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.FetchType; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; @Table(name = "TypeManyToOneUUIDRoot") +//for Mongo +@Entity(value = "TypeManyToOneUUIDRoot") public class TypeManyToOneUUIDRootExpand extends UUIDGenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeOneToManyRemote.java b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRemote.java similarity index 76% rename from test/src/test/kar/archidata/model/TypeOneToManyRemote.java rename to test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRemote.java index 01dd6c3..461fd76 100644 --- a/test/src/test/kar/archidata/model/TypeOneToManyRemote.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRemote.java @@ -1,10 +1,12 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.ManyToOne; +@Entity public class TypeOneToManyRemote extends GenericData { @ManyToOne(fetch = FetchType.LAZY, targetEntity = TypeOneToManyRoot.class) diff --git a/test/src/test/kar/archidata/model/TypeOneToManyRoot.java b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRoot.java similarity index 76% rename from test/src/test/kar/archidata/model/TypeOneToManyRoot.java rename to test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRoot.java index 697c990..f10dbfd 100644 --- a/test/src/test/kar/archidata/model/TypeOneToManyRoot.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRoot.java @@ -1,11 +1,13 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; import org.kar.archidata.model.GenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.OneToMany; +@Entity public class TypeOneToManyRoot extends GenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeOneToManyRootExpand.java b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRootExpand.java similarity index 82% rename from test/src/test/kar/archidata/model/TypeOneToManyRootExpand.java rename to test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRootExpand.java index 875d9f0..b32d114 100644 --- a/test/src/test/kar/archidata/model/TypeOneToManyRootExpand.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyRootExpand.java @@ -1,7 +1,8 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -10,6 +11,8 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.Table; @Table(name = "TypeOneToManyRoot") +//for Mongo +@Entity(value = "TypeOneToManyRoot") public class TypeOneToManyRootExpand { @Id diff --git a/test/src/test/kar/archidata/model/TypeOneToManyUUIDRemote.java b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRemote.java similarity index 78% rename from test/src/test/kar/archidata/model/TypeOneToManyUUIDRemote.java rename to test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRemote.java index 012b480..c1b009a 100644 --- a/test/src/test/kar/archidata/model/TypeOneToManyUUIDRemote.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRemote.java @@ -1,12 +1,14 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.UUID; import org.kar.archidata.model.UUIDGenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.ManyToOne; +@Entity public class TypeOneToManyUUIDRemote extends UUIDGenericData { @ManyToOne(fetch = FetchType.LAZY, targetEntity = TypeOneToManyUUIDRoot.class) diff --git a/test/src/test/kar/archidata/model/TypeOneToManyUUIDRoot.java b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRoot.java similarity index 81% rename from test/src/test/kar/archidata/model/TypeOneToManyUUIDRoot.java rename to test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRoot.java index 576dc78..5313a5b 100644 --- a/test/src/test/kar/archidata/model/TypeOneToManyUUIDRoot.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRoot.java @@ -1,13 +1,15 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; import java.util.UUID; import org.kar.archidata.model.UUIDGenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.OneToMany; +@Entity public class TypeOneToManyUUIDRoot extends UUIDGenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypeOneToManyUUIDRootExpand.java b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRootExpand.java similarity index 77% rename from test/src/test/kar/archidata/model/TypeOneToManyUUIDRootExpand.java rename to test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRootExpand.java index 01804f2..7ce137d 100644 --- a/test/src/test/kar/archidata/model/TypeOneToManyUUIDRootExpand.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypeOneToManyUUIDRootExpand.java @@ -1,14 +1,17 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.util.List; import org.kar.archidata.model.UUIDGenericData; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; @Table(name = "TypeOneToManyUUIDRoot") +//for Mongo +@Entity(value = "TypeOneToManyUUIDRoot") public class TypeOneToManyUUIDRootExpand extends UUIDGenericData { public String otherData; diff --git a/test/src/test/kar/archidata/model/TypesEnum1.java b/test/src/test/kar/archidata/dataAccess/model/TypesEnum1.java similarity index 78% rename from test/src/test/kar/archidata/model/TypesEnum1.java rename to test/src/test/kar/archidata/dataAccess/model/TypesEnum1.java index 50770cd..70e061a 100644 --- a/test/src/test/kar/archidata/model/TypesEnum1.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypesEnum1.java @@ -1,10 +1,12 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +@Entity public class TypesEnum1 { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/test/src/test/kar/archidata/model/TypesEnum2.java b/test/src/test/kar/archidata/dataAccess/model/TypesEnum2.java similarity index 78% rename from test/src/test/kar/archidata/model/TypesEnum2.java rename to test/src/test/kar/archidata/dataAccess/model/TypesEnum2.java index 489fed3..810cea4 100644 --- a/test/src/test/kar/archidata/model/TypesEnum2.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypesEnum2.java @@ -1,10 +1,12 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +@Entity public class TypesEnum2 { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/test/src/test/kar/archidata/model/TypesTable.java b/test/src/test/kar/archidata/dataAccess/model/TypesTable.java similarity index 90% rename from test/src/test/kar/archidata/model/TypesTable.java rename to test/src/test/kar/archidata/dataAccess/model/TypesTable.java index 9dfbc41..1c5d076 100644 --- a/test/src/test/kar/archidata/model/TypesTable.java +++ b/test/src/test/kar/archidata/dataAccess/model/TypesTable.java @@ -1,15 +1,17 @@ -package test.kar.archidata.model; +package test.kar.archidata.dataAccess.model; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalTime; import java.util.Date; +import dev.morphia.annotations.Entity; import jakarta.persistence.Column; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +@Entity public class TypesTable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/test/src/test/kar/archidata/migration/MigrationFail.java b/test/src/test/kar/archidata/migration/MigrationFail.java index b231b14..5beaab2 100644 --- a/test/src/test/kar/archidata/migration/MigrationFail.java +++ b/test/src/test/kar/archidata/migration/MigrationFail.java @@ -1,5 +1,8 @@ package test.kar.archidata.migration; +import java.io.IOException; + +import org.kar.archidata.dataAccess.DBAccess; import org.kar.archidata.migration.MigrationSqlStep; class MigrationFail extends MigrationSqlStep { @@ -16,10 +19,9 @@ class MigrationFail extends MigrationSqlStep { @Override public void generateStep() throws Exception { - addAction(""" - ALTER TABLE `TestTableMigrationqs` - RENAME COLUMN `testDataMisqdgration1` TO `testDataMiqsdgration2` - """); + addAction((final DBAccess da) -> { + throw new IOException("FAIL migration"); + }); display(); } diff --git a/test/src/test/kar/archidata/migration/TestMigrationFail.java b/test/src/test/kar/archidata/migration/TestMigrationFail.java index e5ef927..29445b4 100644 --- a/test/src/test/kar/archidata/migration/TestMigrationFail.java +++ b/test/src/test/kar/archidata/migration/TestMigrationFail.java @@ -10,15 +10,13 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.GlobalConfiguration; -import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.db.DBEntry; +import org.kar.archidata.db.DbConfig; import org.kar.archidata.migration.MigrationEngine; import org.kar.archidata.migration.MigrationException; -import org.kar.archidata.tools.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import test.kar.archidata.ConfigureDb; import test.kar.archidata.StepwiseExtension; import test.kar.archidata.migration.model.TypesMigrationInitialisationFirst; @@ -29,22 +27,12 @@ public class TestMigrationFail { @BeforeAll public static void configureWebServer() throws Exception { - if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) { - ConfigBaseVariable.dbType = "sqlite"; - ConfigBaseVariable.dbHost = "memory"; - // for test we need to connect all time the DB - ConfigBaseVariable.dbKeepConnected = "true"; - } - // Connect the dataBase... - final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - entry.connect(); + ConfigureDb.configure(); } @AfterAll public static void removeDataBase() throws IOException { - LOGGER.info("Remove the test db"); - DBEntry.closeAllForceMode(); - ConfigBaseVariable.clearAllValue(); + ConfigureDb.clear(); } @Order(1) @@ -53,11 +41,11 @@ public class TestMigrationFail { final MigrationEngine migrationEngine = new MigrationEngine(); // add initialization: migrationEngine.setInit(new InitializationFirst()); - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + migrationEngine.migrateErrorThrow(new DbConfig()); final TypesMigrationInitialisationFirst test = new TypesMigrationInitialisationFirst(); test.testData = 95.0; - final TypesMigrationInitialisationFirst insertedData = DataAccess.insert(test); + final TypesMigrationInitialisationFirst insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertEquals(95.0, insertedData.testData); } @@ -71,8 +59,8 @@ public class TestMigrationFail { migrationEngine.add(new Migration1()); migrationEngine.add(new MigrationFail()); Assertions.assertThrows(MigrationException.class, () -> { - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + migrationEngine.migrateErrorThrow(new DbConfig()); }); } -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/migration/TestMigrationFirstInit.java b/test/src/test/kar/archidata/migration/TestMigrationFirstInit.java index 299a6db..07ab201 100644 --- a/test/src/test/kar/archidata/migration/TestMigrationFirstInit.java +++ b/test/src/test/kar/archidata/migration/TestMigrationFirstInit.java @@ -10,14 +10,12 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.GlobalConfiguration; -import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.db.DBEntry; +import org.kar.archidata.db.DbConfig; import org.kar.archidata.migration.MigrationEngine; -import org.kar.archidata.tools.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import test.kar.archidata.ConfigureDb; import test.kar.archidata.StepwiseExtension; import test.kar.archidata.migration.model.TypesMigrationInitialisationCurrent; import test.kar.archidata.migration.model.TypesMigrationInitialisationFirst; @@ -29,22 +27,12 @@ public class TestMigrationFirstInit { @BeforeAll public static void configureWebServer() throws Exception { - if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) { - ConfigBaseVariable.dbType = "sqlite"; - ConfigBaseVariable.dbHost = "memory"; - // for test we need to connect all time the DB - ConfigBaseVariable.dbKeepConnected = "true"; - } - // Connect the dataBase... - final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - entry.connect(); + ConfigureDb.configure(); } @AfterAll public static void removeDataBase() throws IOException { - LOGGER.info("Remove the test db"); - DBEntry.closeAllForceMode(); - ConfigBaseVariable.clearAllValue(); + ConfigureDb.clear(); } @Order(1) @@ -53,11 +41,11 @@ public class TestMigrationFirstInit { final MigrationEngine migrationEngine = new MigrationEngine(); // add initialization: migrationEngine.setInit(new InitializationFirst()); - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + migrationEngine.migrateErrorThrow(new DbConfig()); final TypesMigrationInitialisationFirst test = new TypesMigrationInitialisationFirst(); test.testData = 95.0; - final TypesMigrationInitialisationFirst insertedData = DataAccess.insert(test); + final TypesMigrationInitialisationFirst insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertEquals(95.0, insertedData.testData); } @@ -68,11 +56,11 @@ public class TestMigrationFirstInit { final MigrationEngine migrationEngine = new MigrationEngine(); // add initialization: migrationEngine.setInit(new InitializationFirst()); - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + migrationEngine.migrateErrorThrow(new DbConfig()); final TypesMigrationInitialisationFirst test = new TypesMigrationInitialisationFirst(); test.testData = 99.0; - final TypesMigrationInitialisationFirst insertedData = DataAccess.insert(test); + final TypesMigrationInitialisationFirst insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertEquals(99.0, insertedData.testData); } @@ -85,11 +73,11 @@ public class TestMigrationFirstInit { migrationEngine.setInit(new InitializationCurrent()); migrationEngine.add(new Migration1()); migrationEngine.add(new Migration2()); - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + migrationEngine.migrateErrorThrow(new DbConfig()); final TypesMigrationInitialisationCurrent test = new TypesMigrationInitialisationCurrent(); test.testDataMigration2 = 125.0; - final TypesMigrationInitialisationCurrent insertedData = DataAccess.insert(test); + final TypesMigrationInitialisationCurrent insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertEquals(125.0, insertedData.testDataMigration2); } @@ -102,12 +90,12 @@ public class TestMigrationFirstInit { migrationEngine.setInit(new InitializationCurrent()); migrationEngine.add(new Migration1()); migrationEngine.add(new Migration2()); - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + migrationEngine.migrateErrorThrow(new DbConfig()); final TypesMigrationInitialisationCurrent test = new TypesMigrationInitialisationCurrent(); test.testDataMigration2 = 2563.0; - final TypesMigrationInitialisationCurrent insertedData = DataAccess.insert(test); + final TypesMigrationInitialisationCurrent insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertEquals(2563.0, insertedData.testDataMigration2); } -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/migration/TestMigrationFirstInitWithMigration.java b/test/src/test/kar/archidata/migration/TestMigrationFirstInitWithMigration.java index 34a5297..89538ec 100644 --- a/test/src/test/kar/archidata/migration/TestMigrationFirstInitWithMigration.java +++ b/test/src/test/kar/archidata/migration/TestMigrationFirstInitWithMigration.java @@ -11,15 +11,13 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.kar.archidata.GlobalConfiguration; -import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.db.DBEntry; +import org.kar.archidata.db.DbConfig; import org.kar.archidata.migration.MigrationEngine; import org.kar.archidata.migration.model.Migration; -import org.kar.archidata.tools.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import test.kar.archidata.ConfigureDb; import test.kar.archidata.StepwiseExtension; import test.kar.archidata.migration.model.TypesMigrationInitialisationCurrent; @@ -30,22 +28,12 @@ public class TestMigrationFirstInitWithMigration { @BeforeAll public static void configureWebServer() throws Exception { - if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) { - ConfigBaseVariable.dbType = "sqlite"; - ConfigBaseVariable.dbHost = "memory"; - // for test we need to connect all time the DB - ConfigBaseVariable.dbKeepConnected = "true"; - } - // Connect the dataBase... - final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - entry.connect(); + ConfigureDb.configure(); } @AfterAll public static void removeDataBase() throws IOException { - LOGGER.info("Remove the test db"); - DBEntry.closeAllForceMode(); - ConfigBaseVariable.clearAllValue(); + ConfigureDb.clear(); } @Order(1) @@ -57,15 +45,15 @@ public class TestMigrationFirstInitWithMigration { // add migration for old version migrationEngine.add(new Migration1()); migrationEngine.add(new Migration2()); - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + Assertions.assertDoesNotThrow(() -> migrationEngine.migrateErrorThrow(new DbConfig())); final TypesMigrationInitialisationCurrent test = new TypesMigrationInitialisationCurrent(); test.testDataMigration2 = 95.0; - final TypesMigrationInitialisationCurrent insertedData = DataAccess.insert(test); + final TypesMigrationInitialisationCurrent insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertEquals(95.0, insertedData.testDataMigration2); - final List elements = DataAccess.gets(Migration.class); + final List elements = ConfigureDb.da.gets(Migration.class); LOGGER.info("List of migrations:"); for (final Migration elem : elements) { LOGGER.info(" - {} => {}", elem.id, elem.name); @@ -81,12 +69,12 @@ public class TestMigrationFirstInitWithMigration { // add migration for old version migrationEngine.add(new Migration1()); migrationEngine.add(new Migration2()); - migrationEngine.migrateErrorThrow(GlobalConfiguration.dbConfig); + migrationEngine.migrateErrorThrow(new DbConfig()); final TypesMigrationInitialisationCurrent test = new TypesMigrationInitialisationCurrent(); test.testDataMigration2 = 99.0; - final TypesMigrationInitialisationCurrent insertedData = DataAccess.insert(test); + final TypesMigrationInitialisationCurrent insertedData = ConfigureDb.da.insert(test); Assertions.assertNotNull(insertedData); Assertions.assertEquals(99.0, insertedData.testDataMigration2); } -} \ No newline at end of file +} diff --git a/test/src/test/kar/archidata/model/SimpleTable.java b/test/src/test/kar/archidata/model/SimpleTable.java deleted file mode 100644 index 2a9c642..0000000 --- a/test/src/test/kar/archidata/model/SimpleTable.java +++ /dev/null @@ -1,8 +0,0 @@ -package test.kar.archidata.model; - -import org.kar.archidata.model.GenericData; - -public class SimpleTable extends GenericData { - public String data; - -} \ No newline at end of file diff --git a/test/src/test/kar/archidata/model/SimpleTableSoftDelete.java b/test/src/test/kar/archidata/model/SimpleTableSoftDelete.java deleted file mode 100644 index deb8356..0000000 --- a/test/src/test/kar/archidata/model/SimpleTableSoftDelete.java +++ /dev/null @@ -1,7 +0,0 @@ -package test.kar.archidata.model; - -import org.kar.archidata.model.GenericDataSoftDelete; - -public class SimpleTableSoftDelete extends GenericDataSoftDelete { - public String data; -} \ No newline at end of file