[DEV] continue review integration JPA

This commit is contained in:
Edouard DUPIN 2023-10-23 00:36:04 +02:00
parent e64c70cd86
commit 9730b89b15
10 changed files with 446 additions and 128 deletions

View File

@ -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 {
}

View File

@ -7,12 +7,25 @@ import java.util.List;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.db.DBEntry;
import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
record Action(
String action,
List<String> 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 { public class MigrationSqlStep implements MigrationInterface {
final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class); final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class);
private final List<String> actions = new ArrayList<>(); private final List<Action> actions = new ArrayList<>();
@Override @Override
public String getName() { public String getName() {
@ -21,8 +34,8 @@ public class MigrationSqlStep implements MigrationInterface {
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 String action = this.actions.get(iii); final Action action = this.actions.get(iii);
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> \n{}", iii, this.actions.size(), action); 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++) { 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 String action = this.actions.get(iii); final Action action = this.actions.get(iii);
LOGGER.info("SQL request: ```{}```", action);
log.append("SQL: " + action + "\n"); 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 { try {
SqlWrapper.executeQuerry(action); SqlWrapper.executeQuerry(action.action());
} catch (SQLException | IOException ex) { } catch (SQLException | IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
LOGGER.info("SQL request ERROR: ", ex.getMessage()); LOGGER.info("SQL request ERROR: ", ex.getMessage());
@ -75,12 +103,18 @@ public class MigrationSqlStep implements MigrationInterface {
} }
public void addAction(final String action) { 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 { public void addClass(final Class<?> clazz) throws Exception {
final List<String> tmp = SqlWrapper.createTable(clazz, false); final List<String> tmp = SqlWrapper.createTable(clazz, false);
this.actions.addAll(tmp); for (String elem : tmp) {
this.actions.add(new Action(elem));
}
} }
@Override @Override

View File

@ -169,6 +169,27 @@ public class SqlWrapper {
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.
* @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<Long> getListOfIds(ResultSet rs, int iii, String separator) throws SQLException {
String trackString = rs.getString(iii);
if (rs.wasNull()) {
return null;
}
List<Long> 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 { public static String convertTypeInSQL(final Class<?> type) throws Exception {
if (!ConfigBaseVariable.getDBType().equals("sqlite")) { if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
if (type == Long.class || type == long.class) { if (type == Long.class || type == long.class) {
@ -212,10 +233,10 @@ public class SqlWrapper {
return "REAL"; return "REAL";
} }
if (type == Timestamp.class) { if (type == Timestamp.class) {
return "INTEGER"; return "DATETIME";
} }
if (type == Date.class) { if (type == Date.class) {
return "NUMERIC"; return "DATETIME";
} }
if (type == String.class) { if (type == String.class) {
return "text"; return "text";
@ -369,12 +390,27 @@ public class SqlWrapper {
field.setBoolean(data, tmp); field.setBoolean(data, tmp);
} }
} else if (type == Timestamp.class) { } else if (type == Timestamp.class) {
try {
final Timestamp tmp = rs.getTimestamp(index); final Timestamp tmp = rs.getTimestamp(index);
if (rs.wasNull()) { if (rs.wasNull()) {
field.set(data, null); field.set(data, null);
} else { } else {
field.set(data, tmp); 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) { } else if (type == Date.class) {
final Date tmp = rs.getDate(index); final Date tmp = rs.getDate(index);
if (rs.wasNull()) { if (rs.wasNull()) {
@ -853,7 +889,7 @@ public class SqlWrapper {
continue; continue;
} }
final SqlWrapperAddOn addOn = findAddOnforField(elem); final SqlWrapperAddOn addOn = findAddOnforField(elem);
if (addOn != null) { if (addOn != null && addOn.isExternal()) {
continue; continue;
} }
// TODO: Manage it with AddOn // TODO: Manage it with AddOn
@ -872,11 +908,14 @@ public class SqlWrapper {
querry.append(","); querry.append(",");
} }
querry.append(" "); querry.append(" ");
if (addOn != null) {
addOn.generateQuerry(tableName, elem, querry, name, count, options);
} else {
querry.append(tableName); querry.append(tableName);
querry.append("."); querry.append(".");
querry.append(name); querry.append(name);
} }
}
querry.append(" FROM `"); querry.append(" FROM `");
querry.append(tableName); querry.append(tableName);
querry.append("` "); querry.append("` ");
@ -906,7 +945,7 @@ public class SqlWrapper {
continue; continue;
} }
final SqlWrapperAddOn addOn = findAddOnforField(elem); final SqlWrapperAddOn addOn = findAddOnforField(elem);
if (addOn != null) { if (addOn != null && addOn.isExternal()) {
continue; continue;
} }
// TODO: Manage it with AddOn // TODO: Manage it with AddOn
@ -914,9 +953,14 @@ public class SqlWrapper {
if (!readAllfields && notRead) { if (!readAllfields && notRead) {
continue; continue;
} }
if (addOn != null) {
int nbRowRead = addOn.fillFromQuerry(rs, elem, data, count, options);
count += nbRowRead;
} else {
setValueFromDb(elem.getType(), data, count, elem, rs); setValueFromDb(elem.getType(), data, count, elem, rs);
count++; count++;
} }
}
final T out = (T) data; final T out = (T) data;
outs.add(out); outs.add(out);
} }
@ -1063,8 +1107,8 @@ public class SqlWrapper {
return createTable(clazz, true); return createTable(clazz, true);
} }
public static void createTablesSpecificType(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> ListOtherTables, final boolean createIfNotExist, public static void createTablesSpecificType(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preOtherTables, final List<String> postOtherTables,
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);
@ -1117,7 +1161,29 @@ public class SqlWrapper {
if (!ConfigBaseVariable.getDBType().equals("sqlite")) { if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP"); mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP");
mainTableBuilder.append("(3)"); 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(" "); mainTableBuilder.append(" ");
} }
} else { } else {
@ -1178,7 +1244,8 @@ public class SqlWrapper {
public static List<String> createTable(final Class<?> clazz, final boolean createDrop) throws Exception { public static List<String> createTable(final Class<?> clazz, final boolean createDrop) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz);
final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final List<String> outList = new ArrayList<>(); final List<String> preActionList = new ArrayList<>();
final List<String> postActionList = new ArrayList<>();
final StringBuilder out = new StringBuilder(); final StringBuilder out = new StringBuilder();
// Drop Table // Drop Table
if (createIfNotExist && createDrop) { if (createIfNotExist && createDrop) {
@ -1186,7 +1253,7 @@ public class SqlWrapper {
tableTmp.append("DROP TABLE IF EXISTS `"); tableTmp.append("DROP TABLE IF EXISTS `");
tableTmp.append(tableName); tableTmp.append(tableName);
tableTmp.append("`;"); tableTmp.append("`;");
outList.add(tableTmp.toString()); postActionList.add(tableTmp.toString());
} }
// create Table: // create Table:
out.append("CREATE TABLE `"); out.append("CREATE TABLE `");
@ -1212,13 +1279,13 @@ public class SqlWrapper {
final SqlWrapperAddOn addOn = findAddOnforField(elem); final SqlWrapperAddOn addOn = findAddOnforField(elem);
LOGGER.info("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType()); LOGGER.info("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType());
if (addOn != null) { if (addOn != null) {
addOn.createTables(tableName, elem, out, outList, createIfNotExist, createDrop, fieldId); addOn.createTables(tableName, elem, out, preActionList, postActionList, createIfNotExist, createDrop, fieldId);
} else { } 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()); 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 { } else {
LOGGER.info("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType()); 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++; fieldId++;
} }
@ -1237,8 +1304,9 @@ public class SqlWrapper {
out.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci"); out.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci");
} }
out.append(";"); out.append(";");
outList.add(out.toString()); preActionList.add(out.toString());
return outList; preActionList.addAll(postActionList);
return preActionList;
} }
} }

View File

@ -6,6 +6,8 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import jakarta.validation.constraints.NotNull;
public interface SqlWrapperAddOn { public interface SqlWrapperAddOn {
/** /**
* Get the Class of the declaration annotation * Get the Class of the declaration annotation
@ -27,17 +29,38 @@ public interface SqlWrapperAddOn {
*/ */
boolean isCompatibleField(Field elem); 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; int insertData(PreparedStatement ps, Object data, int iii) throws SQLException;
// External mean that the type of the object is absolutely not obvious... // External mean that the type of the object is absolutely not obvious...
boolean isExternal(); boolean isExternal();
int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List<StateLoad> 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; int fillFromQuerry(ResultSet rs, Field elem, Object data, int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException;
boolean canUpdate(); boolean canUpdate();
void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List<String> 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<String> preActionList, List<String> postActionList, boolean createIfNotExist, boolean createDrop, int fieldId)
throws Exception;
} }

View File

@ -1,5 +0,0 @@
package org.kar.archidata.sqlWrapper;
public enum StateLoad {
DISABLE, NORMAL, ARRAY
}

View File

@ -5,10 +5,7 @@ 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.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.kar.archidata.GlobalConfiguration; import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.annotation.AnnotationTools; 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;
import org.kar.archidata.sqlWrapper.SqlWrapper.ExceptionDBInterface; import org.kar.archidata.sqlWrapper.SqlWrapper.ExceptionDBInterface;
import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; import org.kar.archidata.sqlWrapper.SqlWrapperAddOn;
import org.kar.archidata.sqlWrapper.StateLoad;
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;
import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToMany;
import jakarta.validation.constraints.NotNull;
public class AddOnManyToMany implements SqlWrapperAddOn { public class AddOnManyToMany implements SqlWrapperAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class);
static final String SEPARATOR = "-";
/**
* Convert the list if external id in a string '-' separated
* @param ids List of value (null are removed)
* @return '-' string separated
*/
protected static String getStringOfIds(final List<Long> ids) {
final List<Long> tmp = new ArrayList<>(ids);
return tmp.stream().map(String::valueOf).collect(Collectors.joining("-"));
}
/**
* extract a list of "-" separated element from a SQL input data.
* @param rs Result Set of the BDD
* @param iii Id in the result set
* @return The list of Long value
* @throws SQLException if an error is generated in the sql request.
*/
protected static List<Long> getListOfIds(final ResultSet rs, final int iii) throws SQLException {
final String trackString = rs.getString(iii);
if (rs.wasNull()) {
return null;
}
final List<Long> out = new ArrayList<>();
final String[] elements = trackString.split("-");
for (final String elem : elements) {
final Long tmp = Long.parseLong(elem);
out.add(tmp);
}
return out;
}
@Override @Override
public Class<?> getAnnotationClass() { public Class<?> getAnnotationClass() {
@ -76,15 +43,7 @@ public class AddOnManyToMany implements SqlWrapperAddOn {
@Override @Override
public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException {
if (data == null) { return iii;
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<Long>) data);
ps.setString(iii++, dataTmp);
}
return iii++;
} }
@Override @Override
@ -94,19 +53,26 @@ public class AddOnManyToMany implements SqlWrapperAddOn {
} }
@Override @Override
public int generateQuerry(final String tableName, final Field elem, final StringBuilder querry, final String name, final List<StateLoad> autoClasify, QuerryOptions options) { 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) {
autoClasify.add(StateLoad.ARRAY);
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);
} }
final String tmpVariable = "tmp_" + Integer.toString(autoClasify.size()); 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(".");
querry.append(localName); 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(tableName);
querry.append("_link_"); querry.append("_link_");
querry.append(localName); querry.append(localName);
@ -139,7 +105,9 @@ public class AddOnManyToMany implements SqlWrapperAddOn {
@Override @Override
public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { 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<Long> idList = SqlWrapper.getListOfIds(rs, count, SEPARATOR);
elem.set(data, idList);
return 1;
} }
@Override @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 // 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> ListOtherTables, final boolean createIfNotExist, public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preActionList, List<String> postActionList,
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;
if (name.endsWith("s")) { if (name.endsWith("s")) {
@ -222,7 +190,7 @@ public class AddOnManyToMany implements SqlWrapperAddOn {
tableTmp.append("_link_"); tableTmp.append("_link_");
tableTmp.append(localName); tableTmp.append(localName);
tableTmp.append("`;"); tableTmp.append("`;");
ListOtherTables.add(tableTmp.toString()); postActionList.add(tableTmp.toString());
} }
final StringBuilder otherTable = new StringBuilder(); final StringBuilder otherTable = new StringBuilder();
otherTable.append("CREATE TABLE `"); 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(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n");
} }
otherTable.append(";"); otherTable.append(";");
ListOtherTables.add(otherTable.toString()); postActionList.add(otherTable.toString());
} }
} }

