Compare commits

...

31 Commits

Author SHA1 Message Date
875b4b313b [RELEASE] new version 0.7.0 2024-03-19 08:42:29 +01:00
15a7814a3b [DEV] update new model 2024-03-19 08:37:07 +01:00
530d254bf2 Many correction of the cover, data ... 2024-03-17 23:43:56 +01:00
e1d9da70c8 [DEV] better zod export 2024-03-15 07:57:13 +01:00
c13f910620 [DEV] better management of generation of multiple Type requested 2024-03-11 22:51:04 +01:00
6944331761 [DEV] add capability to copy the tool file 2024-03-11 22:51:04 +01:00
151aa498e5 [DEV] manage native enum instead of String enum mode 2024-03-11 22:51:04 +01:00
db6a20fa02 [DEV] add mulktipart management 2024-03-11 22:51:04 +01:00
8e913b54ad [DEV] update capacity to upload file 2024-03-11 22:51:04 +01:00
092bef5a7b [DEV] add missing tools for TS 2024-03-11 00:02:35 +01:00
e5d75bc97b Simplify the model 2024-03-10 23:58:44 +01:00
7c217716c9 [DEV] update Typescript API generation 2024-03-10 11:09:52 +01:00
526f902eae [DEV] add API generation (base) 2024-03-09 08:42:26 +01:00
42ac2f3056 [DEV] add capacity to manage isXXX on Zod element 2024-03-04 23:50:44 +01:00
389e4138c3 [DEV] continue migration of the Zood and UUID for Data 2024-03-03 08:49:20 +01:00
6584022861 [DEV] correct timing 2024-03-02 15:21:03 +01:00
41fb181545 [DEV] work on uuid and callbak migration 2024-02-27 08:00:51 +01:00
56609e4f59 [DEV] add management of UUID (not tested) 2024-02-26 19:37:51 +01:00
e0b7ed1e1e [DEV] update dev tag version 2024-02-25 23:57:01 +01:00
48c32a3744 [RELEASE] new version 0.6.3 2024-02-25 23:56:41 +01:00
fc521d2287 [DEV] correct some retreave data from json 2024-02-25 23:55:29 +01:00
15125e2d6d [DEV] add condition in row request and better name naming in condition 2024-02-25 19:11:54 +01:00
6f1dd991c5 [DEV] update dev tag version 2024-02-25 19:10:51 +01:00
009831f5db [RELEASE] new version 0.6.2 2024-02-25 19:10:19 +01:00
1bcdb1df8c [DEBUG] fix the UserDBAccess 2024-02-03 18:47:30 +01:00
7ae948bb79 [DEV] add raw query 2024-02-03 18:47:11 +01:00
29402fc27e [DEV] add csv serializator for user export 2024-02-03 18:46:30 +01:00
eca28292d5 [DEV] start retreive from random request 2024-01-29 01:06:24 +01:00
aef4cdabc3 [DEV] configure mode to access on multiple database 2024-01-28 23:49:12 +01:00
04114aa0cf [DEV] format code 2024-01-19 21:23:29 +01:00
575102fbfa [DEV] update dev tag version 2024-01-19 21:21:43 +01:00
66 changed files with 3196 additions and 253 deletions

View File

@@ -30,5 +30,16 @@
<attribute name="maven.pomderived" 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="test" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

20
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.6.1</version>
<version>0.7.0</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
@@ -107,8 +107,19 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
@@ -174,6 +185,11 @@
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src/resources</directory>
</resource>
</resources>
<testSourceDirectory>test/src</testSourceDirectory>
<testResources>
<testResource>

View File

