[DEV] add sub-element with object and serialization as json

This commit is contained in:
Edouard DUPIN 2023-11-03 22:45:28 +01:00
parent bc5c37e02a
commit f69bc8097a
37 changed files with 871 additions and 699 deletions

View File

@ -47,25 +47,25 @@ public class AnnotationTools {
}
public static String getComment(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLComment.class);
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataComment.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @SQLComment on " + element.getClass().getCanonicalName());
}
return ((SQLComment) annotation[0]).value();
return ((DataComment) annotation[0]).value();
}
public static String getDefault(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLDefault.class);
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataDefault.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @SQLDefault on " + element.getClass().getCanonicalName());
}
return ((SQLDefault) annotation[0]).value();
return ((DataDefault) annotation[0]).value();
}
public static Integer getLimitSize(final Field element) throws Exception {
@ -151,7 +151,7 @@ public class AnnotationTools {
}
public static boolean isDeletedField(final Field element) throws Exception {
return element.getDeclaredAnnotationsByType(SQLDeleted.class).length != 0;
return element.getDeclaredAnnotationsByType(DataDeleted.class).length != 0;
}
public static boolean isCreatedAtField(final Field element) throws Exception {
@ -163,7 +163,7 @@ public class AnnotationTools {
}
public static boolean isdefaultNotRead(final Field element) throws Exception {
return element.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0;
return element.getDeclaredAnnotationsByType(DataNotRead.class).length != 0;
}
public static boolean isIdField(final Field element) throws Exception {

View File

@ -7,7 +7,7 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLComment {
public @interface DataComment {
String value();

View File

@ -7,7 +7,7 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLDefault {
public @interface DataDefault {
String value();

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLNotRead {
public @interface DataDeleted {
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLIfNotExists {
public @interface DataIfNotExists {
}

View File

@ -5,8 +5,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.ANNOTATION_TYPE)
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DataAddOn {
}
public @interface DataJson {}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLDeleted {
public @interface DataNotRead {
}

View File

@ -1,15 +0,0 @@
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

@ -5,11 +5,8 @@ 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 SQLTableExternalForeinKeyAsList {
}

View File

@ -0,0 +1,17 @@
package org.kar.archidata.dataAccess;
public class CountInOut {
public int value = 0;
public CountInOut() {
// TODO Auto-generated constructor stub
}
public CountInOut(final int i) {
this.value = i;
}
public void inc() {
this.value++;
}
}

View File

@ -19,9 +19,9 @@ import java.util.List;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.DataAddOn;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOn.AddOnManyToOne;
import org.kar.archidata.dataAccess.addOn.AddOnSQLTableExternalForeinKeyAsList;
@ -33,8 +33,6 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.ws.rs.InternalServerErrorException;
public class DataAccess {
@ -45,6 +43,7 @@ public class DataAccess {
addOn.add(new AddOnManyToMany());
addOn.add(new AddOnManyToOne());
addOn.add(new AddOnSQLTableExternalForeinKeyAsList());
addOn.add(new AddOnDataJson());
}
public static void addAddOn(final DataAccessAddOn addOn) {
@ -183,223 +182,240 @@ public class DataAccess {
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, final CountInOut iii, final Field field, final PreparedStatement ps) throws Exception {
if (type == Long.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.BIGINT);
ps.setNull(iii.value, Types.BIGINT);
} else {
ps.setLong(index++, (Long) tmp);
ps.setLong(iii.value, (Long) tmp);
}
} else if (type == long.class) {
ps.setLong(index++, field.getLong(data));
ps.setLong(iii.value, field.getLong(data));
} else if (type == Integer.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.INTEGER);
ps.setNull(iii.value, Types.INTEGER);
} else {
ps.setInt(index++, (Integer) tmp);
ps.setInt(iii.value, (Integer) tmp);
}
} else if (type == int.class) {
ps.setInt(index++, field.getInt(data));
ps.setInt(iii.value, field.getInt(data));
} else if (type == Float.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.FLOAT);
ps.setNull(iii.value, Types.FLOAT);
} else {
ps.setFloat(index++, (Float) tmp);
ps.setFloat(iii.value, (Float) tmp);
}
} else if (type == float.class) {
ps.setFloat(index++, field.getFloat(data));
ps.setFloat(iii.value, field.getFloat(data));
} else if (type == Double.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.DOUBLE);
ps.setNull(iii.value, Types.DOUBLE);
} else {
ps.setDouble(index++, (Double) tmp);
ps.setDouble(iii.value, (Double) tmp);
}
} else if (type == Double.class) {
ps.setDouble(index++, field.getDouble(data));
ps.setDouble(iii.value, field.getDouble(data));
} else if (type == Boolean.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.INTEGER);
ps.setNull(iii.value, Types.INTEGER);
} else {
ps.setBoolean(index++, (Boolean) tmp);
ps.setBoolean(iii.value, (Boolean) tmp);
}
} else if (type == boolean.class) {
ps.setBoolean(index++, field.getBoolean(data));
ps.setBoolean(iii.value, field.getBoolean(data));
} else if (type == Timestamp.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.INTEGER);
ps.setNull(iii.value, Types.INTEGER);
} else {
ps.setTimestamp(index++, (Timestamp) tmp);
ps.setTimestamp(iii.value, (Timestamp) tmp);
}
} else if (type == Date.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.INTEGER);
ps.setNull(iii.value, Types.INTEGER);
} else {
final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant());
ps.setTimestamp(index++, sqlDate);
ps.setTimestamp(iii.value, sqlDate);
}
} else if (type == LocalDate.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.INTEGER);
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Date sqlDate = java.sql.Date.valueOf((LocalDate) tmp);
ps.setDate(index++, sqlDate);
ps.setDate(iii.value, sqlDate);
}
} else if (type == LocalTime.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.INTEGER);
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Time sqlDate = java.sql.Time.valueOf((LocalTime) tmp);
ps.setTime(index++, sqlDate);
ps.setTime(iii.value, sqlDate);
}
} else if (type == String.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.VARCHAR);
ps.setNull(iii.value, Types.VARCHAR);
} else {
ps.setString(index++, (String) tmp);
ps.setString(iii.value, (String) tmp);
}
} else if (type.isEnum()) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(index++, Types.VARCHAR);
ps.setNull(iii.value, Types.VARCHAR);
} else {
ps.setString(index++, tmp.toString());
ps.setString(iii.value, tmp.toString());
}
} else {
throw new Exception("Unknown Field Type");
}
iii.inc();
}
// 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 Object data, final CountInOut count, final Field field, final ResultSet rs, final CountInOut countNotNull) throws Exception {
if (type == Long.class) {
final Long tmp = rs.getLong(index);
final Long tmp = rs.getLong(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
//logger.debug(" ==> {}", tmp);
field.set(data, tmp);
countNotNull.inc();
}
} else if (type == long.class) {
final Long tmp = rs.getLong(index);
final Long tmp = rs.getLong(count.value);
if (rs.wasNull()) {
//field.set(data, null);
} else {
field.setLong(data, tmp);
countNotNull.inc();
}
} else if (type == Integer.class) {
final Integer tmp = rs.getInt(index);
final Integer tmp = rs.getInt(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp);
countNotNull.inc();
}
} else if (type == int.class) {
final Integer tmp = rs.getInt(index);
final Integer tmp = rs.getInt(count.value);
if (rs.wasNull()) {
//field.set(data, null);
} else {
field.setInt(data, tmp);
countNotNull.inc();
}
} else if (type == Float.class) {
final Float tmp = rs.getFloat(index);
final Float tmp = rs.getFloat(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp);
countNotNull.inc();
}
} else if (type == float.class) {
final Float tmp = rs.getFloat(index);
final Float tmp = rs.getFloat(count.value);
if (rs.wasNull()) {
//field.set(data, null);
} else {
field.setFloat(data, tmp);
countNotNull.inc();
}
} else if (type == Double.class) {
final Double tmp = rs.getDouble(index);
final Double tmp = rs.getDouble(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp);
countNotNull.inc();
}
} else if (type == double.class) {
final Double tmp = rs.getDouble(index);
final Double tmp = rs.getDouble(count.value);
if (rs.wasNull()) {
//field.set(data, null);
} else {
field.setDouble(data, tmp);
countNotNull.inc();
}
} else if (type == Boolean.class) {
final Boolean tmp = rs.getBoolean(index);
final Boolean tmp = rs.getBoolean(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp);
countNotNull.inc();
}
} else if (type == boolean.class) {
final Boolean tmp = rs.getBoolean(index);
final Boolean tmp = rs.getBoolean(count.value);
if (rs.wasNull()) {
//field.set(data, null);
} else {
field.setBoolean(data, tmp);
countNotNull.inc();
}
} else if (type == Timestamp.class) {
final Timestamp tmp = rs.getTimestamp(index);
final Timestamp tmp = rs.getTimestamp(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp);
countNotNull.inc();
}
} else if (type == Date.class) {
try {
final Timestamp tmp = rs.getTimestamp(index);
final Timestamp tmp = rs.getTimestamp(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, Date.from(tmp.toInstant()));
countNotNull.inc();
}
} catch (final SQLException ex) {
final String tmp = rs.getString(index);
final String tmp = rs.getString(count.value);
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));
countNotNull.inc();
}
}
} else if (type == LocalDate.class) {
final java.sql.Date tmp = rs.getDate(index);
final java.sql.Date tmp = rs.getDate(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp.toLocalDate());
countNotNull.inc();
}
} else if (type == LocalTime.class) {
final java.sql.Time tmp = rs.getTime(index);
final java.sql.Time tmp = rs.getTime(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp.toLocalTime());
countNotNull.inc();
}
} else if (type == String.class) {
final String tmp = rs.getString(index);
final String tmp = rs.getString(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, tmp);
countNotNull.inc();
}
} else if (type.isEnum()) {
final String tmp = rs.getString(index);
final String tmp = rs.getString(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
@ -407,6 +423,7 @@ public class DataAccess {
for (final Object elem : arr) {
if (elem.toString().equals(tmp)) {
field.set(data, elem);
countNotNull.inc();
break;
}
}
@ -415,21 +432,11 @@ public class DataAccess {
} else {
throw new Exception("Unknown Field Type");
}
count.inc();
}
public static boolean isAddOnField(final Field field) {
final boolean ret = AnnotationTools.isAnnotationGroup(field, DataAddOn.class);
if (ret) {
return true;
}
// The specific element of the JPA manage fy generic add-on system:
if (field.getDeclaredAnnotationsByType(ManyToMany.class).length != 0) {
return true;
}
if (field.getDeclaredAnnotationsByType(ManyToOne.class).length != 0) {
return true;
}
return ret;
return findAddOnforField(field) != null;
}
public static DataAccessAddOn findAddOnforField(final Field field) {
@ -453,10 +460,10 @@ public class DataAccess {
try {
final String tableName = AnnotationTools.getTableName(clazz, options);
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final StringBuilder querry = new StringBuilder();
querry.append("INSERT INTO `");
querry.append(tableName);
querry.append("` (");
final StringBuilder query = new StringBuilder();
query.append("INSERT INTO `");
query.append(tableName);
query.append("` (");
boolean firstField = true;
int count = 0;
@ -482,7 +489,7 @@ public class DataAccess {
}
if (!elem.getClass().isPrimitive()) {
final Object tmp = elem.get(data);
if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) {
if (tmp == null && elem.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
continue;
}
}
@ -491,28 +498,28 @@ public class DataAccess {
if (firstField) {
firstField = false;
} else {
querry.append(",");
query.append(",");
}
querry.append(" `");
querry.append(name);
querry.append("`");
query.append(" `");
query.append(name);
query.append("`");
}
firstField = true;
querry.append(") VALUES (");
query.append(") VALUES (");
for (int iii = 0; iii < count; iii++) {
if (firstField) {
firstField = false;
} else {
querry.append(",");
query.append(",");
}
querry.append("?");
query.append("?");
}
querry.append(")");
LOGGER.warn("generate the querry: '{}'", querry.toString());
query.append(")");
LOGGER.warn("generate the query: '{}'", query.toString());
// prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS);
final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
Field primaryKeyField = null;
int iii = 1;
final CountInOut iii = new CountInOut(1);
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
@ -536,17 +543,17 @@ public class DataAccess {
}
if (addOn != null) {
// Add-on specific insertion.
iii = addOn.insertData(ps, elem, data, iii);
addOn.insertData(ps, elem, data, iii);
} else {
// Generic class insertion...
final Class<?> type = elem.getType();
if (!type.isPrimitive()) {
final Object tmp = elem.get(data);
if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) {
if (tmp == null && elem.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
continue;
}
}
setValuedb(type, data, iii++, elem, ps);
setValuedb(type, data, iii, elem, ps);
}
count++;
}
@ -674,10 +681,10 @@ public class DataAccess {
try {
final String tableName = AnnotationTools.getTableName(clazz, options);
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final StringBuilder querry = new StringBuilder();
querry.append("UPDATE `");
querry.append(tableName);
querry.append("` SET ");
final StringBuilder query = new StringBuilder();
query.append("UPDATE `");
query.append(tableName);
query.append("` SET ");
boolean firstField = true;
for (final Field field : clazz.getFields()) {
@ -699,27 +706,27 @@ public class DataAccess {
}
if (!field.getClass().isPrimitive()) {
final Object tmp = field.get(data);
if (tmp == null && field.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) {
if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
continue;
}
}
if (firstField) {
firstField = false;
} else {
querry.append(",");
query.append(",");
}
querry.append(" `");
querry.append(name);
querry.append("` = ? ");
query.append(" `");
query.append(name);
query.append("` = ? ");
}
querry.append(" ");
query.append(" ");
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
whereAppendQuery(querry, tableName, condition, null, deletedFieldName);
whereAppendQuery(query, tableName, condition, null, deletedFieldName);
firstField = true;
LOGGER.debug("generate the querry: '{}'", querry.toString());
LOGGER.debug("generate the query: '{}'", query.toString());
// prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS);
int iii = 1;
final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
final CountInOut iii = new CountInOut(1);
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@ -741,16 +748,16 @@ public class DataAccess {
final Class<?> type = field.getType();
if (!type.isPrimitive()) {
final Object tmp = field.get(data);
if (tmp == null && field.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) {
if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
continue;
}
}
setValuedb(type, data, iii++, field, ps);
setValuedb(type, data, iii, field, ps);
} else {
iii = addOn.insertData(ps, field, data, iii);
addOn.insertData(ps, field, data, iii);
}
}
iii = whereInjectValue(ps, condition, iii);
whereInjectValue(ps, condition, iii);
return ps.executeUpdate();
} catch (final SQLException ex) {
@ -762,41 +769,41 @@ public class DataAccess {
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 CountInOut iii) throws Exception {
if (value instanceof final Long tmp) {
ps.setLong(iii, tmp);
ps.setLong(iii.value, tmp);
} else if (value instanceof final Integer tmp) {
ps.setInt(iii, tmp);
ps.setInt(iii.value, tmp);
} else if (value instanceof final String tmp) {
ps.setString(iii, tmp);
ps.setString(iii.value, tmp);
} else if (value instanceof final Short tmp) {
ps.setShort(iii, tmp);
ps.setShort(iii.value, tmp);
} else if (value instanceof final Byte tmp) {
ps.setByte(iii, tmp);
ps.setByte(iii.value, tmp);
} else if (value instanceof final Float tmp) {
ps.setFloat(iii, tmp);
ps.setFloat(iii.value, tmp);
} else if (value instanceof final Double tmp) {
ps.setDouble(iii, tmp);
ps.setDouble(iii.value, tmp);
} else if (value instanceof final Boolean tmp) {
ps.setBoolean(iii, tmp);
ps.setBoolean(iii.value, tmp);
} else if (value instanceof final Boolean tmp) {
ps.setBoolean(iii, tmp);
ps.setBoolean(iii.value, tmp);
} else if (value instanceof final Timestamp tmp) {
ps.setTimestamp(iii, tmp);
ps.setTimestamp(iii.value, tmp);
} else if (value instanceof final Date tmp) {
ps.setTimestamp(iii, java.sql.Timestamp.from((tmp).toInstant()));
ps.setTimestamp(iii.value, java.sql.Timestamp.from((tmp).toInstant()));
} else if (value instanceof final LocalDate tmp) {
ps.setDate(iii, java.sql.Date.valueOf(tmp));
ps.setDate(iii.value, java.sql.Date.valueOf(tmp));
} else if (value instanceof final LocalTime tmp) {
ps.setTime(iii, java.sql.Time.valueOf(tmp));
ps.setTime(iii.value, java.sql.Time.valueOf(tmp));
} else if (value.getClass().isEnum()) {
ps.setString(iii, value.toString());
ps.setString(iii.value, value.toString());
} else {
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 query, final String tableName, final QueryItem condition, final QueryOptions options, final String deletedFieldName)
throws ExceptionDBInterface {
boolean exclude_deleted = true;
if (options != null) {
@ -810,54 +817,52 @@ public class DataAccess {
// Check if we have a condition to generate
if (condition == null) {
if (exclude_deleted && deletedFieldName != null) {
querry.append(" WHERE ");
querry.append(tableName);
querry.append(".");
querry.append(deletedFieldName);
querry.append(" = false ");
query.append(" WHERE ");
query.append(tableName);
query.append(".");
query.append(deletedFieldName);
query.append(" = false ");
}
return;
}
querry.append(" WHERE (");
condition.generateQuerry(querry, tableName);
query.append(" WHERE (");
condition.generateQuerry(query, tableName);
querry.append(") ");
query.append(") ");
if (exclude_deleted && deletedFieldName != null) {
querry.append("AND ");
querry.append(tableName);
querry.append(".");
querry.append(deletedFieldName);
querry.append(" = false ");
query.append("AND ");
query.append(tableName);
query.append(".");
query.append(deletedFieldName);
query.append(" = false ");
}
}
public static int whereInjectValue(final PreparedStatement ps, final QueryItem condition, int iii) throws Exception {
public static void whereInjectValue(final PreparedStatement ps, final QueryItem condition, final CountInOut iii) throws Exception {
// Check if we have a condition to generate
if (condition == null) {
return iii;
if (condition != null) {
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 query, final boolean root) throws SQLException, IOException {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root);
final Statement stmt = entry.connection.createStatement();
return stmt.executeUpdate(querry);
return stmt.executeUpdate(query);
}
public static int executeSimpleQuerry(final String querry) throws SQLException, IOException {
return executeSimpleQuerry(querry, false);
public static int executeSimpleQuerry(final String query) throws SQLException, IOException {
return executeSimpleQuerry(query, false);
}
public static boolean executeQuerry(final String querry, final boolean root) throws SQLException, IOException {
public static boolean executeQuerry(final String query, final boolean root) throws SQLException, IOException {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root);
final Statement stmt = entry.connection.createStatement();
return stmt.execute(querry);
return stmt.execute(query);
}
public static boolean executeQuerry(final String querry) throws SQLException, IOException {
return executeQuerry(querry, false);
public static boolean executeQuerry(final String query) throws SQLException, IOException {
return executeQuerry(query, false);
}
public static <T> T getWhere(final Class<T> clazz, final QueryItem condition) throws Exception {
@ -884,10 +889,11 @@ public class DataAccess {
return getsWhere(clazz, condition, null, options, linit);
}
public static int generateSelectField(final StringBuilder querry, final Class<?> clazz, final QueryOptions options, int count) throws Exception {
public static void generateSelectField(final StringBuilder querySelect, final StringBuilder query, final Class<?> clazz, final QueryOptions options, final CountInOut count) throws Exception {
final boolean readAllfields = QueryOptions.readAllFields(options);
final String tableName = AnnotationTools.getTableName(clazz, options);
boolean firstField = true;
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
@ -903,85 +909,70 @@ public class DataAccess {
continue;
}
final String name = AnnotationTools.getFieldName(elem);
count++;
if (firstField) {
firstField = false;
} else {
querry.append(",");
querySelect.append(",");
}
querry.append(" ");
querySelect.append(" ");
if (addOn != null) {
count = addOn.generateQuerry(tableName, elem, querry, name, count, options);
addOn.generateQuerry(tableName, elem, querySelect, query, name, count, options);
} else {
querry.append(tableName);
querry.append(".");
querry.append(name);
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(name);
count.inc();
}
}
querry.append(" FROM `");
querry.append(tableName);
querry.append("` ");
return count;
}
// TODO: set limit as an query Option...
@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 {
final boolean readAllfields = QueryOptions.readAllFields(options);
final List<LazyGetter> lazyCall = new ArrayList<>();
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final List<T> outs = new ArrayList<>();
// real add in the BDD:
try {
int count = 0;
final StringBuilder querry = new StringBuilder();
querry.append("SELECT ");
count = generateSelectField(querry, clazz, options, count);
final CountInOut count = new CountInOut();
final StringBuilder querySelect = new StringBuilder();
StringBuilder query = new StringBuilder();
final String tableName = AnnotationTools.getTableName(clazz, options);
whereAppendQuery(querry, tableName, condition, options, deletedFieldName);
querySelect.append("SELECT ");
query.append(" FROM `");
query.append(tableName);
query.append("` ");
generateSelectField(querySelect, query, clazz, options, count);
querySelect.append(query.toString());
query = querySelect;
whereAppendQuery(query, tableName, condition, options, deletedFieldName);
if (orderBy != null && orderBy.length() >= 1) {
querry.append(" ORDER BY ");
querry.append(orderBy);
query.append(" ORDER BY ");
query.append(orderBy);
}
if (linit != null && linit >= 1) {
querry.append(" LIMIT " + linit);
query.append(" LIMIT " + linit);
}
LOGGER.debug("generate the querry: '{}'", querry.toString());
LOGGER.debug("generate the query: '{}'", query.toString());
// prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS);
whereInjectValue(ps, condition, 1);
final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
final CountInOut iii = new CountInOut(1);
whereInjectValue(ps, condition, iii);
// execute the request
final ResultSet rs = ps.executeQuery();
while (rs.next()) {
// TODO: manage class that is defined inside a class ==> Not manage for now...
final Object data = clazz.getConstructors()[0].newInstance();
count = 1;
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
// TODO: Manage it with AddOn
final boolean notRead = AnnotationTools.isdefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
if (addOn != null) {
final int nbRowRead = addOn.fillFromQuerry(rs, elem, data, count, options);
count += nbRowRead;
} else {
setValueFromDb(elem.getType(), data, count, elem, rs);
count++;
}
}
count.value = 1;
final CountInOut countNotNull = new CountInOut(0);
final Object data = createObjectFromSQLRequest(rs, clazz, count, countNotNull, options, lazyCall);
final T out = (T) data;
outs.add(out);
}
LOGGER.info("Async calls: {}", lazyCall.size());
for (final LazyGetter elem : lazyCall) {
elem.doRequest();
}
} catch (final SQLException ex) {
ex.printStackTrace();
throw ex;
@ -994,6 +985,34 @@ public class DataAccess {
return outs;
}
public static Object createObjectFromSQLRequest(final ResultSet rs, final Class<?> clazz, final CountInOut count, final CountInOut countNotNull, final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final boolean readAllfields = QueryOptions.readAllFields(options);
// TODO: manage class that is defined inside a class ==> Not manage for now...
final Object data = clazz.getConstructors()[0].newInstance();
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
// TODO: Manage it with AddOn
final boolean notRead = AnnotationTools.isdefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
if (addOn != null) {
addOn.fillFromQuerry(rs, elem, data, count, options, lazyCall);
} else {
setValueFromDb(elem.getType(), data, count, elem, rs, countNotNull);
}
}
return data;
}
// TODO : detect the @Id
public static <T> T get(final Class<T> clazz, final long id) throws Exception {
return get(clazz, id, null);
@ -1061,15 +1080,16 @@ public class DataAccess {
// find the deleted field
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final StringBuilder querry = new StringBuilder();
querry.append("DELETE FROM `");
querry.append(tableName);
querry.append("` ");
whereAppendQuery(querry, tableName, condition, null, deletedFieldName);
final StringBuilder query = new StringBuilder();
query.append("DELETE FROM `");
query.append(tableName);
query.append("` ");
whereAppendQuery(query, tableName, condition, null, deletedFieldName);
try {
LOGGER.debug("APPLY: {}", querry.toString());
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString());
whereInjectValue(ps, condition, 1);
LOGGER.debug("APPLY: {}", query.toString());
final PreparedStatement ps = entry.connection.prepareStatement(query.toString());
final CountInOut iii = new CountInOut(1);
whereInjectValue(ps, condition, iii);
return ps.executeUpdate();
} finally {
entry.close();
@ -1100,26 +1120,27 @@ public class DataAccess {
// find the deleted field
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final StringBuilder querry = new StringBuilder();
querry.append("UPDATE `");
querry.append(tableName);
querry.append("` SET `");
querry.append(deletedFieldName);
querry.append("`=true ");
final StringBuilder query = new StringBuilder();
query.append("UPDATE `");
query.append(tableName);
query.append("` SET `");
query.append(deletedFieldName);
query.append("`=true ");
/*
* The trigger work well, but the timestamp is store @ seconds...
if (updateFieldName != null) {
// done only in SQLite (the trigger does not work...
querry.append(", `");
querry.append(updateFieldName);
querry.append("`=DATE()");
query.append(", `");
query.append(updateFieldName);
query.append("`=DATE()");
}
*/
whereAppendQuery(querry, tableName, condition, null, deletedFieldName);
whereAppendQuery(query, tableName, condition, null, deletedFieldName);
try {
LOGGER.debug("APPLY UPDATE: {}", querry.toString());
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString());
whereInjectValue(ps, condition, 1);
LOGGER.debug("APPLY UPDATE: {}", query.toString());
final PreparedStatement ps = entry.connection.prepareStatement(query.toString());
final CountInOut iii = new CountInOut(1);
whereInjectValue(ps, condition, iii);
return ps.executeUpdate();
} finally {
entry.close();
@ -1142,24 +1163,25 @@ public class DataAccess {
throw new Exception("The class " + clazz.getCanonicalName() + " has no deleted field");
}
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final StringBuilder querry = new StringBuilder();
querry.append("UPDATE `");
querry.append(tableName);
querry.append("` SET `");
querry.append(deletedFieldName);
querry.append("`=false ");
final StringBuilder query = new StringBuilder();
query.append("UPDATE `");
query.append(tableName);
query.append("` SET `");
query.append(deletedFieldName);
query.append("`=false ");
/*
* is is needed only for SQLite ???
querry.append("`modify_date`=");
querry.append(getDBNow());
querry.append(", ");
query.append("`modify_date`=");
query.append(getDBNow());
query.append(", ");
*/
// need to disable the deleted false because the model must be unselected to be updated.
options.put(QueryOptions.SQL_DELETED_DISABLE, true);
whereAppendQuery(querry, tableName, condition, options, deletedFieldName);
whereAppendQuery(query, tableName, condition, options, deletedFieldName);
try {
final PreparedStatement ps = entry.connection.prepareStatement(querry.toString());
whereInjectValue(ps, condition, 1);
final PreparedStatement ps = entry.connection.prepareStatement(query.toString());
final CountInOut iii = new CountInOut(1);
whereInjectValue(ps, condition, iii);
return ps.executeUpdate();
} finally {
entry.close();

View File

@ -37,7 +37,7 @@ public interface DataAccessAddOn {
* @return the new index of injection in case of multiple value management
* @throws SQLException
*/
int insertData(PreparedStatement ps, final Field field, Object data, int iii) throws Exception, SQLException, IllegalArgumentException, IllegalAccessException;
void insertData(PreparedStatement ps, final Field field, Object data, CountInOut iii) throws Exception, SQLException, IllegalArgumentException, IllegalAccessException;
// Element can insert in the single request
boolean canInsert(final Field field);
@ -45,10 +45,12 @@ public interface DataAccessAddOn {
// Element can be retrieve with the specific mode
boolean canRetrieve(final Field field);
int generateQuerry(@NotNull String tableName, @NotNull Field field, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QueryOptions options) throws Exception;
void generateQuerry(@NotNull String tableName, @NotNull Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull String name,
@NotNull CountInOut count, QueryOptions options) throws Exception;
// Return the number of colomn read
int fillFromQuerry(ResultSet rs, Field field, Object data, int count, QueryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException;
void fillFromQuerry(ResultSet rs, Field field, Object data, CountInOut count, QueryOptions options, final List<LazyGetter> lazyCall)
throws Exception, SQLException, IllegalArgumentException, IllegalAccessException;
/**
* Create associated table of the specific element.

View File

@ -10,12 +10,14 @@ import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.persistence.GenerationType;
public class DataFactory {
@ -50,6 +52,9 @@ public class DataFactory {
if (type == String.class) {
return "text";
}
if (type == JsonValue.class) {
return "json";
}
if (type.isEnum()) {
final Object[] arr = type.getEnumConstants();
final StringBuilder out = new StringBuilder();
@ -95,6 +100,9 @@ public class DataFactory {
if (type == String.class) {
return "text";
}
if (type == JsonValue.class) {
return "text";
}
if (type.isEnum()) {
final Object[] arr = type.getEnumConstants();
final StringBuilder out = new StringBuilder();
@ -189,7 +197,7 @@ public class DataFactory {
triggerBuilder.append(tableName);
triggerBuilder.append(" SET ");
triggerBuilder.append(name);
triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n");
triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n");
triggerBuilder.append("END;");
postOtherTables.add(triggerBuilder.toString());
@ -289,7 +297,7 @@ public class DataFactory {
}
}
final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(DataIfNotExists.class).length != 0;
final List<String> preActionList = new ArrayList<>();
final List<String> postActionList = new ArrayList<>();
final StringBuilder out = new StringBuilder();

View File

@ -0,0 +1,5 @@
package org.kar.archidata.dataAccess;
public interface LazyGetter {
void doRequest() throws Exception;
}

View File

@ -2,28 +2,28 @@ package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class QueryAnd implements QueryItem {
protected final List<QueryItem> childs;
public QueryAnd(List<QueryItem> childs) {
public QueryAnd(final List<QueryItem> childs) {
this.childs = childs;
}
public QueryAnd(QueryItem... items) {
public QueryAnd(final QueryItem... items) {
this.childs = new ArrayList<>();
for (int iii = 0; iii < items.length; iii++) {
this.childs.add(items[iii]);
}
Collections.addAll(this.childs, items);
}
public void generateQuerry(StringBuilder querry, String tableName) {
@Override
public void generateQuerry(final StringBuilder querry, final String tableName) {
if (this.childs.size() >= 1) {
querry.append(" (");
}
boolean first = true;
for (QueryItem elem : this.childs) {
for (final QueryItem elem : this.childs) {
if (first) {
first = false;
} else {
@ -35,13 +35,12 @@ public class QueryAnd implements QueryItem {
querry.append(")");
}
}
@Override
public int injectQuerry(PreparedStatement ps, int iii) throws Exception {
for (QueryItem elem : this.childs) {
iii = elem.injectQuerry(ps, iii);
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) {
elem.injectQuerry(ps, iii);
}
return iii;
}
}

View File

@ -6,26 +6,27 @@ public class QueryCondition implements QueryItem {
private final String key;
private final String comparator;
private final Object value;
public QueryCondition(String key, String comparator, Object value) {
public QueryCondition(final String key, final String comparator, final Object value) {
this.key = key;
this.comparator = comparator;
this.value = value;
}
public void generateQuerry(StringBuilder querry, String tableName) {
@Override
public void generateQuerry(final StringBuilder querry, final String tableName) {
querry.append(tableName);
querry.append(".");
querry.append(this.key);
querry.append(" ");
querry.append(this.comparator);
querry.append(" ?");
}
@Override
public int injectQuerry(PreparedStatement ps, int iii) throws Exception {
DataAccess.addElement(ps, this.value, iii++);
return iii;
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {
DataAccess.addElement(ps, this.value, iii);
iii.inc();
}
}

View File

@ -4,6 +4,6 @@ import java.sql.PreparedStatement;
public interface QueryItem {
void generateQuerry(StringBuilder querry, String tableName);
int injectQuerry(PreparedStatement ps, int iii) throws Exception;
void injectQuerry(PreparedStatement ps, CountInOut iii) throws Exception;
}

View File

@ -6,16 +6,17 @@ import java.util.List;
public class QueryOr implements QueryItem {
protected final List<QueryItem> childs;
public QueryOr(List<QueryItem> childs) {
public QueryOr(final List<QueryItem> childs) {
this.childs = childs;
}
public void generateQuerry(StringBuilder querry, String tableName) {
@Override
public void generateQuerry(final StringBuilder querry, final String tableName) {
if (this.childs.size() >= 1) {
querry.append(" (");
}
boolean first = true;
for (QueryItem elem : this.childs) {
for (final QueryItem elem : this.childs) {
if (first) {
first = false;
} else {
@ -29,11 +30,9 @@ public class QueryOr implements QueryItem {
}
@Override
public int injectQuerry(PreparedStatement ps, int iii) throws Exception {
for (QueryItem elem : this.childs) {
iii = elem.injectQuerry(ps, iii);
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) {
elem.injectQuerry(ps, iii);
}
return iii;
}
}

View File

@ -0,0 +1,93 @@
package org.kar.archidata.dataAccess.addOn;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.validation.constraints.NotNull;
public class AddOnDataJson implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnDataJson.class);
@Override
public Class<?> getAnnotationClass() {
return DataJson.class;
}
@Override
public String getSQLFieldType(final Field elem) throws Exception {
final String fieldName = AnnotationTools.getFieldName(elem);
return DataFactory.convertTypeInSQL(String.class, fieldName);
}
@Override
public boolean isCompatibleField(final Field elem) {
final DataJson decorators = elem.getDeclaredAnnotation(DataJson.class);
return decorators != null;
}
@Override
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) throws Exception {
final Object data = field.get(rootObject);
if (data == null) {
ps.setNull(iii.value, Types.VARCHAR);
}
final ObjectMapper objectMapper = new ObjectMapper();
final String dataString = objectMapper.writeValueAsString(data);
ps.setString(iii.value, dataString);
iii.inc();
}
@Override
public boolean canInsert(final Field field) {
return true;
}
@Override
public boolean canRetrieve(final Field field) {
return true;
}
@Override
public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name,
@NotNull final CountInOut elemCount, final QueryOptions options) throws Exception {
querrySelect.append(" ");
querrySelect.append(tableName);
querrySelect.append(".");
querrySelect.append(name);
elemCount.inc();
return;
}
@Override
public void fillFromQuerry(final ResultSet rs, final Field field, final Object data, final CountInOut count, final QueryOptions options, final List<LazyGetter> lazyCall) throws Exception {
final String jsonData = rs.getString(count.value);
count.inc();
if (!rs.wasNull()) {
final ObjectMapper objectMapper = new ObjectMapper();
final Object dataParsed = objectMapper.readValue(jsonData, field.getType());
field.set(data, dataParsed);
}
}
@Override
public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List<String> preActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {
DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class);
}
}

View File

@ -1,23 +1,30 @@
package org.kar.archidata.dataAccess.addOn;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryItem;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.QueryOr;
import org.kar.archidata.dataAccess.addOn.model.LinkTable;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
import jakarta.validation.constraints.NotNull;
@ -42,8 +49,8 @@ public class AddOnManyToMany implements DataAccessAddOn {
}
@Override
public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, final int iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
return iii;
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
}
@Override
@ -69,42 +76,41 @@ public class AddOnManyToMany implements DataAccessAddOn {
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) {
public void generateConcatQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry,
@NotNull final String name, @NotNull final CountInOut elemCount, final QueryOptions options) {
final String linkTableName = generateLinkTableName(tableName, name);
final String tmpVariable = "tmp_" + Integer.toString(elemCount);
querry.append(" (SELECT GROUP_CONCAT(");
querry.append(tmpVariable);
querry.append(".object2Id");
final String tmpVariable = "tmp_" + Integer.toString(elemCount.value);
querrySelect.append(" (SELECT GROUP_CONCAT(");
querrySelect.append(tmpVariable);
querrySelect.append(".object2Id");
if (ConfigBaseVariable.getDBType().equals("sqlite")) {
querry.append(", ");
querrySelect.append(", ");
} else {
querry.append("SEPARATOR ");
querrySelect.append("SEPARATOR ");
}
querry.append("'");
querry.append(SEPARATOR);
querry.append("') FROM ");
querry.append(linkTableName);
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("object1Id ");
querrySelect.append("'");
querrySelect.append(SEPARATOR);
querrySelect.append("') FROM ");
querrySelect.append(linkTableName);
querrySelect.append(" ");
querrySelect.append(tmpVariable);
querrySelect.append(" WHERE ");
querrySelect.append(tmpVariable);
querrySelect.append(".deleted = false AND ");
querrySelect.append(tableName);
querrySelect.append(".id = ");
querrySelect.append(tmpVariable);
querrySelect.append(".");
querrySelect.append("object1Id ");
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
querry.append(" GROUP BY ");
querry.append(tmpVariable);
querry.append(".object2Id");
querrySelect.append(" GROUP BY ");
querrySelect.append(tmpVariable);
querrySelect.append(".object2Id");
}
querry.append(") AS ");
querry.append(name);
querry.append(" ");
querrySelect.append(") AS ");
querrySelect.append(name);
querrySelect.append(" ");
/*
" (SELECT GROUP_CONCAT(tmp.data_id SEPARATOR '-')" +
" FROM cover_link_node tmp" +
@ -112,15 +118,73 @@ public class AddOnManyToMany implements DataAccessAddOn {
" AND node.id = tmp.node_id" +
" GROUP BY tmp.node_id) AS covers" +
*/
return 1;
elemCount.inc();
}
@Override
public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, final QueryOptions options)
throws SQLException, IllegalArgumentException, IllegalAccessException {
final List<Long> idList = DataAccess.getListOfIds(rs, count, SEPARATOR);
elem.set(data, idList);
return 1;
public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name,
@NotNull final CountInOut elemCount, final QueryOptions options) throws Exception {
if (field.getType() != List.class) {
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
if (objectClass == Long.class) {
generateConcatQuerry(tableName, field, querrySelect, querry, name, elemCount, options);
}
final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class);
if (decorators == null) {
return;
}
if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) {
throw new Exception("EAGER is not supported for list of element...");
} else {
generateConcatQuerry(tableName, field, querrySelect, querry, name, elemCount, options);
}
}
}
@Override
public void fillFromQuerry(final ResultSet rs, final Field field, final Object data, final CountInOut count, final QueryOptions options, final List<LazyGetter> lazyCall) throws Exception {
if (field.getType() != List.class) {
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
if (objectClass == Long.class) {
final List<Long> idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR);
field.set(data, idList);
count.inc();
}
final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class);
if (decorators == null) {
return;
}
if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) {
throw new Exception("EAGER is not supported for list of element...");
} else {
final List<Long> idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR);
//field.set(data, idList);
count.inc();
if (idList != null && idList.size() > 0) {
final String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass));
// In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> {
final List<QueryItem> childs = new ArrayList<>();
for (final Long elem : idList) {
childs.add(new QueryCondition(idField, "=", elem));
}
// TODO: update to have get with abstract types ....
final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), new QueryOr(childs), options);
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
}
}
}
public static void addLink(final Class<?> clazz, final long localKey, final String column, final long remoteKey) throws Exception {

View File

@ -1,236 +0,0 @@
package org.kar.archidata.dataAccess.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.dataAccess.DataAccess;
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.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 DataAccessAddOn {
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 Field field, final Object rootObject, final int iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
return iii;
}
@Override
public boolean canInsert(final Field field) {
return false;
}
@Override
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;
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, final QueryOptions options)
throws SQLException, IllegalArgumentException, IllegalAccessException {
//throw new IllegalAccessException("This Add-on has not the capability to insert data directly in DB");
return 0;
}
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 (" + 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 {
final String tableName = AnnotationTools.getTableName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final String querry = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=" + DataAccess.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 field, final StringBuilder mainTableBuilder, final List<String> preActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {
final String name = AnnotationTools.getFieldName(field);
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

@ -3,18 +3,20 @@ package org.kar.archidata.dataAccess.addOn;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.NotNull;
@ -45,25 +47,25 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
@Override
public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, int iii) throws Exception {
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) throws Exception {
final Object data = field.get(rootObject);
if (data == null) {
ps.setNull(iii++, Types.BIGINT);
ps.setNull(iii.value, Types.BIGINT);
} else if (field.getType() == Long.class) {
final Long dataLong = (Long) data;
ps.setLong(iii++, dataLong);
ps.setLong(iii.value, dataLong);
} else {
final Field idField = AnnotationTools.getFieldOfId(field.getType());
final Object uid = idField.get(data);
if (uid == null) {
ps.setNull(iii++, Types.BIGINT);
ps.setNull(iii.value, Types.BIGINT);
throw new Exception("Not implemented adding subClasses ==> add it manualy before...");
} else {
final Long dataLong = (Long) uid;
ps.setLong(iii++, dataLong);
ps.setLong(iii.value, dataLong);
}
}
return iii++;
iii.inc();
}
@Override
@ -77,7 +79,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
return false;
}
@Override
public boolean canRetrieve(final Field field) {
if (field.getType() == Long.class) {
@ -91,34 +93,94 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
@Override
public int generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount,
final QueryOptions options) throws Exception {
public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name,
@NotNull final CountInOut elemCount, final QueryOptions options) throws Exception {
if (field.getType() == Long.class) {
querry.append(" ");
querry.append(tableName);
querry.append(".");
querry.append(name);
return elemCount + 1;
querrySelect.append(" ");
querrySelect.append(tableName);
querrySelect.append(".");
querrySelect.append(name);
elemCount.inc();
return;
}
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
if (field.getType() == decorators.targetEntity()) {
return DataAccess.generateSelectField(querry, field.getType(), options, elemCount);
if (decorators.fetch() == FetchType.EAGER) {
// TODO: rework this to have a lazy mode ...
DataAccess.generateSelectField(querrySelect, querry, field.getType(), options, elemCount);
final Class<?> subType = field.getType();
final String subTableName = AnnotationTools.getTableName(subType);
final Field idField = AnnotationTools.getFieldOfId(subType);
querry.append("LEFT OUTER JOIN `");
querry.append(subTableName);
querry.append("` ON ");
querry.append(subTableName);
querry.append(".");
querry.append(AnnotationTools.getFieldName(idField));
querry.append(" = ");
querry.append(tableName);
querry.append(".");
querry.append(AnnotationTools.getFieldName(field));
} else {
querrySelect.append(" ");
querrySelect.append(tableName);
querrySelect.append(".");
querrySelect.append(name);
elemCount.inc();
return;
}
}
return elemCount;
/*
SELECT k.id, r.id
FROM `right` k
LEFT OUTER JOIN `rightDescription` r ON k.rightDescriptionId=r.id
*/
}
@Override
public int fillFromQuerry(final ResultSet rs, final Field field, final Object data, final int count, final QueryOptions options)
throws SQLException, IllegalArgumentException, IllegalAccessException {
final Long foreignKey = rs.getLong(count);
if (rs.wasNull()) {
return 0;
public void fillFromQuerry(final ResultSet rs, final Field field, final Object data, final CountInOut count, final QueryOptions options, final List<LazyGetter> lazyCall) throws Exception {
if (field.getType() == Long.class) {
final Long foreignKey = rs.getLong(count.value);
count.inc();
if (!rs.wasNull()) {
field.set(data, foreignKey);
}
return;
}
final Class<?> objectClass = field.getType();
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
if (decorators == null) {
return;
}
if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) {
final CountInOut countNotNull = new CountInOut(0);
final Object dataNew = DataAccess.createObjectFromSQLRequest(rs, objectClass, count, countNotNull, options, lazyCall);
if (dataNew != null && countNotNull.value != 0) {
field.set(data, dataNew);
}
} else {
// here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ...
final Long foreignKey = rs.getLong(count.value);
count.inc();
if (!rs.wasNull()) {
// In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> {
// TODO: update to have get with abstract types ....
final Object foreignData = DataAccess.get(decorators.targetEntity(), foreignKey);
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
}
}
field.set(data, foreignKey);
return 1;
}
// 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 serialisable with the default system
@Override
public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List<String> preActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {

View File

@ -10,8 +10,10 @@ import java.util.List;
import java.util.stream.Collectors;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,7 +23,7 @@ import jakarta.validation.constraints.NotNull;
public class AddOnOneToMany implements DataAccessAddOn {
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)
@ -31,7 +33,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
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
@ -52,12 +54,12 @@ public class AddOnOneToMany implements DataAccessAddOn {
}
return out;
}
@Override
public Class<?> getAnnotationClass() {
return OneToMany.class;
}
@Override
public String getSQLFieldType(final Field field) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field);
@ -69,57 +71,57 @@ public class AddOnOneToMany implements DataAccessAddOn {
}
return null;
}
@Override
public boolean isCompatibleField(final Field field) {
final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class);
return decorators != null;
}
@Override
public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, int iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
final Object data = field.get(rootObject);
iii.inc();
if (data == null) {
ps.setNull(iii++, Types.BIGINT);
ps.setNull(iii.value, Types.BIGINT);
} else {
@SuppressWarnings("unchecked")
final String dataTmp = getStringOfIds((List<Long>) data);
ps.setString(iii++, dataTmp);
ps.setString(iii.value, dataTmp);
}
return iii++;
}
@Override
public boolean canInsert(final Field field) {
return false;
}
@Override
public boolean canRetrieve(final Field field) {
return false;
}
@Override
public int generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount,
final QueryOptions options) {
querry.append(" ");
querry.append(tableName);
querry.append(".");
querry.append(name);
return 1;
public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name,
@NotNull final CountInOut elemCount, final QueryOptions options) {
querrySelect.append(" ");
querrySelect.append(tableName);
querrySelect.append(".");
querrySelect.append(name);
elemCount.inc();
}
@Override
public int fillFromQuerry(final ResultSet rs, final Field field, final Object data, final int count, final QueryOptions options)
public void fillFromQuerry(final ResultSet rs, final Field field, final Object data, final CountInOut count, final QueryOptions options, final List<LazyGetter> lazyCall)
throws SQLException, IllegalArgumentException, IllegalAccessException {
final Long foreignKey = rs.getLong(count);
if (rs.wasNull()) {
return 0;
final Long foreignKey = rs.getLong(count.value);
count.inc();
if (!rs.wasNull()) {
field.set(data, foreignKey);
}
field.set(data, foreignKey);
return 1;
}
// 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 field, final StringBuilder mainTableBuilder, final List<String> preActionList, final List<String> postActionList,

View File

@ -11,9 +11,11 @@ import java.util.stream.Collectors;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.addOn.SQLTableExternalForeinKeyAsList;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -23,7 +25,7 @@ import jakarta.validation.constraints.NotNull;
public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn {
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)
@ -33,12 +35,12 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn {
final List<Long> tmp = new ArrayList<>(ids);
return tmp.stream().map(String::valueOf).collect(Collectors.joining(SEPARATOR));
}
@Override
public Class<?> getAnnotationClass() {
return SQLTableExternalForeinKeyAsList.class;
}
@Override
public String getSQLFieldType(final Field field) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field);
@ -50,59 +52,59 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn {
}
return null;
}
@Override
public boolean isCompatibleField(final Field field) {
final SQLTableExternalForeinKeyAsList decorators = field.getDeclaredAnnotation(SQLTableExternalForeinKeyAsList.class);
return decorators != null;
}
@Override
public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, int iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
final Object data = field.get(rootObject);
iii.inc();
if (data == null) {
ps.setNull(iii++, Types.BIGINT);
ps.setNull(iii.value, Types.BIGINT);
} else {
@SuppressWarnings("unchecked")
final String dataTmp = getStringOfIds((List<Long>) data);
ps.setString(iii++, dataTmp);
ps.setString(iii.value, dataTmp);
}
return iii++;
}
@Override
public boolean canInsert(final Field field) {
return false;
}
@Override
public boolean canRetrieve(final Field field) {
return false;
}
@Override
public int generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount,
final QueryOptions options) {
querry.append(" ");
querry.append(tableName);
querry.append(".");
querry.append(name);
return 1;
public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name,
@NotNull final CountInOut elemCount, final QueryOptions options) {
elemCount.inc();
querrySelect.append(" ");
querrySelect.append(tableName);
querrySelect.append(".");
querrySelect.append(name);
}
@Override
public int fillFromQuerry(final ResultSet rs, final Field field, final Object data, final int count, final QueryOptions options)
public void fillFromQuerry(final ResultSet rs, final Field field, final Object data, final CountInOut count, final QueryOptions options, final List<LazyGetter> lazyCall)
throws SQLException, IllegalArgumentException, IllegalAccessException {
final List<Long> idList = DataAccess.getListOfIds(rs, count, SEPARATOR);
final List<Long> idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR);
field.set(data, idList);
return 1;
count.inc();
}
@Override
public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List<String> preActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {
// TODO Auto-generated method stub
DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, String.class);
}
}

