[DEV] refacto dataAccess and ManyToMany interface (get Long)

This commit is contained in:
Edouard DUPIN 2023-11-02 15:14:55 +01:00
parent 81cfe8a713
commit 8d271601be
19 changed files with 626 additions and 378 deletions

View File

@ -27,6 +27,7 @@
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes> <attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>

View File

@ -10,16 +10,6 @@
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.jdt.core.javabuilder.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name> <name>org.eclipse.m2e.core.maven2Builder</name>
<arguments> <arguments>

View File

@ -2,7 +2,10 @@ package org.kar.archidata.annotation;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.dataAccess.QueryOptions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -15,6 +18,18 @@ import jakarta.persistence.Table;
public class AnnotationTools { public class AnnotationTools {
static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class); static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class);
public static String getTableName(final Class<?> clazz, final QueryOptions options) throws Exception {
if (options != null) {
final Object data = options.get(QueryOptions.OVERRIDE_TABLE_NAME);
if (data instanceof final String optionString) {
return optionString;
} else if (data != null) {
LOGGER.error("'{}' ==> has not a String value: {}", QueryOptions.SQL_DELETED_DISABLE, data);
}
}
return AnnotationTools.getTableName(clazz);
}
public static String getTableName(final Class<?> element) throws Exception { public static String getTableName(final Class<?> element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class);
if (annotation.length == 0) { if (annotation.length == 0) {
@ -205,5 +220,32 @@ public class AnnotationTools {
} }
return null; return null;
} }
public static List<String> getFieldsNames(final Class<?> clazz) throws Exception {
return getFieldsNamesFilter(clazz, false);
}
public static List<String> getAllFieldsNames(final Class<?> clazz) throws Exception {
return getFieldsNamesFilter(clazz, true);
}
private static List<String> getFieldsNamesFilter(final Class<?> clazz, final boolean full) throws Exception {
final List<String> out = 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;
}
if (!full && AnnotationTools.isGenericField(elem)) {
continue;
}
out.add(AnnotationTools.getFieldName(elem));
}
return out;
}
public static boolean isGenericField(final Field elem) throws Exception {
return AnnotationTools.isPrimaryKey(elem) || AnnotationTools.isCreatedAtField(elem) || AnnotationTools.isUpdateAtField(elem);
}
} }

View File

