Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d8d4d9d2a | |||
| 745b0cb39b | |||
| 9bad883866 | |||
| f1c3b88a00 | |||
| 8c30336bdb | |||
| 6f36f98cd6 | |||
| c843d7a64b |
2
pom.xml
2
pom.xml
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>kangaroo-and-rabbit</groupId>
|
<groupId>kangaroo-and-rabbit</groupId>
|
||||||
<artifactId>archidata</artifactId>
|
<artifactId>archidata</artifactId>
|
||||||
<version>0.9.0</version>
|
<version>0.10.0</version>
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
<maven.compiler.version>3.1</maven.compiler.version>
|
<maven.compiler.version>3.1</maven.compiler.version>
|
||||||
|
|||||||
@@ -5,21 +5,25 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import org.kar.archidata.tools.UuidUtils;
|
import org.kar.archidata.tools.UuidUtils;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
|
|
||||||
public class RestErrorResponse {
|
public class RestErrorResponse {
|
||||||
@NotNull
|
|
||||||
public UUID uuid = UuidUtils.nextUUID();
|
public UUID uuid = UuidUtils.nextUUID();
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Column(length = 0)
|
||||||
public String name; // Mandatory for TS generic error
|
public String name; // Mandatory for TS generic error
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Column(length = 0)
|
||||||
public String message; // Mandatory for TS generic error
|
public String message; // Mandatory for TS generic error
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Column(length = 0)
|
||||||
public String time;
|
public String time;
|
||||||
@NotNull
|
@NotNull
|
||||||
final public int status;
|
final public int status;
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Column(length = 0)
|
||||||
final public String statusMessage;
|
final public String statusMessage;
|
||||||
|
|
||||||
public RestErrorResponse(final Response.Status status, final String time, final String error,
|
public RestErrorResponse(final Response.Status status, final String time, final String error,
|
||||||
|
|||||||
@@ -796,7 +796,7 @@ public class DataAccess {
|
|||||||
// External checker of data:
|
// External checker of data:
|
||||||
final List<CheckFunction> checks = options.get(CheckFunction.class);
|
final List<CheckFunction> checks = options.get(CheckFunction.class);
|
||||||
for (final CheckFunction check : checks) {
|
for (final CheckFunction check : checks) {
|
||||||
check.getChecker().check("", data, AnnotationTools.getFieldsNames(clazz));
|
check.getChecker().check("", data, AnnotationTools.getFieldsNames(clazz), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
|
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
|
||||||
@@ -1119,7 +1119,7 @@ public class DataAccess {
|
|||||||
if (options != null) {
|
if (options != null) {
|
||||||
final List<CheckFunction> checks = options.get(CheckFunction.class);
|
final List<CheckFunction> checks = options.get(CheckFunction.class);
|
||||||
for (final CheckFunction check : checks) {
|
for (final CheckFunction check : checks) {
|
||||||
check.getChecker().check("", data, filter.getValues());
|
check.getChecker().check("", data, filter.getValues(), options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final List<LazyGetter> asyncActions = new ArrayList<>();
|
final List<LazyGetter> asyncActions = new ArrayList<>();
|
||||||
@@ -1293,8 +1293,7 @@ public class DataAccess {
|
|||||||
return stmt.execute(query);
|
return stmt.execute(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T getWhere(final Class<T> clazz, final QueryOption... option) throws Exception {
|
public static <T> T getWhere(final Class<T> clazz, final QueryOptions options) throws Exception {
|
||||||
final QueryOptions options = new QueryOptions(option);
|
|
||||||
options.add(new Limit(1));
|
options.add(new Limit(1));
|
||||||
final List<T> values = getsWhere(clazz, options);
|
final List<T> values = getsWhere(clazz, options);
|
||||||
if (values.size() == 0) {
|
if (values.size() == 0) {
|
||||||
@@ -1303,6 +1302,11 @@ public class DataAccess {
|
|||||||
return values.get(0);
|
return values.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T getWhere(final Class<T> clazz, final QueryOption... option) throws Exception {
|
||||||
|
final QueryOptions options = new QueryOptions(option);
|
||||||
|
return getWhere(clazz, options);
|
||||||
|
}
|
||||||
|
|
||||||
public static void generateSelectField(//
|
public static void generateSelectField(//
|
||||||
final StringBuilder querySelect, //
|
final StringBuilder querySelect, //
|
||||||
final StringBuilder query, //
|
final StringBuilder query, //
|
||||||
@@ -1484,12 +1488,19 @@ public class DataAccess {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <ID_TYPE> long count(final Class<?> clazz, final ID_TYPE id) throws Exception {
|
public static <ID_TYPE> long count(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
|
||||||
return DataAccess.countWhere(clazz, new Condition(getTableIdCondition(clazz, id)));
|
throws Exception {
|
||||||
|
final QueryOptions options = new QueryOptions(option);
|
||||||
|
options.add(new Condition(getTableIdCondition(clazz, id)));
|
||||||
|
return DataAccess.countWhere(clazz, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
|
public static long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
|
||||||
final QueryOptions options = new QueryOptions(option);
|
final QueryOptions options = new QueryOptions(option);
|
||||||
|
return countWhere(clazz, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long countWhere(final Class<?> clazz, final QueryOptions options) throws Exception {
|
||||||
final Condition condition = conditionFusionOrEmpty(options, false);
|
final Condition condition = conditionFusionOrEmpty(options, false);
|
||||||
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
|
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
|
||||||
DBEntry entry = DBInterfaceOption.getAutoEntry(options);
|
DBEntry entry = DBInterfaceOption.getAutoEntry(options);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.kar.archidata.dataAccess;
|
package org.kar.archidata.dataAccess;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
|
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
|
||||||
@@ -25,10 +24,16 @@ public class QueryOptions {
|
|||||||
if (elems == null || elems.length == 0) {
|
if (elems == null || elems.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Collections.addAll(this.options, elems);
|
for (final QueryOption elem : elems) {
|
||||||
|
add(elem);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(final QueryOption option) {
|
public void add(final QueryOption option) {
|
||||||
|
if (option == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.options.add(option);
|
this.options.add(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.kar.archidata.dataAccess.options;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.kar.archidata.annotation.AnnotationTools;
|
import org.kar.archidata.annotation.AnnotationTools;
|
||||||
|
import org.kar.archidata.dataAccess.QueryOptions;
|
||||||
|
|
||||||
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
|
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
|
||||||
public interface CheckFunctionInterface {
|
public interface CheckFunctionInterface {
|
||||||
@@ -11,10 +12,11 @@ public interface CheckFunctionInterface {
|
|||||||
* @param data The object that might be injected.
|
* @param data The object that might be injected.
|
||||||
* @param filterValue List of fields that might be check. If null, then all column must be checked.
|
* @param filterValue List of fields that might be check. If null, then all column must be checked.
|
||||||
* @throws Exception Exception is generate if the data are incorrect. */
|
* @throws Exception Exception is generate if the data are incorrect. */
|
||||||
void check(final String baseName, Object data, List<String> filterValue) throws Exception;
|
void check(final String baseName, Object data, List<String> filterValue, final QueryOptions options)
|
||||||
|
throws Exception;
|
||||||
|
|
||||||
default void checkAll(final String baseName, final Object data) throws Exception {
|
default void checkAll(final String baseName, final Object data, final QueryOptions options) throws Exception {
|
||||||
check(baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()));
|
check(baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ package org.kar.archidata.dataAccess.options;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.kar.archidata.dataAccess.QueryOptions;
|
||||||
|
|
||||||
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
|
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
|
||||||
public class CheckFunctionVoid implements CheckFunctionInterface {
|
public class CheckFunctionVoid implements CheckFunctionInterface {
|
||||||
@Override
|
@Override
|
||||||
public void check(final String baseName, Object data, List<String> filterValue) {
|
public void check(
|
||||||
|
final String baseName,
|
||||||
|
final Object data,
|
||||||
|
final List<String> filterValue,
|
||||||
|
final QueryOptions options) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.kar.archidata.annotation.AnnotationTools;
|
|||||||
import org.kar.archidata.annotation.DataJson;
|
import org.kar.archidata.annotation.DataJson;
|
||||||
import org.kar.archidata.dataAccess.DataAccess;
|
import org.kar.archidata.dataAccess.DataAccess;
|
||||||
import org.kar.archidata.dataAccess.QueryCondition;
|
import org.kar.archidata.dataAccess.QueryCondition;
|
||||||
|
import org.kar.archidata.dataAccess.QueryOptions;
|
||||||
import org.kar.archidata.exception.DataAccessException;
|
import org.kar.archidata.exception.DataAccessException;
|
||||||
import org.kar.archidata.exception.InputException;
|
import org.kar.archidata.exception.InputException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -37,7 +38,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
* @param data The object that might be injected.
|
* @param data The object that might be injected.
|
||||||
* @param filterValue List of fields that might be check. If null, then all column must be checked.
|
* @param filterValue List of fields that might be check. If null, then all column must be checked.
|
||||||
* @throws Exception Exception is generate if the data are incorrect. */
|
* @throws Exception Exception is generate if the data are incorrect. */
|
||||||
void check(final String baseName, final K data) throws Exception;
|
void check(final String baseName, final K data, final QueryOptions options) throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, List<CheckInterface<T>>> checking = null;
|
protected Map<String, List<CheckInterface<T>>> checking = null;
|
||||||
@@ -66,20 +67,20 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
for (final Field field : this.clazz.getFields()) {
|
for (final Field field : this.clazz.getFields()) {
|
||||||
final String fieldName = field.getName(); // AnnotationTools.getFieldName(field);
|
final String fieldName = field.getName(); // AnnotationTools.getFieldName(field);
|
||||||
if (AnnotationTools.isPrimaryKey(field)) {
|
if (AnnotationTools.isPrimaryKey(field)) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
throw new InputException(baseName + fieldName,
|
throw new InputException(baseName + fieldName,
|
||||||
"This is a '@Id' (primaryKey) ==> can not be change");
|
"This is a '@Id' (primaryKey) ==> can not be change");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (AnnotationTools.getConstraintsNotNull(field)) {
|
if (AnnotationTools.getConstraintsNotNull(field)) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
if (field.get(data) == null) {
|
if (field.get(data) == null) {
|
||||||
throw new InputException(baseName + fieldName, "Can not be null");
|
throw new InputException(baseName + fieldName, "Can not be null");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (AnnotationTools.isCreatedAtField(field) || AnnotationTools.isUpdateAtField(field)) {
|
if (AnnotationTools.isCreatedAtField(field) || AnnotationTools.isUpdateAtField(field)) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
throw new InputException(baseName + fieldName, "It is forbidden to change this field");
|
throw new InputException(baseName + fieldName, "It is forbidden to change this field");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -88,7 +89,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
if (type == Long.class || type == long.class) {
|
if (type == Long.class || type == long.class) {
|
||||||
final Long maxValue = AnnotationTools.getConstraintsMax(field);
|
final Long maxValue = AnnotationTools.getConstraintsMax(field);
|
||||||
if (maxValue != null) {
|
if (maxValue != null) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -101,7 +102,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
}
|
}
|
||||||
final Long minValue = AnnotationTools.getConstraintsMin(field);
|
final Long minValue = AnnotationTools.getConstraintsMin(field);
|
||||||
if (minValue != null) {
|
if (minValue != null) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -114,12 +115,19 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
}
|
}
|
||||||
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
|
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
|
||||||
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
|
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem);
|
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
|
||||||
|
long count = 0;
|
||||||
|
if (condCheckers.isEmpty()) {
|
||||||
|
count = DataAccess.count(annotationManyToOne.targetEntity(), elem);
|
||||||
|
} else {
|
||||||
|
count = DataAccess.count(annotationManyToOne.targetEntity(), elem,
|
||||||
|
condCheckers.get(0).toCondition());
|
||||||
|
}
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
throw new InputException(baseName + fieldName,
|
throw new InputException(baseName + fieldName,
|
||||||
"Foreign element does not exist in the DB:" + elem);
|
"Foreign element does not exist in the DB:" + elem);
|
||||||
@@ -131,7 +139,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
|
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
|
||||||
if (maxValueRoot != null) {
|
if (maxValueRoot != null) {
|
||||||
final int maxValue = maxValueRoot.intValue();
|
final int maxValue = maxValueRoot.intValue();
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -145,7 +153,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
|
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
|
||||||
if (minValueRoot != null) {
|
if (minValueRoot != null) {
|
||||||
final int minValue = minValueRoot.intValue();
|
final int minValue = minValueRoot.intValue();
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -158,7 +166,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
}
|
}
|
||||||
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
|
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
|
||||||
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
|
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -173,7 +181,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
} else if (type == UUID.class) {
|
} else if (type == UUID.class) {
|
||||||
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
|
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
|
||||||
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
|
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -191,7 +199,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
|
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
|
||||||
if (maxValueRoot != null) {
|
if (maxValueRoot != null) {
|
||||||
final float maxValue = maxValueRoot.floatValue();
|
final float maxValue = maxValueRoot.floatValue();
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -205,7 +213,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
|
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
|
||||||
if (minValueRoot != null) {
|
if (minValueRoot != null) {
|
||||||
final float minValue = minValueRoot.floatValue();
|
final float minValue = minValueRoot.floatValue();
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -220,7 +228,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
|
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
|
||||||
if (maxValueRoot != null) {
|
if (maxValueRoot != null) {
|
||||||
final double maxValue = maxValueRoot.doubleValue();
|
final double maxValue = maxValueRoot.doubleValue();
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -234,7 +242,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
|
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
|
||||||
if (minValueRoot != null) {
|
if (minValueRoot != null) {
|
||||||
final double minValue = minValueRoot.doubleValue();
|
final double minValue = minValueRoot.doubleValue();
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -254,7 +262,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
} else if (type == String.class) {
|
} else if (type == String.class) {
|
||||||
final int maxSizeString = AnnotationTools.getLimitSize(field);
|
final int maxSizeString = AnnotationTools.getLimitSize(field);
|
||||||
if (maxSizeString > 0) {
|
if (maxSizeString > 0) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -268,7 +276,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
}
|
}
|
||||||
final Size limitSize = AnnotationTools.getConstraintsSize(field);
|
final Size limitSize = AnnotationTools.getConstraintsSize(field);
|
||||||
if (limitSize != null) {
|
if (limitSize != null) {
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -280,14 +288,14 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
}
|
}
|
||||||
if (elemTyped.length() < limitSize.min()) {
|
if (elemTyped.length() < limitSize.min()) {
|
||||||
throw new InputException(baseName + fieldName,
|
throw new InputException(baseName + fieldName,
|
||||||
"Too small size (constraints) must be >= " + limitSize.max());
|
"Too small size (constraints) must be >= " + limitSize.min());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
final String patternString = AnnotationTools.getConstraintsPattern(field);
|
final String patternString = AnnotationTools.getConstraintsPattern(field);
|
||||||
if (patternString != null) {
|
if (patternString != null) {
|
||||||
final Pattern pattern = Pattern.compile(patternString);
|
final Pattern pattern = Pattern.compile(patternString);
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object elem = field.get(data);
|
final Object elem = field.get(data);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
return;
|
return;
|
||||||
@@ -306,8 +314,8 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
// Here if we have an error it crash at start and no new instance after creation...
|
// Here if we have an error it crash at start and no new instance after creation...
|
||||||
final CheckFunctionInterface instance = jsonAnnotation.checker().getDeclaredConstructor()
|
final CheckFunctionInterface instance = jsonAnnotation.checker().getDeclaredConstructor()
|
||||||
.newInstance();
|
.newInstance();
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
instance.checkAll(baseName + fieldName + ".", field.get(data));
|
instance.checkAll(baseName + fieldName + ".", field.get(data), options);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (type.isEnum()) {
|
} else if (type.isEnum()) {
|
||||||
@@ -316,9 +324,17 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
// keep this is last ==> take more time...
|
// keep this is last ==> take more time...
|
||||||
if (AnnotationTools.isUnique(field)) {
|
if (AnnotationTools.isUnique(field)) {
|
||||||
// Create the request ...
|
// Create the request ...
|
||||||
add(fieldName, (final String baseName, final T data) -> {
|
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
|
||||||
final Object other = DataAccess.getWhere(this.clazz,
|
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
|
||||||
new Condition(new QueryCondition(fieldName, "==", field.get(data))));
|
Object other = null;
|
||||||
|
if (condCheckers.isEmpty()) {
|
||||||
|
other = DataAccess.getWhere(this.clazz,
|
||||||
|
new Condition(new QueryCondition(fieldName, "==", field.get(data))));
|
||||||
|
} else {
|
||||||
|
other = DataAccess.getWhere(this.clazz,
|
||||||
|
new Condition(new QueryCondition(fieldName, "==", field.get(data))),
|
||||||
|
condCheckers.get(0).toCondition());
|
||||||
|
}
|
||||||
if (other != null) {
|
if (other != null) {
|
||||||
throw new InputException(baseName + fieldName, "Name already exist in the DB");
|
throw new InputException(baseName + fieldName, "Name already exist in the DB");
|
||||||
}
|
}
|
||||||
@@ -333,7 +349,11 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void check(final String baseName, final Object data, final List<String> filterValue) throws Exception {
|
public void check(
|
||||||
|
final String baseName,
|
||||||
|
final Object data,
|
||||||
|
final List<String> filterValue,
|
||||||
|
final QueryOptions options) throws Exception {
|
||||||
if (this.checking == null) {
|
if (this.checking == null) {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
@@ -348,13 +368,13 @@ public class CheckJPA<T> implements CheckFunctionInterface {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (final CheckInterface<T> action : actions) {
|
for (final CheckInterface<T> action : actions) {
|
||||||
action.check(baseName, dataCasted);
|
action.check(baseName, dataCasted, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkTyped(dataCasted, filterValue);
|
checkTyped(dataCasted, filterValue, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkTyped(final T data, final List<String> filterValue) throws Exception {
|
public void checkTyped(final T data, final List<String> filterValue, final QueryOptions options) throws Exception {
|
||||||
// nothing to do ...
|
// nothing to do ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.kar.archidata.dataAccess.options;
|
||||||
|
|
||||||
|
import org.kar.archidata.dataAccess.QueryItem;
|
||||||
|
|
||||||
|
/** Condition model apply to the check models. */
|
||||||
|
public class ConditionChecker extends QueryOption {
|
||||||
|
public final QueryItem condition;
|
||||||
|
|
||||||
|
public ConditionChecker(final QueryItem items) {
|
||||||
|
this.condition = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConditionChecker() {
|
||||||
|
this.condition = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Condition toCondition() {
|
||||||
|
return new Condition(this.condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -55,7 +55,7 @@ public class TsApiGeneration {
|
|||||||
if (tsModel.nativeType != DefinedPosition.NATIVE) {
|
if (tsModel.nativeType != DefinedPosition.NATIVE) {
|
||||||
imports.add(model);
|
imports.add(model);
|
||||||
}
|
}
|
||||||
if (tsModel.nativeType == DefinedPosition.BASIC) {
|
if (tsModel.nativeType != DefinedPosition.NORMAL) {
|
||||||
return tsModel.tsTypeName;
|
return tsModel.tsTypeName;
|
||||||
}
|
}
|
||||||
if (writeMode) {
|
if (writeMode) {
|
||||||
@@ -348,11 +348,11 @@ public class TsApiGeneration {
|
|||||||
data.append(", is");
|
data.append(", is");
|
||||||
data.append(returnModelNameIfComplex);
|
data.append(returnModelNameIfComplex);
|
||||||
} else {
|
} else {
|
||||||
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, tsGroup, imports,
|
final TsClassElement retType = tsGroup.find(interfaceElement.returnTypes.get(0));
|
||||||
false);
|
if (retType.tsCheckType != null) {
|
||||||
if (!"void".equals(returnType)) {
|
data.append(", ");
|
||||||
data.append(", is");
|
data.append(retType.tsCheckType);
|
||||||
data.append(returnType);
|
imports.add(interfaceElement.returnTypes.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.append(");");
|
data.append(");");
|
||||||
@@ -393,7 +393,9 @@ public class TsApiGeneration {
|
|||||||
if (tsModel.nativeType == DefinedPosition.NATIVE) {
|
if (tsModel.nativeType == DefinedPosition.NATIVE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
finalImportList.add("is" + tsModel.tsTypeName);
|
if (tsModel.tsCheckType != null) {
|
||||||
|
finalImportList.add(tsModel.tsCheckType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (final ClassModel model : zodImports) {
|
for (final ClassModel model : zodImports) {
|
||||||
final TsClassElement tsModel = tsGroup.find(model);
|
final TsClassElement tsModel = tsGroup.find(model);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.glassfish.jersey.media.multipart.ContentDisposition;
|
||||||
|
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||||
import org.kar.archidata.catcher.RestErrorResponse;
|
import org.kar.archidata.catcher.RestErrorResponse;
|
||||||
import org.kar.archidata.externalRestApi.TsClassElement.DefinedPosition;
|
import org.kar.archidata.externalRestApi.TsClassElement.DefinedPosition;
|
||||||
import org.kar.archidata.externalRestApi.model.ApiGroupModel;
|
import org.kar.archidata.externalRestApi.model.ApiGroupModel;
|
||||||
@@ -128,7 +130,8 @@ public class TsGenerateApi {
|
|||||||
tsModels.add(
|
tsModels.add(
|
||||||
new TsClassElement(models, "zod.string()", "string", null, "zod.string()", DefinedPosition.NATIVE));
|
new TsClassElement(models, "zod.string()", "string", null, "zod.string()", DefinedPosition.NATIVE));
|
||||||
}
|
}
|
||||||
models = api.getCompatibleModels(List.of(InputStream.class));
|
models = api.getCompatibleModels(
|
||||||
|
List.of(InputStream.class, FormDataContentDisposition.class, ContentDisposition.class));
|
||||||
if (models != null) {
|
if (models != null) {
|
||||||
tsModels.add(new TsClassElement(models, "z.instanceof(File)", "File", null, "z.instanceof(File)",
|
tsModels.add(new TsClassElement(models, "z.instanceof(File)", "File", null, "z.instanceof(File)",
|
||||||
DefinedPosition.NATIVE));
|
DefinedPosition.NATIVE));
|
||||||
|
|||||||
@@ -147,11 +147,17 @@ public class ApiModel {
|
|||||||
final String queryParam = ApiTool.apiAnnotationGetQueryParam(parameter);
|
final String queryParam = ApiTool.apiAnnotationGetQueryParam(parameter);
|
||||||
final String formDataParam = ApiTool.apiAnnotationGetFormDataParam(parameter);
|
final String formDataParam = ApiTool.apiAnnotationGetFormDataParam(parameter);
|
||||||
if (queryParam != null) {
|
if (queryParam != null) {
|
||||||
this.queries.put(queryParam, parameterModel);
|
if (!this.queries.containsKey(queryParam)) {
|
||||||
|
this.queries.put(queryParam, parameterModel);
|
||||||
|
}
|
||||||
} else if (pathParam != null) {
|
} else if (pathParam != null) {
|
||||||
this.parameters.put(pathParam, parameterModel);
|
if (!this.parameters.containsKey(pathParam)) {
|
||||||
|
this.parameters.put(pathParam, parameterModel);
|
||||||
|
}
|
||||||
} else if (formDataParam != null) {
|
} else if (formDataParam != null) {
|
||||||
this.multiPartParameters.put(formDataParam, parameterModel);
|
if (!this.multiPartParameters.containsKey(formDataParam)) {
|
||||||
|
this.multiPartParameters.put(formDataParam, parameterModel);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.unnamedElement.addAll(parameterModel);
|
this.unnamedElement.addAll(parameterModel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,25 +4,25 @@
|
|||||||
* @license MPL-2
|
* @license MPL-2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RestErrorResponse } from "./model"
|
import { RestErrorResponse } from "./model";
|
||||||
|
|
||||||
export enum HTTPRequestModel {
|
export enum HTTPRequestModel {
|
||||||
DELETE = 'DELETE',
|
DELETE = "DELETE",
|
||||||
GET = 'GET',
|
GET = "GET",
|
||||||
PATCH = 'PATCH',
|
PATCH = "PATCH",
|
||||||
POST = 'POST',
|
POST = "POST",
|
||||||
PUT = 'PUT',
|
PUT = "PUT",
|
||||||
}
|
}
|
||||||
export enum HTTPMimeType {
|
export enum HTTPMimeType {
|
||||||
ALL = '*/*',
|
ALL = "*/*",
|
||||||
CSV = 'text/csv',
|
CSV = "text/csv",
|
||||||
IMAGE = 'image/*',
|
IMAGE = "image/*",
|
||||||
IMAGE_JPEG = 'image/jpeg',
|
IMAGE_JPEG = "image/jpeg",
|
||||||
IMAGE_PNG = 'image/png',
|
IMAGE_PNG = "image/png",
|
||||||
JSON = 'application/json',
|
JSON = "application/json",
|
||||||
MULTIPART = 'multipart/form-data',
|
MULTIPART = "multipart/form-data",
|
||||||
OCTET_STREAM = 'application/octet-stream',
|
OCTET_STREAM = "application/octet-stream",
|
||||||
TEXT_PLAIN = 'text/plain',
|
TEXT_PLAIN = "text/plain",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RESTConfig {
|
export interface RESTConfig {
|
||||||
@@ -58,52 +58,61 @@ function isNullOrUndefined(data: any): data is undefined | null {
|
|||||||
export type ProgressCallback = (count: number, total: number) => void;
|
export type ProgressCallback = (count: number, total: number) => void;
|
||||||
|
|
||||||
export interface RESTAbort {
|
export interface RESTAbort {
|
||||||
abort?: () => boolean
|
abort?: () => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Rest generic callback have a basic model to upload and download advancement.
|
// Rest generic callback have a basic model to upload and download advancement.
|
||||||
export interface RESTCallbacks {
|
export interface RESTCallbacks {
|
||||||
progressUpload?: ProgressCallback,
|
progressUpload?: ProgressCallback;
|
||||||
progressDownload?: ProgressCallback,
|
progressDownload?: ProgressCallback;
|
||||||
abortHandle?: RESTAbort,
|
abortHandle?: RESTAbort;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface RESTRequestType {
|
export interface RESTRequestType {
|
||||||
restModel: RESTModel,
|
restModel: RESTModel;
|
||||||
restConfig: RESTConfig,
|
restConfig: RESTConfig;
|
||||||
data?: any,
|
data?: any;
|
||||||
params?: object,
|
params?: object;
|
||||||
queries?: object,
|
queries?: object;
|
||||||
callback?: RESTCallbacks,
|
callback?: RESTCallbacks;
|
||||||
};
|
}
|
||||||
|
|
||||||
function replaceAll(input, searchValue, replaceValue) {
|
function replaceAll(input, searchValue, replaceValue) {
|
||||||
return input.split(searchValue).join(replaceValue);
|
return input.split(searchValue).join(replaceValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeTrailingSlashes(input: string): string {
|
function removeTrailingSlashes(input: string): string {
|
||||||
if (isNullOrUndefined(input)) {
|
if (isNullOrUndefined(input)) {
|
||||||
return "undefined";
|
return "undefined";
|
||||||
}
|
}
|
||||||
return input.replace(/\/+$/, '');
|
return input.replace(/\/+$/, "");
|
||||||
}
|
}
|
||||||
function removeLeadingSlashes(input: string): string {
|
function removeLeadingSlashes(input: string): string {
|
||||||
if (isNullOrUndefined(input)) {
|
if (isNullOrUndefined(input)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return input.replace(/^\/+/, '');
|
return input.replace(/^\/+/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTUrl({ restModel, restConfig, params, queries }: RESTRequestType): string {
|
export function RESTUrl({
|
||||||
|
restModel,
|
||||||
|
restConfig,
|
||||||
|
params,
|
||||||
|
queries,
|
||||||
|
}: RESTRequestType): string {
|
||||||
// Create the URL PATH:
|
// Create the URL PATH:
|
||||||
let generateUrl = `${removeTrailingSlashes(restConfig.server)}/${removeLeadingSlashes(restModel.endPoint)}`;
|
let generateUrl = `${removeTrailingSlashes(
|
||||||
|
restConfig.server
|
||||||
|
)}/${removeLeadingSlashes(restModel.endPoint)}`;
|
||||||
if (params !== undefined) {
|
if (params !== undefined) {
|
||||||
for (let key of Object.keys(params)) {
|
for (let key of Object.keys(params)) {
|
||||||
generateUrl = replaceAll(generateUrl, `{${key}}`, `${params[key]}`);
|
generateUrl = replaceAll(generateUrl, `{${key}}`, `${params[key]}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (queries === undefined && (restConfig.token === undefined || restModel.tokenInUrl !== true)) {
|
if (
|
||||||
|
queries === undefined &&
|
||||||
|
(restConfig.token === undefined || restModel.tokenInUrl !== true)
|
||||||
|
) {
|
||||||
return generateUrl;
|
return generateUrl;
|
||||||
}
|
}
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
@@ -111,8 +120,8 @@ export function RESTUrl({ restModel, restConfig, params, queries }: RESTRequestT
|
|||||||
for (let key of Object.keys(queries)) {
|
for (let key of Object.keys(queries)) {
|
||||||
const value = queries[key];
|
const value = queries[key];
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
for (let iii = 0; iii < value.length; iii++) {
|
for (const element of value) {
|
||||||
searchParams.append(`${key}`, `${value[iii]}`);
|
searchParams.append(`${key}`, `${element}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
searchParams.append(`${key}`, `${value}`);
|
searchParams.append(`${key}`, `${value}`);
|
||||||
@@ -120,36 +129,43 @@ export function RESTUrl({ restModel, restConfig, params, queries }: RESTRequestT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
|
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
|
||||||
searchParams.append('Authorization', `Bearer ${restConfig.token}`);
|
searchParams.append("Authorization", `Bearer ${restConfig.token}`);
|
||||||
}
|
}
|
||||||
return generateUrl + "?" + searchParams.toString();
|
return generateUrl + "?" + searchParams.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchProgress(
|
||||||
export function fetchProgress(generateUrl: string, { method, headers, body }: {
|
generateUrl: string,
|
||||||
method: HTTPRequestModel,
|
{
|
||||||
headers: any,
|
method,
|
||||||
body: any,
|
headers,
|
||||||
}, { progressUpload, progressDownload, abortHandle }: RESTCallbacks): Promise<Response> {
|
body,
|
||||||
const xhr = {
|
}: {
|
||||||
io: new XMLHttpRequest()
|
method: HTTPRequestModel;
|
||||||
}
|
headers: any;
|
||||||
|
body: any;
|
||||||
|
},
|
||||||
|
{ progressUpload, progressDownload, abortHandle }: RESTCallbacks
|
||||||
|
): Promise<Response> {
|
||||||
|
const xhr: {
|
||||||
|
io?: XMLHttpRequest;
|
||||||
|
} = {
|
||||||
|
io: new XMLHttpRequest(),
|
||||||
|
};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Stream the upload progress
|
// Stream the upload progress
|
||||||
if (progressUpload) {
|
if (progressUpload) {
|
||||||
xhr.io.upload.addEventListener("progress", (dataEvent) => {
|
xhr.io?.upload.addEventListener("progress", (dataEvent) => {
|
||||||
if (dataEvent.lengthComputable) {
|
if (dataEvent.lengthComputable) {
|
||||||
//console.log(` ==> has a progress event: ${dataEvent.loaded} / ${dataEvent.total}`);
|
|
||||||
progressUpload(dataEvent.loaded, dataEvent.total);
|
progressUpload(dataEvent.loaded, dataEvent.total);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Stream the download progress
|
// Stream the download progress
|
||||||
if (progressDownload) {
|
if (progressDownload) {
|
||||||
xhr.io.addEventListener("progress", (dataEvent) => {
|
xhr.io?.addEventListener("progress", (dataEvent) => {
|
||||||
if (dataEvent.lengthComputable) {
|
if (dataEvent.lengthComputable) {
|
||||||
//console.log(` ==> download progress:: ${dataEvent.loaded} / ${dataEvent.total}`);
|
progressDownload(dataEvent.loaded, dataEvent.total);
|
||||||
progressUpload(dataEvent.loaded, dataEvent.total);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -160,38 +176,43 @@ export function fetchProgress(generateUrl: string, { method, headers, body }: {
|
|||||||
xhr.io.abort();
|
xhr.io.abort();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
console.log(`Request abort (FAIL) on the XMLHttpRequest: ${generateUrl}`);
|
console.log(
|
||||||
|
`Request abort (FAIL) on the XMLHttpRequest: ${generateUrl}`
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
// Check if we have an internal Fail:
|
// Check if we have an internal Fail:
|
||||||
xhr.io.addEventListener('error', () => {
|
xhr.io?.addEventListener("error", () => {
|
||||||
xhr.io = undefined;
|
xhr.io = undefined;
|
||||||
reject(new TypeError('Failed to fetch'))
|
reject(new TypeError("Failed to fetch"));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Capture the end of the stream
|
// Capture the end of the stream
|
||||||
xhr.io.addEventListener("loadend", () => {
|
xhr.io?.addEventListener("loadend", () => {
|
||||||
if (xhr.io.readyState !== XMLHttpRequest.DONE) {
|
if (xhr.io?.readyState !== XMLHttpRequest.DONE) {
|
||||||
//console.log(` ==> READY state`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (xhr.io.status === 0) {
|
if (xhr.io?.status === 0) {
|
||||||
//the stream has been aborted
|
//the stream has been aborted
|
||||||
reject(new TypeError('Fetch has been aborted'));
|
reject(new TypeError("Fetch has been aborted"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Stream is ended, transform in a generic response:
|
// Stream is ended, transform in a generic response:
|
||||||
const response = new Response(xhr.io.response, {
|
const response = new Response(xhr.io.response, {
|
||||||
status: xhr.io.status,
|
status: xhr.io.status,
|
||||||
statusText: xhr.io.statusText
|
statusText: xhr.io.statusText,
|
||||||
});
|
});
|
||||||
const headersArray = replaceAll(xhr.io.getAllResponseHeaders().trim(), "\r\n", "\n").split('\n');
|
const headersArray = replaceAll(
|
||||||
|
xhr.io.getAllResponseHeaders().trim(),
|
||||||
|
"\r\n",
|
||||||
|
"\n"
|
||||||
|
).split("\n");
|
||||||
headersArray.forEach(function (header) {
|
headersArray.forEach(function (header) {
|
||||||
const firstColonIndex = header.indexOf(':');
|
const firstColonIndex = header.indexOf(":");
|
||||||
if (firstColonIndex !== -1) {
|
if (firstColonIndex !== -1) {
|
||||||
var key = header.substring(0, firstColonIndex).trim();
|
const key = header.substring(0, firstColonIndex).trim();
|
||||||
var value = header.substring(firstColonIndex + 1).trim();
|
const value = header.substring(firstColonIndex + 1).trim();
|
||||||
response.headers.set(key, value);
|
response.headers.set(key, value);
|
||||||
} else {
|
} else {
|
||||||
response.headers.set(header, "");
|
response.headers.set(header, "");
|
||||||
@@ -200,31 +221,38 @@ export function fetchProgress(generateUrl: string, { method, headers, body }: {
|
|||||||
xhr.io = undefined;
|
xhr.io = undefined;
|
||||||
resolve(response);
|
resolve(response);
|
||||||
});
|
});
|
||||||
xhr.io.open(method, generateUrl, true);
|
xhr.io?.open(method, generateUrl, true);
|
||||||
if (!isNullOrUndefined(headers)) {
|
if (!isNullOrUndefined(headers)) {
|
||||||
for (const [key, value] of Object.entries(headers)) {
|
for (const [key, value] of Object.entries(headers)) {
|
||||||
xhr.io.setRequestHeader(key, value as string);
|
xhr.io?.setRequestHeader(key, value as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xhr.io.send(body);
|
xhr.io?.send(body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTRequest({ restModel, restConfig, data, params, queries, callback }: RESTRequestType): Promise<ModelResponseHttp> {
|
export function RESTRequest({
|
||||||
|
restModel,
|
||||||
|
restConfig,
|
||||||
|
data,
|
||||||
|
params,
|
||||||
|
queries,
|
||||||
|
callback,
|
||||||
|
}: RESTRequestType): Promise<ModelResponseHttp> {
|
||||||
// Create the URL PATH:
|
// Create the URL PATH:
|
||||||
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
|
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
|
||||||
let headers: any = {};
|
let headers: any = {};
|
||||||
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
|
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
|
||||||
headers['Authorization'] = `Bearer ${restConfig.token}`;
|
headers["Authorization"] = `Bearer ${restConfig.token}`;
|
||||||
}
|
}
|
||||||
if (restModel.accept !== undefined) {
|
if (restModel.accept !== undefined) {
|
||||||
headers['Accept'] = restModel.accept;
|
headers["Accept"] = restModel.accept;
|
||||||
}
|
}
|
||||||
if (restModel.requestType !== HTTPRequestModel.GET) {
|
if (restModel.requestType !== HTTPRequestModel.GET) {
|
||||||
// if Get we have not a content type, the body is empty
|
// if Get we have not a content type, the body is empty
|
||||||
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
|
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
|
||||||
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
|
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
|
||||||
headers['Content-Type'] = restModel.contentType;
|
headers["Content-Type"] = restModel.contentType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let body = data;
|
let body = data;
|
||||||
@@ -235,14 +263,16 @@ export function RESTRequest({ restModel, restConfig, data, params, queries, call
|
|||||||
for (const name in data) {
|
for (const name in data) {
|
||||||
formData.append(name, data[name]);
|
formData.append(name, data[name]);
|
||||||
}
|
}
|
||||||
body = formData
|
body = formData;
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let action: undefined | Promise<Response> = undefined;
|
let action: undefined | Promise<Response> = undefined;
|
||||||
if (isNullOrUndefined(callback)
|
if (
|
||||||
|| (isNullOrUndefined(callback.progressDownload)
|
isNullOrUndefined(callback) ||
|
||||||
&& isNullOrUndefined(callback.progressUpload)
|
(isNullOrUndefined(callback.progressDownload) &&
|
||||||
&& isNullOrUndefined(callback.abortHandle))) {
|
isNullOrUndefined(callback.progressUpload) &&
|
||||||
|
isNullOrUndefined(callback.abortHandle))
|
||||||
|
) {
|
||||||
// No information needed: call the generic fetch interface
|
// No information needed: call the generic fetch interface
|
||||||
action = fetch(generateUrl, {
|
action = fetch(generateUrl, {
|
||||||
method: restModel.requestType,
|
method: restModel.requestType,
|
||||||
@@ -251,92 +281,112 @@ export function RESTRequest({ restModel, restConfig, data, params, queries, call
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// need progression information: call old fetch model (XMLHttpRequest) that permit to keep % upload and % download for HTTP1.x
|
// need progression information: call old fetch model (XMLHttpRequest) that permit to keep % upload and % download for HTTP1.x
|
||||||
action = fetchProgress(generateUrl, {
|
action = fetchProgress(
|
||||||
method: restModel.requestType ?? HTTPRequestModel.GET,
|
generateUrl,
|
||||||
headers,
|
{
|
||||||
body,
|
method: restModel.requestType ?? HTTPRequestModel.GET,
|
||||||
}, callback);
|
headers,
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
callback
|
||||||
|
);
|
||||||
}
|
}
|
||||||
action.then((response: Response) => {
|
action
|
||||||
if (response.status >= 200 && response.status <= 299) {
|
.then((response: Response) => {
|
||||||
const contentType = response.headers.get('Content-Type');
|
if (response.status >= 200 && response.status <= 299) {
|
||||||
if (!isNullOrUndefined(restModel.accept) && restModel.accept !== contentType) {
|
const contentType = response.headers.get("Content-Type");
|
||||||
reject({
|
if (
|
||||||
time: Date().toString(),
|
!isNullOrUndefined(restModel.accept) &&
|
||||||
status: 901,
|
restModel.accept !== contentType
|
||||||
error: `REST check wrong type: ${restModel.accept} != ${contentType}`,
|
) {
|
||||||
statusMessage: "Fetch error",
|
reject({
|
||||||
message: "rest-tools.ts Wrong type in the message return type"
|
name: "Model accept type incompatible",
|
||||||
} as RestErrorResponse);
|
time: Date().toString(),
|
||||||
} else if (contentType === HTTPMimeType.JSON) {
|
status: 901,
|
||||||
response
|
error: `REST check wrong type: ${restModel.accept} != ${contentType}`,
|
||||||
.json()
|
statusMessage: "Fetch error",
|
||||||
.then((value: any) => {
|
message: "rest-tools.ts Wrong type in the message return type",
|
||||||
//console.log(`RECEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
|
} as RestErrorResponse);
|
||||||
resolve({ status: response.status, data: value });
|
} else if (contentType === HTTPMimeType.JSON) {
|
||||||
})
|
response
|
||||||
.catch((reason: any) => {
|
.json()
|
||||||
reject({
|
.then((value: any) => {
|
||||||
time: Date().toString(),
|
resolve({ status: response.status, data: value });
|
||||||
status: 902,
|
})
|
||||||
error: `REST parse json fail: ${reason}`,
|
.catch((reason: any) => {
|
||||||
statusMessage: "Fetch parse error",
|
reject({
|
||||||
message: "rest-tools.ts Wrong message model to parse"
|
name: "API serialization error",
|
||||||
} as RestErrorResponse);
|
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 {
|
} else {
|
||||||
resolve({ status: response.status, data: response.body });
|
reject({
|
||||||
|
name: "REST return no OK status",
|
||||||
|
time: Date().toString(),
|
||||||
|
status: response.status,
|
||||||
|
error: `${response.body}`,
|
||||||
|
statusMessage: "Fetch code error",
|
||||||
|
message: "rest-tools.ts Wrong return code",
|
||||||
|
} as RestErrorResponse);
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
reject({
|
reject({
|
||||||
time: Date().toString(),
|
name: "Request fail",
|
||||||
status: response.status,
|
time: Date(),
|
||||||
error: `${response.body}`,
|
status: 999,
|
||||||
statusMessage: "Fetch code error",
|
error: error,
|
||||||
message: "rest-tools.ts Wrong return code"
|
statusMessage: "Fetch catch error",
|
||||||
} as RestErrorResponse);
|
message: "rest-tools.ts detect an error in the fetch request",
|
||||||
}
|
});
|
||||||
}).catch((error: any) => {
|
|
||||||
reject({
|
|
||||||
time: Date(),
|
|
||||||
status: 999,
|
|
||||||
error: error,
|
|
||||||
statusMessage: "Fetch catch error",
|
|
||||||
message: "rest-tools.ts detect an error in the fetch request"
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTRequestJson<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE> {
|
export function RESTRequestJson<TYPE>(
|
||||||
|
request: RESTRequestType,
|
||||||
|
checker?: (data: any) => data is TYPE
|
||||||
|
): Promise<TYPE> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
RESTRequest(request).then((value: ModelResponseHttp) => {
|
RESTRequest(request)
|
||||||
if (isNullOrUndefined(checker)) {
|
.then((value: ModelResponseHttp) => {
|
||||||
console.log(`Have no check of MODEL in API: ${RESTUrl(request)}`);
|
if (isNullOrUndefined(checker)) {
|
||||||
resolve(value.data);
|
console.log(`Have no check of MODEL in API: ${RESTUrl(request)}`);
|
||||||
} else if (checker(value.data)) {
|
resolve(value.data);
|
||||||
resolve(value.data);
|
} else if (checker === undefined || checker(value.data)) {
|
||||||
} else {
|
resolve(value.data);
|
||||||
reject({
|
} else {
|
||||||
time: Date().toString(),
|
reject({
|
||||||
status: 950,
|
name: "Model check fail",
|
||||||
error: "REST Fail to verify the data",
|
time: Date().toString(),
|
||||||
statusMessage: "API cast ERROR",
|
status: 950,
|
||||||
message: "api.ts Check type as fail"
|
error: "REST Fail to verify the data",
|
||||||
} as RestErrorResponse);
|
statusMessage: "API cast ERROR",
|
||||||
}
|
message: "api.ts Check type as fail",
|
||||||
}).catch((reason: RestErrorResponse) => {
|
} as RestErrorResponse);
|
||||||
reject(reason);
|
}
|
||||||
});
|
})
|
||||||
|
.catch((reason: RestErrorResponse) => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTRequestVoid(request: RESTRequestType): Promise<void> {
|
export function RESTRequestVoid(request: RESTRequestType): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
RESTRequest(request).then((value: ModelResponseHttp) => {
|
RESTRequest(request)
|
||||||
resolve();
|
.then((value: ModelResponseHttp) => {
|
||||||
}).catch((reason: RestErrorResponse) => {
|
resolve();
|
||||||
reject(reason);
|
})
|
||||||
});
|
.catch((reason: RestErrorResponse) => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.9.0
|
0.10.0
|
||||||
|
|||||||
Reference in New Issue
Block a user