View File

@ -1,6 +1,6 @@
package org.kar.archidata.dataAccess.addOn.model;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.DataComment;
import org.kar.archidata.model.GenericDataSoftDelete;
import jakarta.persistence.Column;
@ -15,10 +15,10 @@ public class LinkTable extends GenericDataSoftDelete {
this.object2Id = object2Id;
}
@SQLComment("Object reference 1")
@DataComment("Object reference 1")
@Column(nullable = false)
public Long object1Id;
@SQLComment("Object reference 2")
@DataComment("Object reference 2")
@Column(nullable = false)
public Long object2Id;

View File

@ -1,8 +1,8 @@
package org.kar.archidata.migration.model;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.DataComment;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -14,20 +14,20 @@ import jakarta.persistence.Table;
//public static final String TABLE_NAME = "KAR_migration";
@Table(name = "KAR_migration")
@SQLIfNotExists
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Migration extends GenericDataSoftDelete {
@SQLComment("Name of the migration")
@DataComment("Name of the migration")
@Column(length = 256)
public String name;
@Column(nullable = false)
@SQLDefault("'0'")
@SQLComment("if the migration is well terminated or not")
@DataDefault("'0'")
@DataComment("if the migration is well terminated or not")
public Boolean terminated = false;
@SQLComment("index in the migration progression")
@DataComment("index in the migration progression")
public Integer stepId = 0;
@SQLComment("number of element in the migration")
@DataComment("number of element in the migration")
public Integer count;
@SQLComment("Log generate by the migration")
@DataComment("Log generate by the migration")
public String log = "";
}

