diff --git a/pom.xml b/pom.xml index 9949de5..a799c1f 100644 --- a/pom.xml +++ b/pom.xml @@ -96,7 +96,7 @@ org.glassfish.jersey.test-framework.providers jersey-test-framework-provider-grizzly2 - test + test org.glassfish.jersey.media diff --git a/src/org/kar/archidata/annotation/addOn/DataAddOnManyToManyOrdered.java b/src/org/kar/archidata/annotation/addOn/DataAddOnManyToManyOrdered.java new file mode 100644 index 0000000..8a19385 --- /dev/null +++ b/src/org/kar/archidata/annotation/addOn/DataAddOnManyToManyOrdered.java @@ -0,0 +1,15 @@ +package org.kar.archidata.annotation.addOn; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.kar.archidata.annotation.DataAddOn; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@DataAddOn +public @interface DataAddOnManyToManyOrdered { + +} diff --git a/src/org/kar/archidata/migration/MigrationSqlStep.java b/src/org/kar/archidata/migration/MigrationSqlStep.java index 2ce21d4..2eb06ae 100644 --- a/src/org/kar/archidata/migration/MigrationSqlStep.java +++ b/src/org/kar/archidata/migration/MigrationSqlStep.java @@ -7,12 +7,25 @@ import java.util.List; import org.kar.archidata.db.DBEntry; import org.kar.archidata.sqlWrapper.SqlWrapper; +import org.kar.archidata.util.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +record Action( + String action, + List filterDB) { + public Action(String action) { + this(action, List.of()); + } + + public Action(String action, String filterDB) { + this(action, List.of(filterDB)); + } +} + public class MigrationSqlStep implements MigrationInterface { final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class); - private final List actions = new ArrayList<>(); + private final List actions = new ArrayList<>(); @Override public String getName() { @@ -21,8 +34,8 @@ public class MigrationSqlStep implements MigrationInterface { public void display() { for (int iii = 0; iii < this.actions.size(); iii++) { - final String action = this.actions.get(iii); - LOGGER.info(" >>>> SQL ACTION : {}/{} ==> \n{}", iii, this.actions.size(), action); + final Action action = this.actions.get(iii); + LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action()); } } @@ -31,11 +44,26 @@ public class MigrationSqlStep implements MigrationInterface { for (int iii = 0; iii < this.actions.size(); iii++) { log.append("action [" + (iii + 1) + "/" + this.actions.size() + "]\n"); LOGGER.info(" >>>> SQL ACTION : {}/{}", iii + 1, this.actions.size()); - final String action = this.actions.get(iii); - LOGGER.info("SQL request: ```{}```", action); - log.append("SQL: " + action + "\n"); + final Action action = this.actions.get(iii); + + LOGGER.info("SQL request: ```{}``` on '{}' current={}", action.action(), action.filterDB(), ConfigBaseVariable.getDBType()); + log.append("SQL: " + action.action() + " on " + action.filterDB() + "\n"); + boolean isValid = true; + if (action.filterDB() != null && action.filterDB().size() > 0) { + isValid = false; + for (String elem : action.filterDB()) { + if (ConfigBaseVariable.getDBType().equals(elem)) { + isValid = true; + } + } + } + if (!isValid) { + log.append("==> Skip (DB is not compatible: " + ConfigBaseVariable.getDBType() + ")\n"); + LOGGER.info(" >>>> SQL ACTION : {}/{} ==> SKIP", iii + 1, this.actions.size()); + continue; + } try { - SqlWrapper.executeQuerry(action); + SqlWrapper.executeQuerry(action.action()); } catch (SQLException | IOException ex) { ex.printStackTrace(); LOGGER.info("SQL request ERROR: ", ex.getMessage()); @@ -75,12 +103,18 @@ public class MigrationSqlStep implements MigrationInterface { } public void addAction(final String action) { - this.actions.add(action); + this.actions.add(new Action(action)); + } + + public void addAction(final String action, String filterdBType) { + this.actions.add(new Action(action, filterdBType)); } public void addClass(final Class clazz) throws Exception { final List tmp = SqlWrapper.createTable(clazz, false); - this.actions.addAll(tmp); + for (String elem : tmp) { + this.actions.add(new Action(elem)); + } } @Override diff --git a/src/org/kar/archidata/sqlWrapper/SqlWrapper.java b/src/org/kar/archidata/sqlWrapper/SqlWrapper.java index 7c2ca36..6dc3fd2 100644 --- a/src/org/kar/archidata/sqlWrapper/SqlWrapper.java +++ b/src/org/kar/archidata/sqlWrapper/SqlWrapper.java @@ -169,6 +169,27 @@ public class SqlWrapper { throw new InternalServerErrorException("Can Not manage the DB-access"); } + /** + * extract a list of "-" separated element from a SQL input data. + * @param rs Result Set of the BDD + * @param iii Id in the result set + * @return The list of Long value + * @throws SQLException if an error is generated in the sql request. + */ + public static List getListOfIds(ResultSet rs, int iii, String separator) throws SQLException { + String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + List out = new ArrayList<>(); + String[] elements = trackString.split("-"); + for (String elem : elements) { + Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + public static String convertTypeInSQL(final Class type) throws Exception { if (!ConfigBaseVariable.getDBType().equals("sqlite")) { if (type == Long.class || type == long.class) { @@ -212,10 +233,10 @@ public class SqlWrapper { return "REAL"; } if (type == Timestamp.class) { - return "INTEGER"; + return "DATETIME"; } if (type == Date.class) { - return "NUMERIC"; + return "DATETIME"; } if (type == String.class) { return "text"; @@ -369,11 +390,26 @@ public class SqlWrapper { field.setBoolean(data, tmp); } } else if (type == Timestamp.class) { - final Timestamp tmp = rs.getTimestamp(index); - if (rs.wasNull()) { - field.set(data, null); - } else { - field.set(data, tmp); + try { + final Timestamp tmp = rs.getTimestamp(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } catch (java.sql.SQLException ex) { + try { + final Date tmp = rs.getDate(index); + if (rs.wasNull()) { + + field.set(data, null); + } else { + field.set(data, new Timestamp(tmp.toInstant().toEpochMilli())); + } + } catch (java.sql.SQLException ex2) { + final String tmp = rs.getString(index); + LOGGER.error("plop {}", tmp); + } } } else if (type == Date.class) { final Date tmp = rs.getDate(index); @@ -853,7 +889,7 @@ public class SqlWrapper { continue; } final SqlWrapperAddOn addOn = findAddOnforField(elem); - if (addOn != null) { + if (addOn != null && addOn.isExternal()) { continue; } // TODO: Manage it with AddOn @@ -872,10 +908,13 @@ public class SqlWrapper { querry.append(","); } querry.append(" "); - querry.append(tableName); - querry.append("."); - - querry.append(name); + if (addOn != null) { + addOn.generateQuerry(tableName, elem, querry, name, count, options); + } else { + querry.append(tableName); + querry.append("."); + querry.append(name); + } } querry.append(" FROM `"); querry.append(tableName); @@ -906,7 +945,7 @@ public class SqlWrapper { continue; } final SqlWrapperAddOn addOn = findAddOnforField(elem); - if (addOn != null) { + if (addOn != null && addOn.isExternal()) { continue; } // TODO: Manage it with AddOn @@ -914,8 +953,13 @@ public class SqlWrapper { if (!readAllfields && notRead) { continue; } - setValueFromDb(elem.getType(), data, count, elem, rs); - count++; + if (addOn != null) { + int nbRowRead = addOn.fillFromQuerry(rs, elem, data, count, options); + count += nbRowRead; + } else { + setValueFromDb(elem.getType(), data, count, elem, rs); + count++; + } } final T out = (T) data; outs.add(out); @@ -1063,8 +1107,8 @@ public class SqlWrapper { return createTable(clazz, true); } - public static void createTablesSpecificType(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List ListOtherTables, final boolean createIfNotExist, - final boolean createDrop, final int fieldId, final Class classModel) throws Exception { + public static void createTablesSpecificType(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preOtherTables, final List postOtherTables, + final boolean createIfNotExist, final boolean createDrop, final int fieldId, final Class classModel) throws Exception { final String name = AnnotationTools.getFieldName(elem); final Integer limitSize = AnnotationTools.getLimitSize(elem); final boolean notNull = AnnotationTools.getNotNull(elem); @@ -1117,7 +1161,29 @@ public class SqlWrapper { if (!ConfigBaseVariable.getDBType().equals("sqlite")) { mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP"); mainTableBuilder.append("(3)"); + } else { + // TODO: add trigger: + /* + CREATE TRIGGER your_table_trig AFTER UPDATE ON your_table + BEGIN + update your_table SET updated_on = datetime('now') WHERE user_id = NEW.user_id; + END; + */ + StringBuilder triggerBuilder = new StringBuilder(); + triggerBuilder.append("CREATE TRIGGER "); + triggerBuilder.append(tableName); + triggerBuilder.append("_update_trigger AFTER UPDATE ON "); + triggerBuilder.append(tableName); + triggerBuilder.append(" \nBEGIN \n update "); + triggerBuilder.append(tableName); + triggerBuilder.append(" SET "); + triggerBuilder.append(name); + triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n"); + triggerBuilder.append("END;"); + + postOtherTables.add(triggerBuilder.toString()); } + mainTableBuilder.append(" "); } } else { @@ -1178,7 +1244,8 @@ public class SqlWrapper { public static List createTable(final Class clazz, final boolean createDrop) throws Exception { final String tableName = AnnotationTools.getTableName(clazz); final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - final List outList = new ArrayList<>(); + final List preActionList = new ArrayList<>(); + final List postActionList = new ArrayList<>(); final StringBuilder out = new StringBuilder(); // Drop Table if (createIfNotExist && createDrop) { @@ -1186,7 +1253,7 @@ public class SqlWrapper { tableTmp.append("DROP TABLE IF EXISTS `"); tableTmp.append(tableName); tableTmp.append("`;"); - outList.add(tableTmp.toString()); + postActionList.add(tableTmp.toString()); } // create Table: out.append("CREATE TABLE `"); @@ -1212,13 +1279,13 @@ public class SqlWrapper { final SqlWrapperAddOn addOn = findAddOnforField(elem); LOGGER.info("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType()); if (addOn != null) { - addOn.createTables(tableName, elem, out, outList, createIfNotExist, createDrop, fieldId); + addOn.createTables(tableName, elem, out, preActionList, postActionList, createIfNotExist, createDrop, fieldId); } else { throw new Exception("Element matked as add-on but add-on does not loaded: table:" + tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type=" + elem.getType()); } } else { LOGGER.info("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType()); - SqlWrapper.createTablesSpecificType(tableName, elem, out, outList, createIfNotExist, createDrop, fieldId, elem.getType()); + SqlWrapper.createTablesSpecificType(tableName, elem, out, preActionList, postActionList, createIfNotExist, createDrop, fieldId, elem.getType()); } fieldId++; } @@ -1237,8 +1304,9 @@ public class SqlWrapper { out.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci"); } out.append(";"); - outList.add(out.toString()); - return outList; + preActionList.add(out.toString()); + preActionList.addAll(postActionList); + return preActionList; } } \ No newline at end of file diff --git a/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java b/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java index a3803dc..b0bcf98 100644 --- a/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java +++ b/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java @@ -6,6 +6,8 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; +import jakarta.validation.constraints.NotNull; + public interface SqlWrapperAddOn { /** * Get the Class of the declaration annotation @@ -27,17 +29,38 @@ public interface SqlWrapperAddOn { */ boolean isCompatibleField(Field elem); + /** + * Insert data in the specific field (the field must be in the current db, otherwiise it does not work at all. + * @param ps DB statement interface. + * @param data The date to inject. + * @param iii The index of injection + * @return the new index of injection in case of multiple value management + * @throws SQLException + */ int insertData(PreparedStatement ps, Object data, int iii) throws SQLException; // External mean that the type of the object is absolutely not obvious... boolean isExternal(); - int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List autoClasify, QuerryOptions options); + int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QuerryOptions options); + // Return the number of colomn read int fillFromQuerry(ResultSet rs, Field elem, Object data, int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException; boolean canUpdate(); - void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List ListOtherTables, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception; + /** + * Create associated table of the specific element. + * @param tableName + * @param elem + * @param mainTableBuilder + * @param ListOtherTables + * @param createIfNotExist + * @param createDrop + * @param fieldId + * @throws Exception + */ + void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List preActionList, List postActionList, boolean createIfNotExist, boolean createDrop, int fieldId) + throws Exception; } diff --git a/src/org/kar/archidata/sqlWrapper/StateLoad.java b/src/org/kar/archidata/sqlWrapper/StateLoad.java deleted file mode 100644 index 08f6519..0000000 --- a/src/org/kar/archidata/sqlWrapper/StateLoad.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.kar.archidata.sqlWrapper; - -public enum StateLoad { - DISABLE, NORMAL, ARRAY -} \ No newline at end of file diff --git a/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToMany.java b/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToMany.java index 71c861e..60b099a 100644 --- a/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToMany.java +++ b/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToMany.java @@ -5,10 +5,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.sql.Types; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import org.kar.archidata.GlobalConfiguration; import org.kar.archidata.annotation.AnnotationTools; @@ -17,46 +14,16 @@ import org.kar.archidata.sqlWrapper.QuerryOptions; import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.sqlWrapper.SqlWrapper.ExceptionDBInterface; import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; -import org.kar.archidata.sqlWrapper.StateLoad; import org.kar.archidata.util.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jakarta.persistence.ManyToMany; +import jakarta.validation.constraints.NotNull; public class AddOnManyToMany implements SqlWrapperAddOn { static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); - - /** - * Convert the list if external id in a string '-' separated - * @param ids List of value (null are removed) - * @return '-' string separated - */ - protected static String getStringOfIds(final List ids) { - final List tmp = new ArrayList<>(ids); - return tmp.stream().map(String::valueOf).collect(Collectors.joining("-")); - } - - /** - * extract a list of "-" separated element from a SQL input data. - * @param rs Result Set of the BDD - * @param iii Id in the result set - * @return The list of Long value - * @throws SQLException if an error is generated in the sql request. - */ - protected static List getListOfIds(final ResultSet rs, final int iii) throws SQLException { - final String trackString = rs.getString(iii); - if (rs.wasNull()) { - return null; - } - final List out = new ArrayList<>(); - final String[] elements = trackString.split("-"); - for (final String elem : elements) { - final Long tmp = Long.parseLong(elem); - out.add(tmp); - } - return out; - } + static final String SEPARATOR = "-"; @Override public Class getAnnotationClass() { @@ -76,15 +43,7 @@ public class AddOnManyToMany implements SqlWrapperAddOn { @Override public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { - if (data == null) { - ps.setNull(iii++, Types.BIGINT); - } else { - // TODO: we must check if the model of data in a list of Long ... !!!! - @SuppressWarnings("unchecked") - final String dataTmp = getStringOfIds((List) data); - ps.setString(iii++, dataTmp); - } - return iii++; + return iii; } @Override @@ -94,19 +53,26 @@ public class AddOnManyToMany implements SqlWrapperAddOn { } @Override - public int generateQuerry(final String tableName, final Field elem, final StringBuilder querry, final String name, final List autoClasify, QuerryOptions options) { - - autoClasify.add(StateLoad.ARRAY); + public int generateQuerry(@NotNull final String tableName, @NotNull final Field elem, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount, + QuerryOptions options) { String localName = name; if (name.endsWith("s")) { localName = name.substring(0, name.length() - 1); } - final String tmpVariable = "tmp_" + Integer.toString(autoClasify.size()); + final String tmpVariable = "tmp_" + Integer.toString(elemCount); querry.append(" (SELECT GROUP_CONCAT("); querry.append(tmpVariable); querry.append("."); querry.append(localName); - querry.append("_id SEPARATOR '-') FROM "); + querry.append("_id "); + if (ConfigBaseVariable.getDBType().equals("sqlite")) { + querry.append(", "); + } else { + querry.append("SEPARATOR "); + } + querry.append("'"); + querry.append(SEPARATOR); + querry.append("') FROM "); querry.append(tableName); querry.append("_link_"); querry.append(localName); @@ -139,7 +105,9 @@ public class AddOnManyToMany implements SqlWrapperAddOn { @Override public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { - throw new IllegalAccessException("This Add-on has not the capability to insert data directly in DB"); + List idList = SqlWrapper.getListOfIds(rs, count, SEPARATOR); + elem.set(data, idList); + return 1; } @Override @@ -208,8 +176,8 @@ public class AddOnManyToMany implements SqlWrapperAddOn { // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system @Override - public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List ListOtherTables, final boolean createIfNotExist, - final boolean createDrop, final int fieldId) throws Exception { + public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preActionList, List postActionList, + final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { final String name = AnnotationTools.getFieldName(elem); String localName = name; if (name.endsWith("s")) { @@ -222,7 +190,7 @@ public class AddOnManyToMany implements SqlWrapperAddOn { tableTmp.append("_link_"); tableTmp.append(localName); tableTmp.append("`;"); - ListOtherTables.add(tableTmp.toString()); + postActionList.add(tableTmp.toString()); } final StringBuilder otherTable = new StringBuilder(); otherTable.append("CREATE TABLE `"); @@ -263,6 +231,6 @@ public class AddOnManyToMany implements SqlWrapperAddOn { otherTable.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n"); } otherTable.append(";"); - ListOtherTables.add(otherTable.toString()); + postActionList.add(otherTable.toString()); } } diff --git a/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToManyOrdered.java b/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToManyOrdered.java new file mode 100644 index 0000000..14000fc --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToManyOrdered.java @@ -0,0 +1,235 @@ +package org.kar.archidata.sqlWrapper.addOn; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; + +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.annotation.addOn.DataAddOnManyToManyOrdered; +import org.kar.archidata.db.DBEntry; +import org.kar.archidata.sqlWrapper.QuerryOptions; +import org.kar.archidata.sqlWrapper.SqlWrapper; +import org.kar.archidata.sqlWrapper.SqlWrapper.ExceptionDBInterface; +import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; +import org.kar.archidata.util.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.validation.constraints.NotNull; + +/** + * Manage the decorator element @DataAddOnManyToManyOrdered to be injected in the DB. + * The objective of this table is to manage a link between 2 table that have a specific order (Only work in 1 direction) + */ +public class AddOnManyToManyOrdered implements SqlWrapperAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToManyOrdered.class); + static final String SEPARATOR = "-"; + + @Override + public Class getAnnotationClass() { + return DataAddOnManyToManyOrdered.class; + } + + @Override + public String getSQLFieldType(final Field elem) { + return null; + } + + @Override + public boolean isCompatibleField(final Field elem) { + final DataAddOnManyToManyOrdered decorators = elem.getDeclaredAnnotation(DataAddOnManyToManyOrdered.class); + return decorators != null; + } + + @Override + public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { + return iii; + } + + @Override + public boolean isExternal() { + // TODO Auto-generated method stub + return false; + } + + @Override + public int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QuerryOptions options) { + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length() - 1); + } + final String tmpVariable = "tmp_" + Integer.toString(elemCount); + querry.append(" (SELECT GROUP_CONCAT("); + querry.append(tmpVariable); + querry.append("."); + querry.append(localName); + querry.append("_id "); + if (ConfigBaseVariable.getDBType().equals("sqlite")) { + querry.append(", "); + } else { + querry.append("SEPARATOR "); + } + querry.append("'"); + querry.append(SEPARATOR); + querry.append("') FROM "); + querry.append(tableName); + querry.append("_link_"); + querry.append(localName); + querry.append(" "); + querry.append(tmpVariable); + querry.append(" WHERE "); + querry.append(tmpVariable); + querry.append(".deleted = false AND "); + querry.append(tableName); + querry.append(".id = "); + querry.append(tmpVariable); + querry.append("."); + querry.append(tableName); + querry.append("_id ORDER BY "); + querry.append(tmpVariable); + querry.append(".order ASC"); + querry.append(" GROUP BY "); + querry.append(tmpVariable); + querry.append("."); + querry.append(tableName); + querry.append("_id ) AS "); + querry.append(name); + querry.append(" "); + return 1; + } + + @Override + public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { + //throw new IllegalAccessException("This Add-on has not the capability to insert data directly in DB"); + return 0; + } + + @Override + public boolean canUpdate() { + return false; + } + + public static void addLink(final Class clazz, final long localKey, final String table, final long remoteKey) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + long uniqueSQLID = -1; + // real add in the BDD: + try { + // prepare the request: + final String querry = "INSERT INTO " + tableName + "_link_" + table + " (create_date, modify_date, " + tableName + "_id, " + table + "_id)" + " VALUES (" + SqlWrapper.getDBNow() + ", " + + SqlWrapper.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 { + final String tableName = AnnotationTools.getTableName(clazz); + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final String querry = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=" + SqlWrapper.getDBNow() + ", `deleted`=true WHERE `" + tableName + "_id` = ? AND `" + table + + "_id` = ?"; + try { + 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 + public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preActionList, List postActionList, + final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { + final String name = AnnotationTools.getFieldName(elem); + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length() - 1); + } + 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`order` INTEGER NOT NULL DEFAULT 0,\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()); + } +} diff --git a/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToOne.java b/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToOne.java index 7cd57a3..76e58da 100644 --- a/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToOne.java +++ b/src/org/kar/archidata/sqlWrapper/addOn/AddOnManyToOne.java @@ -12,11 +12,11 @@ import java.util.stream.Collectors; import org.kar.archidata.sqlWrapper.QuerryOptions; import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; -import org.kar.archidata.sqlWrapper.StateLoad; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jakarta.persistence.ManyToOne; +import jakarta.validation.constraints.NotNull; public class AddOnManyToOne implements SqlWrapperAddOn { static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); @@ -93,8 +93,7 @@ public class AddOnManyToOne implements SqlWrapperAddOn { } @Override - public int generateQuerry(final String tableName, final Field elem, final StringBuilder querry, final String name, final List autoClasify, QuerryOptions options) { - autoClasify.add(StateLoad.NORMAL); + public int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QuerryOptions options) { querry.append(" "); querry.append(tableName); querry.append("."); @@ -119,8 +118,8 @@ public class AddOnManyToOne implements SqlWrapperAddOn { // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system @Override - public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List ListOtherTables, final boolean createIfNotExist, - final boolean createDrop, final int fieldId) throws Exception { - SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, ListOtherTables, createIfNotExist, createDrop, fieldId, Long.class); + public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preActionList, List postActionList, + final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { + SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class); } } diff --git a/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalForeinKeyAsList.java b/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalForeinKeyAsList.java index 0493226..f17c5da 100644 --- a/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalForeinKeyAsList.java +++ b/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalForeinKeyAsList.java @@ -13,12 +13,14 @@ import org.kar.archidata.annotation.addOn.SQLTableExternalForeinKeyAsList; import org.kar.archidata.sqlWrapper.QuerryOptions; import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; -import org.kar.archidata.sqlWrapper.StateLoad; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.validation.constraints.NotNull; + public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn { static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); + static final String SEPARATOR = "-"; /** * Convert the list if external id in a string '-' separated @@ -30,28 +32,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn { for (Long elem : ids) { tmp.add(elem); } - return tmp.stream().map(x -> String.valueOf(x)).collect(Collectors.joining("-")); - } - - /** - * extract a list of "-" separated element from a SQL input data. - * @param rs Result Set of the BDD - * @param iii Id in the result set - * @return The list of Long value - * @throws SQLException if an error is generated in the sql request. - */ - protected static List getListOfIds(ResultSet rs, int iii) throws SQLException { - String trackString = rs.getString(iii); - if (rs.wasNull()) { - return null; - } - List out = new ArrayList<>(); - String[] elements = trackString.split("-"); - for (String elem : elements) { - Long tmp = Long.parseLong(elem); - out.add(tmp); - } - return out; + return tmp.stream().map(x -> String.valueOf(x)).collect(Collectors.joining(SEPARATOR)); } @Override @@ -92,8 +73,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn { } @Override - public int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List autoClasify, QuerryOptions options) { - autoClasify.add(StateLoad.ARRAY); + public int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QuerryOptions options) { querry.append(" "); querry.append(tableName); querry.append("."); @@ -103,7 +83,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn { @Override public int fillFromQuerry(ResultSet rs, Field elem, Object data, int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { - List idList = getListOfIds(rs, count); + List idList = SqlWrapper.getListOfIds(rs, count, SEPARATOR); elem.set(data, idList); return 1; } @@ -114,9 +94,10 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn { } @Override - public void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List ListOtherTables, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception { + public void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List preActionList, List postActionList, boolean createIfNotExist, boolean createDrop, + int fieldId) throws Exception { // TODO Auto-generated method stub - SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, ListOtherTables, createIfNotExist, createDrop, fieldId, String.class); + SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, String.class); } }