@ -1,9 +1,12 @@
package org.kar.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.Types; import java.sql.Types;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -11,9 +14,8 @@ import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import org.aopalliance.reflect.Class;
import org.glassfish.jaxb.runtime.v2.schemagen.xmlschema.List;
import org.kar.archidata.GlobalConfiguration; import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp; import org.kar.archidata.annotation.CreationTimestamp;
@ -30,43 +32,39 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.Timestamp;
import com.mysql.cj.x.protobuf.MysqlxDatatypes.Scalar.String;
import com.mysql.cj.xdevapi.Statement;
import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.ws.rs.InternalServerErrorException; import jakarta.ws.rs.InternalServerErrorException;
import javassist.bytecode.Descriptor.Iterator;
public class DataAccess { public class DataAccess {
static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.class); static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.class);
static final List<DataAccessAddOn> addOn = new ArrayList<>(); static final List<DataAccessAddOn> addOn = new ArrayList<>();
static { static {
addOn.add(new AddOnManyToMany()); addOn.add(new AddOnManyToMany());
addOn.add(new AddOnManyToOne()); addOn.add(new AddOnManyToOne());
addOn.add(new AddOnSQLTableExternalForeinKeyAsList()); addOn.add(new AddOnSQLTableExternalForeinKeyAsList());
} }
public static void addAddOn(final DataAccessAddOn addOn) { public static void addAddOn(final DataAccessAddOn addOn) {
DataAccess.addOn.add(addOn); DataAccess.addOn.add(addOn);
} }
public static class ExceptionDBInterface extends Exception { public static class ExceptionDBInterface extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public int errorID; public int errorID;
public ExceptionDBInterface(final int errorId, final String message) { public ExceptionDBInterface(final int errorId, final String message) {
super(message); super(message);
this.errorID = errorId; this.errorID = errorId;
} }
} }
public DataAccess() { public DataAccess() {
} }
public static boolean isDBExist(final String name) throws InternalServerErrorException { public static boolean isDBExist(final String name) throws InternalServerErrorException {
if ("sqlite".equals(ConfigBaseVariable.getDBType())) { if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
// no base manage in sqLite ... // no base manage in sqLite ...
@ -108,7 +106,7 @@ public class DataAccess {
} }
throw new InternalServerErrorException("Can Not manage the DB-access"); throw new InternalServerErrorException("Can Not manage the DB-access");
} }
public static boolean createDB(final String name) { public static boolean createDB(final String name) {
if ("sqlite".equals(ConfigBaseVariable.getDBType())) { if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
// no base manage in sqLite ... // no base manage in sqLite ...
@ -123,7 +121,7 @@ public class DataAccess {
return false; return false;
} }
} }
public static boolean isTableExist(final String name) throws InternalServerErrorException { public static boolean isTableExist(final String name) throws InternalServerErrorException {
try { try {
String request = ""; String request = "";
@ -163,7 +161,7 @@ public class DataAccess {
} }
throw new InternalServerErrorException("Can Not manage the DB-access"); throw new InternalServerErrorException("Can Not manage the DB-access");
} }
/** /**
* extract a list of "-" separated element from a SQL input data. * extract a list of "-" separated element from a SQL input data.
* @param rs Result Set of the BDD * @param rs Result Set of the BDD
@ -184,7 +182,7 @@ public class DataAccess {
} }
return out; return out;
} }
protected static <T> void setValuedb(final Class<?> type, final T data, int index, final Field field, final PreparedStatement ps) throws Exception { protected static <T> void setValuedb(final Class<?> type, final T data, int index, final Field field, final PreparedStatement ps) throws Exception {
if (type == Long.class) { if (type == Long.class) {
final Object tmp = field.get(data); final Object tmp = field.get(data);
@ -280,7 +278,7 @@ public class DataAccess {
throw new Exception("Unknown Field Type"); throw new Exception("Unknown Field Type");
} }
} }
// TODO: maybe wrap this if the use of sqlite ==> maybe some problems came with sqlite ... // TODO: maybe wrap this if the use of sqlite ==> maybe some problems came with sqlite ...
protected static <T> void setValueFromDb(final Class<?> type, final T data, final int index, final Field field, final ResultSet rs) throws Exception { protected static <T> void setValueFromDb(final Class<?> type, final T data, final int index, final Field field, final ResultSet rs) throws Exception {
if (type == Long.class) { if (type == Long.class) {
@ -362,11 +360,22 @@ public class DataAccess {
field.set(data, tmp); field.set(data, tmp);
} }
} else if (type == Date.class) { } else if (type == Date.class) {
final Timestamp tmp = rs.getTimestamp(index); try {
if (rs.wasNull()) { final Timestamp tmp = rs.getTimestamp(index);
field.set(data, null); if (rs.wasNull()) {
} else { field.set(data, null);
field.set(data, Date.from(tmp.toInstant())); } else {
field.set(data, Date.from(tmp.toInstant()));
}
} catch (final SQLException ex) {
final String tmp = rs.getString(index);
LOGGER.error("Fail to parse the SQL time !!! {}", tmp);
LOGGER.error("Fail to parse the SQL time !!! {}", Date.parse(tmp));
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, Date.parse(tmp));
}
} }
} else if (type == LocalDate.class) { } else if (type == LocalDate.class) {
final java.sql.Date tmp = rs.getDate(index); final java.sql.Date tmp = rs.getDate(index);
@ -407,7 +416,7 @@ public class DataAccess {
throw new Exception("Unknown Field Type"); throw new Exception("Unknown Field Type");
} }
} }
public static boolean isAddOnField(final Field field) { public static boolean isAddOnField(final Field field) {
final boolean ret = AnnotationTools.isAnnotationGroup(field, DataAddOn.class); final boolean ret = AnnotationTools.isAnnotationGroup(field, DataAddOn.class);
if (ret) { if (ret) {
@ -422,7 +431,7 @@ public class DataAccess {
} }
return ret; return ret;
} }
public static DataAccessAddOn findAddOnforField(final Field field) { public static DataAccessAddOn findAddOnforField(final Field field) {
for (final DataAccessAddOn elem : addOn) { for (final DataAccessAddOn elem : addOn) {
if (elem.isCompatibleField(field)) { if (elem.isCompatibleField(field)) {
@ -433,19 +442,22 @@ public class DataAccess {
} }
public static <T> T insert(final T data) throws Exception { public static <T> T insert(final T data) throws Exception {
return insert(data, null);
}
public static <T> T insert(final T data, final QueryOptions options) throws Exception {
final Class<?> clazz = data.getClass(); final Class<?> clazz = data.getClass();
//public static NodeSmall createNode(String typeInNode, String name, String descrition, Long parentId) {
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
// real add in the BDD: // real add in the BDD:
try { try {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz, options);
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final StringBuilder querry = new StringBuilder(); final StringBuilder querry = new StringBuilder();
querry.append("INSERT INTO `"); querry.append("INSERT INTO `");
querry.append(tableName); querry.append(tableName);
querry.append("` ("); querry.append("` (");
boolean firstField = true; boolean firstField = true;
int count = 0; int count = 0;
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
@ -457,7 +469,7 @@ public class DataAccess {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(elem); final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && addOn.isExternal()) { if (addOn != null && !addOn.canInsert()) {
continue; continue;
} }
final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
@ -496,7 +508,7 @@ public class DataAccess {
querry.append("?"); querry.append("?");
} }
querry.append(")"); querry.append(")");
//LOGGER.warn("generate the querry: '{}'", querry.toString()); LOGGER.warn("generate the querry: '{}'", querry.toString());
// prepare the request: // prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS);
Field primaryKeyField = null; Field primaryKeyField = null;
@ -511,7 +523,7 @@ public class DataAccess {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(elem); final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && addOn.isExternal()) { if (addOn != null && !addOn.canInsert()) {
continue; continue;
} }
final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
@ -575,16 +587,27 @@ public class DataAccess {
} }
return data; return data;
} }
// seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated... // seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated...
public static <T> T insertWithJson(final Class<T> clazz, final String jsonData) throws Exception { public static <T> T insertWithJson(final Class<T> clazz, final String jsonData) throws Exception {
final ObjectMapper mapper = new ObjectMapper(); final ObjectMapper mapper = new ObjectMapper();
// parse the object to be sure the data are valid: // parse the object to be sure the data are valid:
final T data = mapper.readValue(jsonData, clazz); final T data = mapper.readValue(jsonData, clazz);
return insert(data); return insert(data);
} }
/**
* Update an object with the inserted json data
*
* @param <T> Type of the object to insert
* @param <ID_TYPE> 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 static <T, ID_TYPE> int updateWithJson(final Class<T> clazz, final ID_TYPE id, final String jsonData) throws Exception { public static <T, ID_TYPE> int updateWithJson(final Class<T> clazz, final ID_TYPE id, final String jsonData) throws Exception {
// Find the ID field type .... // Find the ID field type ....
final Field idField = AnnotationTools.getIdField(clazz); final Field idField = AnnotationTools.getIdField(clazz);
@ -592,14 +615,14 @@ public class DataAccess {
throw new Exception("The class have no annotation @Id ==> can not determine the default type searching"); throw new Exception("The class have no annotation @Id ==> can not determine the default type searching");
} }
// check the compatibility of the id and the declared ID // check the compatibility of the id and the declared ID
if (id instanceof idField.getType()) { final Class<?> typeClass = idField.getType();
if (id == typeClass) {
throw new Exception("Request update with the wriong type ..."); throw new Exception("Request update with the wriong type ...");
} }
// Udpade Json Value // Udpade Json Value
return updateWithJson(clazz, QueryCondition(AnnotationTools.getFieldName(idField), "=", id), jsonData); return updateWithJson(clazz, new QueryCondition(AnnotationTools.getFieldName(idField), "=", id), jsonData);
} }
public static <T> int updateWithJson(final Class<T> clazz, final QueryItem condition, final String jsonData) throws Exception { public static <T> int updateWithJson(final Class<T> clazz, final QueryItem condition, final String jsonData) throws Exception {
final ObjectMapper mapper = new ObjectMapper(); final ObjectMapper mapper = new ObjectMapper();
// parse the object to be sure the data are valid: // parse the object to be sure the data are valid:
@ -607,17 +630,19 @@ public class DataAccess {
// Read the tree to filter injection of data: // Read the tree to filter injection of data:
final JsonNode root = mapper.readTree(jsonData); final JsonNode root = mapper.readTree(jsonData);
final List<String> keys = new ArrayList<>(); final List<String> keys = new ArrayList<>();
final Iterator<String> iterator = root.fieldNames(); final var iterator = root.fieldNames();
iterator.forEachRemaining(e -> keys.add(e)); iterator.forEachRemaining(e -> keys.add(e));
return update(data, id, keys); return update(data, condition, keys);
return 0; }
public static <T, ID_TYPE> int update(final T data, final ID_TYPE id) throws Exception {
return update(data, id, null);
} }
public static <T> int update(final T data, final QueryItem condition) throws Exception { public static <T> int update(final T data, final QueryItem condition) throws Exception {
return update(data, condition, null);
return 0;
} }
/** /**
* *
* @param <T> * @param <T>
@ -627,42 +652,50 @@ public class DataAccess {
* @return the affected rows. * @return the affected rows.
* @throws Exception * @throws Exception
*/ */
public static <T> int update(final T data, final long id, final List<String> filterValue) throws Exception { public static <T, ID_TYPE> int update(final T data, final ID_TYPE id, final List<String> filterValue) throws Exception {
// Find the ID field type ....
final Field idField = AnnotationTools.getIdField(data.getClass());
if (idField == null) {
throw new Exception("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 (id == typeClass) {
throw new Exception("Request update with the wriong type ...");
}
return update(data, new QueryCondition(AnnotationTools.getFieldName(idField), "=", id), filterValue);
}
public static <T> int update(final T data, final QueryItem condition, final QueryOptions options, final List<String> filterValue) throws Exception {
final Class<?> clazz = data.getClass(); final Class<?> clazz = data.getClass();
//public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) { //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) {
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
// real add in the BDD: // real add in the BDD:
try { try {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz, options);
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final StringBuilder querry = new StringBuilder(); final StringBuilder querry = new StringBuilder();
querry.append("UPDATE `"); querry.append("UPDATE `");
querry.append(tableName); querry.append(tableName);
querry.append("` SET "); querry.append("` SET ");
boolean firstField = true; boolean firstField = true;
Field primaryKeyField = null;
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue; continue;
} }
if (AnnotationTools.isPrimaryKey(elem)) { final String name = AnnotationTools.getFieldName(elem);
primaryKeyField = elem; if (filterValue != null) {
if (!filterValue.contains(name)) {
continue;
}
} else if (AnnotationTools.isGenericField(elem)) {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(elem); final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && addOn.isExternal()) { if (addOn != null && !addOn.canUpdate()) {
continue;
}
final boolean createTime = AnnotationTools.isCreatedAtField(elem);
if (createTime) {
continue;
}
final String name = AnnotationTools.getFieldName(elem);
final boolean updateTime = AnnotationTools.isUpdateAtField(elem);
if (!updateTime && !filterValue.contains(name)) {
continue; continue;
} }
if (!elem.getClass().isPrimitive()) { if (!elem.getClass().isPrimitive()) {
@ -678,19 +711,13 @@ public class DataAccess {
} }
querry.append(" `"); querry.append(" `");
querry.append(name); querry.append(name);
querry.append("` = "); querry.append("` = ? ");
if (updateTime) {
querry.append(getDBNow());
querry.append(" ");
} else {
querry.append("? ");
}
} }
querry.append(" WHERE `"); querry.append(" ");
querry.append(AnnotationTools.getFieldName(primaryKeyField)); final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
querry.append("` = ?"); whereAppendQuery(querry, tableName, condition, null, deletedFieldName);
firstField = true; firstField = true;
// logger.debug("generate the querry: '{}'", querry.toString()); LOGGER.debug("generate the querry: '{}'", querry.toString());
// prepare the request: // prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS);
int iii = 1; int iii = 1;
@ -699,22 +726,18 @@ public class DataAccess {
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue; continue;
} }
if (AnnotationTools.isPrimaryKey(elem)) { final String name = AnnotationTools.getFieldName(elem);
if (filterValue != null) {
if (!filterValue.contains(name)) {
continue;
}
} else if (AnnotationTools.isGenericField(elem)) {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(elem); final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canUpdate()) { if (addOn != null && !addOn.canUpdate()) {
continue; continue;
} }
final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
if (createTime) {
continue;
}
final String name = AnnotationTools.getFieldName(elem);
final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime || !filterValue.contains(name)) {
continue;
}
if (addOn == null) { if (addOn == null) {
final Class<?> type = elem.getType(); final Class<?> type = elem.getType();
if (!type.isPrimitive()) { if (!type.isPrimitive()) {
@ -728,7 +751,8 @@ public class DataAccess {
iii = addOn.insertData(ps, data, iii); iii = addOn.insertData(ps, data, iii);
} }
} }
ps.setLong(iii++, id); iii = whereInjectValue(ps, condition, iii);
return ps.executeUpdate(); return ps.executeUpdate();
} catch (final SQLException ex) { } catch (final SQLException ex) {
ex.printStackTrace(); ex.printStackTrace();
@ -738,7 +762,7 @@ public class DataAccess {
} }
return 0; return 0;
} }
static void addElement(final PreparedStatement ps, final Object value, final int iii) throws Exception { static void addElement(final PreparedStatement ps, final Object value, final int iii) throws Exception {
if (value instanceof final Long tmp) { if (value instanceof final Long tmp) {
ps.setLong(iii, tmp); ps.setLong(iii, tmp);
@ -772,7 +796,7 @@ public class DataAccess {
throw new Exception("Not manage type ==> need to add it ..."); throw new Exception("Not manage type ==> need to add it ...");
} }
} }
public static void whereAppendQuery(final StringBuilder querry, final String tableName, final QueryItem condition, final QueryOptions options, final String deletedFieldName) public static void whereAppendQuery(final StringBuilder querry, final String tableName, final QueryItem condition, final QueryOptions options, final String deletedFieldName)
throws ExceptionDBInterface { throws ExceptionDBInterface {
boolean exclude_deleted = true; boolean exclude_deleted = true;
@ -797,7 +821,7 @@ public class DataAccess {
} }
querry.append(" WHERE ("); querry.append(" WHERE (");
condition.generateQuerry(querry, tableName); condition.generateQuerry(querry, tableName);
querry.append(") "); querry.append(") ");
if (exclude_deleted && deletedFieldName != null) { if (exclude_deleted && deletedFieldName != null) {
querry.append("AND "); querry.append("AND ");
@ -807,40 +831,40 @@ public class DataAccess {
querry.append(" = false "); querry.append(" = false ");
} }
} }
public static void whereInjectValue(final PreparedStatement ps, final QueryItem condition) throws Exception { public static int whereInjectValue(final PreparedStatement ps, final QueryItem condition, int iii) throws Exception {
// Check if we have a condition to generate // Check if we have a condition to generate
if (condition == null) { if (condition == null) {
return; return iii;
} }
int iii = 1;
iii = condition.injectQuerry(ps, iii); iii = condition.injectQuerry(ps, iii);
return iii;
} }
public static int executeSimpleQuerry(final String querry, final boolean root) throws SQLException, IOException { public static int executeSimpleQuerry(final String querry, final boolean root) throws SQLException, IOException {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root);
final Statement stmt = entry.connection.createStatement(); final Statement stmt = entry.connection.createStatement();
return stmt.executeUpdate(querry); return stmt.executeUpdate(querry);
} }
public static int executeSimpleQuerry(final String querry) throws SQLException, IOException { public static int executeSimpleQuerry(final String querry) throws SQLException, IOException {
return executeSimpleQuerry(querry, false); return executeSimpleQuerry(querry, false);
} }
public static boolean executeQuerry(final String querry, final boolean root) throws SQLException, IOException { public static boolean executeQuerry(final String querry, final boolean root) throws SQLException, IOException {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root);
final Statement stmt = entry.connection.createStatement(); final Statement stmt = entry.connection.createStatement();
return stmt.execute(querry); return stmt.execute(querry);
} }
public static boolean executeQuerry(final String querry) throws SQLException, IOException { public static boolean executeQuerry(final String querry) throws SQLException, IOException {
return executeQuerry(querry, false); return executeQuerry(querry, false);
} }
public static <T> T getWhere(final Class<T> clazz, final QueryItem condition) throws Exception { public static <T> T getWhere(final Class<T> clazz, final QueryItem condition) throws Exception {
return getWhere(clazz, condition, null); return getWhere(clazz, condition, null);
} }
public static <T> T getWhere(final Class<T> clazz, final QueryItem condition, final QueryOptions options) throws Exception { public static <T> T getWhere(final Class<T> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
final List<T> values = getsWhere(clazz, condition, options, 1); final List<T> values = getsWhere(clazz, condition, options, 1);
if (values.size() == 0) { if (values.size() == 0) {
@ -848,23 +872,23 @@ public class DataAccess {
} }
return values.get(0); return values.get(0);
} }
public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition) throws Exception { public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition) throws Exception {
return getsWhere(clazz, condition, null, null, null); return getsWhere(clazz, condition, null, null, null);
} }
public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition, final QueryOptions options) throws Exception { public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
return getsWhere(clazz, condition, null, options, null); return getsWhere(clazz, condition, null, options, null);
} }
public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition, final QueryOptions options, final Integer linit) throws Exception { public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition, final QueryOptions options, final Integer linit) throws Exception {
return getsWhere(clazz, condition, null, options, linit); return getsWhere(clazz, condition, null, options, linit);
} }
// TODO: set limit as an querry Option... // TODO: set limit as an query Option...
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition, final String orderBy, final QueryOptions options, final Integer linit) throws Exception { public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition, final String orderBy, final QueryOptions options, final Integer linit) throws Exception {
boolean readAllfields = false; boolean readAllfields = false;
if (options != null) { if (options != null) {
final Object data = options.get(QueryOptions.SQL_NOT_READ_DISABLE); final Object data = options.get(QueryOptions.SQL_NOT_READ_DISABLE);
@ -874,18 +898,18 @@ public class DataAccess {
LOGGER.error("'{}' ==> has not a boolean value: {}", QueryOptions.SQL_NOT_READ_DISABLE, data); LOGGER.error("'{}' ==> has not a boolean value: {}", QueryOptions.SQL_NOT_READ_DISABLE, data);
} }
} }
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final List<T> outs = new ArrayList<>(); final List<T> outs = new ArrayList<>();
// real add in the BDD: // real add in the BDD:
try { try {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz, options);
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final StringBuilder querry = new StringBuilder(); final StringBuilder querry = new StringBuilder();
querry.append("SELECT "); querry.append("SELECT ");
//querry.append(tableName); //querry.append(tableName);
//querry.append(" SET "); //querry.append(" SET ");
boolean firstField = true; boolean firstField = true;
int count = 0; int count = 0;
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
@ -895,7 +919,7 @@ public class DataAccess {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(elem); final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && addOn.isExternal()) { if (addOn != null && !addOn.canRetrieve(elem)) {
continue; continue;
} }
// TODO: Manage it with AddOn // TODO: Manage it with AddOn
@ -936,7 +960,7 @@ public class DataAccess {
LOGGER.debug("generate the querry: '{}'", querry.toString()); LOGGER.debug("generate the querry: '{}'", querry.toString());
// prepare the request: // prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS);
whereInjectValue(ps, condition); whereInjectValue(ps, condition, 1);
// execute the request // execute the request
final ResultSet rs = ps.executeQuery(); final ResultSet rs = ps.executeQuery();
while (rs.next()) { while (rs.next()) {
@ -949,7 +973,7 @@ public class DataAccess {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(elem); final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && addOn.isExternal()) { if (addOn != null && !addOn.canRetrieve(elem)) {
continue; continue;
} }
// TODO: Manage it with AddOn // TODO: Manage it with AddOn
@ -968,7 +992,7 @@ public class DataAccess {
final T out = (T) data; final T out = (T) data;
outs.add(out); outs.add(out);
} }
} catch (final SQLException ex) { } catch (final SQLException ex) {
ex.printStackTrace(); ex.printStackTrace();
throw ex; throw ex;
@ -980,12 +1004,12 @@ public class DataAccess {
} }
return outs; return outs;
} }
// TODO : detect the @Id // TODO : detect the @Id
public static <T> T get(final Class<T> clazz, final long id) throws Exception { public static <T> T get(final Class<T> clazz, final long id) throws Exception {
return get(clazz, id, null); return get(clazz, id, null);
} }
public static <T> T get(final Class<T> clazz, final long id, final QueryOptions options) throws Exception { public static <T> T get(final Class<T> clazz, final long id, final QueryOptions options) throws Exception {
Field primaryKeyField = null; Field primaryKeyField = null;
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
@ -1002,44 +1026,48 @@ public class DataAccess {
} }
throw new Exception("Missing primary Key..."); throw new Exception("Missing primary Key...");
} }
public static String getCurrentTimeStamp() { public static String getCurrentTimeStamp() {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
} }
public static <T> List<T> gets(final Class<T> clazz) throws Exception { public static <T> List<T> gets(final Class<T> clazz) throws Exception {
return getsWhere(clazz, null); return getsWhere(clazz, null);
} }
public static <T> List<T> gets(final Class<T> clazz, final QueryOptions options) throws Exception { public static <T> List<T> gets(final Class<T> clazz, final QueryOptions options) throws Exception {
return getsWhere(clazz, null, options); return getsWhere(clazz, null, options);
} }
// TODO : detect the @Id // TODO : detect the @Id
public static int delete(final Class<?> clazz, final long id) throws Exception { public static int delete(final Class<?> clazz, final long id) throws Exception {
return delete(clazz, id, null);
}
public static int delete(final Class<?> clazz, final long id, final QueryOptions options) throws Exception {
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (hasDeletedFieldName != null) { if (hasDeletedFieldName != null) {
return deleteSoft(clazz, id); return deleteSoft(clazz, id, options);
} else { } else {
return deleteHard(clazz, id); return deleteHard(clazz, id, options);
} }
} }
public static int deleteWhere(final Class<?> clazz, final QueryItem condition) throws Exception { public static int deleteWhere(final Class<?> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (hasDeletedFieldName != null) { if (hasDeletedFieldName != null) {
return deleteSoftWhere(clazz, condition); return deleteSoftWhere(clazz, condition, options);
} else { } else {
return deleteHardWhere(clazz, condition); return deleteHardWhere(clazz, condition, options);
} }
} }
public static int deleteHard(final Class<?> clazz, final long id) throws Exception { public static int deleteHard(final Class<?> clazz, final long id, final QueryOptions options) throws Exception {
return deleteHardWhere(clazz, new QueryCondition("id", "=", id)); return deleteHardWhere(clazz, new QueryCondition("id", "=", id), options);
} }
public static int deleteHardWhere(final Class<?> clazz, final QueryItem condition) throws Exception { public static int deleteHardWhere(final Class<?> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
// find the deleted field // find the deleted field
@ -1052,27 +1080,27 @@ public class DataAccess {
try { try {
LOGGER.debug("APPLY: {}", querry.toString()); LOGGER.debug("APPLY: {}", querry.toString());
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString()); final PreparedStatement ps = entry.connection.prepareStatement(querry.toString());
whereInjectValue(ps, condition); whereInjectValue(ps, condition, 1);
return ps.executeUpdate(); return ps.executeUpdate();
} finally { } finally {
entry.close(); entry.close();
entry = null; entry = null;
} }
} }
private static int deleteSoft(final Class<?> clazz, final long id) throws Exception { private static int deleteSoft(final Class<?> clazz, final long id, final QueryOptions options) throws Exception {
return deleteSoftWhere(clazz, new QueryCondition("id", "=", id)); return deleteSoftWhere(clazz, new QueryCondition("id", "=", id), options);
} }
public static String getDBNow() { public static String getDBNow() {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
return "now(3)"; return "now(3)";
} }
return "DATE()"; return "DATE()";
} }
public static int deleteSoftWhere(final Class<?> clazz, final QueryItem condition) throws Exception { public static int deleteSoftWhere(final Class<?> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
/* /*
String updateFieldName = null; String updateFieldName = null;
@ -1081,7 +1109,7 @@ public class DataAccess {
} }
*/ */
// find the deleted field // find the deleted field
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final StringBuilder querry = new StringBuilder(); final StringBuilder querry = new StringBuilder();
querry.append("UPDATE `"); querry.append("UPDATE `");
@ -1102,7 +1130,7 @@ public class DataAccess {
try { try {
LOGGER.debug("APPLY UPDATE: {}", querry.toString()); LOGGER.debug("APPLY UPDATE: {}", querry.toString());
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString()); final PreparedStatement ps = entry.connection.prepareStatement(querry.toString());
whereInjectValue(ps, condition); whereInjectValue(ps, condition, 1);
return ps.executeUpdate(); return ps.executeUpdate();
} finally { } finally {
entry.close(); entry.close();
@ -1111,11 +1139,15 @@ public class DataAccess {
} }
public static int unsetDelete(final Class<?> clazz, final long id) throws Exception { public static int unsetDelete(final Class<?> clazz, final long id) throws Exception {
return unsetDeleteWhere(clazz, new QueryCondition("id", "=", id)); return unsetDeleteWhere(clazz, new QueryCondition("id", "=", id), null);
} }
public static int unsetDeleteWhere(final Class<?> clazz, final QueryItem condition) throws Exception { public static int unsetDelete(final Class<?> clazz, final long id, final QueryOptions options) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz); return unsetDeleteWhere(clazz, new QueryCondition("id", "=", id), options);
}
public static int unsetDeleteWhere(final Class<?> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (deletedFieldName == null) { if (deletedFieldName == null) {
throw new Exception("The class " + clazz.getCanonicalName() + " has no deleted field"); throw new Exception("The class " + clazz.getCanonicalName() + " has no deleted field");
@ -1134,16 +1166,16 @@ public class DataAccess {
querry.append(", "); querry.append(", ");
*/ */
// need to disable the deleted false because the model must be unselected to be updated. // need to disable the deleted false because the model must be unselected to be updated.
final QueryOptions options = new QueryOptions(QueryOptions.SQL_DELETED_DISABLE, true); options.put(QueryOptions.SQL_DELETED_DISABLE, true);
whereAppendQuery(querry, tableName, condition, options, deletedFieldName); whereAppendQuery(querry, tableName, condition, options, deletedFieldName);
try { try {
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString()); final PreparedStatement ps = entry.connection.prepareStatement(querry.toString());
whereInjectValue(ps, condition); whereInjectValue(ps, condition, 1);
return ps.executeUpdate(); return ps.executeUpdate();
} finally { } finally {
entry.close(); entry.close();
entry = null; entry = null;
} }
} }
} }

View File

@ -39,8 +39,11 @@ public interface DataAccessAddOn {
*/ */
int insertData(PreparedStatement ps, Object data, int iii) throws SQLException; int insertData(PreparedStatement ps, Object data, int iii) throws SQLException;
// External mean that the type of the object is absolutely not obvious... // Element can insert in the single request
boolean isExternal(); boolean canInsert();
// Element can be retrieve with the specific mode
boolean canRetrieve(final Field field);
int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QueryOptions options); int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QueryOptions options);