@@ -5,6 +5,9 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryOption;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.DBInterfaceOption;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.model.User;
@@ -12,21 +15,22 @@ public class UserDB {
public UserDB() {}
public static User getUsers(final long userId) throws Exception {
return DataAccess.get(User.class, userId);
public static User getUsers(final long userId, QueryOption... option) throws Exception {
return DataAccess.get(User.class, userId, option);
}
public static User getUserOrCreate(final long userId, final String userLogin) throws Exception {
public static User getUserOrCreate(final long userId, final String userLogin, QueryOption... option) throws Exception {
final User user = getUsers(userId);
if (user != null) {
return user;
}
createUsersInfoFromOAuth(userId, userLogin);
createUsersInfoFromOAuth(userId, userLogin, option);
return getUsers(userId);
}
private static void createUsersInfoFromOAuth(final long userId, final String login) throws IOException {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
private static void createUsersInfoFromOAuth(final long userId, final String login, QueryOption... option) throws IOException {
QueryOptions options = new QueryOptions(option);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')";
try {
final PreparedStatement ps = entry.connection.prepareStatement(query);

View File

@@ -22,6 +22,7 @@ import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import jakarta.ws.rs.DefaultValue;
public class AnnotationTools {
static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class);
@@ -52,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;
@@ -66,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());
@@ -75,14 +109,14 @@ public class AnnotationTools {
}
public static String getDefault(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataDefault.class);
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DefaultValue.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @DataDefault on " + element.getClass().getCanonicalName());
}
return ((DataDefault) annotation[0]).value();
return ((DefaultValue) annotation[0]).value();
}
public static ManyToOne getManyToOne(final Field element) throws Exception {
@@ -364,4 +398,17 @@ public class AnnotationTools {
return null;
}
public static Field getFieldNamed(final Class<?> clazz, final String name) throws Exception {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.getFieldName(field).equals(name)) {
return field;
}
}
return null;
}
}

View File

@@ -5,10 +5,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
/** In case of the update parameter with String input to detect null element. */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataDefault {
String value();
public @interface AsyncType {
Class<?> value();
}

View File

@@ -12,4 +12,6 @@ import org.kar.archidata.dataAccess.options.CheckFunctionVoid;
@Retention(RetentionPolicy.RUNTIME)
public @interface DataJson {
Class<? extends CheckFunctionInterface> checker() default CheckFunctionVoid.class;
Class<?> targetEntity() default Void.class;
}

View File

@@ -16,6 +16,7 @@ import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.UUID;
import javax.imageio.ImageIO;
@@ -56,7 +57,7 @@ import jakarta.ws.rs.core.StreamingOutput;
@Path("/data")
@Produces(MediaType.APPLICATION_JSON)
public class DataResource {
private static final Logger LOGGER = LoggerFactory.getLogger(MediaType.class);
private static final Logger LOGGER = LoggerFactory.getLogger(DataResource.class);
private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/** Upload some datas */
@@ -83,7 +84,7 @@ public class DataResource {
return filePath;
}
public static String getFileData(final long tmpFolderId) {
public static String getFileDataOld(final long tmpFolderId) {
final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
@@ -92,6 +93,24 @@ public class DataResource {
}
return filePath;
}
public static String getFileData(final UUID uuid) {
final String stringUUID = uuid.toString();
final String part1 = stringUUID.substring(0, 2);
final String part2 = stringUUID.substring(2, 4);
final String part3 = stringUUID.substring(4);
final String finalPath = part1 + File.separator + part2;
String filePath = ConfigBaseVariable.getMediaDataFolder() + "_uuid" + File.separator + finalPath + File.separator;
try {
createFolder(filePath);
} catch (final IOException e) {
e.printStackTrace();
}
filePath += part3;
return filePath;
}
public static String getFileMetaData(final UUID uuid) {
return getFileData(uuid) + ".json";
}
public static Data getWithSha512(final String sha512) {
LOGGER.info("find sha512 = {}", sha512);
@@ -137,7 +156,6 @@ public class DataResource {
try {
injectedData = DataAccess.insert(injectedData);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
@@ -149,6 +167,25 @@ public class DataResource {
return injectedData;
}
public static void modeFileOldModelToNewModel(final long id, final UUID uuid) throws IOException {
String mediaCurentPath = getFileDataOld(id);
String mediaDestPath = getFileData(uuid);
LOGGER.info("src = {}", mediaCurentPath);
LOGGER.info("dst = {}", mediaDestPath);
if (Files.exists(Paths.get(mediaCurentPath))) {
LOGGER.info("move: {} ==> {}", mediaCurentPath, mediaDestPath);
Files.move(Paths.get(mediaCurentPath), Paths.get(mediaDestPath), StandardCopyOption.ATOMIC_MOVE);
}
// Move old meta-data...
mediaCurentPath = mediaCurentPath.substring(mediaCurentPath.length() - 4) + "meta.json";
mediaDestPath = mediaCurentPath.substring(mediaDestPath.length() - 4) + "meta.json";
if (Files.exists(Paths.get(mediaCurentPath))) {
LOGGER.info("moveM: {} ==> {}", mediaCurentPath, mediaDestPath);
Files.move(Paths.get(mediaCurentPath), Paths.get(mediaDestPath), StandardCopyOption.ATOMIC_MOVE);
}
LOGGER.info("Move done");
}
public static String saveTemporaryFile(final InputStream uploadedInputStream, final long idData) {
return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
}
@@ -207,7 +244,7 @@ public class DataResource {
return sb.toString();
}
public Data getSmall(final Long id) {
public Data getSmall(final UUID id) {
try {
return DataAccess.get(Data.class, id);
} catch (final Exception e) {
@@ -222,7 +259,7 @@ public class DataResource {
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@RolesAllowed("ADMIN")
@Operation(description = "Insert a new data in the data environment", tags = "SYSTEM")
public Response uploadFile(@Context final SecurityContext sc, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
public void uploadFile(@Context final SecurityContext sc, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("===================================================");
LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken));
@@ -236,8 +273,6 @@ public class DataResource {
e.printStackTrace();
}
saveFile(fileInputStream, filePath);
return Response.ok("Data uploaded successfully !!").build();
// return null;
}
@GET
@@ -246,17 +281,17 @@ public class DataResource {
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Operation(description = "Get back some data from the data environment", tags = "SYSTEM")
public Response retriveDataId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final Long id) throws Exception {
public Response retrieveDataId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final UUID id) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
LOGGER.info("== DATA retriveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
LOGGER.info("== DATA retrieveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
// logger.info("===================================================");
final Data value = getSmall(id);
if (value == null) {
Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
return buildStream(getFileData(id), range, value.mimeType);
}
@GET
@@ -266,24 +301,24 @@ public class DataResource {
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Operation(description = "Get a thumbnail of from the data environment (if resize is possible)", tags = "SYSTEM")
// @CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retriveDataThumbnailId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final Long id) throws Exception {
public Response retrieveDataThumbnailId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final UUID id) throws Exception {
// GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
// logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user));
// logger.info("== DATA retrieveDataThumbnailId ? {}", (gc==null?"null":gc.user));
// logger.info("===================================================");
final Data value = getSmall(id);
if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
final String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
final String filePathName = getFileData(id);
final File inputFile = new File(filePathName);
if (!inputFile.exists()) {
return Response.status(404).entity("{\"error\":\"media Does not exist: " + id + "\"}").type("application/json").build();
}
if (value.mimeType.contentEquals("image/jpeg") || value.mimeType.contentEquals("image/png")
// || value.mimeType.contentEquals("image/webp")
) {
// || value.mimeType.contentEquals("image/webp")
) {
// reads input image
final BufferedImage inputImage = ImageIO.read(inputFile);
final int scaledWidth = 250;
@@ -325,17 +360,17 @@ public class DataResource {
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Operation(description = "Get back some data from the data environment (with a beautifull name (permit download with basic name)", tags = "SYSTEM")
public Response retriveDataFull(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final Long id, @PathParam("name") final String name) throws Exception {
public Response retrieveDataFull(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final UUID id, @PathParam("name") final String name) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
LOGGER.info("== DATA retriveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
LOGGER.info("== DATA retrieveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
// logger.info("===================================================");
final Data value = getSmall(id);
if (value == null) {
Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
return buildStream(getFileData(id), range, value.mimeType);
}
/** Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541

View File

@@ -13,6 +13,7 @@ public class FailExceptionCatcher implements ExceptionMapper<FailException> {
@Override
public Response toResponse(final FailException exception) {
LOGGER.warn("Catch FailException:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={}", ret.uuid);
// Not display backtrace ==> this may be a normal case ...

View File

@@ -13,6 +13,7 @@ public class InputExceptionCatcher implements ExceptionMapper<InputException> {
@Override
public Response toResponse(final InputException exception) {
LOGGER.warn("Catch InputException:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={} ==> '{}'=>'{}'", ret.uuid, exception.missingVariable, exception.getLocalizedMessage());
// exception.printStackTrace();

View File

@@ -13,6 +13,7 @@ public class SystemExceptionCatcher implements ExceptionMapper<SystemException>
@Override
public Response toResponse(final SystemException exception) {
LOGGER.warn("Catch SystemException:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={}", ret.uuid);
exception.printStackTrace();

View File

@@ -5,20 +5,21 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
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;
@@ -26,27 +27,26 @@ import org.kar.archidata.dataAccess.addOn.AddOnManyToOne;
import org.kar.archidata.dataAccess.addOn.AddOnSQLTableExternalForeinKeyAsList;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.DBInterfaceOption;
import org.kar.archidata.dataAccess.options.DBInterfaceRoot;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.TransmitKey;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.DateTools;
import org.kar.archidata.tools.UuidUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.InternalServerErrorException;
/* TODO list:
- useful code to manage external query: List<T> query<T>(class<T> clazz, String query, List<Object> parameters);
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
ResultSetMetaData rsmd = rs.getMetaData();
String name = rsmd.getColumnName(1);
- Manage to group of SQL action to permit to commit only at the end.
*/
/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite
@@ -73,7 +73,8 @@ public class DataAccess {
}
public static boolean isDBExist(final String name) throws InternalServerErrorException {
public static boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException {
final QueryOptions options = new QueryOptions(option);
if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
// no base manage in sqLite ...
// TODO: check if the file exist or not ...
@@ -81,7 +82,7 @@ public class DataAccess {
}
DBEntry entry;
try {
entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, true);
entry = DBInterfaceOption.getAutoEntry(options);
} catch (final IOException ex) {
ex.printStackTrace();
LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage());
@@ -124,7 +125,7 @@ public class DataAccess {
return true;
}
try {
return 1 == DataAccess.executeSimpleQuerry("CREATE DATABASE `" + name + "`;", true);
return 1 == DataAccess.executeSimpleQuerry("CREATE DATABASE `" + name + "`;", new DBInterfaceRoot(true));
} catch (final SQLException | IOException ex) {
ex.printStackTrace();
LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage());
@@ -132,7 +133,8 @@ public class DataAccess {
}
}
public static boolean isTableExist(final String name) throws InternalServerErrorException {
public static boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException {
final QueryOptions options = new QueryOptions(option);
try {
String request = "";
if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
@@ -143,14 +145,14 @@ public class DataAccess {
AND name = ?;
""";
// PreparedStatement ps = entry.connection.prepareStatement("show tables");
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final PreparedStatement ps = entry.connection.prepareStatement(request);
ps.setString(1, name);
final ResultSet ret = ps.executeQuery();
final int count = ret.getInt("total");
return count == 1;
} else {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
// TODO : Maybe connect with a temporary not specified connection interface to a db ...
final PreparedStatement ps = entry.connection.prepareStatement("show tables");
final ResultSet rs = ps.executeQuery();
@@ -192,7 +194,15 @@ public class DataAccess {
}
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) {
if (type == UUID.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.BINARY);
} else {
final byte[] dataByte = UuidUtils.asBytes((UUID) tmp);
ps.setBytes(iii.value, dataByte);
}
} else if (type == Long.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.BIGINT);
@@ -252,6 +262,14 @@ public class DataAccess {
final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant());
ps.setTimestamp(iii.value, sqlDate);
}
} else if (type == Instant.class) {
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final String sqlDate = ((Instant) tmp).toString();
ps.setString(iii.value, sqlDate);
}
} else if (type == LocalDate.class) {
final Object tmp = field.get(data);
if (tmp == null) {
@@ -289,7 +307,18 @@ 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 == Long.class) {
if (type == UUID.class) {
final byte[] tmp = rs.getBytes(count.value);
// final UUID tmp = rs.getObject(count.value, UUID.class);
if (rs.wasNull()) {
field.set(data, null);
} else {
// field.set(data, tmp);
final UUID uuid = UuidUtils.asUuid(tmp);
field.set(data, uuid);
countNotNull.inc();
}
} else if (type == Long.class) {
final Long tmp = rs.getLong(count.value);
if (rs.wasNull()) {
field.set(data, null);
@@ -398,6 +427,14 @@ public class DataAccess {
countNotNull.inc();
}
}
} else if (type == Instant.class) {
final String tmp = rs.getString(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
field.set(data, Instant.parse(tmp));
countNotNull.inc();
}
} else if (type == LocalDate.class) {
final java.sql.Date tmp = rs.getDate(count.value);
if (rs.wasNull()) {
@@ -447,6 +484,220 @@ public class DataAccess {
count.inc();
}
// TODO: this function will replace the previous one !!!
protected static RetreiveFromDB createSetValueFromDbCallback(final int count, final Field field) throws Exception {
final Class<?> type = field.getType();
if (type == UUID.class) {
return (final ResultSet rs, final Object obj) -> {
final byte[] tmp = rs.getBytes(count);
// final UUID tmp = rs.getObject(count, UUID.class);
if (rs.wasNull()) {
field.set(obj, null);
} else {
// field.set(obj, tmp);
final UUID uuid = UuidUtils.asUuid(tmp);
field.set(obj, uuid);
}
};
}
if (type == Long.class) {
return (final ResultSet rs, final Object obj) -> {
final Long tmp = rs.getLong(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp);
}
};
}
if (type == long.class) {
return (final ResultSet rs, final Object obj) -> {
final Long tmp = rs.getLong(count);
if (rs.wasNull()) {
// field.set(data, null);
} else {
field.setLong(obj, tmp);
}
};
}
if (type == Integer.class) {
return (final ResultSet rs, final Object obj) -> {
final Integer tmp = rs.getInt(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp);
}
};
}
if (type == int.class) {
return (final ResultSet rs, final Object obj) -> {
final Integer tmp = rs.getInt(count);
if (rs.wasNull()) {
// field.set(obj, null);
} else {
field.setInt(obj, tmp);
}
};
}
if (type == Float.class) {
return (final ResultSet rs, final Object obj) -> {
final Float tmp = rs.getFloat(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp);
}
};
}
if (type == float.class) {
return (final ResultSet rs, final Object obj) -> {
final Float tmp = rs.getFloat(count);
if (rs.wasNull()) {
// field.set(obj, null);
} else {
field.setFloat(obj, tmp);
}
};
}
if (type == Double.class) {
return (final ResultSet rs, final Object obj) -> {
final Double tmp = rs.getDouble(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp);
}
};
}
if (type == double.class) {
return (final ResultSet rs, final Object obj) -> {
final Double tmp = rs.getDouble(count);
if (rs.wasNull()) {
// field.set(obj, null);
} else {
field.setDouble(obj, tmp);
}
};
}
if (type == Boolean.class) {
return (final ResultSet rs, final Object obj) -> {
final Boolean tmp = rs.getBoolean(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp);
}
};
}
if (type == boolean.class) {
return (final ResultSet rs, final Object obj) -> {
final Boolean tmp = rs.getBoolean(count);
if (rs.wasNull()) {
// field.set(obj, null);
} else {
field.setBoolean(obj, tmp);
}
};
}
if (type == Timestamp.class) {
return (final ResultSet rs, final Object obj) -> {
final Timestamp tmp = rs.getTimestamp(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp);
}
};
}
if (type == Date.class) {
return (final ResultSet rs, final Object obj) -> {
try {
final Timestamp tmp = rs.getTimestamp(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, Date.from(tmp.toInstant()));
}
} catch (final SQLException ex) {
final String tmp = rs.getString(count);
LOGGER.error("Fail to parse the SQL time !!! {}", tmp);
if (rs.wasNull()) {
field.set(obj, null);
} else {
final Date date = DateTools.parseDate(tmp);
LOGGER.error("Fail to parse the SQL time !!! {}", date);
field.set(obj, date);
}
}
};
}
if (type == Instant.class) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, Instant.parse(tmp));
}
};
}
if (type == LocalDate.class) {
return (final ResultSet rs, final Object obj) -> {
final java.sql.Date tmp = rs.getDate(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp.toLocalDate());
}
};
}
if (type == LocalTime.class) {
return (final ResultSet rs, final Object obj) -> {
final java.sql.Time tmp = rs.getTime(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp.toLocalTime());
}
};
}
if (type == String.class) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
field.set(obj, tmp);
}
};
}
if (type.isEnum()) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (rs.wasNull()) {
field.set(obj, null);
} else {
boolean find = false;
final Object[] arr = type.getEnumConstants();
for (final Object elem : arr) {
if (elem.toString().equals(tmp)) {
field.set(obj, elem);
find = true;
break;
}
}
if (!find) {
throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'");
}
}
};
}
throw new DataAccessException("Unknown Field Type");
}
public static boolean isAddOnField(final Field field) {
return findAddOnforField(field) != null;
}
@@ -480,10 +731,13 @@ public class DataAccess {
check.getChecker().check("", data, AnnotationTools.getFieldsNames(clazz));
}
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final List<Field> asyncFieldUpdate = new ArrayList<>();
Long uniqueSQLID = null;
UUID uniqueSQLUUID = null;
final String tableName = AnnotationTools.getTableName(clazz, options);
Field primaryKeyField = null;
boolean generateUUID = false;
// real add in the BDD:
try {
// boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
@@ -494,6 +748,30 @@ public class DataAccess {
boolean firstField = true;
int count = 0;
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.isPrimaryKey(field)) {
primaryKeyField = field;
if (primaryKeyField.getType() != UUID.class) {
break;
}
generateUUID = true;
count++;
final String name = AnnotationTools.getFieldName(field);
if (firstField) {
firstField = false;
} else {
query.append(",");
}
query.append(" `");
query.append(name);
query.append("`");
break;
}
}
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@@ -519,7 +797,7 @@ public class DataAccess {
}
if (!field.getClass().isPrimitive()) {
final Object tmp = field.get(data);
if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) {
continue;
}
}
@@ -552,15 +830,21 @@ public class DataAccess {
LOGGER.warn("generate the query: '{}'", query.toString());
// prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
Field primaryKeyField = null;
final CountInOut iii = new CountInOut(1);
UUID uuid = null;
if (generateUUID) {
firstField = false;
uuid = UUID.randomUUID();
addElement(ps, uuid, iii);
iii.inc();
}
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
if (AnnotationTools.isPrimaryKey(elem)) {
primaryKeyField = elem;
continue;
}
final DataAccessAddOn addOn = findAddOnforField(elem);
@@ -583,7 +867,7 @@ public class DataAccess {
final Class<?> type = elem.getType();
if (!type.isPrimitive()) {
final Object tmp = elem.get(data);
if (tmp == null && elem.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
if (tmp == null && elem.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) {
continue;
}
}
@@ -597,22 +881,44 @@ public class DataAccess {
throw new SQLException("Creating node failed, no rows affected.");
}
// Retrieve uid inserted
try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
if (generatedKeys.next()) {
uniqueSQLID = generatedKeys.getLong(1);
} else {
throw new SQLException("Creating node failed, no ID obtained (1).");
if (generateUUID) {
// we generate the UUID, otherwise we can not retrieve it
uniqueSQLUUID = uuid;
} else {
try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
if (generatedKeys.next()) {
if (primaryKeyField.getType() == UUID.class) {
// uniqueSQLUUID = generatedKeys.getObject(1, UUID.class);
/*
final Object obj = generatedKeys.getObject(1);
final BigInteger bigint = (BigInteger) generatedKeys.getObject(1);
uniqueSQLUUID = UuidUtils.asUuid(bigint);
final UUID generatedUUID = (UUID) generatedKeys.getObject(1);
System.out.println("UUID généré: " + generatedUUID);
*/
final Object obj = generatedKeys.getObject(1);
final byte[] tmpid = generatedKeys.getBytes(1);
uniqueSQLUUID = UuidUtils.asUuid(tmpid);
} else {
uniqueSQLID = generatedKeys.getLong(1);
}
} else {
throw new SQLException("Creating node failed, no ID obtained (1).");
}
} catch (final Exception ex) {
LOGGER.error("Can not get the UID key inserted ... ");
ex.printStackTrace();
throw new SQLException("Creating node failed, no ID obtained (2).");
}
} catch (final Exception ex) {
LOGGER.error("Can not get the UID key inserted ... ");
ex.printStackTrace();
throw new SQLException("Creating node failed, no ID obtained (2).");
}
if (primaryKeyField != null) {
if (primaryKeyField.getType() == Long.class) {
primaryKeyField.set(data, uniqueSQLID);
} else if (primaryKeyField.getType() == long.class) {
primaryKeyField.setLong(data, uniqueSQLID);
} else if (primaryKeyField.getType() == UUID.class) {
primaryKeyField.set(data, uniqueSQLUUID);
} else {
LOGGER.error("Can not manage the primary filed !!!");
}
@@ -622,7 +928,6 @@ public class DataAccess {
ex.printStackTrace();
} finally {
entry.close();
entry = null;
}
final List<LazyGetter> asyncActions = new ArrayList<>();
for (final Field field : asyncFieldUpdate) {
@@ -711,13 +1016,21 @@ public class DataAccess {
* @param filterValue
* @return the affected rows.
* @throws Exception */
public static <T, ID_TYPE> int update(final T data, final ID_TYPE id, final List<String> updateColomn) throws Exception {
return updateWhere(data, new Condition(getTableIdCondition(data.getClass(), id)), new FilterValue(updateColomn), new TransmitKey(id));
public static <T, ID_TYPE> int update(final T data, final ID_TYPE id, final List<String> updateColomn, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(data.getClass(), id)));
options.add(new FilterValue(updateColomn));
options.add(new TransmitKey(id));
return updateWhere(data, options);
}
public static <T> int updateWhere(final T data, final QueryOption... option) throws Exception {
final Class<?> clazz = data.getClass();
final QueryOptions options = new QueryOptions(option);
return updateWhere(data, options);
}
public static <T> int updateWhere(final T data, final QueryOptions options) throws Exception {
final Class<?> clazz = data.getClass();
final Condition condition = options.get(Condition.class);
if (condition == null) {
throw new DataAccessException("request a gets without any condition");
@@ -734,9 +1047,9 @@ public class DataAccess {
}
}
final List<LazyGetter> asyncActions = new ArrayList<>();
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
// real add in the BDD:
try {
try (entry) {
final String tableName = AnnotationTools.getTableName(clazz, options);
// boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
final StringBuilder query = new StringBuilder();
@@ -769,7 +1082,7 @@ public class DataAccess {
}
if (!field.getClass().isPrimitive()) {
final Object tmp = field.get(data);
if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) {
continue;
}
}
@@ -816,7 +1129,7 @@ public class DataAccess {
final Class<?> type = field.getType();
if (!type.isPrimitive()) {
final Object tmp = field.get(data);
if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) {
if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) {
continue;
}
}
@@ -830,9 +1143,6 @@ public class DataAccess {
}
} catch (final SQLException ex) {
ex.printStackTrace();
} finally {
entry.close();
entry = null;
}
for (final LazyGetter action : asyncActions) {
action.doRequest();
@@ -841,7 +1151,10 @@ public class DataAccess {
}
static void addElement(final PreparedStatement ps, final Object value, final CountInOut iii) throws Exception {
if (value instanceof final Long tmp) {
if (value instanceof final UUID tmp) {
final byte[] dataByte = UuidUtils.asBytes(tmp);
ps.setBytes(iii.value, dataByte);
} else if (value instanceof final Long tmp) {
LOGGER.debug("Inject Long => {}", tmp);
ps.setLong(iii.value, tmp);
} else if (value instanceof final Integer tmp) {
@@ -885,26 +1198,20 @@ public class DataAccess {
}
}
public static int executeSimpleQuerry(final String query, final boolean root) throws SQLException, IOException {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root);
public static int executeSimpleQuerry(final String query, final QueryOption... option) throws SQLException, IOException {
final QueryOptions options = new QueryOptions(option);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final Statement stmt = entry.connection.createStatement();
return stmt.executeUpdate(query);
}
public static int executeSimpleQuerry(final String query) throws SQLException, IOException {
return executeSimpleQuerry(query, false);
}
public static boolean executeQuerry(final String query, final boolean root) throws SQLException, IOException {
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root);
public static boolean executeQuerry(final String query, final QueryOption... option) throws SQLException, IOException {
final QueryOptions options = new QueryOptions(option);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final Statement stmt = entry.connection.createStatement();
return stmt.execute(query);
}
public static boolean executeQuerry(final String query) throws SQLException, IOException {
return executeQuerry(query, false);
}
public static <T> T getWhere(final Class<T> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Limit(1));
@@ -915,8 +1222,6 @@ public class DataAccess {
return values.get(0);
}
/* public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition) throws Exception { return getsWhere(clazz, condition, null); } */
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.readAllColomn(options);
final String tableName = AnnotationTools.getTableName(clazz, options);
@@ -966,7 +1271,7 @@ public class DataAccess {
}
final List<LazyGetter> lazyCall = new ArrayList<>();
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final List<T> outs = new ArrayList<>();
// real add in the BDD:
try {
@@ -983,6 +1288,10 @@ public class DataAccess {
querySelect.append(query.toString());
query = querySelect;
condition.whereAppendQuery(query, tableName, options, deletedFieldName);
final GroupBy groups = options.get(GroupBy.class);
if (groups != null) {
groups.generateQuerry(query, null);
}
final OrderBy orders = options.get(OrderBy.class);
if (orders != null) {
orders.generateQuerry(query, tableName);
@@ -1019,7 +1328,6 @@ public class DataAccess {
ex.printStackTrace();
} finally {
entry.close();
entry = null;
}
return outs;
}
@@ -1070,7 +1378,7 @@ public class DataAccess {
condition = new Condition();
}
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
DBEntry entry = DBInterfaceOption.getAutoEntry(options);
long count = 0;
// real add in the BDD:
try {
@@ -1172,8 +1480,7 @@ public class DataAccess {
final String tableName = AnnotationTools.getTableName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
// find the deleted field
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final StringBuilder query = new StringBuilder();
query.append("DELETE FROM `");
query.append(tableName);
@@ -1187,7 +1494,6 @@ public class DataAccess {
return ps.executeUpdate();
} finally {
entry.close();
entry = null;
}
}
@@ -1207,8 +1513,7 @@ public class DataAccess {
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
/* String updateFieldName = null; if ("sqlite".equalsIgnoreCase(ConfigBaseVariable.getDBType())) { updateFieldName = AnnotationTools.getUpdatedFieldName(clazz); } */
// find the deleted field
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final StringBuilder query = new StringBuilder();
query.append("UPDATE `");
query.append(tableName);
@@ -1226,7 +1531,6 @@ public class DataAccess {
return ps.executeUpdate();
} finally {
entry.close();
entry = null;
}
}
@@ -1251,7 +1555,7 @@ public class DataAccess {
if (deletedFieldName == null) {
throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field");
}
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final StringBuilder query = new StringBuilder();
query.append("UPDATE `");
query.append(tableName);
@@ -1268,14 +1572,13 @@ public class DataAccess {
return ps.executeUpdate();
} finally {
entry.close();
entry = null;
}
}
public static void drop(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final String tableName = AnnotationTools.getTableName(clazz, options);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final StringBuilder query = new StringBuilder();
query.append("DROP TABLE IF EXISTS `");
query.append(tableName);
@@ -1301,14 +1604,13 @@ public class DataAccess {
}
} finally {
entry.close();
entry = null;
}
}
public static void cleanAll(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final String tableName = AnnotationTools.getTableName(clazz, options);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final StringBuilder query = new StringBuilder();
query.append("DELETE FROM `");
query.append(tableName);
@@ -1338,4 +1640,110 @@ public class DataAccess {
}
}
/** Execute a simple query with external property.
* @param <TYPE> Type of the data generate.
* @param clazz Class that might be analyze.
* @param query Base of the query.
* @param parameters "?" parameter of the query.
* @param option Optional parameters
* @return The list of element requested
* @throws Exception */
public static <TYPE> List<TYPE> query(final Class<TYPE> clazz, final String query, final List<Object> parameters, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return query(clazz, query, parameters, options);
}
public static <TYPE> List<TYPE> query(final Class<TYPE> clazz, final String queryBase, final List<Object> parameters, final QueryOptions options) throws Exception {
final List<LazyGetter> lazyCall = new ArrayList<>();
// TODO ... final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
Condition condition = options.get(Condition.class);
if (condition == null) {
condition = new Condition();
}
final StringBuilder query = new StringBuilder(queryBase);
final List<TYPE> outs = new ArrayList<>();
// real add in the BDD:
try {
final CountInOut count = new CountInOut();
condition.whereAppendQuery(query, null, options, null);
final GroupBy groups = options.get(GroupBy.class);
if (groups != null) {
groups.generateQuerry(query, null);
}
final OrderBy orders = options.get(OrderBy.class);
if (orders != null) {
orders.generateQuerry(query, null);
}
final Limit limit = options.get(Limit.class);
if (limit != null) {
limit.generateQuerry(query, null);
}
LOGGER.warn("generate the query: '{}'", query.toString());
// prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
final CountInOut iii = new CountInOut(1);
if (parameters != null) {
for (final Object elem : parameters) {
DataAccess.addElement(ps, elem, iii);
}
iii.inc();
}
condition.injectQuerry(ps, iii);
if (limit != null) {
limit.injectQuerry(ps, iii);
}
// execute the request
final ResultSet rs = ps.executeQuery();
final ResultSetMetaData rsmd = rs.getMetaData();
final List<RetreiveFromDB> actionToRetreive = new ArrayList<>();
LOGGER.info("Field:");
for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) {
final String label = rsmd.getColumnLabel(jjj + 1);
LOGGER.info(" - {}:{}", jjj, label);
// find field name ...
final Field field = AnnotationTools.getFieldNamed(clazz, label);
if (field == null) {
throw new DataAccessException("Querry with unknown field: '" + label + "'");
}
// create the callback...
final RetreiveFromDB element = createSetValueFromDbCallback(jjj + 1, field);
actionToRetreive.add(element);
}
while (rs.next()) {
count.value = 1;
Object data = null;
for (final Constructor<?> contructor : clazz.getConstructors()) {
if (contructor.getParameterCount() == 0) {
data = contructor.newInstance();
}
}
if (data == null) {
// TODO...
} else {
for (final RetreiveFromDB action : actionToRetreive) {
action.doRequest(rs, data);
}
}
@SuppressWarnings("unchecked")
final TYPE out = (TYPE) 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;
} catch (final Exception ex) {
ex.printStackTrace();
} finally {
entry.close();
}
return outs;
}
}

View File

@@ -0,0 +1,399 @@
package org.kar.archidata.dataAccess;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.dataAccess.exportTools.TableQuery;
import org.kar.archidata.dataAccess.exportTools.TableQueryTypes;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.DBInterfaceOption;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.DateTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class DataExport {
static final Logger LOGGER = LoggerFactory.getLogger(DataExport.class);
public static final String CSV_TYPE = "text/csv";
@SuppressWarnings("unchecked")
protected static RetreiveFromDB createSetValueFromDbCallbackTable(final int count, final Class<?> type, final int id) throws Exception {
if (type == UUID.class) {
return (final ResultSet rs, final Object obj) -> {
final UUID tmp = rs.getObject(count, UUID.class);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Long.class) {
return (final ResultSet rs, final Object obj) -> {
final Long tmp = rs.getLong(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == long.class) {
return (final ResultSet rs, final Object obj) -> {
final Long tmp = rs.getLong(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Integer.class) {
return (final ResultSet rs, final Object obj) -> {
final Integer tmp = rs.getInt(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == int.class) {
return (final ResultSet rs, final Object obj) -> {
final Integer tmp = rs.getInt(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Float.class) {
return (final ResultSet rs, final Object obj) -> {
final Float tmp = rs.getFloat(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == float.class) {
return (final ResultSet rs, final Object obj) -> {
final Float tmp = rs.getFloat(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Double.class) {
return (final ResultSet rs, final Object obj) -> {
final Double tmp = rs.getDouble(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == double.class) {
return (final ResultSet rs, final Object obj) -> {
final Double tmp = rs.getDouble(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Boolean.class) {
return (final ResultSet rs, final Object obj) -> {
final Boolean tmp = rs.getBoolean(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == boolean.class) {
return (final ResultSet rs, final Object obj) -> {
final Boolean tmp = rs.getBoolean(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Timestamp.class) {
return (final ResultSet rs, final Object obj) -> {
final Timestamp tmp = rs.getTimestamp(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Date.class) {
return (final ResultSet rs, final Object obj) -> {
try {
final Timestamp tmp = rs.getTimestamp(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, Date.from(tmp.toInstant()));
}
} catch (final SQLException ex) {
final String tmp = rs.getString(count);
LOGGER.error("Fail to parse the SQL time !!! {}", tmp);
if (!rs.wasNull()) {
final Date date = DateTools.parseDate(tmp);
LOGGER.error("Fail to parse the SQL time !!! {}", date);
final List<Object> data = (List<Object>) (obj);
data.set(id, date);
}
}
};
}
if (type == Instant.class) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (!rs.wasNull()) {
final Instant date = Instant.parse(tmp);
LOGGER.error("Fail to parse the SQL time !!! {}", date);
final List<Object> data = (List<Object>) (obj);
data.set(id, date);
}
};
}
if (type == LocalDate.class) {
return (final ResultSet rs, final Object obj) -> {
final java.sql.Date tmp = rs.getDate(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp.toLocalDate());
}
};
}
if (type == LocalTime.class) {
return (final ResultSet rs, final Object obj) -> {
final java.sql.Time tmp = rs.getTime(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp.toLocalTime());
}
};
}
if (type == String.class) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type.isEnum()) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (!rs.wasNull()) {
boolean find = false;
final Object[] arr = type.getEnumConstants();
for (final Object elem : arr) {
if (elem.toString().equals(tmp)) {
final List<Object> data = (List<Object>) (obj);
data.set(id, elem);
find = true;
break;
}
}
if (!find) {
throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'");
}
}
};
}
throw new DataAccessException("Unknown Field Type");
}
private static int getQueryPropertyId(final List<TableQueryTypes> properties, final String name) throws DataAccessException {
for (int iii = 0; iii < properties.size(); iii++) {
if (properties.get(iii).name.equals(name)) {
return iii;
}
}
throw new DataAccessException("Querry with unknown field: '" + name + "'");
}
public static TableQuery queryTable(final List<TableQueryTypes> headers, final String query, final List<Object> parameters, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return queryTable(headers, query, parameters, options);
}
public static TableQuery queryTable(final List<TableQueryTypes> headers, final String queryBase, final List<Object> parameters, final QueryOptions options) throws Exception {
final List<LazyGetter> lazyCall = new ArrayList<>();
// TODO ... final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
Condition condition = options.get(Condition.class);
if (condition == null) {
condition = new Condition();
}
final StringBuilder query = new StringBuilder(queryBase);
final TableQuery out = new TableQuery(headers);
// real add in the BDD:
try {
final CountInOut count = new CountInOut();
condition.whereAppendQuery(query, null, options, null);
final GroupBy groups = options.get(GroupBy.class);
if (groups != null) {
groups.generateQuerry(query, null);
}
final OrderBy orders = options.get(OrderBy.class);
if (orders != null) {
orders.generateQuerry(query, null);
}
final Limit limit = options.get(Limit.class);
if (limit != null) {
limit.generateQuerry(query, null);
}
LOGGER.warn("generate the query: '{}'", query.toString());
// prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
final CountInOut iii = new CountInOut(1);
if (parameters != null) {
for (final Object elem : parameters) {
DataAccess.addElement(ps, elem, iii);
}
iii.inc();
}
condition.injectQuerry(ps, iii);
if (limit != null) {
limit.injectQuerry(ps, iii);
}
// execute the request
final ResultSet rs = ps.executeQuery();
final ResultSetMetaData rsmd = rs.getMetaData();
final List<RetreiveFromDB> actionToRetreive = new ArrayList<>();
LOGGER.info("Field:");
for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) {
final String label = rsmd.getColumnLabel(jjj + 1);
final String typeName = rsmd.getColumnTypeName(jjj + 1);
final int typeId = rsmd.getColumnType(jjj + 1);
final int id = getQueryPropertyId(headers, label);
LOGGER.info(" - {}:{} type=[{}] {} REQUEST={}", jjj, label, typeId, typeName, headers.get(id).type.getCanonicalName());
// create the callback...
final RetreiveFromDB element = createSetValueFromDbCallbackTable(jjj + 1, headers.get(id).type, id);
actionToRetreive.add(element);
}
while (rs.next()) {
count.value = 1;
final List<Object> data = Arrays.asList(new Object[headers.size()]);
for (final RetreiveFromDB action : actionToRetreive) {
action.doRequest(rs, data);
}
out.values.add(data);
}
LOGGER.info("Async calls: {}", lazyCall.size());
for (final LazyGetter elem : lazyCall) {
elem.doRequest();
}
} catch (final SQLException ex) {
ex.printStackTrace();
throw ex;
} catch (final Exception ex) {
ex.printStackTrace();
} finally {
entry.close();
}
return out;
}
public static String CSVReplaceSeparator(final String data, final String separator) {
if (data == null) {
return "";
}
final String separatorLine = "\n";
final String separatorLineReplace = "\\n";
return data.replaceAll(separator, "__SEP__").replaceAll(separatorLine, separatorLineReplace);
}
public static String tableToCSV(final TableQuery data) {
final String separator = ";";
final StringBuilder out = new StringBuilder();
// generate header:
boolean first = true;
for (final TableQueryTypes elem : data.headers) {
if (!first) {
out.append(separator);
} else {
first = false;
}
out.append(CSVReplaceSeparator(elem.title, separator));
}
out.append("\n");
// generate body:
first = true;
for (final List<Object> line : data.values) {
for (final Object elem : line) {
if (!first) {
out.append(separator);
} else {
first = false;
}
if (elem != null) {
out.append(CSVReplaceSeparator(elem.toString(), separator));
}
}
out.append("\n");
}
return out.toString();
}
public static Response convertInResponse(final TableQuery dataOut, final String accept) throws DataAccessException, IOException {
if (CSV_TYPE.equals(accept)) {
// CSV serialization
String out = null;
try {
out = DataExport.tableToCSV(dataOut);
} catch (final Exception e) {
LOGGER.error("Fail to generate CSV....");
e.printStackTrace();
throw new DataAccessException("Fail in CSV convertion data");
}
return Response.ok(out).header("Content-Type", CSV_TYPE).build();
}
if (MediaType.APPLICATION_JSON.equals(accept)) {
LOGGER.info("Start mapping josn");
final ObjectMapper objectMapper = new ObjectMapper();
LOGGER.info("Start find modules josn");
objectMapper.findAndRegisterModules();
LOGGER.info("Start map object");
String out;
try {
out = objectMapper.writeValueAsString(dataOut);
} catch (final JsonProcessingException e) {
LOGGER.error("Fail to generate JSON....");
e.printStackTrace();
throw new DataAccessException("Fail in JSON convertion data");
}
LOGGER.info("generate response");
return Response.ok(out).header("Content-Type", MediaType.APPLICATION_JSON).build();
}
throw new IOException("This type is not managed: '" + accept + "'");
}
}

View File

@@ -2,11 +2,13 @@ package org.kar.archidata.dataAccess;
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.List;
import java.util.UUID;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
@@ -27,6 +29,9 @@ public class DataFactory {
public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws Exception {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
if (type == UUID.class) {
return "binary(16)";
}
if (type == Long.class || type == long.class) {
return "bigint";
}
@@ -42,6 +47,9 @@ public class DataFactory {
if (type == Double.class || type == double.class) {
return "double";
}
if (type == Instant.class) {
return "varchar(33)";
}
if (type == Date.class || type == Timestamp.class) {
return "timestamp(3)";
}
@@ -75,6 +83,9 @@ public class DataFactory {
return out.toString();
}
} else {
if (type == UUID.class) {
return "BINARY(16)";
}
if (type == Long.class || type == long.class) {
return "INTEGER";
}
@@ -90,6 +101,9 @@ public class DataFactory {
if (type == Double.class || type == double.class) {
return "REAL";
}
if (type == Instant.class) {
return "text";
}
if (type == Date.class || type == Timestamp.class) {
return "DATETIME";
}
@@ -172,16 +186,24 @@ public class DataFactory {
}
if (defaultValue == null) {
if (updateTime || createTime) {
mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP");
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("(3)");
if ("varchar(33)".equals(typeValue)) {
mainTableBuilder.append("DEFAULT DATE_FORMAT(now(6), '%Y-%m-%dT%H:%m:%s.%fZ')");
} else {
mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP");
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("(3)");
}
}
mainTableBuilder.append(" ");
}
if (updateTime) {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP");
mainTableBuilder.append("(3)");
if ("varchar(33)".equals(typeValue)) {
mainTableBuilder.append("ON UPDATE DATE_FORMAT(now(6), '%Y-%m-%dT%H:%m:%s.%fZ')");
} else {
mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP");
mainTableBuilder.append("(3)");
}
} else {
// TODO: add trigger:
/* CREATE TRIGGER your_table_trig AFTER UPDATE ON your_table BEGIN update your_table SET updated_on = datetime('now') WHERE user_id = NEW.user_id; END; */
@@ -195,7 +217,11 @@ public class DataFactory {
triggerBuilder.append(" SET ");
triggerBuilder.append(name);
// triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n");
triggerBuilder.append(" = strftime('%Y-%m-%d %H:%M:%f', 'now') WHERE id = NEW.id; \n");
if ("varchar(33)".equals(typeValue)) {
triggerBuilder.append(" = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = NEW.id; \n");
} else {
triggerBuilder.append(" = strftime('%Y-%m-%d %H:%M:%f', 'now') WHERE id = NEW.id; \n");
}
triggerBuilder.append("END;");
postOtherTables.add(triggerBuilder.toString());
@@ -241,8 +267,11 @@ public class DataFactory {
mainTableBuilder.append("PRIMARY KEY ");
}
if (strategy == GenerationType.IDENTITY) {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
if ("binary(16)".equals(typeValue)) {
} else if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("AUTO_INCREMENT ");
} else {
mainTableBuilder.append("AUTOINCREMENT ");

View File

@@ -0,0 +1,572 @@
package org.kar.archidata.dataAccess;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.catcher.RestErrorResponse;
import org.kar.archidata.dataAccess.DataFactoryZod.ClassElement;
import org.kar.archidata.dataAccess.DataFactoryZod.GeneratedTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class DataFactoryTsApi {
static final Logger LOGGER = LoggerFactory.getLogger(DataFactoryTsApi.class);
record APIModel(String data, String className) {
}
/** Request the generation of the TypeScript file for the "Zod" export model
* @param classs List of class used in the model
* @throws Exception */
public static List<String> createApi(final List<Class<?>> classs, final GeneratedTypes previous, final String pathPackage) throws Exception {
final List<String> apis = new ArrayList<>();
final String globalheader = """
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { """;
for (final Class<?> clazz : classs) {
final Set<Class<?>> includeModel = new HashSet<>();
final Set<Class<?>> includeCheckerModel = new HashSet<>();
final APIModel api = createSingleApi(clazz, includeModel, includeCheckerModel, previous);
final StringBuilder generatedData = new StringBuilder();
generatedData.append(globalheader);
for (final Class<?> elem : includeModel) {
if (elem == null) {
continue;
}
final ClassElement classElement = DataFactoryZod.createTable(elem, previous);
if (classElement.nativeType) {
continue;
}
generatedData.append(classElement.tsTypeName);
generatedData.append(", ");
}
for (final Class<?> elem : includeCheckerModel) {
if (elem == null) {
continue;
}
final ClassElement classElement = DataFactoryZod.createTable(elem, previous);
if (classElement.nativeType) {
continue;
}
generatedData.append(classElement.tsCheckType);
generatedData.append(", ");
}
generatedData.append("} from \"./model\"\n");
generatedData.append(api.data());
String fileName = api.className();
fileName = fileName.replaceAll("([A-Z])", "-$1").toLowerCase();
fileName = fileName.replaceAll("^\\-*", "");
apis.add(fileName);
final FileWriter myWriter = new FileWriter(pathPackage + File.separator + fileName + ".ts");
myWriter.write(generatedData.toString());
myWriter.close();
}
return apis;
}
public static String apiAnnotationGetPath(final Class<?> element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Path.class);
if (annotation.length == 0) {
return null;
}
return ((Path) annotation[0]).value();
}
public static List<String> apiAnnotationProduces(final Class<?> element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Produces.class);
if (annotation.length == 0) {
return null;
}
return Arrays.asList(((Produces) annotation[0]).value());
}
public static List<String> apiAnnotationProduces(final Method element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Produces.class);
if (annotation.length == 0) {
return null;
}
return Arrays.asList(((Produces) annotation[0]).value());
}
public static List<String> apiAnnotationProduces(final Class<?> clazz, final Method method) throws Exception {
final List<String> data = apiAnnotationProduces(method);
if (data != null) {
return data;
}
return apiAnnotationProduces(clazz);
}
public static String apiAnnotationGetOperationDescription(final Method element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Operation.class);
if (annotation.length == 0) {
return null;
}
return ((Operation) annotation[0]).description();
}
public static String apiAnnotationGetPath(final Method element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Path.class);
if (annotation.length == 0) {
return null;
}
return ((Path) annotation[0]).value();
}
public static String apiAnnotationGetTypeRequest(final Method element) throws Exception {
if (element.getDeclaredAnnotationsByType(GET.class).length == 1) {
return "GET";
}
if (element.getDeclaredAnnotationsByType(POST.class).length == 1) {
return "POST";
}
if (element.getDeclaredAnnotationsByType(PUT.class).length == 1) {
return "PUT";
}
if (element.getDeclaredAnnotationsByType(PATCH.class).length == 1) {
return "PATCH";
}
if (element.getDeclaredAnnotationsByType(DELETE.class).length == 1) {
return "DELETE";
}
return null;
}
public static String apiAnnotationGetPathParam(final Parameter element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(PathParam.class);
if (annotation.length == 0) {
return null;
}
return ((PathParam) annotation[0]).value();
}
public static String apiAnnotationGetQueryParam(final Parameter element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(QueryParam.class);
if (annotation.length == 0) {
return null;
}
return ((QueryParam) annotation[0]).value();
}
public static String apiAnnotationGetFormDataParam(final Parameter element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(FormDataParam.class);
if (annotation.length == 0) {
return null;
}
return ((FormDataParam) annotation[0]).value();
}
public static Class<?> apiAnnotationGetAsyncType(final Parameter element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(AsyncType.class);
if (annotation.length == 0) {
return null;
}
return ((AsyncType) annotation[0]).value();
}
public static Class<?> apiAnnotationGetAsyncType(final Method element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(AsyncType.class);
if (annotation.length == 0) {
return null;
}
return ((AsyncType) annotation[0]).value();
}
public static List<String> apiAnnotationGetConsumes(final Method element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Consumes.class);
if (annotation.length == 0) {
return null;
}
return Arrays.asList(((Consumes) annotation[0]).value());
}
public static List<String> apiAnnotationGetConsumes(final Class<?> element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Consumes.class);
if (annotation.length == 0) {
return null;
}
return Arrays.asList(((Consumes) annotation[0]).value());
}
public static List<String> apiAnnotationGetConsumes(final Class<?> clazz, final Method method) throws Exception {
final List<String> data = apiAnnotationGetConsumes(method);
if (data != null) {
return data;
}
return apiAnnotationGetConsumes(clazz);
}
public static boolean apiAnnotationIsContext(final Parameter element) throws Exception {
return element.getDeclaredAnnotationsByType(Context.class).length != 0;
}
public static APIModel createSingleApi(final Class<?> clazz, final Set<Class<?>> includeModel, final Set<Class<?>> includeCheckerModel, final GeneratedTypes previous) throws Exception {
final StringBuilder builder = new StringBuilder();
// the basic path has no specific elements...
final String basicPath = apiAnnotationGetPath(clazz);
final String classSimpleName = clazz.getSimpleName();
builder.append("export namespace ");
builder.append(classSimpleName);
builder.append(" {\n");
LOGGER.info("Parse Class for path: {} => {}", classSimpleName, basicPath);
for (final Method method : clazz.getDeclaredMethods()) {
final String methodName = method.getName();
final String methodPath = apiAnnotationGetPath(method);
final String methodType = apiAnnotationGetTypeRequest(method);
if (methodType == null) {
LOGGER.error(" [{}] {} => {}/{} ==> No methode type @PATH, @GET ...", methodType, methodName, basicPath, methodPath);
continue;
}
final String methodDescription = apiAnnotationGetOperationDescription(method);
final List<String> consumes = apiAnnotationGetConsumes(clazz, method);
final List<String> produces = apiAnnotationProduces(clazz, method);
LOGGER.trace(" [{}] {} => {}/{}", methodType, methodName, basicPath, methodPath);
if (methodDescription != null) {
LOGGER.trace(" description: {}", methodDescription);
}
Class<?> returnTypeModel = apiAnnotationGetAsyncType(method);
if (returnTypeModel == null) {
returnTypeModel = method.getReturnType();
}
boolean isUnmanagedReturnType = false;
if (returnTypeModel == Response.class ) {
isUnmanagedReturnType = true;
returnTypeModel = Void.class;
}
boolean returnModelIsArray = false;
ClassElement tmpReturn;
if (returnTypeModel == List.class) {
final ParameterizedType listType = (ParameterizedType) method.getGenericReturnType();
returnTypeModel = (Class<?>) listType.getActualTypeArguments()[0];
tmpReturn = DataFactoryZod.createTable(returnTypeModel, previous);
returnModelIsArray = true;
includeModel.add(tmpReturn.model[0]);
} else {
tmpReturn = DataFactoryZod.createTable(returnTypeModel, previous);
}
includeModel.add(tmpReturn.model[0]);
includeCheckerModel.add(tmpReturn.model[0]);
LOGGER.trace(" return: {}", tmpReturn.tsTypeName);
final Map<String, String> queryParams = new HashMap<>();
final Map<String, String> pathParams = new HashMap<>();
final Map<String, String> formDataParams = new HashMap<>();
final List<String> emptyElement = new ArrayList<>();
// LOGGER.info(" Parameters:");
for (final Parameter parameter : method.getParameters()) {
// Security context are internal parameter (not available from API)
if (apiAnnotationIsContext(parameter)) {
continue;
}
final Class<?> parameterType = parameter.getType();
String parameterTypeString;
final Class<?> asyncType = apiAnnotationGetAsyncType(parameter);
if (parameterType == List.class) {
if (asyncType == null) {
LOGGER.warn("Detext List param ==> not managed type ==> any[] !!!");
parameterTypeString = "any[]";
} else {
final ClassElement tmp = DataFactoryZod.createTable(asyncType, previous);
includeModel.add(tmp.model[0]);
parameterTypeString = tmp.tsTypeName + "[]";
}
} else if (asyncType == null) {
final ClassElement tmp = DataFactoryZod.createTable(parameterType, previous);
includeModel.add(tmp.model[0]);
parameterTypeString = tmp.tsTypeName;
} else {
final ClassElement tmp = DataFactoryZod.createTable(asyncType, previous);
includeModel.add(tmp.model[0]);
parameterTypeString = tmp.tsTypeName;
}
final String pathParam = apiAnnotationGetPathParam(parameter);
final String queryParam = apiAnnotationGetQueryParam(parameter);
final String formDataParam = apiAnnotationGetFormDataParam(parameter);
if (queryParam != null) {
queryParams.put(queryParam, parameterTypeString);
} else if (pathParam != null) {
pathParams.put(pathParam, parameterTypeString);
} else if (formDataParam != null) {
formDataParams.put(formDataParam, parameterTypeString);
} else if (asyncType != null) {
final ClassElement tmp = DataFactoryZod.createTable(asyncType, previous);
includeModel.add(tmp.model[0]);
emptyElement.add(tmp.tsTypeName);
} else if (parameterType == List.class) {
parameterTypeString = "any[]";
final Class<?> plop = parameterType.arrayType();
LOGGER.info("ArrayType = {}", plop);
} else {
final ClassElement tmp = DataFactoryZod.createTable(parameterType, previous);
includeModel.add(tmp.model[0]);
emptyElement.add(tmp.tsTypeName);
}
}
if (!queryParams.isEmpty()) {
LOGGER.trace(" Query parameter:");
for (final Entry<String, String> queryEntry : queryParams.entrySet()) {
LOGGER.trace(" - {}: {}", queryEntry.getKey(), queryEntry.getValue());
}
}
if (!pathParams.isEmpty()) {
LOGGER.trace(" Path parameter:");
for (final Entry<String, String> pathEntry : pathParams.entrySet()) {
LOGGER.trace(" - {}: {}", pathEntry.getKey(), pathEntry.getValue());
}
}
if (emptyElement.size() > 1) {
LOGGER.error(" Fail to parse: Too much element in the model for the data ...");
continue;
} else if (emptyElement.size() == 1 && formDataParams.size() != 0) {
LOGGER.error(" Fail to parse: Incompatible form data & direct data ...");
continue;
} else if (emptyElement.size() == 1) {
LOGGER.trace(" data type: {}", emptyElement.get(0));
}
// ALL is good can generate the Elements
if (methodDescription != null) {
builder.append("\n\t/**\n\t * ");
builder.append(methodDescription);
builder.append("\n\t */");
}
if (isUnmanagedReturnType) {
builder.append("\n\t// TODO: unmanaged \"Response\" type: please specify @AsyncType or considered as 'void'.");
}
builder.append("\n\texport function ");
builder.append(methodName);
builder.append("({ restConfig,");
if (!queryParams.isEmpty()) {
builder.append(" queries,");
}
if (!pathParams.isEmpty()) {
builder.append(" params,");
}
if (produces.size() > 1) {
builder.append(" produce,");
}
if (emptyElement.size() == 1) {
builder.append(" data,");
} else if (formDataParams.size() != 0) {
builder.append(" data,");
}
builder.append(" }: {");
builder.append("\n\t\trestConfig: RESTConfig,");
if (!queryParams.isEmpty()) {
builder.append("\n\t\tqueries: {");
for (final Entry<String, String> queryEntry : queryParams.entrySet()) {
builder.append("\n\t\t\t");
builder.append(queryEntry.getKey());
builder.append(": ");
builder.append(queryEntry.getValue());
builder.append(",");
}
builder.append("\n\t\t},");
}
if (!pathParams.isEmpty()) {
builder.append("\n\t\tparams: {");
for (final Entry<String, String> pathEntry : pathParams.entrySet()) {
builder.append("\n\t\t\t");
builder.append(pathEntry.getKey());
builder.append(": ");
builder.append(pathEntry.getValue());
builder.append(",");
}
builder.append("\n\t\t},");
}
if (emptyElement.size() == 1) {
builder.append("\n\t\tdata: ");
builder.append(emptyElement.get(0));
builder.append(",");
} else if (formDataParams.size() != 0) {
builder.append("\n\t\tdata: {");
for (final Entry<String, String> pathEntry : formDataParams.entrySet()) {
builder.append("\n\t\t\t");
builder.append(pathEntry.getKey());
builder.append(": ");
builder.append(pathEntry.getValue());
builder.append(",");
}
builder.append("\n\t\t},");
}
if (produces.size() > 1) {
builder.append("\n\t\tproduce: ");
String isFist = null;
for (final String elem : produces) {
String lastElement = null;
if (MediaType.APPLICATION_JSON.equals(elem)) {
lastElement = "HTTPMimeType.JSON";
}
if (MediaType.MULTIPART_FORM_DATA.equals(elem)) {
lastElement = "HTTPMimeType.MULTIPART";
}
if (DataExport.CSV_TYPE.equals(elem)) {
lastElement = "HTTPMimeType.CSV";
}
if (lastElement != null) {
if (isFist == null) {
isFist = lastElement;
} else {
builder.append(" | ");
}
builder.append(lastElement);
} else {
LOGGER.error("Unmanaged model type: {}", elem);
}
}
builder.append(",");
}
builder.append("\n\t}): Promise<");
builder.append(tmpReturn.tsTypeName);
if (returnModelIsArray) {
builder.append("[]");
}
builder.append("> {");
if (tmpReturn.tsTypeName.equals("void")) {
builder.append("\n\t\treturn RESTRequestVoid({");
} else if (returnModelIsArray) {
builder.append("\n\t\treturn RESTRequestJsonArray({");
} else {
builder.append("\n\t\treturn RESTRequestJson({");
}
builder.append("\n\t\t\trestModel: {");
builder.append("\n\t\t\t\tendPoint: \"");
builder.append(basicPath);
if (methodPath != null) {
builder.append("/");
builder.append(methodPath);
}
builder.append("\",");
builder.append("\n\t\t\t\trequestType: HTTPRequestModel.");
builder.append(methodType);
builder.append(",");
if (consumes != null) {
for (final String elem : consumes) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
builder.append("\n\t\t\t\tcontentType: HTTPMimeType.JSON,");
break;
} else if (MediaType.MULTIPART_FORM_DATA.equals(elem)) {
builder.append("\n\t\t\t\tcontentType: HTTPMimeType.MULTIPART,");
break;
} else if (MediaType.TEXT_PLAIN.equals(elem)) {
builder.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,");
break;
}
}
} else if ("DELETE".equals(methodType)) {
builder.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,");
}
if (produces != null) {
if (produces.size() > 1) {
builder.append("\n\t\t\t\taccept: produce,");
} else {
for (final String elem : produces) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
builder.append("\n\t\t\t\taccept: HTTPMimeType.JSON,");
break;
}
}
}
}
builder.append("\n\t\t\t},");
builder.append("\n\t\t\trestConfig,");
if (!pathParams.isEmpty()) {
builder.append("\n\t\t\tparams,");
}
if (!queryParams.isEmpty()) {
builder.append("\n\t\t\tqueries,");
}
if (emptyElement.size() == 1) {
builder.append("\n\t\t\tdata,");
} else if (formDataParams.size() != 0) {
builder.append("\n\t\t\tdata,");
}
builder.append("\n\t\t}");
if (tmpReturn.tsCheckType != null) {
builder.append(", ");
builder.append(tmpReturn.tsCheckType);
}
builder.append(");");
builder.append("\n\t};");
}
builder.append("\n}\n");
return new APIModel(builder.toString(), classSimpleName);
}
public static void generatePackage(final List<Class<?>> classApi, final List<Class<?>> classModel, final String pathPackage) throws Exception {
final GeneratedTypes previous = DataFactoryZod.createBasicType();
DataFactoryZod.createTable(RestErrorResponse.class, previous);
final List<String> listApi = createApi(classApi, previous, pathPackage);
final String packageApi = DataFactoryZod.createTables(new ArrayList<>(classModel), previous);
FileWriter myWriter = new FileWriter(pathPackage + File.separator + "model.ts");
myWriter.write(packageApi.toString());
myWriter.close();
final StringBuilder index = new StringBuilder("""
/**
* Global import of the package
*/
export * from "./model";
""");
for (final String api : listApi) {
index.append("export * from \"./").append(api).append("\";\n");
}
myWriter = new FileWriter(pathPackage + File.separator + "index.ts");
myWriter.write(index.toString());
myWriter.close();
final InputStream ioStream = DataFactoryTsApi.class
.getClassLoader()
.getResourceAsStream("rest-tools.ts");
if (ioStream == null) {
throw new IllegalArgumentException("rest-tools.ts is not found");
}
final BufferedReader buffer = new BufferedReader(new InputStreamReader(ioStream));
myWriter = new FileWriter(pathPackage + File.separator + "rest-tools.ts");
String line;
while( (line = buffer.readLine()) != null) {
myWriter.write(line);
myWriter.write("\n");
}
ioStream.close();
myWriter.close();
return;
}
}

View File

@@ -0,0 +1,436 @@
package org.kar.archidata.dataAccess;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
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.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
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);
static public class ClassElement {
public Class<?>[] model;
public String zodName;
public String tsTypeName;
public String tsCheckType;
public String declaration;
public String comment = null;
public boolean isEnum = false;
public boolean nativeType;
public ClassElement(final Class<?> model[], final String zodName, final String tsTypeName, final String tsCheckType, final String declaration, final boolean nativeType) {
this.model = model;
this.zodName = zodName;
this.tsTypeName = tsTypeName;
this.tsCheckType = tsCheckType;
this.declaration = declaration;
this.nativeType = nativeType;
}
public ClassElement(final Class<?> model) {
this(new Class<?>[] { model });
}
public ClassElement(final Class<?> model[]) {
this.model = model;
this.zodName = "Zod" + model[0].getSimpleName();
this.tsTypeName = model[0].getSimpleName();
this.tsCheckType = "is" + model[0].getSimpleName();
this.declaration = null;
this.nativeType = false;
}
}
public static class GeneratedTypes {
final List<ClassElement> previousGeneration = new ArrayList<>();
final List<Class<?>> order = new ArrayList<>();
public ClassElement find(final Class<?> clazz) {
for (final ClassElement elem : this.previousGeneration) {
for (final Class<?> elemClass : elem.model) {
if (elemClass == clazz) {
return elem;
}
}
}
return null;
}
public void add(final ClassElement elem) {
this.previousGeneration.add(elem);
}
public void add(final ClassElement elem, final boolean addOrder) {
this.previousGeneration.add(elem);
if (addOrder) {
this.order.add(elem.model[0]);
}
}
public void addOrder(final ClassElement elem) {
this.order.add(elem.model[0]);
}
}
public static ClassElement convertTypeZodEnum(final Class<?> clazz, final GeneratedTypes previous) throws Exception {
final ClassElement element = new ClassElement(clazz);
previous.add(element);
final Object[] arr = clazz.getEnumConstants();
final StringBuilder out = new StringBuilder();
if (System.getenv("ARCHIDATA_GENERATE_ZOD_ENUM") != null) {
boolean first = true;
out.append("zod.enum([");
for (final Object elem : arr) {
if (!first) {
out.append(", \n\t");
} else {
out.append("\n\t");
first = false;
}
out.append("'");
out.append(elem.toString());
out.append("'");
}
out.append("\n\t])");
} else {
element.isEnum = true;
boolean first = true;
out.append("{");
for (final Object elem : arr) {
if (!first) {
out.append(", \n\t");
} else {
out.append("\n\t");
first = false;
}
out.append(elem.toString());
out.append(" = '");
out.append(elem.toString());
out.append("'");
}
out.append("}");
}
element.declaration = out.toString();
previous.addOrder(element);
return element;
}
public static String convertTypeZod(final Class<?> type, final GeneratedTypes previous) throws Exception {
final ClassElement previousType = previous.find(type);
if (previousType != null) {
return previousType.zodName;
}
if (type.isEnum()) {
return convertTypeZodEnum(type, previous).zodName;
}
if (type == List.class) {
throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName() + " Unmanaged List of List ... ");
}
final ClassElement elemCreated = createTable(type, previous);
if (elemCreated != null) {
return elemCreated.zodName;
}
throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName());
}
public static String convertTypeZod(final Field field, final GeneratedTypes previous) throws Exception {
final Class<?> type = field.getType();
final ClassElement previousType = previous.find(type);
if (previousType != null) {
return previousType.zodName;
}
if (type.isEnum()) {
return convertTypeZodEnum(type, previous).zodName;
}
if (type == List.class) {
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
final String simpleSubType = convertTypeZod(listClass, previous);
return "zod.array(" + simpleSubType + ")";
}
final ClassElement elemCreated = createTable(type, previous);
if (elemCreated != null) {
return elemCreated.zodName;
}
throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName());
}
public static String optionalTypeZod(final Class<?> type) throws Exception {
if (type.isPrimitive()) {
return "";
}
return ".optional()";
}
public static void createTablesSpecificType(final Field elem, final int fieldId, final StringBuilder builder, final GeneratedTypes previous) 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(": ");
builder.append(convertTypeZod(elem, previous));
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;
}
public static GeneratedTypes createBasicType() throws Exception {
final GeneratedTypes previous = new GeneratedTypes();
previous.add(new ClassElement(new Class<?>[] { Void.class, void.class }, "void", "void", null, null, true));
previous.add(new ClassElement(new Class<?>[] { String.class }, "zod.string()", "string", null, "zod.string()", true));
previous.add(new ClassElement(new Class<?>[] { InputStream.class, FormDataContentDisposition.class }, "z.instanceof(File)", "File", null, "z.instanceof(File)", true));
previous.add(new ClassElement(new Class<?>[] { Boolean.class, boolean.class }, "zod.boolean()", "boolean", null, "zod.boolean()", true));
previous.add(new ClassElement(new Class<?>[] { UUID.class }, "ZodUUID", "UUID", "isUUID", "zod.string().uuid()", false), true);
previous.add(new ClassElement(new Class<?>[] { Long.class, long.class }, "ZodLong", "Long", "isLong",
// "zod.bigint()",
"zod.number()", false), true);
previous.add(new ClassElement(new Class<?>[] { Integer.class, int.class }, "ZodInteger", "Integer", "isInteger", "zod.number().safe()", false), true);
previous.add(new ClassElement(new Class<?>[] { Double.class, double.class }, "ZodDouble", "Double", "isDouble", "zod.number()", true), true);
previous.add(new ClassElement(new Class<?>[] { Float.class, float.class }, "ZodFloat", "Float", "isFloat", "zod.number()", false), true);
previous.add(new ClassElement(new Class<?>[] { Instant.class }, "ZodInstant", "Instant", "isInstant", "zod.string()", false), true);
previous.add(new ClassElement(new Class<?>[] { Date.class }, "ZodDate", "Date", "isDate", "zod.date()", false), true);
previous.add(new ClassElement(new Class<?>[] { Timestamp.class }, "ZodTimestamp", "Timestamp", "isTimestamp", "zod.date()", false), true);
previous.add(new ClassElement(new Class<?>[] { LocalDate.class }, "ZodLocalDate", "LocalDate", "isLocalDate", "zod.date()", false), true);
previous.add(new ClassElement(new Class<?>[] { LocalTime.class }, "ZodLocalTime", "LocalTime", "isLocalTime", "zod.date()", false), true);
return previous;
}
/** 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 {
return createTables(classs, createBasicType());
}
public static String createTables(final List<Class<?>> classs, final GeneratedTypes previous) throws Exception {
for (final Class<?> clazz : classs) {
createTable(clazz, previous);
}
final StringBuilder generatedData = new StringBuilder();
generatedData.append("""
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from \"zod\";
""");
for (final Class<?> elem : previous.order) {
final ClassElement data = previous.find(elem);
if (!data.nativeType) {
if (data.comment != null) {
generatedData.append(data.comment);
}
generatedData.append(createDeclaration(data));
generatedData.append("\n\n");
}
}
LOGGER.info("generated: {}", generatedData.toString());
return generatedData.toString();
}
public static ClassElement createTable(final Class<?> clazz, final GeneratedTypes previous) throws Exception {
if (clazz == null) {
return null;
}
final ClassElement alreadyExist = previous.find(clazz);
if (previous.find(clazz) != null) {
return alreadyExist;
}
if (clazz.isPrimitive()) {
return null;
}
// add the current class to prevent multiple creation
final ClassElement curentElementClass = new ClassElement(clazz);
previous.add(curentElementClass);
// 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 (false && 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, previous);
fieldId++;
}
}
final String description = AnnotationTools.getSchemaDescription(clazz);
final String example = AnnotationTools.getSchemaExample(clazz);
final StringBuilder generatedCommentedData = new StringBuilder();
if (description != null || example != null) {
generatedCommentedData.append("/**\n");
if (description != null) {
for (final String elem : description.split("\n")) {
generatedCommentedData.append(" * ");
generatedCommentedData.append(elem);
generatedCommentedData.append("\n");
}
}
if (example != null) {
generatedCommentedData.append(" * Example:\n");
generatedCommentedData.append(" * ```\n");
for (final String elem : example.split("\n")) {
generatedCommentedData.append(" * ");
generatedCommentedData.append(elem);
generatedCommentedData.append("\n");
}
generatedCommentedData.append(" * ```\n");
}
generatedCommentedData.append(" */\n");
}
curentElementClass.comment = generatedCommentedData.toString();
final StringBuilder generatedData = new StringBuilder();
final Class<?> parentClass = clazz.getSuperclass();
if (parentClass != null && parentClass != Object.class && parentClass != Record.class) {
final ClassElement parentDeclaration = createTable(parentClass, previous);
generatedData.append(parentDeclaration.zodName);
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.
curentElementClass.declaration = generatedData.toString();
previous.addOrder(curentElementClass);
return curentElementClass;
}
public static String createDeclaration(final ClassElement elem) {
final StringBuilder generatedData = new StringBuilder();
if (elem.isEnum) {
generatedData.append("export enum ");
generatedData.append(elem.tsTypeName);
generatedData.append(" ");
generatedData.append(elem.declaration);
generatedData.append(";");
generatedData.append("\nexport const ");
generatedData.append(elem.zodName);
generatedData.append(" = zod.nativeEnum(");
generatedData.append(elem.tsTypeName);
generatedData.append(");");
} else {
generatedData.append("export const ");
generatedData.append(elem.zodName);
generatedData.append(" = ");
generatedData.append(elem.declaration);
generatedData.append(";");
generatedData.append("\nexport type ");
generatedData.append(elem.tsTypeName);
generatedData.append(" = zod.infer<typeof ");
generatedData.append(elem.zodName);
generatedData.append(">;");
}
// declare generic isXXX:
generatedData.append("\nexport function ");
generatedData.append(elem.tsCheckType);
generatedData.append("(data: any): data is ");
generatedData.append(elem.tsTypeName);
generatedData.append(" {\n\ttry {\n\t\t");
generatedData.append(elem.zodName);
generatedData.append("""
.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
""");
return generatedData.toString();
}
public static void generatePackage(final List<Class<?>> classs, final String pathPackage) throws Exception {
final String packageApi = createTables(classs);
FileWriter myWriter = new FileWriter(pathPackage + File.separator + "model.ts");
myWriter.write(packageApi.toString());
myWriter.close();
final String index = """
/**
* Global import of the package
*/
export * from "./model.ts";
""";
myWriter = new FileWriter(pathPackage + File.separator + "index.ts");
myWriter.write(index);
myWriter.close();
}
}

View File

@@ -0,0 +1,39 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
public class GroupBy extends QueryOption {
protected final List<String> childs;
public GroupBy(final List<String> childs) {
this.childs = childs;
}
public GroupBy(final String... childs) {
this.childs = List.of(childs);
}
public void generateQuerry(final StringBuilder query, final String tableName) {
if (this.childs.size() == 0) {
return;
}
query.append(" GROUP BY ");
boolean first = true;
for (final String elem : this.childs) {
if (first) {
first = false;
} else {
query.append(", ");
}
// query.append("`");
query.append(elem);
// query.append("` ");
}
query.append("\n");
}
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {
// nothing to add.
}
}

View File

@@ -10,7 +10,7 @@ public class Limit extends QueryOption {
}
public void generateQuerry(final StringBuilder query, final String tableName) {
query.append(" LIMIT ? ");
query.append(" LIMIT ? \n");
}
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {

View File

@@ -15,9 +15,10 @@ public class OrderBy extends QueryOption {
}
public void generateQuerry(final StringBuilder query, final String tableName) {
if (this.childs.size() >= 1) {
query.append(" ORDER BY ");
if (this.childs.size() == 0) {
return;
}
query.append(" ORDER BY ");
boolean first = true;
for (final OrderItem elem : this.childs) {
if (first) {
@@ -25,14 +26,13 @@ public class OrderBy extends QueryOption {
} else {
query.append(", ");
}
query.append("`");
// query.append("`");
query.append(elem.value);
query.append("` ");
// query.append("`");
query.append(" ");
query.append(elem.order.toString());
}
if (this.childs.size() >= 1) {
query.append(")");
}
query.append("\n");
}
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {

View File

@@ -17,6 +17,10 @@ public class QueryAnd implements QueryItem {
Collections.addAll(this.childs, items);
}
public void add(final QueryItem... items) {
Collections.addAll(this.childs, items);
}
@Override
public void generateQuerry(final StringBuilder query, final String tableName) {
if (this.childs.size() >= 1) {
@@ -43,4 +47,8 @@ public class QueryAnd implements QueryItem {
elem.injectQuerry(ps, iii);
}
}
public int size() {
return this.childs.size();
}
}

View File

@@ -15,8 +15,10 @@ public class QueryCondition implements QueryItem {
@Override
public void generateQuerry(final StringBuilder query, final String tableName) {
query.append(tableName);
query.append(".");
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" ");
query.append(this.comparator);

View File

@@ -24,8 +24,10 @@ public class QueryInList<T> implements QueryItem {
@Override
public void generateQuerry(final StringBuilder query, final String tableName) {
query.append(tableName);
query.append(".");
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" ");
query.append(this.comparator);

View File

@@ -0,0 +1,24 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
public class QueryNotNull implements QueryItem {
private final String key;
public QueryNotNull(final String key) {
this.key = key;
}
@Override
public void generateQuerry(final StringBuilder query, final String tableName) {
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" IS NOT NULL");
}
@Override
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {}
}

View File

@@ -0,0 +1,24 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
public class QueryNull implements QueryItem {
private final String key;
public QueryNull(final String key) {
this.key = key;
}
@Override
public void generateQuerry(final StringBuilder query, final String tableName) {
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" IS NULL");
}
@Override
public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {}
}

View File

@@ -64,5 +64,4 @@ public class QueryOptions {
}
return false;
}
}

View File

@@ -0,0 +1,7 @@
package org.kar.archidata.dataAccess;
import java.sql.ResultSet;
public interface RetreiveFromDB {
void doRequest(final ResultSet rs, Object obj) throws Exception;
}

View File

@@ -1,22 +1,32 @@
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.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.DataJson;
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.kar.archidata.dataAccess.addOn.model.TableCoversLongLong;
import org.kar.archidata.dataAccess.addOn.model.TableCoversLongUUID;
import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDLong;
import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDUUID;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.validation.constraints.NotNull;
@@ -85,6 +95,46 @@ public class AddOnDataJson implements DataAccessAddOn {
count.inc();
if (!rs.wasNull()) {
final ObjectMapper objectMapper = new ObjectMapper();
if (field.getType() == List.class) {
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
if (listClass == Long.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Float.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Float>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Double.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Double>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Integer.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Integer>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Short.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Short>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == String.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == UUID.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
LOGGER.warn("Maybe fail to translate Model in datajson list: List<{}>", listClass.getCanonicalName());
}
final Object dataParsed = objectMapper.readValue(jsonData, field.getType());
field.set(data, dataParsed);
}
@@ -95,4 +145,143 @@ public class AddOnDataJson implements DataAccessAddOn {
final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception {
DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class);
}
public static void addLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongLong data = DataAccess.get(TableCoversLongLong.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void addLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void addLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void addLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<Long> newList = new ArrayList<>();
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<UUID> newList = new ArrayList<>();
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongLong data = DataAccess.get(TableCoversLongLong.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<Long> newList = new ArrayList<>();
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id, new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<UUID> newList = new ArrayList<>();
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
/*
public static <TYPE> void addLink(final Class<TYPE> clazz, final Object localKey, final String column, final Object remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TYPE data = DataAccess.get(clazz, localKey); // TODO: add filter of the "column"
// find the field column:
// add the remoteKey in the list:
// post new data in the DB
final String linkTableName = generateLinkTableName(this.tableName, this.column);
final LinkTable insertElement = new LinkTable(this.localKey, this.remoteKey);
DataAccess.insert(insertElement, new OverrideTableName(linkTableName));
}*/
}

View File

@@ -73,7 +73,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn {
@Override
public boolean canInsert(final Field field) {
return false;
return true;
}
@Override

View File

@@ -0,0 +1,28 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.List;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericData;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversLongLong extends GenericData {
public TableCoversLongLong() {
// nothing to do...
}
public TableCoversLongLong(final Long id, final List<Long> covers) {
this.id = id;
this.covers = covers;
}
@Column(nullable = false)
@Id
public Long id;
@DataJson()
@Column(nullable = false)
public List<Long> covers;
}

View File

@@ -0,0 +1,29 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericData;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversLongUUID extends GenericData {
public TableCoversLongUUID() {
// nothing to do...
}
public TableCoversLongUUID(final Long id, final List<UUID> covers) {
this.id = id;
this.covers = covers;
}
@Column(nullable = false)
@Id
public Long id;
@DataJson()
@Column(nullable = false)
public List<UUID> covers;
}

View File

@@ -0,0 +1,29 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericData;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversUUIDLong extends GenericData {
public TableCoversUUIDLong() {
// nothing to do...
}
public TableCoversUUIDLong(final UUID id, final List<Long> covers) {
this.id = id;
this.covers = covers;
}
@Column(nullable = false)
@Id
public UUID id;
@DataJson()
@Column(nullable = false)
public List<Long> covers;
}

View File

@@ -0,0 +1,29 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericData;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversUUIDUUID extends GenericData {
public TableCoversUUIDUUID() {
// nothing to do...
}
public TableCoversUUIDUUID(final UUID id, final List<UUID> covers) {
this.id = id;
this.covers = covers;
}
@Column(nullable = false)
@Id
public UUID id;
@DataJson()
@Column(nullable = false)
public List<UUID> covers;
}

View File

@@ -0,0 +1,14 @@
package org.kar.archidata.dataAccess.exportTools;
import java.util.ArrayList;
import java.util.List;
public class TableQuery {
public final List<TableQueryTypes> headers;
public final List<List<Object>> values = new ArrayList<>();
public TableQuery(final List<TableQueryTypes> headers) {
this.headers = headers;
}
}

View File

@@ -0,0 +1,20 @@
package org.kar.archidata.dataAccess.exportTools;
public class TableQueryTypes {
public Class<?> type;
public String name;
public String title;
public TableQueryTypes(final Class<?> type, final String name, final String title) {
this.type = type;
this.name = name;
this.title = title;
}
public TableQueryTypes(final Class<?> type, final String name) {
this.type = type;
this.name = name;
this.title = name;
}
}

View File

@@ -43,13 +43,12 @@ public class Condition extends QueryOption {
query.append(tableName);
query.append(".");
query.append(deletedFieldName);
query.append(" = false ");
query.append(" = false \n");
}
return;
}
query.append(" WHERE (");
this.condition.generateQuerry(query, tableName);
query.append(") ");
if (exclude_deleted && deletedFieldName != null) {
query.append("AND ");
@@ -58,5 +57,6 @@ public class Condition extends QueryOption {
query.append(deletedFieldName);
query.append(" = false ");
}
query.append("\n");
}
}

View File

@@ -0,0 +1,48 @@
package org.kar.archidata.dataAccess.options;
import java.io.IOException;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.dataAccess.QueryOption;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.db.DBConfig;
import org.kar.archidata.db.DBEntry;
public class DBInterfaceOption extends QueryOption {
private DBEntry entry = null;
private final DBConfig config;
private final boolean root;
public DBInterfaceOption(final DBConfig config) {
this.config = config;
this.root = false;
}
public DBInterfaceOption(final DBConfig config, boolean root) {
this.config = config;
this.root = root;
}
public DBEntry getEntry(QueryOptions options) throws IOException {
if (this.entry == null) {
final DBInterfaceRoot isRoot = options.get(DBInterfaceRoot.class);
this.entry = DBEntry.createInterface(this.config, isRoot != null && isRoot.getRoot());
}
return this.entry;
}
public boolean getRoot() {
return this.root;
}
public static DBEntry getAutoEntry(QueryOptions options) throws IOException {
final DBInterfaceOption dbOption = options.get(DBInterfaceOption.class);
if (dbOption == null) {
final DBInterfaceRoot isRoot = options.get(DBInterfaceRoot.class);
return DBEntry.createInterface(GlobalConfiguration.dbConfig, isRoot != null && isRoot.getRoot());
} else {
return dbOption.getEntry(options);
}
}
}

View File

@@ -0,0 +1,16 @@
package org.kar.archidata.dataAccess.options;
import org.kar.archidata.dataAccess.QueryOption;
public class DBInterfaceRoot extends QueryOption {
private final boolean root;
public DBInterfaceRoot(boolean root) {
this.root = root;
}
public boolean getRoot() {
return this.root;
}
}

View File

@@ -15,8 +15,7 @@ public class CORSFilter implements ContainerResponseFilter {
// System.err.println("filter cors ..." + request.toString());
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers", "*");
// "Origin, content-type, Content-type, Accept, authorization, mime-type, filename");
response.getHeaders().add("Access-Control-Allow-Headers", "Origin, content-type, Content-type, Accept, Authorization, mime-type, filename");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD");
}

View File

@@ -2,6 +2,9 @@ package org.kar.archidata.filter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
@@ -11,8 +14,11 @@ import jakarta.ws.rs.ext.Provider;
@Provider
@PreMatching
public class OptionFilter implements ContainerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(OptionFilter.class);
@Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
LOGGER.warn("Receive message from: [{}] {}", requestContext.getMethod(), requestContext.getUriInfo().getPath());
if (requestContext.getMethod().contentEquals("OPTIONS")) {
requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build());
}

View File

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

View File

@@ -13,13 +13,21 @@ import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
record Action(String action, List<String> filterDB) {
record Action(String action, AsyncCall async, List<String> filterDB) {
public Action(final String action) {
this(action, List.of());
this(action, null, List.of());
}
public Action(final String action, final String filterDB) {
this(action, List.of(filterDB));
this(action, null, List.of(filterDB));
}
public Action(final AsyncCall async) {
this(null, async, List.of());
}
public Action(final AsyncCall async, final String filterDB) {
this(null, async, List.of(filterDB));
}
}
@@ -40,7 +48,11 @@ public class MigrationSqlStep implements MigrationInterface {
}
for (int iii = 0; iii < this.actions.size(); iii++) {
final Action action = this.actions.get(iii);
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action());
if (action.action() != null) {
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action());
} else {
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\nAsync lambda", iii, this.actions.size(), action.filterDB());
}
}
}
@@ -63,8 +75,13 @@ public class MigrationSqlStep implements MigrationInterface {
LOGGER.info(" >>>> SQL ACTION : {}/{}", iii + 1, this.actions.size());
final Action action = this.actions.get(iii);
LOGGER.info("SQL request: ```{}``` on '{}' current={}", action.action(), action.filterDB(), ConfigBaseVariable.getDBType());
log.append("SQL: " + action.action() + " on " + action.filterDB() + "\n");
if (action.action() != null) {
LOGGER.info("SQL request: ```{}``` on '{}' current={}", action.action(), action.filterDB(), ConfigBaseVariable.getDBType());
log.append("SQL: " + action.action() + " on " + action.filterDB() + "\n");
} else {
LOGGER.info("SQL request: <Lambda> on '{}' current={}", action.filterDB(), ConfigBaseVariable.getDBType());
log.append("SQL: <Lambda> on " + action.filterDB() + "\n");
}
boolean isValid = true;
if (action.filterDB() != null && action.filterDB().size() > 0) {
isValid = false;
@@ -80,7 +97,11 @@ public class MigrationSqlStep implements MigrationInterface {
continue;
}
try {
DataAccess.executeQuerry(action.action());
if (action.action() != null) {
DataAccess.executeQuerry(action.action());
} else {
action.async().doRequest();
}
} catch (SQLException | IOException ex) {
ex.printStackTrace();
LOGGER.info("SQL request ERROR: ", ex.getMessage());
@@ -123,10 +144,18 @@ public class MigrationSqlStep implements MigrationInterface {
this.actions.add(new Action(action));
}
public void addAction(final AsyncCall async) {
this.actions.add(new Action(async));
}
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));
}
public void addClass(final Class<?> clazz) throws Exception {
final List<String> tmp = DataFactory.createTable(clazz);
for (final String elem : tmp) {

View File

@@ -1,6 +1,5 @@
package org.kar.archidata.migration.model;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.model.GenericDataSoftDelete;
@@ -10,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.ws.rs.DefaultValue;
// For logs only
//public static final String TABLE_NAME = "KAR_migration";
@@ -24,11 +24,11 @@ public class Migration extends GenericDataSoftDelete {
@Column(length = 256)
public String name;
@DataNotRead
@DataDefault("'2'")
@DefaultValue("'2'")
@Schema(description = "Version of the migration engine")
public Integer version;
@Column(nullable = false)
@DataDefault("'0'")
@DefaultValue("'0'")
@Schema(description = "if the migration is well terminated or not")
public Boolean terminated = false;
@Schema(description = "index in the migration progression")

View File

@@ -1,6 +1,5 @@
package org.kar.archidata.migration.model;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.model.GenericDataSoftDelete;
@@ -9,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.ws.rs.DefaultValue;
// For logs only
//public static final String TABLE_NAME = "KAR_migration";
@@ -22,7 +22,7 @@ public class Migration1 extends GenericDataSoftDelete {
@Column(length = 256)
public String name;
@Column(nullable = false)
@DataDefault("'0'")
@DefaultValue("'0'")
@Schema(description = "if the migration is well terminated or not")
public Boolean terminated = false;
@Schema(description = "index in the migration progression")

View File

@@ -11,8 +11,7 @@ import jakarta.persistence.Table;
@Table(name = "data")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Data extends GenericDataSoftDelete {
public class Data extends UUIDGenericDataSoftDelete {
@Column(length = 128, nullable = false)
@Schema(description = "Sha512 of the data")
public String sha512;

View File

@@ -1,38 +1,15 @@
package org.kar.archidata.model;
import java.util.Date;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.annotation.UpdateTimestamp;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.validation.constraints.NotNull;
public class GenericData {
public class GenericData extends GenericTiming {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, unique = true)
@Schema(description = "Unique Id of the object", required = false, readOnly = true, example = "123456")
public Long id = null;
@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)
public Date createdAt = null;
@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)
public Date updatedAt = null;
}

View File

@@ -1,17 +1,17 @@
package org.kar.archidata.model;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.DataDeleted;
import org.kar.archidata.annotation.DataNotRead;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.DefaultValue;
public class GenericDataSoftDelete extends GenericData {
@DataNotRead
@Column(nullable = false)
@DataDefault("'0'")
@DefaultValue("'0'")
@DataDeleted
@NotNull
@Schema(description = "Deleted state", hidden = true, required = false, readOnly = true)

View File

@@ -0,0 +1,31 @@
package org.kar.archidata.model;
import java.util.Date;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.annotation.UpdateTimestamp;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
public class GenericTiming {
@DataNotRead
@CreationTimestamp
@Column(nullable = false)
@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")
public Date createdAt = null;
@DataNotRead
@UpdateTimestamp
@Column(nullable = false)
@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 Date updatedAt = null;
}

View File

@@ -0,0 +1,16 @@
package org.kar.archidata.model;
import java.util.UUID;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
import jakarta.ws.rs.DefaultValue;
public class UUIDGenericData extends GenericTiming {
@Id
@DefaultValue("(UUID_TO_BIN(UUID(), TRUE))")
@Column(nullable = false, unique = true)
@Schema(description = "Unique UUID of the object", required = false, readOnly = true, example = "e6b33c1c-d24d-11ee-b616-02420a030102")
public UUID id = null;
}

View File

@@ -0,0 +1,19 @@
package org.kar.archidata.model;
import org.kar.archidata.annotation.DataDeleted;
import org.kar.archidata.annotation.DataNotRead;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.DefaultValue;
public class UUIDGenericDataSoftDelete extends UUIDGenericData {
@DataNotRead
@Column(nullable = false)
@DefaultValue("'0'")
@DataDeleted
@NotNull
@Schema(description = "Deleted state", hidden = true, required = false, readOnly = true)
public Boolean deleted = null;
}

View File

@@ -17,7 +17,6 @@ CREATE TABLE `user` (
import java.sql.Timestamp;
import java.util.List;
import org.kar.archidata.annotation.DataDefault;
import org.kar.archidata.annotation.DataIfNotExists;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -26,6 +25,7 @@ import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import jakarta.ws.rs.DefaultValue;
@Table(name = "user")
@DataIfNotExists
@@ -35,13 +35,13 @@ public class User extends GenericDataSoftDelete {
public String login = null;
public Timestamp lastConnection = null;
@DataDefault("'0'")
@DefaultValue("'0'")
@Column(nullable = false)
public boolean admin = false;
@DataDefault("'0'")
@DefaultValue("'0'")
@Column(nullable = false)
public boolean blocked = false;
@DataDefault("'0'")
@DefaultValue("'0'")
@Column(nullable = false)
public boolean removed = false;

View File

@@ -12,13 +12,16 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.ReadAllColumn;
import org.kar.archidata.model.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,19 +67,9 @@ public class DataTools {
return filePath;
}
public static String getFileData(final long tmpFolderId) {
final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (final IOException e) {
e.printStackTrace();
}
return filePath;
}
public static Data getWithSha512(final String sha512) {
try {
return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)));
return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)), new ReadAllColumn());
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -122,7 +115,7 @@ public class DataTools {
return null;
}
final String mediaPath = getFileData(out.id);
final String mediaPath = DataResource.getFileData(out.id);
LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
@@ -132,7 +125,7 @@ public class DataTools {
return out;
}
public static void undelete(final Long id) {
public static void undelete(final UUID id) {
try {
DataAccess.unsetDelete(Data.class, id);
} catch (final Exception e) {
@@ -218,7 +211,7 @@ public class DataTools {
return data;
}
public static <T> Response uploadCover(final Class<T> clazz, final Long id, String fileName, final InputStream fileInputStream, final FormDataContentDisposition fileMetaData) {
public static <CLASS_TYPE, ID_TYPE> Response uploadCover(final Class<CLASS_TYPE> clazz, final ID_TYPE id, String fileName, final InputStream fileInputStream, final FormDataContentDisposition fileMetaData) {
try {
// correct input string stream :
fileName = multipartCorrection(fileName);
@@ -229,7 +222,7 @@ public class DataTools {
LOGGER.info(" - file_name: ", fileName);
LOGGER.info(" - fileInputStream: {}", fileInputStream);
LOGGER.info(" - fileMetaData: {}", fileMetaData);
final T media = DataAccess.get(clazz, id);
final CLASS_TYPE media = DataAccess.get(clazz, id);
if (media == null) {
return Response.notModified("Media Id does not exist or removed...").build();
}
@@ -259,7 +252,13 @@ public class DataTools {
}
// Fist step: retrieve all the Id of each parents:...
LOGGER.info("Find typeNode");
AddOnManyToMany.addLink(clazz, id, "cover", data.id);
if (id instanceof final Long idLong) {
AddOnDataJson.addLink(clazz, idLong, "covers", data.id);
} else if (id instanceof final UUID idUUID) {
AddOnDataJson.addLink(clazz, idUUID, "covers", data.id);
} else {
throw new IOException("Fail to add Cover can not detect type...");
}
return Response.ok(DataAccess.get(clazz, id)).build();
} catch (final Exception ex) {
System.out.println("Cat ann unexpected error ... ");

View File

@@ -0,0 +1,28 @@
package org.kar.archidata.tools;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.UUID;
public class UuidUtils {
public static UUID asUuid(final BigInteger bigInteger) {
final long mostSignificantBits = bigInteger.longValue();
final long leastSignificantBits = bigInteger.shiftRight(64).longValue();
return new UUID(mostSignificantBits, leastSignificantBits);
}
public static UUID asUuid(final byte[] bytes) {
final ByteBuffer bb = ByteBuffer.wrap(bytes);
final long firstLong = bb.getLong();
final long secondLong = bb.getLong();
return new UUID(firstLong, secondLong);
}
public static byte[] asBytes(final UUID uuid) {
final ByteBuffer bb = ByteBuffer.allocate(16);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
}

246
src/resources/rest-tools.ts Normal file
View File

@@ -0,0 +1,246 @@
/** @file
* @author Edouard DUPIN
* @copyright 2024, Edouard DUPIN, all right reserved
* @license MPL-2
*/
import { RestErrorResponse } from "./model"
export enum HTTPRequestModel {
DELETE = 'DELETE',
GET = 'GET',
PATCH = 'PATCH',
POST = 'POST',
PUT = 'PUT',
}
export enum HTTPMimeType {
ALL = '*/*',
CSV = 'text/csv',
IMAGE = 'image/*',
IMAGE_JPEG = 'image/jpeg',
IMAGE_PNG = 'image/png',
JSON = 'application/json',
MULTIPART = 'multipart/form-data',
OCTET_STREAM = 'application/octet-stream',
TEXT_PLAIN = 'text/plain',
}
export interface RESTConfig {
// base of the server: http(s)://my.server.org/plop/api/
server: string;
// Token to access of the data.
token?: string;
}
export interface RESTModel {
// base of the local API request: "sheep/{id}".
endPoint: string;
// Type of the request.
requestType?: HTTPRequestModel;
// Input type requested.
accept?: HTTPMimeType;
// Content of the local data.
contentType?: HTTPMimeType;
// Mode of the TOKEN in urk or Header
tokenInUrl?: boolean;
}
export interface ModelResponseHttp {
status: number;
data: any;
}
export function isArrayOf<TYPE>(
data: any,
typeChecker: (subData: any) => subData is TYPE,
length?: number
): data is TYPE[] {
if (!Array.isArray(data)) {
return false;
}
if (!data.every(typeChecker)) {
return false;
}
if (length !== undefined && data.length != length) {
return false;
}
return true;
}
export type RESTRequestType = {
restModel: RESTModel,
restConfig: RESTConfig,
data?: any,
params?: object,
queries?: object,
};
function removeTrailingSlashes(input: string): string {
return input.replace(/\/+$/, '');
}
function removeLeadingSlashes(input: string): string {
return input.replace(/^\/+/, '');
}
export function RESTUrl({ restModel, restConfig, data, params, queries }: RESTRequestType): string {
// Create the URL PATH:
let generateUrl = `${removeTrailingSlashes(restConfig.server)}/${removeLeadingSlashes(restModel.endPoint)}`;
if (params !== undefined) {
for (let key of Object.keys(params)) {
generateUrl = generateUrl.replaceAll(`{${key}}`, `${params[key]}`);
}
}
if (queries === undefined && (restConfig.token === undefined || restModel.tokenInUrl !== true)) {
return generateUrl;
}
const searchParams = new URLSearchParams();
if (queries !== undefined) {
for (let key of Object.keys(queries)) {
const value = queries[key];
if (Array.isArray(value)) {
for (let iii = 0; iii < value.length; iii++) {
searchParams.append(`${key}`, `${value[iii]}`);
}
} else {
searchParams.append(`${key}`, `${value}`);
}
}
}
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
searchParams.append('Authorization', `Bearer ${restConfig.token}`);
}
return generateUrl + "?" + searchParams.toString();
}
export function RESTRequest({ restModel, restConfig, data, params, queries }: RESTRequestType): Promise<ModelResponseHttp> {
// Create the URL PATH:
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
let headers: any = {};
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
headers['Authorization'] = `Bearer ${restConfig.token}`;
}
if (restModel.accept !== undefined) {
headers['Accept'] = restModel.accept;
}
if (restModel.requestType !== HTTPRequestModel.GET) {
// if Get we have not a content type, the body is empty
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
headers['Content-Type'] = restModel.contentType;
}
}
let body = data;
if (restModel.contentType === HTTPMimeType.JSON) {
body = JSON.stringify(data);
} else if (restModel.contentType === HTTPMimeType.MULTIPART) {
const formData = new FormData();
for (const name in data) {
formData.append(name, data[name]);
}
body = formData
}
console.log(`Call ${generateUrl}`)
return new Promise((resolve, reject) => {
fetch(generateUrl, {
method: restModel.requestType,
headers,
body,
}).then((response: Response) => {
if (response.status >= 200 && response.status <= 299) {
const contentType = response.headers.get('Content-Type');
if (restModel.accept !== contentType) {
reject({
time: Date().toString(),
status: 901,
error: `REST check wrong type: ${restModel.accept} != ${contentType}`,
statusMessage: "Fetch error",
message: "rest-tools.ts Wrong type in the message return type"
} as RestErrorResponse);
} else if (contentType === HTTPMimeType.JSON) {
response
.json()
.then((value: any) => {
//console.log(`RECEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
resolve({ status: response.status, data: value });
})
.catch((reason: any) => {
reject({
time: Date().toString(),
status: 902,
error: `REST parse json fail: ${reason}`,
statusMessage: "Fetch parse error",
message: "rest-tools.ts Wrong message model to parse"
} as RestErrorResponse);
});
} else {
resolve({ status: response.status, data: response.body });
}
} else {
reject({
time: Date().toString(),
status: response.status,
error: `${response.body}`,
statusMessage: "Fetch code error",
message: "rest-tools.ts Wrong return code"
} as RestErrorResponse);
}
}).catch((error: any) => {
reject({
time: Date(),
status: 999,
error: error,
statusMessage: "Fetch catch error",
message: "http-wrapper.ts detect an error in the fetch request"
});
});
});
}
export function RESTRequestJson<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE> {
return new Promise((resolve, reject) => {
RESTRequest(request).then((value: ModelResponseHttp) => {
if (checker(value.data)) {
resolve(value.data);
} else {
reject({
time: Date().toString(),
status: 950,
error: "REST Fail to verify the data",
statusMessage: "API cast ERROR",
message: "api.ts Check type as fail"
} as RestErrorResponse);
}
}).catch((reason: RestErrorResponse) => {
reject(reason);
});
});
}
export function RESTRequestJsonArray<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE[]> {
return new Promise((resolve, reject) => {
RESTRequest(request).then((value: ModelResponseHttp) => {
if (isArrayOf(value.data, checker)) {
resolve(value.data);
} else {
reject({
time: Date().toString(),
status: 950,
error: "REST Fail to verify the data",
statusMessage: "API cast ERROR",
message: "api.ts Check type as fail"
} as RestErrorResponse);
}
}).catch((reason: RestErrorResponse) => {
reject(reason);
});
});
}
export function RESTRequestVoid(request: RESTRequestType): Promise<void> {
return new Promise((resolve, reject) => {
RESTRequest(request).then((value: ModelResponseHttp) => {
resolve();
}).catch((reason: RestErrorResponse) => {
reject(reason);
});
});
}

View File

@@ -53,7 +53,7 @@ public class TestJson {
final List<String> sqlCommand = DataFactory.createTable(SerializeAsJson.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -53,7 +53,7 @@ public class TestListJson {
final List<String> sqlCommand = DataFactory.createTable(SerializeListAsJson.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -57,7 +57,7 @@ public class TestManyToMany {
sqlCommand.addAll(sqlCommand2);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -56,7 +56,7 @@ public class TestManyToOne {
sqlCommand.addAll(sqlCommand2);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -51,7 +51,7 @@ public class TestOneToMany {
final List<String> sqlCommand = DataFactory.createTable(TypesTable.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -0,0 +1,121 @@
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.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypesTable;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestRawQuery {
final static private Logger LOGGER = LoggerFactory.getLogger(TestTypes.class);
@BeforeAll
public static void configureWebServer() throws Exception {
if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.dbHost = "memory";
// for test we need to connect all time the DB
ConfigBaseVariable.dbKeepConnected = "true";
}
// Connect the dataBase...
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
entry.connect();
}
@AfterAll
public static void removeDataBase() throws IOException {
LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
}
@Order(1)
@Test
public void testCreateTable() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(TypesTable.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem);
}
}
@Order(2)
@Test
public void testGet() throws Exception {
final TypesTable test = new TypesTable();
test.intData = 95;
test.floatData = 1.0F;
DataAccess.insert(test);
test.intData = 96;
test.floatData = 2.0F;
DataAccess.insert(test);
test.intData = 97;
test.floatData = 3.0F;
DataAccess.insert(test);
test.intData = 98;
test.floatData = 4.0F;
DataAccess.insert(test);
test.intData = 99;
test.floatData = 5.0F;
DataAccess.insert(test);
test.intData = 99;
test.floatData = 6.0F;
DataAccess.insert(test);
test.intData = 99;
test.floatData = 7.0F;
DataAccess.insert(test);
{
String querry = """
SELECT *
FROM TypesTable
WHERE `intData` = ?
ORDER BY id DESC
""";
List<Object> parameters = List.of(Integer.valueOf(99));
// Try to retrieve all the data:
final List<TypesTable> retrieve = DataAccess.query(TypesTable.class, querry, parameters);
Assertions.assertNotNull(retrieve);
Assertions.assertEquals(3, retrieve.size());
Assertions.assertEquals(99, retrieve.get(0).intData);
Assertions.assertEquals(7.0F, retrieve.get(0).floatData);
Assertions.assertEquals(6.0F, retrieve.get(1).floatData);
Assertions.assertEquals(5.0F, retrieve.get(2).floatData);
}
{
String querry = """
SELECT DISTINCT intData
FROM TypesTable
WHERE `intData` = ?
ORDER BY id DESC
""";
List<Object> parameters = List.of(Integer.valueOf(99));
// Try to retrieve all the data:
final List<TypesTable> retrieve = DataAccess.query(TypesTable.class, querry, parameters);
Assertions.assertNotNull(retrieve);
Assertions.assertEquals(1, retrieve.size());
Assertions.assertEquals(99, retrieve.get(0).intData);
}
}
}

View File

@@ -65,7 +65,7 @@ public class TestSimpleTable {
final List<String> sqlCommand = DataFactory.createTable(SimpleTable.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
final SimpleTable test = new SimpleTable();
test.data = TestSimpleTable.DATA_INJECTED;

View File

@@ -65,7 +65,7 @@ public class TestSimpleTableSoftDelete {
final List<String> sqlCommand = DataFactory.createTable(SimpleTableSoftDelete.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
final SimpleTableSoftDelete test = new SimpleTableSoftDelete();
test.data = TestSimpleTableSoftDelete.DATA_INJECTED;

View File

@@ -53,7 +53,7 @@ public class TestTypeEnum1 {
final List<String> sqlCommand = DataFactory.createTable(TypesEnum1.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -53,7 +53,7 @@ public class TestTypeEnum2 {
final List<String> sqlCommand = DataFactory.createTable(TypesEnum2.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -57,7 +57,7 @@ public class TestTypes {
final List<String> sqlCommand = DataFactory.createTable(TypesTable.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuerry(elem, false);
DataAccess.executeSimpleQuerry(elem);
}
}

View File

@@ -1 +1 @@
0.6.1
0.7.0