View File

@ -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<String> preActionList, List<String> 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());
}
}

View File

@ -12,11 +12,11 @@ import java.util.stream.Collectors;
import org.kar.archidata.sqlWrapper.QuerryOptions; import org.kar.archidata.sqlWrapper.QuerryOptions;
import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; import org.kar.archidata.sqlWrapper.SqlWrapperAddOn;
import org.kar.archidata.sqlWrapper.StateLoad;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.NotNull;
public class AddOnManyToOne implements SqlWrapperAddOn { public class AddOnManyToOne implements SqlWrapperAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class);
@ -93,8 +93,7 @@ public class AddOnManyToOne implements SqlWrapperAddOn {
} }
@Override @Override
public int generateQuerry(final String tableName, final Field elem, final StringBuilder querry, final String name, final List<StateLoad> autoClasify, QuerryOptions options) { public int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QuerryOptions options) {
autoClasify.add(StateLoad.NORMAL);
querry.append(" "); querry.append(" ");
querry.append(tableName); querry.append(tableName);
querry.append("."); 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 // 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> ListOtherTables, final boolean createIfNotExist, public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> preActionList, List<String> postActionList,
final boolean createDrop, final int fieldId) throws Exception { final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {
SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, ListOtherTables, createIfNotExist, createDrop, fieldId, Long.class); SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class);
} }
} }