View File

@ -20,7 +20,7 @@ import jakarta.persistence.GenerationType;
public class DataFactory { public class DataFactory {
static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class); static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class);
public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws Exception { public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws Exception {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
if (type == Long.class || type == long.class) { if (type == Long.class || type == long.class) {
@ -117,21 +117,21 @@ public class DataFactory {
} }
throw new Exception("Imcompatible type of element in object for: " + type.getCanonicalName()); throw new Exception("Imcompatible type of element in object for: " + type.getCanonicalName());
} }
public static void createTablesSpecificType(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preOtherTables, final List<String> postOtherTables, public static void createTablesSpecificType(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preOtherTables, final List<String> postOtherTables,
final boolean createIfNotExist, final boolean createDrop, final int fieldId, final Class<?> classModel) throws Exception { final boolean createIfNotExist, final boolean createDrop, final int fieldId, final Class<?> classModel) throws Exception {
final String name = AnnotationTools.getFieldName(elem); final String name = AnnotationTools.getFieldName(elem);
final Integer limitSize = AnnotationTools.getLimitSize(elem); final Integer limitSize = AnnotationTools.getLimitSize(elem);
final boolean notNull = AnnotationTools.getNotNull(elem); final boolean notNull = AnnotationTools.getNotNull(elem);
final boolean primaryKey = AnnotationTools.isPrimaryKey(elem); final boolean primaryKey = AnnotationTools.isPrimaryKey(elem);
final GenerationType strategy = AnnotationTools.getStrategy(elem); final GenerationType strategy = AnnotationTools.getStrategy(elem);
final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
final String comment = AnnotationTools.getComment(elem); final String comment = AnnotationTools.getComment(elem);
final String defaultValue = AnnotationTools.getDefault(elem); final String defaultValue = AnnotationTools.getDefault(elem);
if (fieldId == 0) { if (fieldId == 0) {
mainTableBuilder.append("\n\t\t`"); mainTableBuilder.append("\n\t\t`");
} else { } else {
@ -191,10 +191,10 @@ public class DataFactory {
triggerBuilder.append(name); triggerBuilder.append(name);
triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n"); triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n");
triggerBuilder.append("END;"); triggerBuilder.append("END;");
postOtherTables.add(triggerBuilder.toString()); postOtherTables.add(triggerBuilder.toString());
} }
mainTableBuilder.append(" "); mainTableBuilder.append(" ");
} }
} else { } else {
@ -229,11 +229,11 @@ public class DataFactory {
mainTableBuilder.append("DEFAULT "); mainTableBuilder.append("DEFAULT ");
mainTableBuilder.append(defaultValue); mainTableBuilder.append(defaultValue);
mainTableBuilder.append(" "); mainTableBuilder.append(" ");
} }
if (primaryKey && "sqlite".equals(ConfigBaseVariable.getDBType())) { if (primaryKey && "sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("PRIMARY KEY "); mainTableBuilder.append("PRIMARY KEY ");
} }
if (strategy == GenerationType.IDENTITY) { if (strategy == GenerationType.IDENTITY) {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
@ -244,14 +244,14 @@ public class DataFactory {
} else if (strategy != null) { } else if (strategy != null) {
throw new Exception("Can not generate a stategy different of IDENTITY"); throw new Exception("Can not generate a stategy different of IDENTITY");
} }
if (comment != null && !"sqlite".equals(ConfigBaseVariable.getDBType())) { if (comment != null && !"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("COMMENT '"); mainTableBuilder.append("COMMENT '");
mainTableBuilder.append(comment.replace('\'', '\'')); mainTableBuilder.append(comment.replace('\'', '\''));
mainTableBuilder.append("' "); mainTableBuilder.append("' ");
} }
} }
private static boolean isFieldFromSuperClass(final Class<?> model, final String filedName) { private static boolean isFieldFromSuperClass(final Class<?> model, final String filedName) {
final Class<?> superClass = model.getSuperclass(); final Class<?> superClass = model.getSuperclass();
if (superClass == null) { if (superClass == null) {
@ -271,13 +271,24 @@ public class DataFactory {
} }
return false; return false;
} }
public static List<String> createTable(final Class<?> clazz) throws Exception { public static List<String> createTable(final Class<?> clazz) throws Exception {
return createTable(clazz, true); return createTable(clazz, null);
} }
public static List<String> createTable(final Class<?> clazz, final boolean createDrop) throws Exception { public static List<String> createTable(final Class<?> clazz, final QueryOptions options) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz, options);
boolean createDrop = false;
if (options != null) {
final Object data = options.get(QueryOptions.CREATE_DROP_TABLE);
if (data instanceof final Boolean optionBoolean) {
createDrop = optionBoolean;
} else if (data != null) {
LOGGER.error("'{}' ==> has not a Boolean value: {}", QueryOptions.CREATE_DROP_TABLE, data);
}
}
final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final List<String> preActionList = new ArrayList<>(); final List<String> preActionList = new ArrayList<>();
final List<String> postActionList = new ArrayList<>(); final List<String> postActionList = new ArrayList<>();
@ -297,7 +308,7 @@ public class DataFactory {
int fieldId = 0; int fieldId = 0;
LOGGER.debug("===> TABLE `{}`", tableName); LOGGER.debug("===> TABLE `{}`", tableName);
final List<String> primaryKeys = new ArrayList<>(); final List<String> primaryKeys = new ArrayList<>();
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
// DEtect the primary key (support only one primary key right now... // DEtect the primary key (support only one primary key right now...
if (AnnotationTools.isPrimaryKey(elem)) { if (AnnotationTools.isPrimaryKey(elem)) {
@ -311,7 +322,7 @@ public class DataFactory {
Class<?> currentClazz = clazz; Class<?> currentClazz = clazz;
while (currentClazz != null) { while (currentClazz != null) {
fieldId = 0; fieldId = 0;
LOGGER.info("parse class: '{}'", currentClazz.getCanonicalName()); LOGGER.trace("parse class: '{}'", currentClazz.getCanonicalName());
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
@ -327,10 +338,10 @@ public class DataFactory {
continue; continue;
} }
alreadyAdded.add(dataName); alreadyAdded.add(dataName);
LOGGER.info(" + '{}'", elem.getName()); LOGGER.trace(" + '{}'", elem.getName());
if (DataAccess.isAddOnField(elem)) { if (DataAccess.isAddOnField(elem)) {
final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem); final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem);
LOGGER.info("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType()); LOGGER.trace("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType());
if (addOn != null) { if (addOn != null) {
addOn.createTables(tableName, elem, tmpOut, preActionList, postActionList, createIfNotExist, createDrop, fieldId); addOn.createTables(tableName, elem, tmpOut, preActionList, postActionList, createIfNotExist, createDrop, fieldId);
} else { } else {
@ -338,7 +349,7 @@ public class DataFactory {
"Element matked as add-on but add-on does not loaded: table:" + tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type=" + elem.getType()); "Element matked as add-on but add-on does not loaded: table:" + tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type=" + elem.getType());
} }
} else { } else {
LOGGER.info("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType()); LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType());
DataFactory.createTablesSpecificType(tableName, elem, tmpOut, preActionList, postActionList, createIfNotExist, createDrop, fieldId, elem.getType()); DataFactory.createTablesSpecificType(tableName, elem, tmpOut, preActionList, postActionList, createIfNotExist, createDrop, fieldId, elem.getType());
} }
fieldId++; fieldId++;
@ -378,5 +389,5 @@ public class DataFactory {
preActionList.addAll(postActionList); preActionList.addAll(postActionList);
return preActionList; return preActionList;
} }
} }

View File

@ -6,6 +6,8 @@ import java.util.Map;
public class QueryOptions { public class QueryOptions {
public static final String SQL_NOT_READ_DISABLE = "SQLNotRead_disable"; public static final String SQL_NOT_READ_DISABLE = "SQLNotRead_disable";
public static final String SQL_DELETED_DISABLE = "SQLDeleted_disable"; public static final String SQL_DELETED_DISABLE = "SQLDeleted_disable";
public static final String OVERRIDE_TABLE_NAME = "SQL_OVERRIDE_TABLE_NAME";
public static final String CREATE_DROP_TABLE = "CREATE_DROP_TABLE";
private final Map<String, Object> options = new HashMap<>(); private final Map<String, Object> options = new HashMap<>();
@ -13,26 +15,26 @@ public class QueryOptions {
} }
public QueryOptions(String key, Object value) { public QueryOptions(final String key, final Object value) {
this.options.put(key, value); this.options.put(key, value);
} }
public QueryOptions(String key, Object value, String key2, Object value2) { public QueryOptions(final String key, final Object value, final String key2, final Object value2) {
this.options.put(key, value); this.options.put(key, value);
this.options.put(key2, value2); this.options.put(key2, value2);
} }
public QueryOptions(String key, Object value, String key2, Object value2, String key3, Object value3) { public QueryOptions(final String key, final Object value, final String key2, final Object value2, final String key3, final Object value3) {
this.options.put(key, value); this.options.put(key, value);
this.options.put(key2, value2); this.options.put(key2, value2);
this.options.put(key3, value3); this.options.put(key3, value3);
} }
public void put(String key, Object value) { public void put(final String key, final Object value) {
this.options.put(key, value); this.options.put(key, value);
} }
public Object get(String value) { public Object get(final String value) {
return this.options.get(value); return this.options.get(value);
} }

View File

@ -4,16 +4,16 @@ import java.lang.reflect.Field;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.util.List; import java.util.List;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataAccess.ExceptionDBInterface; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.addOn.model.LinkTable;
import org.kar.archidata.util.ConfigBaseVariable; import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -24,47 +24,60 @@ import jakarta.validation.constraints.NotNull;
public class AddOnManyToMany implements DataAccessAddOn { public class AddOnManyToMany implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class);
static final String SEPARATOR = "-"; static final String SEPARATOR = "-";
@Override @Override
public Class<?> getAnnotationClass() { public Class<?> getAnnotationClass() {
return ManyToMany.class; return ManyToMany.class;
} }
@Override @Override
public String getSQLFieldType(final Field elem) { public String getSQLFieldType(final Field elem) {
return null; return null;
} }
@Override @Override
public boolean isCompatibleField(final Field elem) { public boolean isCompatibleField(final Field elem) {
final ManyToMany decorators = elem.getDeclaredAnnotation(ManyToMany.class); final ManyToMany decorators = elem.getDeclaredAnnotation(ManyToMany.class);
return decorators != null; return decorators != null;
} }
@Override @Override
public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { public int insertData(final PreparedStatement ps, final Object data, final int iii) throws SQLException {
return iii; return iii;
} }
@Override @Override
public boolean isExternal() { public boolean canInsert() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public int generateQuerry(@NotNull final String tableName, @NotNull final Field elem, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount, public boolean canRetrieve(final Field field) {
QueryOptions options) { return true;
}
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; String localName = name;
if (name.endsWith("s")) { if (name.endsWith("s")) {
localName = name.substring(0, name.length() - 1); localName = name.substring(0, name.length() - 1);
} }
return tableName + "_link_" + localName;
}
@Override
public int generateQuerry(@NotNull final String tableName, @NotNull final Field elem, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount,
final QueryOptions options) {
final String linkTableName = generateLinkTableName(tableName, name);
final String tmpVariable = "tmp_" + Integer.toString(elemCount); final String tmpVariable = "tmp_" + Integer.toString(elemCount);
querry.append(" (SELECT GROUP_CONCAT("); querry.append(" (SELECT GROUP_CONCAT(");
querry.append(tmpVariable); querry.append(tmpVariable);
querry.append("."); querry.append(".object2Id");
querry.append(localName);
querry.append("_id ");
if (ConfigBaseVariable.getDBType().equals("sqlite")) { if (ConfigBaseVariable.getDBType().equals("sqlite")) {
querry.append(", "); querry.append(", ");
} else { } else {
@ -73,9 +86,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
querry.append("'"); querry.append("'");
querry.append(SEPARATOR); querry.append(SEPARATOR);
querry.append("') FROM "); querry.append("') FROM ");
querry.append(tableName); querry.append(linkTableName);
querry.append("_link_");
querry.append(localName);
querry.append(" "); querry.append(" ");
querry.append(tmpVariable); querry.append(tmpVariable);
querry.append(" WHERE "); querry.append(" WHERE ");
@ -85,12 +96,13 @@ public class AddOnManyToMany implements DataAccessAddOn {
querry.append(".id = "); querry.append(".id = ");
querry.append(tmpVariable); querry.append(tmpVariable);
querry.append("."); querry.append(".");
querry.append(tableName); querry.append("object1Id ");
querry.append("_id GROUP BY "); if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
querry.append(tmpVariable); querry.append(" GROUP BY ");
querry.append("."); querry.append(tmpVariable);
querry.append(tableName); querry.append(".object2Id");
querry.append("_id ) AS "); }
querry.append(") AS ");
querry.append(name); querry.append(name);
querry.append(" "); querry.append(" ");
/* /*
@ -102,135 +114,43 @@ public class AddOnManyToMany implements DataAccessAddOn {
*/ */
return 1; return 1;
} }
@Override @Override
public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, QueryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, final QueryOptions options)
List<Long> idList = DataAccess.getListOfIds(rs, count, SEPARATOR); throws SQLException, IllegalArgumentException, IllegalAccessException {
final List<Long> idList = DataAccess.getListOfIds(rs, count, SEPARATOR);
elem.set(data, idList); elem.set(data, idList);
return 1; return 1;
} }
@Override @Override
public boolean canUpdate() { public boolean canUpdate() {
return false; return false;
} }
public static void addLink(final Class<?> clazz, final long localKey, final String table, final long remoteKey) throws Exception { 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 tableName = AnnotationTools.getTableName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); final String linkTableName = generateLinkTableName(tableName, column);
long uniqueSQLID = -1; final LinkTable insertElement = new LinkTable(localKey, remoteKey);
// real add in the BDD: final QueryOptions options = new QueryOptions(QueryOptions.OVERRIDE_TABLE_NAME, linkTableName);
try { DataAccess.insert(insertElement, options);
// prepare the request:
final String querry = "INSERT INTO " + tableName + "_link_" + table + " (create_date, modify_date, " + tableName + "_id, " + table + "_id)" + " VALUES (" + DataAccess.getDBNow() + ", "
+ DataAccess.getDBNow() + ", ?, ?)";
final PreparedStatement ps = entry.connection.prepareStatement(querry, Statement.RETURN_GENERATED_KEYS);
int iii = 1;
ps.setLong(iii++, localKey);
ps.setLong(iii++, remoteKey);
// execute the request
final int affectedRows = ps.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating data failed, no rows affected.");
}
// retrieve uid inserted
try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
if (generatedKeys.next()) {
uniqueSQLID = generatedKeys.getLong(1);
} else {
throw new SQLException("Creating user failed, no ID obtained (1).");
}
} catch (final Exception ex) {
LOGGER.debug("Can not get the UID key inserted ... ");
ex.printStackTrace();
throw new SQLException("Creating user failed, no ID obtained (2).");
}
} catch (final SQLException ex) {
ex.printStackTrace();
throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage());
} finally {
entry.close();
entry = null;
}
} }
public static void removeLink(final Class<?> clazz, final long localKey, final String table, final long remoteKey) throws Exception { 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 tableName = AnnotationTools.getTableName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); final String linkTableName = generateLinkTableName(tableName, column);
final String querry = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=" + DataAccess.getDBNow() + ", `deleted`=true WHERE `" + tableName + "_id` = ? AND `" + table final QueryOptions options = new QueryOptions(QueryOptions.OVERRIDE_TABLE_NAME, linkTableName);
+ "_id` = ?"; final QueryAnd condition = new QueryAnd(new QueryCondition("object1Id", "=", localKey), new QueryCondition("object2Id", "=", remoteKey));
try { return DataAccess.deleteWhere(LinkTable.class, condition, options);
final PreparedStatement ps = entry.connection.prepareStatement(querry);
int iii = 1;
ps.setLong(iii++, localKey);
ps.setLong(iii++, remoteKey);
ps.executeUpdate();
} catch (final SQLException ex) {
ex.printStackTrace();
throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage());
} finally {
entry.close();
entry = null;
}
} }
// TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system
@Override @Override
public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preActionList, List<String> postActionList, public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {
final String name = AnnotationTools.getFieldName(elem); final String linkTableName = generateLinkTableNameField(tableName, elem);
String localName = name; final QueryOptions options = new QueryOptions(QueryOptions.OVERRIDE_TABLE_NAME, linkTableName);
if (name.endsWith("s")) { final List<String> sqlCommand = DataFactory.createTable(LinkTable.class, options);
localName = name.substring(0, name.length() - 1); postActionList.addAll(sqlCommand);
}
if (createIfNotExist && createDrop) {
final StringBuilder tableTmp = new StringBuilder();
tableTmp.append("DROP TABLE IF EXISTS `");
tableTmp.append(tableName);
tableTmp.append("_link_");
tableTmp.append(localName);
tableTmp.append("`;");
postActionList.add(tableTmp.toString());
}
final StringBuilder otherTable = new StringBuilder();
otherTable.append("CREATE TABLE `");
otherTable.append(tableName);
otherTable.append("_link_");
otherTable.append(localName);
otherTable.append("`(\n");
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("\t\t`id` bigint NOT NULL AUTO_INCREMENT,\n");
otherTable.append("\t\t`deleted` tinyint(1) NOT NULL DEFAULT '0',\n");
otherTable.append("\t\t`createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n");
otherTable.append("\t\t`updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n");
} else {
otherTable.append("\t\t`id` INTEGER PRIMARY KEY AUTOINCREMENT,\n");
otherTable.append("\t\t`deleted` INTEGER NOT NULL DEFAULT '0',\n");
otherTable.append("\t\t`createdAt` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n");
otherTable.append("\t\t`updatedAt` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n");
}
otherTable.append("\t\t`");
otherTable.append(tableName);
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("_id` bigint NOT NULL,\n");
} else {
otherTable.append("_id` INTEGER NOT NULL,\n");
}
otherTable.append("\t\t`");
otherTable.append(localName);
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("_id` bigint NOT NULL\n");
} else {
otherTable.append("_id` INTEGER NOT NULL\n");
}
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("\t, PRIMARY KEY (`id`)\n");
}
otherTable.append("\t)");
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n");
}
otherTable.append(";");
postActionList.add(otherTable.toString());
} }
} }

