[DEV] correct timing

This commit is contained in:
Edouard DUPIN 2024-03-02 15:21:03 +01:00
parent 41fb181545
commit 6584022861
6 changed files with 301 additions and 19 deletions

View File

@ -25,21 +25,24 @@
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -53,7 +53,40 @@ public class AnnotationTools {
return tmp;
}
public static String getSchemedescription(final Field element) throws Exception {
public static boolean getSchemaReadOnly(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return false;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName());
}
return ((Schema) annotation[0]).readOnly();
}
public static String getSchemaExample(final Class<?> element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName());
}
return ((Schema) annotation[0]).example();
}
public static String getSchemaDescription(final Class<?> element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName());
}
return ((Schema) annotation[0]).description();
}
public static String getSchemaDescription(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
@ -67,7 +100,7 @@ public class AnnotationTools {
public static String getComment(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataComment.class);
if (annotation.length == 0) {
return getSchemedescription(element);
return getSchemaDescription(element);
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @DataComment on " + element.getClass().getCanonicalName());

View File

@ -309,11 +309,11 @@ public class DataAccess {
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 == UUID.class) {
final byte[] tmp = rs.getBytes(count.value);
//final UUID tmp = rs.getObject(count.value, UUID.class);
// final UUID tmp = rs.getObject(count.value, UUID.class);
if (rs.wasNull()) {
field.set(data, null);
} else {
//field.set(data, tmp);
// field.set(data, tmp);
final UUID uuid = UuidUtils.asUuid(tmp);
field.set(data, uuid);
countNotNull.inc();
@ -491,11 +491,11 @@ public class DataAccess {
return (final ResultSet rs, final Object obj) -> {
final byte[] tmp = rs.getBytes(count);
//final UUID tmp = rs.getObject(count, UUID.class);
// final UUID tmp = rs.getObject(count, UUID.class);
if (rs.wasNull()) {
field.set(obj, null);
} else {
//field.set(obj, tmp);
// field.set(obj, tmp);
final UUID uuid = UuidUtils.asUuid(tmp);
field.set(obj, uuid);
}
@ -852,7 +852,7 @@ public class DataAccess {
try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
if (generatedKeys.next()) {
if (primaryKeyField.getType() == UUID.class) {
//uniqueSQLUUID = generatedKeys.getObject(1, UUID.class);
// uniqueSQLUUID = generatedKeys.getObject(1, UUID.class);
final byte[] tmpid = generatedKeys.getBytes(1);
uniqueSQLUUID = UuidUtils.asUuid(tmpid);
} else {

View File

@ -0,0 +1,247 @@
package org.kar.archidata.dataAccess;
import java.io.FileWriter;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DataFactoryZod {
static final Logger LOGGER = LoggerFactory.getLogger(DataFactoryZod.class);
public static String convertTypeZod(final Class<?> type) throws Exception {
if (type == UUID.class) {
return "string()";
}
if (type == Long.class) {
return "bigint()";
}
if (type == long.class) {
return "bigint()";
}
if (type == Integer.class || type == int.class) {
return "number().safe()";
}
if (type == Boolean.class || type == boolean.class) {
return "boolean()";
}
if (type == double.class || type == float.class || type == Double.class || type == Float.class) {
return "number()";
}
if (type == Instant.class) {
return "string().utc()";
}
if (type == Date.class || type == Timestamp.class) {
return "date()";
}
if (type == LocalDate.class) {
return "date()";
}
if (type == LocalTime.class) {
return "date()";
}
if (type == String.class) {
return "string()";
}
if (type.isEnum()) {
final Object[] arr = type.getEnumConstants();
final StringBuilder out = new StringBuilder();
boolean first = true;
out.append("enum([");
for (final Object elem : arr) {
if (!first) {
out.append(",");
}
first = false;
out.append("\"");
out.append(elem.toString());
out.append("\"");
}
out.append("])");
return out.toString();
}
throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName());
}
public static String optionalTypeZod(final Class<?> type) throws Exception {
if (type.isEnum() || type == UUID.class || type == Long.class || type == Integer.class || type == Boolean.class | type == Double.class || type == Float.class || type == Instant.class
|| type == Date.class || type == Timestamp.class || type == LocalDate.class || type == LocalTime.class || type == String.class) {
return ".optional()";
}
return "";
}
public static void createTablesSpecificType(final Field elem, final int fieldId, final StringBuilder builder) throws Exception {
final String name = elem.getName();
final Class<?> classModel = elem.getType();
final int limitSize = AnnotationTools.getLimitSize(elem);
final String comment = AnnotationTools.getComment(elem);
if (fieldId != 0) {
builder.append(",");
}
if (comment != null) {
builder.append("\n\t// ");
builder.append(comment);
}
builder.append("\n\t");
builder.append(name);
builder.append(": zod.");
builder.append(convertTypeZod(classModel));
if (limitSize > 0 && classModel == String.class) {
builder.append(".max(");
builder.append(limitSize);
builder.append(")");
}
if (AnnotationTools.getSchemaReadOnly(elem)) {
builder.append(".readonly()");
}
builder.append(optionalTypeZod(classModel));
}
private static boolean isFieldFromSuperClass(final Class<?> model, final String filedName) {
final Class<?> superClass = model.getSuperclass();
if (superClass == null) {
return false;
}
for (final Field field : superClass.getFields()) {
String name;
try {
name = AnnotationTools.getFieldName(field);
if (filedName.equals(name)) {
return true;
}
} catch (final Exception e) {
// TODO Auto-generated catch block
LOGGER.trace("Catch error field name in parent create data table: {}", e.getMessage());
}
}
return false;
}
/** Request the generation of the TypeScript file for the "Zod" export model
* @param classs List of class used in the model
* @return A string representing the Server models
* @throws Exception */
public static String createTables(final List<Class<?>> classs) throws Exception {
final Map<String, String> previousClassesGenerated = new LinkedHashMap<>();
final List<String> order = new ArrayList<>();
for (final Class<?> clazz : classs) {
createTable(clazz, previousClassesGenerated, order);
}
final StringBuilder generatedData = new StringBuilder();
generatedData.append("""
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from \"zod\";
""");
for (final String elem : order) {
final String data = previousClassesGenerated.get(elem);
generatedData.append(data);
generatedData.append("\n\n");
}
LOGGER.info("generated: {}", generatedData.toString());
final FileWriter myWriter = new FileWriter("api.ts");
myWriter.write(generatedData.toString());
myWriter.close();
return generatedData.toString();
}
public static void createTable(final Class<?> clazz, final Map<String, String> previousClassesGenerated, final List<String> order) throws Exception {
if (previousClassesGenerated.get(clazz.getCanonicalName()) != null) {
return;
}
// add the current class to prevent multiple creation
previousClassesGenerated.put(clazz.getCanonicalName(), "In Generation");
// Local generation of class:
final StringBuilder internalBuilder = new StringBuilder();
final List<String> alreadyAdded = new ArrayList<>();
LOGGER.trace("parse class: '{}'", clazz.getCanonicalName());
int fieldId = 0;
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 String dataName = elem.getName();
if (isFieldFromSuperClass(clazz, dataName)) {
LOGGER.trace(" SKIP: '{}'", elem.getName());
continue;
}
if (alreadyAdded.contains(dataName)) {
LOGGER.trace(" SKIP2: '{}'", elem.getName());
continue;
}
alreadyAdded.add(dataName);
LOGGER.trace(" + '{}'", elem.getName());
if (DataAccess.isAddOnField(elem)) {
final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem);
LOGGER.error("Create type for: {} ==> {} (ADD-ON) ==> Not managed now ....", AnnotationTools.getFieldName(elem), elem.getType());
/* LOGGER.trace("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType()); if (addOn != null) { addOn.createTables(tableName, elem, tmpOut,
* preActionList, postActionList, createIfNotExist, createDrop, fieldId); } else { throw new DataAccessException( "Element matked as add-on but add-on does not loaded: table:" +
* tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type=" + elem.getType()); } fieldId++; */
} else {
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType());
DataFactoryZod.createTablesSpecificType(elem, fieldId, internalBuilder);
fieldId++;
}
}
final String description = AnnotationTools.getSchemaDescription(clazz);
final String example = AnnotationTools.getSchemaExample(clazz);
final StringBuilder generatedData = new StringBuilder();
if (description != null || example != null) {
generatedData.append("/**\n");
if (description != null) {
for (final String elem : description.split("\n")) {
generatedData.append(" * ");
generatedData.append(elem);
generatedData.append("\n");
}
}
if (example != null) {
generatedData.append(" * Example:\n");
generatedData.append(" * ```\n");
for (final String elem : example.split("\n")) {
generatedData.append(" * ");
generatedData.append(elem);
generatedData.append("\n");
}
generatedData.append(" * ```\n");
}
generatedData.append(" */\n");
}
generatedData.append("export const ");
generatedData.append(clazz.getSimpleName());
generatedData.append(" = ");
final Class<?> parentClass = clazz.getSuperclass();
if (parentClass != Object.class) {
createTable(parentClass, previousClassesGenerated, order);
generatedData.append(parentClass.getSimpleName());
generatedData.append(".extend({");
} else {
generatedData.append("zod.object({");
}
generatedData.append(internalBuilder.toString());
generatedData.append("\n});");
// Remove the previous to reorder the map ==> parent must be inserted before us.
previousClassesGenerated.put(clazz.getCanonicalName(), generatedData.toString());
order.add(clazz.getCanonicalName());
}
}

View File

@ -21,6 +21,7 @@ record Action(String action, AsyncCall async, List<String> filterDB) {
public Action(final String action, final String filterDB) {
this(action, null, List.of(filterDB));
}
public Action(final AsyncCall async) {
this(null, async, List.of());
}
@ -142,6 +143,7 @@ public class MigrationSqlStep implements MigrationInterface {
public void addAction(final String action) {
this.actions.add(new Action(action));
}
public void addAction(final AsyncCall async) {
this.actions.add(new Action(async));
}
@ -149,6 +151,7 @@ public class MigrationSqlStep implements MigrationInterface {
public void addAction(final String action, final String filterdBType) {
this.actions.add(new Action(action, filterdBType));
}
public void addAction(final AsyncCall async, final String filterdBType) {
this.actions.add(new Action(async, filterdBType));
}

View File

@ -10,15 +10,12 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.validation.constraints.NotNull;
public class GenericTiming {
@DataNotRead
@CreationTimestamp
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@NotNull
@Schema(description = "Create time of the object", required = false, example = "2000-01-23T01:23:45.678+01:00", readOnly = true)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
@ -26,10 +23,9 @@ public class GenericTiming {
@DataNotRead
@UpdateTimestamp
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@NotNull
@Schema(description = "When update the object", required = false, example = "2000-01-23T00:23:45.678Z", readOnly = true)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
//public Instant updatedAt = null;
// public Instant updatedAt = null;
public Date updatedAt = null;
}