View File

@ -13,12 +13,14 @@ import org.kar.archidata.annotation.addOn.SQLTableExternalForeinKeyAsList;
import org.kar.archidata.sqlWrapper.QuerryOptions; import org.kar.archidata.sqlWrapper.QuerryOptions;
import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; import org.kar.archidata.sqlWrapper.SqlWrapperAddOn;
import org.kar.archidata.sqlWrapper.StateLoad;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.validation.constraints.NotNull;
public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn { public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class);
static final String SEPARATOR = "-";
/** /**
* Convert the list if external id in a string '-' separated * Convert the list if external id in a string '-' separated
@ -30,28 +32,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn {
for (Long elem : ids) { for (Long elem : ids) {
tmp.add(elem); tmp.add(elem);
} }
return tmp.stream().map(x -> String.valueOf(x)).collect(Collectors.joining("-")); return tmp.stream().map(x -> String.valueOf(x)).collect(Collectors.joining(SEPARATOR));
}
/**
* extract a list of "-" separated element from a SQL input data.
* @param rs Result Set of the BDD
* @param iii Id in the result set
* @return The list of Long value
* @throws SQLException if an error is generated in the sql request.
*/
protected static List<Long> getListOfIds(ResultSet rs, int iii) throws SQLException {
String trackString = rs.getString(iii);
if (rs.wasNull()) {
return null;
}
List<Long> out = new ArrayList<>();
String[] elements = trackString.split("-");
for (String elem : elements) {
Long tmp = Long.parseLong(elem);
out.add(tmp);
}
return out;
} }
@Override @Override
@ -92,8 +73,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn {
} }
@Override @Override
public int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List<StateLoad> autoClasify, QuerryOptions options) { public int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QuerryOptions options) {
autoClasify.add(StateLoad.ARRAY);
querry.append(" "); querry.append(" ");
querry.append(tableName); querry.append(tableName);
querry.append("."); querry.append(".");
@ -103,7 +83,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn {
@Override @Override
public int fillFromQuerry(ResultSet rs, Field elem, Object data, int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { public int fillFromQuerry(ResultSet rs, Field elem, Object data, int count, QuerryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException {
List<Long> idList = getListOfIds(rs, count); List<Long> idList = SqlWrapper.getListOfIds(rs, count, SEPARATOR);
elem.set(data, idList); elem.set(data, idList);
return 1; return 1;
} }
@ -114,9 +94,10 @@ public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn {
} }
@Override @Override
public void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List<String> ListOtherTables, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception { public void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List<String> preActionList, List<String> postActionList, boolean createIfNotExist, boolean createDrop,
int fieldId) throws Exception {
// TODO Auto-generated method stub // 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);
} }
} }