View File

@ -10,10 +10,10 @@ import java.util.List;
import org.kar.archidata.GlobalConfiguration; import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.addOn.DataAddOnManyToManyOrdered; import org.kar.archidata.annotation.addOn.DataAddOnManyToManyOrdered;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataAccess.ExceptionDBInterface; import org.kar.archidata.dataAccess.DataAccess.ExceptionDBInterface;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.db.DBEntry;
import org.kar.archidata.util.ConfigBaseVariable; import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -46,18 +46,23 @@ public class AddOnManyToManyOrdered implements DataAccessAddOn {
} }
@Override @Override
public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { public int insertData(final PreparedStatement ps, final Object data, final int iii) throws SQLException {
return iii; return iii;
} }
@Override @Override
public boolean isExternal() { public boolean canInsert() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QueryOptions options) { public boolean canRetrieve(final Field field) {
return false;
}
@Override
public int generateQuerry(@NotNull final String tableName, @NotNull final Field elem, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount,
final QueryOptions options) {
String localName = name; String localName = name;
if (name.endsWith("s")) { if (name.endsWith("s")) {
localName = name.substring(0, name.length() - 1); localName = name.substring(0, name.length() - 1);
@ -103,7 +108,8 @@ public class AddOnManyToManyOrdered implements DataAccessAddOn {
} }
@Override @Override
public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, QueryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, final QueryOptions options)
throws SQLException, IllegalArgumentException, IllegalAccessException {
//throw new IllegalAccessException("This Add-on has not the capability to insert data directly in DB"); //throw new IllegalAccessException("This Add-on has not the capability to insert data directly in DB");
return 0; return 0;
} }
@ -174,7 +180,7 @@ public class AddOnManyToManyOrdered implements DataAccessAddOn {
// TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system
@Override @Override
public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preActionList, List<String> postActionList, public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {
final String name = AnnotationTools.getFieldName(elem); final String name = AnnotationTools.getFieldName(elem);
String localName = name; String localName = name;

View File

@ -89,8 +89,12 @@ public class AddOnManyToOne implements DataAccessAddOn {
} }
@Override @Override
public boolean isExternal() { public boolean canInsert() {
// TODO Auto-generated method stub return false;
}
@Override
public boolean canRetrieve(final Field field) {
return false; return false;
} }

View File

@ -70,8 +70,12 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn {
} }
@Override @Override
public boolean isExternal() { public boolean canInsert() {
// TODO Auto-generated method stub return false;
}
@Override
public boolean canRetrieve(final Field field) {
return false; return false;
} }

View File

@ -0,0 +1,25 @@
package org.kar.archidata.dataAccess.addOn.model;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.model.GenericDataSoftDelete;
import jakarta.persistence.Column;
public class LinkTable extends GenericDataSoftDelete {
public LinkTable() {
// nothing to do...
}
public LinkTable(final long object1Id, final long object2Id) {
this.object1Id = object1Id;
this.object2Id = object2Id;
}
@SQLComment("Object reference 1")
@Column(nullable = false)
public Long object1Id;
@SQLComment("Object reference 2")
@Column(nullable = false)
public Long object2Id;
}

View File

@ -10,24 +10,25 @@ import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.db.DBConfig; import org.kar.archidata.db.DBConfig;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.db.DBEntry;
import org.kar.archidata.migration.model.Migration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class MigrationEngine { public class MigrationEngine {
final static Logger LOGGER = LoggerFactory.getLogger(MigrationEngine.class); final static Logger LOGGER = LoggerFactory.getLogger(MigrationEngine.class);
// List of order migrations // List of order migrations
private final List<MigrationInterface> datas; private final List<MigrationInterface> datas;
// initialization of the migration if the DB is not present... // initialization of the migration if the DB is not present...
private MigrationInterface init; private MigrationInterface init;
/** /**
* Migration engine constructor (empty). * Migration engine constructor (empty).
*/ */
public MigrationEngine() { public MigrationEngine() {
this(new ArrayList<>(), null); this(new ArrayList<>(), null);
} }
/** /**
* Migration engine constructor (specific mode). * Migration engine constructor (specific mode).
* @param datas All the migration ordered. * @param datas All the migration ordered.
@ -37,7 +38,7 @@ public class MigrationEngine {
this.datas = datas; this.datas = datas;
this.init = init; this.init = init;
} }
/** /**
* Add a Migration in the list * Add a Migration in the list
* @param migration Migration to add. * @param migration Migration to add.
@ -45,7 +46,7 @@ public class MigrationEngine {
public void add(final MigrationInterface migration) { public void add(final MigrationInterface migration) {
this.datas.add(migration); this.datas.add(migration);
} }
/** /**
* Set first initialization class * Set first initialization class
* @param migration migration class for first init. * @param migration migration class for first init.
@ -53,17 +54,17 @@ public class MigrationEngine {
public void setInit(final MigrationInterface migration) { public void setInit(final MigrationInterface migration) {
this.init = migration; this.init = migration;
} }
/** /**
* Get the current version/migration name * Get the current version/migration name
* @return Model represent the last migration. If null then no migration has been done. * @return Model represent the last migration. If null then no migration has been done.
*/ */
public MigrationModel getCurrentVersion() { public Migration getCurrentVersion() {
if (!DataAccess.isTableExist("KAR_migration")) { if (!DataAccess.isTableExist("KAR_migration")) {
return null; return null;
} }
try { try {
final List<MigrationModel> data = DataAccess.gets(MigrationModel.class, new QueryOptions("SQLNotRead_disable", true)); final List<Migration> data = DataAccess.gets(Migration.class, new QueryOptions("SQLNotRead_disable", true));
if (data == null) { if (data == null) {
LOGGER.error("Can not collect the migration table in the DB:{}"); LOGGER.error("Can not collect the migration table in the DB:{}");
return null; return null;
@ -73,7 +74,7 @@ public class MigrationEngine {
return null; return null;
} }
LOGGER.debug("List of migrations:"); LOGGER.debug("List of migrations:");
for (final MigrationModel elem : data) { for (final Migration elem : data) {
LOGGER.debug(" - date={} name={} end={}", elem.updatedAt, elem.name, elem.terminated); LOGGER.debug(" - date={} name={} end={}", elem.updatedAt, elem.name, elem.terminated);
} }
return data.get(data.size() - 1); return data.get(data.size() - 1);
@ -83,7 +84,7 @@ public class MigrationEngine {
} }
return null; return null;
} }
/** /**
* Process the automatic migration of the system * Process the automatic migration of the system
* @param config SQL connection for the migration * @param config SQL connection for the migration
@ -92,7 +93,7 @@ public class MigrationEngine {
*/ */
public void migrate(final DBConfig config) throws InterruptedException, IOException { public void migrate(final DBConfig config) throws InterruptedException, IOException {
LOGGER.info("Execute migration ... [BEGIN]"); LOGGER.info("Execute migration ... [BEGIN]");
// STEP 1: Check the DB exist: // STEP 1: Check the DB exist:
LOGGER.info("Verify existance of '{}'", config.getDbName()); LOGGER.info("Verify existance of '{}'", config.getDbName());
boolean exist = DataAccess.isDBExist(config.getDbName()); boolean exist = DataAccess.isDBExist(config.getDbName());
@ -117,7 +118,7 @@ public class MigrationEngine {
// create the table: // create the table:
List<String> sqlQuery; List<String> sqlQuery;
try { try {
sqlQuery = DataFactory.createTable(MigrationModel.class, false); sqlQuery = DataFactory.createTable(Migration.class);
} catch (final Exception ex) { } catch (final Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
while (true) { while (true) {
@ -136,7 +137,7 @@ public class MigrationEngine {
} }
} }
} }
final MigrationModel currentVersion = getCurrentVersion(); final Migration currentVersion = getCurrentVersion();
List<MigrationInterface> toApply = new ArrayList<>(); List<MigrationInterface> toApply = new ArrayList<>();
if (currentVersion == null) { if (currentVersion == null) {
//This is a first migration //This is a first migration
@ -151,7 +152,8 @@ public class MigrationEngine {
} else { } else {
// we insert a placeholder to simulate all migration is well done. // we insert a placeholder to simulate all migration is well done.
final String placeholderName = this.datas.get(this.datas.size() - 1).getName(); final String placeholderName = this.datas.get(this.datas.size() - 1).getName();
MigrationModel migrationResult = new MigrationModel(); Migration migrationResult = new Migration();
migrationResult.id = 1000L;
migrationResult.name = placeholderName; migrationResult.name = placeholderName;
migrationResult.stepId = 0; migrationResult.stepId = 0;
migrationResult.terminated = true; migrationResult.terminated = true;
@ -195,12 +197,14 @@ public class MigrationEngine {
} }
LOGGER.info("Execute migration ... [ END ]"); LOGGER.info("Execute migration ... [ END ]");
} }
public void migrateSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) { public void migrateSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) {
LOGGER.info("Migrate: [{}/{}] {} [BEGIN]", id, count, elem.getName()); LOGGER.info("---------------------------------------------------------");
LOGGER.info("-- Migrate: [{}/{}] {} [BEGIN]", id, count, elem.getName());
LOGGER.info("---------------------------------------------------------");
final StringBuilder log = new StringBuilder(); final StringBuilder log = new StringBuilder();
log.append("Start migration"); log.append("Start migration\n");
MigrationModel migrationResult = new MigrationModel(); Migration migrationResult = new Migration();
migrationResult.name = elem.getName(); migrationResult.name = elem.getName();
migrationResult.stepId = 0; migrationResult.stepId = 0;
migrationResult.terminated = false; migrationResult.terminated = false;
@ -212,7 +216,7 @@ public class MigrationEngine {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
if (elem.applyMigration(entry, log, migrationResult)) { if (elem.applyMigration(entry, log, migrationResult)) {
migrationResult.terminated = true; migrationResult.terminated = true;
try { try {
@ -241,9 +245,9 @@ public class MigrationEngine {
} }
LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName()); LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName());
} }
public void revertTo(final DBEntry entry, final String migrationName) { public void revertTo(final DBEntry entry, final String migrationName) {
final MigrationModel currentVersion = getCurrentVersion(); final Migration currentVersion = getCurrentVersion();
final List<MigrationInterface> toApply = new ArrayList<>(); final List<MigrationInterface> toApply = new ArrayList<>();
boolean find = false; boolean find = false;
for (int iii = this.datas.size() - 1; iii >= 0; iii--) { for (int iii = this.datas.size() - 1; iii >= 0; iii--) {
@ -264,10 +268,10 @@ public class MigrationEngine {
revertSingle(entry, elem, id, count); revertSingle(entry, elem, id, count);
} }
} }
public void revertSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) { public void revertSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) {
LOGGER.info("Revert migration: {} [BEGIN]", elem.getName()); LOGGER.info("Revert migration: {} [BEGIN]", elem.getName());
LOGGER.info("Revert migration: {} [ END ]", elem.getName()); LOGGER.info("Revert migration: {} [ END ]", elem.getName());
} }
} }

View File

@ -1,6 +1,7 @@
package org.kar.archidata.migration; package org.kar.archidata.migration;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.db.DBEntry;
import org.kar.archidata.migration.model.Migration;
public interface MigrationInterface { public interface MigrationInterface {
/** /**
@ -16,7 +17,7 @@ public interface MigrationInterface {
* @param migration Migration post data on each step... * @param migration Migration post data on each step...
* @return true if migration is finished. * @return true if migration is finished.
*/ */
boolean applyMigration(DBEntry entry, StringBuilder log, MigrationModel model); boolean applyMigration(DBEntry entry, StringBuilder log, Migration model);
/** /**
* Remove a migration the system to the previous version. * Remove a migration the system to the previous version.

View File

@ -8,6 +8,7 @@ import java.util.List;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.db.DBEntry;
import org.kar.archidata.migration.model.Migration;
import org.kar.archidata.util.ConfigBaseVariable; import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -18,7 +19,7 @@ record Action(
public Action(final String action) { public Action(final String action) {
this(action, List.of()); this(action, List.of());
} }
public Action(final String action, final String filterDB) { public Action(final String action, final String filterDB) {
this(action, List.of(filterDB)); this(action, List.of(filterDB));
} }
@ -27,26 +28,26 @@ record Action(
public class MigrationSqlStep implements MigrationInterface { public class MigrationSqlStep implements MigrationInterface {
final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class); final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class);
private final List<Action> actions = new ArrayList<>(); private final List<Action> actions = new ArrayList<>();
@Override @Override
public String getName() { public String getName() {
return getClass().getCanonicalName(); return getClass().getCanonicalName();
} }
public void display() { public void display() {
for (int iii = 0; iii < this.actions.size(); iii++) { for (int iii = 0; iii < this.actions.size(); iii++) {
final Action action = this.actions.get(iii); final Action action = this.actions.get(iii);
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action()); LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action());
} }
} }
@Override @Override
public boolean applyMigration(final DBEntry entry, final StringBuilder log, final MigrationModel model) { public boolean applyMigration(final DBEntry entry, final StringBuilder log, final Migration model) {
for (int iii = 0; iii < this.actions.size(); iii++) { for (int iii = 0; iii < this.actions.size(); iii++) {
log.append("action [" + (iii + 1) + "/" + this.actions.size() + "]\n"); log.append("action [" + (iii + 1) + "/" + this.actions.size() + "]\n");
LOGGER.info(" >>>> SQL ACTION : {}/{}", iii + 1, this.actions.size()); LOGGER.info(" >>>> SQL ACTION : {}/{}", iii + 1, this.actions.size());
final Action action = this.actions.get(iii); final Action action = this.actions.get(iii);
LOGGER.info("SQL request: ```{}``` on '{}' current={}", action.action(), action.filterDB(), ConfigBaseVariable.getDBType()); LOGGER.info("SQL request: ```{}``` on '{}' current={}", action.action(), action.filterDB(), ConfigBaseVariable.getDBType());
log.append("SQL: " + action.action() + " on " + action.filterDB() + "\n"); log.append("SQL: " + action.action() + " on " + action.filterDB() + "\n");
boolean isValid = true; boolean isValid = true;
@ -97,30 +98,30 @@ public class MigrationSqlStep implements MigrationInterface {
} }
return true; return true;
} }
@Override @Override
public boolean revertMigration(final DBEntry entry, final StringBuilder log) { public boolean revertMigration(final DBEntry entry, final StringBuilder log) {
return false; return false;
} }
public void addAction(final String action) { public void addAction(final String action) {
this.actions.add(new Action(action)); this.actions.add(new Action(action));
} }
public void addAction(final String action, final String filterdBType) { public void addAction(final String action, final String filterdBType) {
this.actions.add(new Action(action, filterdBType)); this.actions.add(new Action(action, filterdBType));
} }
public void addClass(final Class<?> clazz) throws Exception { public void addClass(final Class<?> clazz) throws Exception {
final List<String> tmp = DataFactory.createTable(clazz, false); final List<String> tmp = DataFactory.createTable(clazz);
for (final String elem : tmp) { for (final String elem : tmp) {
this.actions.add(new Action(elem)); this.actions.add(new Action(elem));
} }
} }
@Override @Override
public int getNumberOfStep() { public int getNumberOfStep() {
return this.actions.size(); return this.actions.size();
} }
} }

View File

@ -1,4 +1,4 @@
package org.kar.archidata.migration; package org.kar.archidata.migration.model;
import org.kar.archidata.annotation.SQLComment; import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault; import org.kar.archidata.annotation.SQLDefault;
@ -16,7 +16,7 @@ import jakarta.persistence.Table;
@Table(name = "KAR_migration") @Table(name = "KAR_migration")
@SQLIfNotExists @SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class MigrationModel extends GenericDataSoftDelete { public class Migration extends GenericDataSoftDelete {
@SQLComment("Name of the migration") @SQLComment("Name of the migration")
@Column(length = 256) @Column(length = 256)
public String name; public String name;

View File

@ -0,0 +1,165 @@
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.GlobalConfiguration;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypeManyToManyRemote;
import test.kar.archidata.model.TypeManyToManyRoot;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestManyToMany {
final static private Logger LOGGER = LoggerFactory.getLogger(TestManyToMany.class);
@BeforeAll
public static void configureWebServer() throws Exception {
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();
}
@AfterAll
public static void removeDataBase() throws IOException {
LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
}
@Order(1)
@Test
public void testCreateTable() throws Exception {
final List<String> sqlCommand2 = DataFactory.createTable(TypeManyToManyRoot.class);
final List<String> sqlCommand = DataFactory.createTable(TypeManyToManyRemote.class);
sqlCommand.addAll(sqlCommand2);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
}
}
@Order(2)
@Test
public void testSimpleInsertAndRetieve() throws Exception {
final TypeManyToManyRoot test = new TypeManyToManyRoot();
test.otherData = "kjhlkjlkj";
final TypeManyToManyRoot insertedData = DataAccess.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);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.otherData);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertNull(retrieve.remote);
DataAccess.delete(TypeManyToManyRoot.class, insertedData.id);
}
@Order(3)
@Test
public void testSimpleInsertAndRetieveZZZ() throws Exception {
TypeManyToManyRemote remote = new TypeManyToManyRemote();
remote.data = "remote1";
final TypeManyToManyRemote insertedRemote1 = DataAccess.insert(remote);
Assertions.assertEquals(insertedRemote1.data, remote.data);
remote = new TypeManyToManyRemote();
remote.data = "remote2";
final TypeManyToManyRemote insertedRemote2 = DataAccess.insert(remote);
Assertions.assertEquals(insertedRemote2.data, remote.data);
final TypeManyToManyRoot test = new TypeManyToManyRoot();
test.otherData = "kjhlkjlkj";
final TypeManyToManyRoot insertedData = DataAccess.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);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.otherData);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
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);
retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.otherData);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertNotNull(retrieve.remote);
Assertions.assertEquals(retrieve.remote.size(), 2);
Assertions.assertEquals(retrieve.remote.get(0), insertedRemote1.id);
Assertions.assertEquals(retrieve.remote.get(1), insertedRemote2.id);
// Remove an element
int count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id);
Assertions.assertEquals(1, count);
retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.otherData);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertNotNull(retrieve.remote);
Assertions.assertEquals(retrieve.remote.size(), 1);
Assertions.assertEquals(retrieve.remote.get(0), insertedRemote2.id);
// Remove the second element
count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id);
Assertions.assertEquals(1, count);
retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.otherData);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertNull(retrieve.remote);
DataAccess.delete(TypeManyToManyRoot.class, insertedData.id);
}
}

View File

@ -0,0 +1,15 @@
package test.kar.archidata.model;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
public class TypeManyToManyRemote {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, unique = true)
public Long id = null;
public String data;
}

View File

@ -0,0 +1,22 @@
package test.kar.archidata.model;
import java.util.List;
import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
public class TypeManyToManyRoot {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, unique = true)
public Long id = null;
public String otherData;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = TypeManyToManyRemote.class)
public List<Long> remote;
}