View File

@ -1,7 +1,7 @@
package org.kar.archidata.model;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.DataComment;
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -9,17 +9,17 @@ import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "data")
@SQLIfNotExists
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Data extends GenericDataSoftDelete {
@Column(length = 128, nullable = false)
@SQLComment("Sha512 of the data")
@DataComment("Sha512 of the data")
public String sha512;
@Column(length = 128, nullable = false)
@SQLComment("Mime -type of the media")
@DataComment("Mime -type of the media")
public String mimeType;
@Column(nullable = false)
@SQLComment("Size in Byte of the data")
@DataComment("Size in Byte of the data")
public Long size;
}

View File

@ -3,8 +3,8 @@ package org.kar.archidata.model;
import java.util.Date;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLNotRead;
import org.kar.archidata.annotation.DataComment;
import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.annotation.UpdateTimestamp;
import jakarta.persistence.Column;
@ -18,18 +18,18 @@ public class GenericData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, unique = true)
@SQLComment("Primary key of the base")
@DataComment("Primary key of the base")
public Long id = null;
@SQLNotRead
@DataNotRead
@CreationTimestamp
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@SQLComment("Create time of the object")
@DataComment("Create time of the object")
public Date createdAt = null;
@SQLNotRead
@DataNotRead
@UpdateTimestamp
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@SQLComment("When update the object")
@DataComment("When update the object")
public Date updatedAt = null;
}

View File

@ -1,17 +1,17 @@
package org.kar.archidata.model;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLDeleted;
import org.kar.archidata.annotation.SQLNotRead;
import org.kar.archidata.annotation.DataComment;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.DataDeleted;
import org.kar.archidata.annotation.DataNotRead;
import jakarta.persistence.Column;
public class GenericDataSoftDelete extends GenericData {
@SQLNotRead
@DataNotRead
@Column(nullable = false)
@SQLDefault("'0'")
@SQLDeleted
@SQLComment("When delete, they are not removed, they are just set in a deleted state")
@DataDefault("'0'")
@DataDeleted
@DataComment("When delete, they are not removed, they are just set in a deleted state")
public Boolean deleted = null;
}

View File

@ -2,7 +2,7 @@ package org.kar.archidata.model;
import java.sql.Timestamp;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -10,7 +10,7 @@ import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "applicationToken")
@SQLIfNotExists
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GenericToken extends GenericDataSoftDelete {
@Column(nullable = false)

View File

@ -17,8 +17,8 @@ CREATE TABLE `user` (
import java.sql.Timestamp;
import java.util.List;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -28,20 +28,20 @@ import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
@Table(name = "user")
@SQLIfNotExists
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User extends GenericDataSoftDelete {
@Column(length = 128)
public String login = null;
public Timestamp lastConnection = null;
@SQLDefault("'0'")
@DataDefault("'0'")
@Column(nullable = false)
public boolean admin = false;
@SQLDefault("'0'")
@DataDefault("'0'")
@Column(nullable = false)
public boolean blocked = false;
@SQLDefault("'0'")
@DataDefault("'0'")
@Column(nullable = false)
public boolean removed = false;

View File

@ -0,0 +1,86 @@
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.db.DBEntry;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.model.SerializeAsJson;
import test.kar.archidata.model.SimpleTable;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestJson {
final static private Logger LOGGER = LoggerFactory.getLogger(TestJson.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 testTableInsertAndRetrieve() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(SerializeAsJson.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
}
}
@Order(2)
@Test
public void testIO() throws Exception {
final SerializeAsJson test = new SerializeAsJson();
test.data = new SimpleTable();
test.data.data = "plopppopql";
final SerializeAsJson insertedData = DataAccess.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertNotNull(insertedData.data);
Assertions.assertNotNull(insertedData.data.data);
Assertions.assertEquals(test.data.data, insertedData.data.data);
// Try to retrieve all the data:
final SerializeAsJson retrieve = DataAccess.get(SerializeAsJson.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertTrue(retrieve.id >= 0);
Assertions.assertNotNull(retrieve.data);
Assertions.assertNotNull(retrieve.data.data);
Assertions.assertEquals(test.data.data, retrieve.data.data);
}
}

View File

@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypeManyToManyRemote;
import test.kar.archidata.model.TypeManyToManyRoot;
import test.kar.archidata.model.TypeManyToManyRootExpand;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -85,7 +86,7 @@ public class TestManyToMany {
@Order(3)
@Test
public void testSimpleInsertAndRetieveZZZ() throws Exception {
public void testSimpleInsertAndRetieveSubValues() throws Exception {
TypeManyToManyRemote remote = new TypeManyToManyRemote();
remote.data = "remote1";
@ -120,7 +121,7 @@ public class TestManyToMany {
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);
@ -130,7 +131,19 @@ public class TestManyToMany {
Assertions.assertEquals(retrieve.remote.size(), 2);
Assertions.assertEquals(retrieve.remote.get(0), insertedRemote1.id);
Assertions.assertEquals(retrieve.remote.get(1), insertedRemote2.id);
final TypeManyToManyRootExpand retrieveExpand = DataAccess.get(TypeManyToManyRootExpand.class, insertedData.id);
Assertions.assertNotNull(retrieveExpand);
Assertions.assertNotNull(retrieveExpand.id);
Assertions.assertEquals(insertedData.id, retrieveExpand.id);
Assertions.assertNotNull(retrieveExpand.otherData);
Assertions.assertEquals(insertedData.otherData, retrieveExpand.otherData);
Assertions.assertNotNull(retrieveExpand.remote);
Assertions.assertEquals(retrieveExpand.remote.size(), 2);
Assertions.assertEquals(retrieveExpand.remote.get(0).id, insertedRemote1.id);
Assertions.assertEquals(retrieveExpand.remote.get(1).id, insertedRemote2.id);
// Remove an element
int count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id);
Assertions.assertEquals(1, count);

View File

@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypeManyToOneRemote;
import test.kar.archidata.model.TypeManyToOneRoot;
import test.kar.archidata.model.TypeManyToOneRootExpand;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -79,7 +80,42 @@ public class TestManyToOne {
Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertEquals(test.otherData, insertedData.otherData);
Assertions.assertEquals(insertedData.remoteId, insertedRemote2.id);
Assertions.assertEquals(insertedRemote2.id, insertedData.remoteId);
TypeManyToOneRoot retrieve = DataAccess.get(TypeManyToOneRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId);
TypeManyToOneRootExpand retrieve2 = DataAccess.get(TypeManyToOneRootExpand.class, insertedData.id);
Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.id);
Assertions.assertEquals(insertedData.id, retrieve2.id);
Assertions.assertEquals(insertedData.otherData, retrieve2.otherData);
Assertions.assertNotNull(retrieve2.remote);
Assertions.assertEquals(insertedRemote2.id, retrieve2.remote.id);
Assertions.assertEquals(insertedRemote2.data, retrieve2.remote.data);
// remove values:
final int count = DataAccess.delete(TypeManyToOneRemote.class, remote.id);
Assertions.assertEquals(1, count);
// check fail:
retrieve = DataAccess.get(TypeManyToOneRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId);
retrieve2 = DataAccess.get(TypeManyToOneRootExpand.class, insertedData.id);
Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.id);
Assertions.assertEquals(insertedData.id, retrieve2.id);
Assertions.assertEquals(insertedData.otherData, retrieve2.otherData);
Assertions.assertNull(retrieve2.remote);
}
}

View File

@ -0,0 +1,11 @@
package test.kar.archidata.model;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericData;
public class SerializeAsJson extends GenericData {
@DataJson
public SimpleTable data;
}

View File

@ -8,13 +8,17 @@ import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
@Table(name = "TypeManyToManyRoot")
public class TypeManyToManyRootExpand {
@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<TypeManyToManyRemote> remote;
}

View File

@ -6,15 +6,17 @@ import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@Table(name = "TypeManyToOneRoot")
public class TypeManyToOneRootExpand {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, unique = true)
public Long id = null;
public String otherData;
public String otherData;
@ManyToOne(fetch = FetchType.LAZY, targetEntity = TypeManyToOneRemote.class)
@Column(name = "remoteId", nullable = false)
public TypeManyToOneRemote remote;