From 2cfcf2a8d7e29aa528ec16dd3d86cf90e0b4113b Mon Sep 17 00:00:00 2001 From: Francesco Date: Tue, 24 Oct 2023 13:29:58 +0200 Subject: [PATCH] Refactored field type system and `Enum` support In order to support the `Enum` field type the `DbFieldType` enum has been converted to an abstract class with an implementation class for each database field type. --- .../tech/ailef/dbadmin/external/DbAdmin.java | 38 +- .../controller/DataExportController.java | 2 +- .../dbmapping/CustomJpaRepository.java | 5 +- .../external/dbmapping/DbAdminRepository.java | 1 + .../external/dbmapping/DbFieldType.java | 675 ----------------- .../external/dbmapping/DbFieldValue.java | 2 + .../dbadmin/external/dbmapping/DbObject.java | 4 +- .../external/dbmapping/DbObjectSchema.java | 1 + .../dbmapping/fields/BigDecimalFieldType.java | 29 + .../dbmapping/fields/BigIntegerFieldType.java | 29 + .../dbmapping/fields/BooleanFieldType.java | 28 + .../dbmapping/fields/ByteArrayFieldType.java | 35 + .../dbmapping/fields/ByteFieldType.java | 29 + .../dbmapping/fields/CharFieldType.java | 29 + .../dbmapping/fields/ComputedFieldType.java | 28 + .../dbmapping/fields/DateFieldType.java | 37 + .../dbmapping/{ => fields}/DbField.java | 9 +- .../dbmapping/fields/DbFieldType.java | 115 +++ .../dbmapping/fields/DoubleFieldType.java | 28 + .../dbmapping/fields/EnumFieldType.java | 62 ++ .../dbmapping/fields/FloatFieldType.java | 27 + .../dbmapping/fields/InstantFieldType.java | 31 + .../dbmapping/fields/IntegerFieldType.java | 27 + .../dbmapping/fields/LocalDateFieldType.java | 28 + .../fields/LocalDateTimeFieldType.java | 29 + .../dbmapping/fields/LongFieldType.java | 27 + .../dbmapping/fields/ManyToManyFieldType.java | 38 + .../fields/OffsetDateTimeFieldType.java | 28 + .../dbmapping/fields/OldDbFieldType.java | 695 ++++++++++++++++++ .../dbmapping/fields/OneToManyFieldType.java | 39 + .../dbmapping/fields/OneToOneFieldType.java | 38 + .../dbmapping/fields/ShortFieldType.java | 28 + .../dbmapping/fields/StringFieldType.java | 27 + .../dbmapping/fields/TextFieldType.java | 28 + .../dbmapping/fields/UUIDFieldType.java | 27 + .../dbmapping/query/DbQueryOutputField.java | 10 +- .../dbadmin/external/dto/QueryFilter.java | 2 +- .../ailef/dbadmin/external/misc/Utils.java | 2 +- .../resources/templates/fragments/inputs.html | 12 + 39 files changed, 1634 insertions(+), 695 deletions(-) delete mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigDecimalFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigIntegerFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BooleanFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteArrayFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/CharFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ComputedFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DateFieldType.java rename src/main/java/tech/ailef/dbadmin/external/dbmapping/{ => fields}/DbField.java (95%) create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DbFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DoubleFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/EnumFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/FloatFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/InstantFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/IntegerFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateTimeFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LongFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ManyToManyFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OffsetDateTimeFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OldDbFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToManyFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToOneFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ShortFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/StringFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/TextFieldType.java create mode 100644 src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/UUIDFieldType.java diff --git a/src/main/java/tech/ailef/dbadmin/external/DbAdmin.java b/src/main/java/tech/ailef/dbadmin/external/DbAdmin.java index edc8e15..6a5ff55 100644 --- a/src/main/java/tech/ailef/dbadmin/external/DbAdmin.java +++ b/src/main/java/tech/ailef/dbadmin/external/DbAdmin.java @@ -40,6 +40,7 @@ import jakarta.annotation.PostConstruct; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EntityManager; +import jakarta.persistence.Enumerated; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.Lob; @@ -50,9 +51,12 @@ import jakarta.persistence.OneToOne; import tech.ailef.dbadmin.external.annotations.Disable; import tech.ailef.dbadmin.external.annotations.DisplayFormat; import tech.ailef.dbadmin.external.dbmapping.CustomJpaRepository; -import tech.ailef.dbadmin.external.dbmapping.DbField; -import tech.ailef.dbadmin.external.dbmapping.DbFieldType; import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; +import tech.ailef.dbadmin.external.dbmapping.fields.DbFieldType; +import tech.ailef.dbadmin.external.dbmapping.fields.EnumFieldType; +import tech.ailef.dbadmin.external.dbmapping.fields.StringFieldType; +import tech.ailef.dbadmin.external.dbmapping.fields.TextFieldType; import tech.ailef.dbadmin.external.dto.MappingError; import tech.ailef.dbadmin.external.exceptions.DbAdminException; import tech.ailef.dbadmin.external.exceptions.DbAdminNotFoundException; @@ -285,16 +289,26 @@ public class DbAdmin { // foreign key, if any Class connectedType = null; - // Try to assign default field type + // Try to assign default field type determining it by the raw field type and its annotations DbFieldType fieldType = null; try { - fieldType = DbFieldType.fromClass(f.getType()); + Class fieldTypeClass = DbFieldType.fromClass(f.getType()); - if (fieldType != null && lob != null && fieldType == DbFieldType.STRING) { - fieldType = DbFieldType.TEXT; + if (fieldTypeClass == StringFieldType.class && lob != null) { + fieldTypeClass = TextFieldType.class; + } + + // Enums are instantiated later because they call a different constructor + if (fieldTypeClass != EnumFieldType.class) { + try { + fieldType = fieldTypeClass.getConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + // If failure, we try to map a relationship on this field later + } } } catch (DbAdminException e) { - // If failure, we try to map a relationship on this field + // If failure, we try to map a relationship on this field later } if (manyToOne != null || oneToOne != null) { @@ -310,6 +324,14 @@ public class DbAdmin { connectedType = targetEntityClass; } + // Check if field has @Enumerated annotation and process accordingly + if (fieldType == null) { + Enumerated enumerated = f.getAnnotation(Enumerated.class); + if (enumerated != null) { + fieldType = new EnumFieldType(f.getType()); + } + } + if (fieldType == null) { throw new UnsupportedFieldTypeException("Unable to determine fieldType for " + f.getType()); } @@ -367,7 +389,7 @@ public class DbAdmin { if (linkType == null) throw new DbAdminException("Unable to find @Id field in Entity class " + entityClass); - return DbFieldType.fromClass(linkType); + return DbFieldType.fromClass(linkType).getConstructor().newInstance(); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { throw new DbAdminException(e); diff --git a/src/main/java/tech/ailef/dbadmin/external/controller/DataExportController.java b/src/main/java/tech/ailef/dbadmin/external/controller/DataExportController.java index 1ec17d2..010b376 100644 --- a/src/main/java/tech/ailef/dbadmin/external/controller/DataExportController.java +++ b/src/main/java/tech/ailef/dbadmin/external/controller/DataExportController.java @@ -57,10 +57,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import tech.ailef.dbadmin.external.DbAdmin; import tech.ailef.dbadmin.external.dbmapping.DbAdminRepository; -import tech.ailef.dbadmin.external.dbmapping.DbField; import tech.ailef.dbadmin.external.dbmapping.DbFieldValue; import tech.ailef.dbadmin.external.dbmapping.DbObject; import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; import tech.ailef.dbadmin.external.dbmapping.query.DbQueryResult; import tech.ailef.dbadmin.external.dbmapping.query.DbQueryResultRow; import tech.ailef.dbadmin.external.dto.DataExportFormat; diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java index e638e05..acf18c6 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java @@ -40,6 +40,9 @@ import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; +import tech.ailef.dbadmin.external.dbmapping.fields.StringFieldType; +import tech.ailef.dbadmin.external.dbmapping.fields.TextFieldType; import tech.ailef.dbadmin.external.dto.CompareOperator; import tech.ailef.dbadmin.external.dto.QueryFilter; import tech.ailef.dbadmin.external.exceptions.DbAdminException; @@ -163,7 +166,7 @@ public class CustomJpaRepository extends SimpleJpaRepository { List finalPredicates = new ArrayList<>(); List stringFields = - schema.getSortedFields().stream().filter(f -> f.getType() == DbFieldType.STRING || f.getType() == DbFieldType.TEXT) + schema.getSortedFields().stream().filter(f -> f.getType() instanceof StringFieldType || f.getType() instanceof TextFieldType) .collect(Collectors.toList()); List queryPredicates = new ArrayList<>(); diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java index 9dc25ae..2a72281 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbAdminRepository.java @@ -46,6 +46,7 @@ import jakarta.validation.Validation; import jakarta.validation.Validator; import tech.ailef.dbadmin.external.DbAdmin; import tech.ailef.dbadmin.external.annotations.ReadOnly; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; import tech.ailef.dbadmin.external.dbmapping.query.DbQueryOutputField; import tech.ailef.dbadmin.external.dbmapping.query.DbQueryResult; import tech.ailef.dbadmin.external.dbmapping.query.DbQueryResultRow; diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldType.java deleted file mode 100644 index 1f76bb6..0000000 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldType.java +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Spring Boot Database Admin - An automatically generated CRUD admin UI for Spring Boot apps - * Copyright (C) 2023 Ailef (http://ailef.tech) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -package tech.ailef.dbadmin.external.dbmapping; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.sql.Date; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.List; -import java.util.Locale; - -import org.springframework.web.multipart.MultipartFile; - -import jakarta.persistence.ManyToMany; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import tech.ailef.dbadmin.external.dto.CompareOperator; -import tech.ailef.dbadmin.external.exceptions.DbAdminException; -import tech.ailef.dbadmin.external.exceptions.UnsupportedFieldTypeException; - -/** - * The enum for supported database field types. - */ -public enum DbFieldType { - SHORT { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return Short.parseShort(value.toString()); - } - - @Override - public Class getJavaClass() { - return Short.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); - } - }, - BIG_INTEGER { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return new BigInteger(value.toString()); - } - - @Override - public Class getJavaClass() { - return BigInteger.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); - } - }, - INTEGER { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return Integer.parseInt(value.toString()); - } - - @Override - public Class getJavaClass() { - return Integer.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); - } - }, - DOUBLE { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return Double.parseDouble(value.toString()); - } - - @Override - public Class getJavaClass() { - return Double.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); - } - }, - LONG { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return Long.parseLong(value.toString()); - } - - @Override - public Class getJavaClass() { - return Long.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); - } - }, - FLOAT { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return Float.parseFloat(value.toString()); - } - - @Override - public Class getJavaClass() { - return Float.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); - } - }, - OFFSET_DATE_TIME { - @Override - public String getFragmentName() { - return "datetime"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return OffsetDateTime.parse(value.toString()); - } - - @Override - public Class getJavaClass() { - return OffsetDateTime.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); - } - - }, - DATE { - @Override - public String getFragmentName() { - return "date"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH); - try { - return format.parse(value.toString()); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - - @Override - public Class getJavaClass() { - return Date.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); - } - }, - LOCAL_DATE { - @Override - public String getFragmentName() { - return "date"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return LocalDate.parse(value.toString()); - } - - @Override - public Class getJavaClass() { - return Float.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); - } - }, - LOCAL_DATE_TIME { - @Override - public String getFragmentName() { - return "datetime"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return LocalDateTime.parse(value.toString()); - } - - @Override - public Class getJavaClass() { - return LocalDateTime.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); - } - }, - INSTANT { - @Override - public String getFragmentName() { - return "datetime"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return LocalDateTime.parse(value.toString()).toInstant(ZoneOffset.UTC); - } - - @Override - public Class getJavaClass() { - return Instant.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); - } - }, - STRING { - @Override - public String getFragmentName() { - return "text"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return value.toString(); - } - - @Override - public Class getJavaClass() { - return String.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.CONTAINS, CompareOperator.STRING_EQ); - } - }, - TEXT { - @Override - public String getFragmentName() { - return "textarea"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return value.toString(); - } - - @Override - public Class getJavaClass() { - return String.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.CONTAINS, CompareOperator.STRING_EQ); - } - - }, - BOOLEAN { - @Override - public String getFragmentName() { - return "text"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return Boolean.parseBoolean(value.toString()); - } - - @Override - public Class getJavaClass() { - return Boolean.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.EQ); - } - }, - BIG_DECIMAL { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return new BigDecimal(value.toString()); - } - - @Override - public Class getJavaClass() { - return BigDecimal.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); - } - }, - CHAR { - @Override - public String getFragmentName() { - return "char"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - if (value.toString().isBlank()) return null; - return value.toString().charAt(0); - } - - @Override - public Class getJavaClass() { - return char.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.STRING_EQ); - } - }, - BYTE { - @Override - public String getFragmentName() { - return "number"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - return value.toString().getBytes()[0]; - } - - @Override - public Class getJavaClass() { - return byte.class; - } - - @Override - public List getCompareOperators() { - throw new DbAdminException("Binary fields are not comparable"); - } - }, - BYTE_ARRAY { - @Override - public String getFragmentName() { - return "file"; - } - - @Override - public Object parseValue(Object value) { - if (value == null || value.toString().isBlank()) return null; - try { - return ((MultipartFile)value).getBytes(); - } catch (IOException e) { - throw new DbAdminException(e); - } - } - - @Override - public Class getJavaClass() { - return byte[].class; - } - - @Override - public List getCompareOperators() { - throw new DbAdminException("Binary fields are not comparable"); - } - }, - UUID { - - @Override - public String getFragmentName() { - return "text"; - } - - @Override - public Object parseValue(Object value) { - return java.util.UUID.fromString(value.toString()); - } - - @Override - public Class getJavaClass() { - return java.util.UUID.class; - } - - @Override - public List getCompareOperators() { - return List.of(CompareOperator.STRING_EQ, CompareOperator.CONTAINS); - } - - }, - ONE_TO_MANY { - @Override - public String getFragmentName() { - throw new UnsupportedOperationException(); - } - - @Override - public Object parseValue(Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public Class getJavaClass() { - return OneToMany.class; - } - - @Override - public boolean isRelationship() { - return true; - } - - @Override - public String toString() { - return "One to Many"; - } - - @Override - public List getCompareOperators() { - throw new DbAdminException(); - } - }, - ONE_TO_ONE { - @Override - public String getFragmentName() { - throw new UnsupportedOperationException(); - } - - @Override - public Object parseValue(Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public Class getJavaClass() { - return OneToOne.class; - } - - @Override - public boolean isRelationship() { - return true; - } - - @Override - public String toString() { - return "One to One"; - } - - @Override - public List getCompareOperators() { - throw new DbAdminException(); - } - }, - MANY_TO_MANY { - @Override - public String getFragmentName() { - throw new UnsupportedOperationException(); - } - - @Override - public Object parseValue(Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public Class getJavaClass() { - return ManyToMany.class; - } - - @Override - public boolean isRelationship() { - return true; - } - - @Override - public String toString() { - return "Many to Many"; - } - - @Override - public List getCompareOperators() { - throw new DbAdminException(); - } - }, - COMPUTED { - @Override - public String getFragmentName() { - throw new UnsupportedOperationException(); - } - - @Override - public Object parseValue(Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public Class getJavaClass() { - throw new UnsupportedOperationException(); - } - - @Override - public List getCompareOperators() { - throw new DbAdminException(); - } - }; - - /** - * Returns the name of the Thymeleaf fragments in the 'inputs.html' - * file, used to render an input field for this specific type. - * For example, a fragment using a file input is used for binary fields. - */ - public abstract String getFragmentName(); - - /** - * Parse the value received through an HTML form into a instance - * of an object of this specific type. This usually involves a conversion - * from string, but, for example, files are sent as MultipartFile instead. - * @param value the value to parse - * @return - */ - public abstract Object parseValue(Object value); - - /** - * Returns the Java class corresponding to this field type. - * @return - */ - public abstract Class getJavaClass(); - - /** - * Returns a list of compare operators that can be used to compare - * two values for this field type. Used in the faceted search to provide - * more operators than just equality (e.g. after/before for dates). - * @return - */ - public abstract List getCompareOperators(); - - public boolean isRelationship() { - return false; - } - - /** - * Returns the corresponding {@linkplain DbFieldType} from a Class object. - * @param klass - * @return - */ - public static DbFieldType fromClass(Class klass) { - if (klass == Boolean.class || klass == boolean.class) { - return BOOLEAN; - } else if (klass == Long.class || klass == long.class) { - return LONG; - } else if (klass == Integer.class || klass == int.class) { - return INTEGER; - } else if (klass == BigInteger.class) { - return BIG_INTEGER; - } else if (klass == Short.class || klass == short.class) { - return SHORT; - } else if (klass == String.class) { - return STRING; - } else if (klass == LocalDate.class) { - return LOCAL_DATE; - } else if (klass == Date.class) { - return DATE; - } else if (klass == LocalDateTime.class) { - return LOCAL_DATE_TIME; - } else if (klass == Instant.class) { - return INSTANT; - } else if (klass == Float.class || klass == float.class) { - return FLOAT; - } else if (klass == Double.class || klass == double.class) { - return DOUBLE; - } else if (klass == BigDecimal.class) { - return BIG_DECIMAL; - } else if (klass == byte[].class) { - return BYTE_ARRAY; - } else if (klass == OffsetDateTime.class) { - return OFFSET_DATE_TIME; - } else if (klass == byte.class || klass == Byte.class) { - return BYTE; - } else if (klass == java.util.UUID.class) { - return UUID; - } else if (klass == char.class || klass == Character.class) { - return CHAR; - } else { - throw new UnsupportedFieldTypeException("Unsupported field type: " + klass); - } - } -} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldValue.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldValue.java index bd309ee..383df4a 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldValue.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbFieldValue.java @@ -27,6 +27,8 @@ import java.util.Objects; import com.fasterxml.jackson.annotation.JsonIgnore; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; + /** * Wrapper for the value of a field * diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObject.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObject.java index 07ca29d..6e33c37 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObject.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObject.java @@ -33,6 +33,8 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import tech.ailef.dbadmin.external.annotations.DisplayName; +import tech.ailef.dbadmin.external.dbmapping.fields.BooleanFieldType; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; import tech.ailef.dbadmin.external.exceptions.DbAdminException; /** @@ -246,7 +248,7 @@ public class DbObject { if (dbField == null) return null; String prefix = "get"; - if (dbField.getType() == DbFieldType.BOOLEAN) { + if (dbField.getType() instanceof BooleanFieldType) { prefix = "is"; } diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObjectSchema.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObjectSchema.java index 5fedc7d..706724d 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObjectSchema.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbObjectSchema.java @@ -46,6 +46,7 @@ import tech.ailef.dbadmin.external.annotations.DisableDelete; import tech.ailef.dbadmin.external.annotations.DisableEdit; import tech.ailef.dbadmin.external.annotations.DisableExport; import tech.ailef.dbadmin.external.annotations.HiddenColumn; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; import tech.ailef.dbadmin.external.dto.MappingError; import tech.ailef.dbadmin.external.exceptions.DbAdminException; import tech.ailef.dbadmin.external.misc.Utils; diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigDecimalFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigDecimalFieldType.java new file mode 100644 index 0000000..17bd0fe --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigDecimalFieldType.java @@ -0,0 +1,29 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.math.BigDecimal; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class BigDecimalFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return new BigDecimal(value.toString()); + } + + @Override + public Class getJavaClass() { + return BigDecimal.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigIntegerFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigIntegerFieldType.java new file mode 100644 index 0000000..5958db7 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BigIntegerFieldType.java @@ -0,0 +1,29 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.math.BigInteger; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class BigIntegerFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return new BigInteger(value.toString()); + } + + @Override + public Class getJavaClass() { + return BigInteger.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BooleanFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BooleanFieldType.java new file mode 100644 index 0000000..3a9af32 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/BooleanFieldType.java @@ -0,0 +1,28 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class BooleanFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "text"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return Boolean.parseBoolean(value.toString()); + } + + @Override + public Class getJavaClass() { + return Boolean.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.EQ); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteArrayFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteArrayFieldType.java new file mode 100644 index 0000000..45eec3e --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteArrayFieldType.java @@ -0,0 +1,35 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.io.IOException; +import java.util.List; + +import org.springframework.web.multipart.MultipartFile; + +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.DbAdminException; + +public class ByteArrayFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "file"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + try { + return ((MultipartFile)value).getBytes(); + } catch (IOException e) { + throw new DbAdminException(e); + } + } + + @Override + public Class getJavaClass() { + return byte[].class; + } + + @Override + public List getCompareOperators() { + throw new DbAdminException("Binary fields are not comparable"); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteFieldType.java new file mode 100644 index 0000000..f4e037d --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ByteFieldType.java @@ -0,0 +1,29 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.DbAdminException; + +public class ByteFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return value.toString().getBytes()[0]; + } + + @Override + public Class getJavaClass() { + return byte.class; + } + + @Override + public List getCompareOperators() { + throw new DbAdminException("Binary fields are not comparable"); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/CharFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/CharFieldType.java new file mode 100644 index 0000000..098ba04 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/CharFieldType.java @@ -0,0 +1,29 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class CharFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "char"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + if (value.toString().isBlank()) return null; + return value.toString().charAt(0); + } + + @Override + public Class getJavaClass() { + return char.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.STRING_EQ); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ComputedFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ComputedFieldType.java new file mode 100644 index 0000000..5677f06 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ComputedFieldType.java @@ -0,0 +1,28 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.DbAdminException; + +public class ComputedFieldType extends DbFieldType { + @Override + public String getFragmentName() { + throw new UnsupportedOperationException(); + } + + @Override + public Object parseValue(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Class getJavaClass() { + throw new UnsupportedOperationException(); + } + + @Override + public List getCompareOperators() { + throw new DbAdminException(); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DateFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DateFieldType.java new file mode 100644 index 0000000..28d4ba6 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DateFieldType.java @@ -0,0 +1,37 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class DateFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "date"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH); + try { + return format.parse(value.toString()); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + @Override + public Class getJavaClass() { + return Date.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbField.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DbField.java similarity index 95% rename from src/main/java/tech/ailef/dbadmin/external/dbmapping/DbField.java rename to src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DbField.java index 9b307cd..6189304 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbField.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DbField.java @@ -17,7 +17,7 @@ */ -package tech.ailef.dbadmin.external.dbmapping; +package tech.ailef.dbadmin.external.dbmapping.fields; import java.lang.reflect.Field; import java.util.List; @@ -36,6 +36,9 @@ import tech.ailef.dbadmin.external.annotations.DisplayImage; import tech.ailef.dbadmin.external.annotations.Filterable; import tech.ailef.dbadmin.external.annotations.FilterableType; import tech.ailef.dbadmin.external.annotations.ReadOnly; +import tech.ailef.dbadmin.external.dbmapping.DbFieldValue; +import tech.ailef.dbadmin.external.dbmapping.DbObject; +import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema; /** * Represent a field on the database, generated from an Entity class instance variable. @@ -172,7 +175,7 @@ public class DbField { } public boolean isBinary() { - return type == DbFieldType.BYTE_ARRAY; + return type instanceof ByteArrayFieldType; } public boolean isImage() { @@ -184,7 +187,7 @@ public class DbField { } public boolean isText() { - return type == DbFieldType.TEXT; + return type instanceof TextFieldType; } /** diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DbFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DbFieldType.java new file mode 100644 index 0000000..0ed9229 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DbFieldType.java @@ -0,0 +1,115 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Date; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.UnsupportedFieldTypeException; +import tech.ailef.dbadmin.external.misc.Utils; + +public abstract class DbFieldType { + + /** + * Returns the name of the Thymeleaf fragments in the 'inputs.html' + * file, used to render an input field for this specific type. + * For example, a fragment using a file input is used for binary fields. + */ + public abstract String getFragmentName(); + + /** + * Parse the value received through an HTML form into a instance + * of an object of this specific type. This usually involves a conversion + * from string, but, for example, files are sent as MultipartFile instead. + * @param value the value to parse + * @return + */ + public abstract Object parseValue(Object value); + + /** + * Returns the Java class corresponding to this field type. + * @return + */ + public abstract Class getJavaClass(); + + /** + * Returns a list of compare operators that can be used to compare + * two values for this field type. Used in the faceted search to provide + * more operators than just equality (e.g. after/before for dates). + * @return + */ + public abstract List getCompareOperators(); + + /** + * Returns all the possible values that this field can have. + * This method is by default unsupported, and it's implemented only + * in subclasses where this is applicable, e.g. EnumFieldType. + * @return + */ + public List getValues() { + throw new UnsupportedOperationException("getValues only supported on Enum type: called on " + this.getClass().getSimpleName()); + } + + public String toString() { + return Utils.camelToSnake(this.getClass().getSimpleName().replace("FieldType", "")).toUpperCase(); + } + + public boolean isRelationship() { + return false; + } + + /** + * Returns the corresponding {@linkplain DbFieldType} from a Class object. + * @param klass + * @return + */ + public static Class fromClass(Class klass) { + if (klass == Boolean.class || klass == boolean.class) { + return BooleanFieldType.class; + } else if (klass == Long.class || klass == long.class) { + return LongFieldType.class; + } else if (klass == Integer.class || klass == int.class) { + return IntegerFieldType.class; + } else if (klass == BigInteger.class) { + return BigIntegerFieldType.class; + } else if (klass == Short.class || klass == short.class) { + return ShortFieldType.class; + } else if (klass == String.class) { + return StringFieldType.class; + } else if (klass == LocalDate.class) { + return LocalDateFieldType.class; + } else if (klass == Date.class) { + return DateFieldType.class; + } else if (klass == LocalDateTime.class) { + return LocalDateTimeFieldType.class; + } else if (klass == Instant.class) { + return InstantFieldType.class; + } else if (klass == Float.class || klass == float.class) { + return FloatFieldType.class; + } else if (klass == Double.class || klass == double.class) { + return DoubleFieldType.class; + } else if (klass == BigDecimal.class) { + return BigDecimalFieldType.class; + } else if (klass == byte[].class) { + return ByteArrayFieldType.class; + } else if (klass == OffsetDateTime.class) { + return OffsetDateTimeFieldType.class; + } else if (klass == byte.class || klass == Byte.class) { + return ByteFieldType.class; + } else if (klass == java.util.UUID.class) { + return UUIDFieldType.class; + } else if (klass == char.class || klass == Character.class) { + return CharFieldType.class; + } else if (Enum.class.isAssignableFrom(klass)) { + return EnumFieldType.class; + } else { + throw new UnsupportedFieldTypeException("Unsupported field type: " + klass); + } + } + +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DoubleFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DoubleFieldType.java new file mode 100644 index 0000000..7ccc3b2 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/DoubleFieldType.java @@ -0,0 +1,28 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class DoubleFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return Double.parseDouble(value.toString()); + } + + @Override + public Class getJavaClass() { + return Double.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/EnumFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/EnumFieldType.java new file mode 100644 index 0000000..c8d4d91 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/EnumFieldType.java @@ -0,0 +1,62 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.DbAdminException; + +public class EnumFieldType extends DbFieldType { + + private Class klass; + + public EnumFieldType(Class klass) { + this.klass = klass; + } + + @Override + public String getFragmentName() { + return "select"; + } + + @Override + public List getValues() { + try { + Method method = getJavaClass().getMethod("values"); + Object[] invoke = (Object[])method.invoke(null); + return Arrays.stream(invoke).collect(Collectors.toList()); + } catch (NoSuchMethodException | SecurityException | InvocationTargetException + | IllegalAccessException | IllegalArgumentException e) { + throw new DbAdminException(e); + } + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + try { + Method valueOf = getJavaClass().getMethod("valueOf", String.class); + return valueOf.invoke(null, value.toString()); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof IllegalArgumentException) + throw new DbAdminException("Invalid value " + value + " for enum type " + getJavaClass().getSimpleName()); + else + throw new DbAdminException(e); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) { + throw new DbAdminException(e); + } + } + + @Override + public Class getJavaClass() { + return klass; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.STRING_EQ); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/FloatFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/FloatFieldType.java new file mode 100644 index 0000000..1ed19f4 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/FloatFieldType.java @@ -0,0 +1,27 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class FloatFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return Float.parseFloat(value.toString()); + } + + @Override + public Class getJavaClass() { + return Float.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/InstantFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/InstantFieldType.java new file mode 100644 index 0000000..e55209c --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/InstantFieldType.java @@ -0,0 +1,31 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class InstantFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "datetime"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return LocalDateTime.parse(value.toString()).toInstant(ZoneOffset.UTC); + } + + @Override + public Class getJavaClass() { + return Instant.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/IntegerFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/IntegerFieldType.java new file mode 100644 index 0000000..c4739a4 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/IntegerFieldType.java @@ -0,0 +1,27 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class IntegerFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return Integer.parseInt(value.toString()); + } + + @Override + public Class getJavaClass() { + return Integer.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateFieldType.java new file mode 100644 index 0000000..ee1ab46 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateFieldType.java @@ -0,0 +1,28 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.time.LocalDate; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class LocalDateFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "date"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return LocalDate.parse(value.toString()); + } + + @Override + public Class getJavaClass() { + return Float.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateTimeFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateTimeFieldType.java new file mode 100644 index 0000000..52a2add --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LocalDateTimeFieldType.java @@ -0,0 +1,29 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.time.LocalDateTime; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class LocalDateTimeFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "datetime"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return LocalDateTime.parse(value.toString()); + } + + @Override + public Class getJavaClass() { + return LocalDateTime.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LongFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LongFieldType.java new file mode 100644 index 0000000..ba8ffee --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/LongFieldType.java @@ -0,0 +1,27 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class LongFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return Long.parseLong(value.toString()); + } + + @Override + public Class getJavaClass() { + return Long.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); + } +} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ManyToManyFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ManyToManyFieldType.java new file mode 100644 index 0000000..82b10ec --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ManyToManyFieldType.java @@ -0,0 +1,38 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.util.List; + +import jakarta.persistence.ManyToMany; +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.DbAdminException; + +public class ManyToManyFieldType extends DbFieldType { + @Override + public String getFragmentName() { + throw new UnsupportedOperationException(); + } + + @Override + public Object parseValue(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Class getJavaClass() { + return ManyToMany.class; + } + + @Override + public boolean isRelationship() { + return true; + } + + @Override + public String toString() { + return "Many to Many"; + } + + @Override + public List getCompareOperators() { + throw new DbAdminException(); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OffsetDateTimeFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OffsetDateTimeFieldType.java new file mode 100644 index 0000000..0f8be6f --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OffsetDateTimeFieldType.java @@ -0,0 +1,28 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.time.OffsetDateTime; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class OffsetDateTimeFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "datetime"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return OffsetDateTime.parse(value.toString()); + } + + @Override + public Class getJavaClass() { + return OffsetDateTime.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OldDbFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OldDbFieldType.java new file mode 100644 index 0000000..dc70d5d --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OldDbFieldType.java @@ -0,0 +1,695 @@ +///* +// * Spring Boot Database Admin - An automatically generated CRUD admin UI for Spring Boot apps +// * Copyright (C) 2023 Ailef (http://ailef.tech) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see . +// */ +// +// +//package tech.ailef.dbadmin.external.dbmapping; +// +//import java.io.IOException; +//import java.lang.reflect.InvocationTargetException; +//import java.lang.reflect.Method; +//import java.math.BigDecimal; +//import java.math.BigInteger; +//import java.sql.Date; +//import java.text.ParseException; +//import java.text.SimpleDateFormat; +//import java.time.Instant; +//import java.time.LocalDate; +//import java.time.LocalDateTime; +//import java.time.OffsetDateTime; +//import java.time.ZoneOffset; +//import java.util.List; +//import java.util.Locale; +// +//import org.springframework.web.multipart.MultipartFile; +// +//import jakarta.persistence.ManyToMany; +//import jakarta.persistence.OneToMany; +//import jakarta.persistence.OneToOne; +//import tech.ailef.dbadmin.external.dto.CompareOperator; +//import tech.ailef.dbadmin.external.exceptions.DbAdminException; +//import tech.ailef.dbadmin.external.exceptions.UnsupportedFieldTypeException; +// +///** +// * The enum for supported database field types. +// */ +//public enum OldDbFieldType { +// BIG_INTEGER { +// @Override +// public String getFragmentName() { +// return "number"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return new BigInteger(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return BigInteger.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); +// } +// }, +// INTEGER { +// @Override +// public String getFragmentName() { +// return "number"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return Integer.parseInt(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return Integer.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); +// } +// }, +// DOUBLE { +// @Override +// public String getFragmentName() { +// return "number"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return Double.parseDouble(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return Double.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); +// } +// }, +// LONG { +// @Override +// public String getFragmentName() { +// return "number"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return Long.parseLong(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return Long.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); +// } +// }, +// FLOAT { +// @Override +// public String getFragmentName() { +// return "number"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return Float.parseFloat(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return Float.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); +// } +// }, +// OFFSET_DATE_TIME { +// @Override +// public String getFragmentName() { +// return "datetime"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return OffsetDateTime.parse(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return OffsetDateTime.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); +// } +// +// }, +// DATE { +// @Override +// public String getFragmentName() { +// return "date"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH); +// try { +// return format.parse(value.toString()); +// } catch (ParseException e) { +// throw new RuntimeException(e); +// } +// } +// +// @Override +// public Class getJavaClass() { +// return Date.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); +// } +// }, +// LOCAL_DATE { +// @Override +// public String getFragmentName() { +// return "date"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return LocalDate.parse(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return Float.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); +// } +// }, +// LOCAL_DATE_TIME { +// @Override +// public String getFragmentName() { +// return "datetime"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return LocalDateTime.parse(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return LocalDateTime.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); +// } +// }, +// INSTANT { +// @Override +// public String getFragmentName() { +// return "datetime"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return LocalDateTime.parse(value.toString()).toInstant(ZoneOffset.UTC); +// } +// +// @Override +// public Class getJavaClass() { +// return Instant.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE); +// } +// }, +// STRING { +// @Override +// public String getFragmentName() { +// return "text"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return value.toString(); +// } +// +// @Override +// public Class getJavaClass() { +// return String.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.CONTAINS, CompareOperator.STRING_EQ); +// } +// }, +// TEXT { +// @Override +// public String getFragmentName() { +// return "textarea"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return value.toString(); +// } +// +// @Override +// public Class getJavaClass() { +// return String.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.CONTAINS, CompareOperator.STRING_EQ); +// } +// +// }, +// BOOLEAN { +// @Override +// public String getFragmentName() { +// return "text"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return Boolean.parseBoolean(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return Boolean.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.EQ); +// } +// }, +// BIG_DECIMAL { +// @Override +// public String getFragmentName() { +// return "number"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return new BigDecimal(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return BigDecimal.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); +// } +// }, +// CHAR { +// @Override +// public String getFragmentName() { +// return "char"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// if (value.toString().isBlank()) return null; +// return value.toString().charAt(0); +// } +// +// @Override +// public Class getJavaClass() { +// return char.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.STRING_EQ); +// } +// }, +// BYTE { +// @Override +// public String getFragmentName() { +// return "number"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// return value.toString().getBytes()[0]; +// } +// +// @Override +// public Class getJavaClass() { +// return byte.class; +// } +// +// @Override +// public List getCompareOperators() { +// throw new DbAdminException("Binary fields are not comparable"); +// } +// }, +// BYTE_ARRAY { +// @Override +// public String getFragmentName() { +// return "file"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// try { +// return ((MultipartFile)value).getBytes(); +// } catch (IOException e) { +// throw new DbAdminException(e); +// } +// } +// +// @Override +// public Class getJavaClass() { +// return byte[].class; +// } +// +// @Override +// public List getCompareOperators() { +// throw new DbAdminException("Binary fields are not comparable"); +// } +// }, +// UUID { +// @Override +// public String getFragmentName() { +// return "text"; +// } +// +// @Override +// public Object parseValue(Object value) { +// return java.util.UUID.fromString(value.toString()); +// } +// +// @Override +// public Class getJavaClass() { +// return java.util.UUID.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.STRING_EQ, CompareOperator.CONTAINS); +// } +// +// }, +// ENUM_STRING { +// @Override +// public String getFragmentName() { +// return "text"; +// } +// +// @Override +// public Object parseValue(Object value) { +// if (value == null || value.toString().isBlank()) return null; +// try { +// Method valueOf = getJavaClass().getMethod("valueOf", String.class); +// return valueOf.invoke(null, value.toString()); +// } catch (NoSuchMethodException | SecurityException | IllegalAccessException +// | IllegalArgumentException | InvocationTargetException e) { +// throw new DbAdminException(e); +// } +// } +// +// @Override +// public Class getJavaClass() { +// return Enum.class; +// } +// +// @Override +// public List getCompareOperators() { +// return List.of(CompareOperator.STRING_EQ); +// } +// +// }, +// ONE_TO_MANY { +// @Override +// public String getFragmentName() { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Object parseValue(Object value) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Class getJavaClass() { +// return OneToMany.class; +// } +// +// @Override +// public boolean isRelationship() { +// return true; +// } +// +// @Override +// public String toString() { +// return "One to Many"; +// } +// +// @Override +// public List getCompareOperators() { +// throw new DbAdminException(); +// } +// }, +// ONE_TO_ONE { +// @Override +// public String getFragmentName() { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Object parseValue(Object value) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Class getJavaClass() { +// return OneToOne.class; +// } +// +// @Override +// public boolean isRelationship() { +// return true; +// } +// +// @Override +// public String toString() { +// return "One to One"; +// } +// +// @Override +// public List getCompareOperators() { +// throw new DbAdminException(); +// } +// }, +// MANY_TO_MANY { +// @Override +// public String getFragmentName() { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Object parseValue(Object value) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Class getJavaClass() { +// return ManyToMany.class; +// } +// +// @Override +// public boolean isRelationship() { +// return true; +// } +// +// @Override +// public String toString() { +// return "Many to Many"; +// } +// +// @Override +// public List getCompareOperators() { +// throw new DbAdminException(); +// } +// }, +// COMPUTED { +// @Override +// public String getFragmentName() { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Object parseValue(Object value) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Class getJavaClass() { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public List getCompareOperators() { +// throw new DbAdminException(); +// } +// }; +// +// /** +// * Returns the name of the Thymeleaf fragments in the 'inputs.html' +// * file, used to render an input field for this specific type. +// * For example, a fragment using a file input is used for binary fields. +// */ +// public abstract String getFragmentName(); +// +// /** +// * Parse the value received through an HTML form into a instance +// * of an object of this specific type. This usually involves a conversion +// * from string, but, for example, files are sent as MultipartFile instead. +// * @param value the value to parse +// * @return +// */ +// public abstract Object parseValue(Object value); +// +// /** +// * Returns the Java class corresponding to this field type. +// * @return +// */ +// public abstract Class getJavaClass(); +// +// /** +// * Returns a list of compare operators that can be used to compare +// * two values for this field type. Used in the faceted search to provide +// * more operators than just equality (e.g. after/before for dates). +// * @return +// */ +// public abstract List getCompareOperators(); +// +// public boolean isRelationship() { +// return false; +// } +// +//// private DbFieldType() { +//// +//// } +//// +//// private DbFieldType(String className) { +//// this.className = className; +//// } +//// +//// private String className; +// +// /** +// * Returns the corresponding {@linkplain DbFieldType} from a Class object. +// * @param klass +// * @return +// */ +// public static DbFieldType fromClass(Class klass) { +// if (klass == Boolean.class || klass == boolean.class) { +// return BOOLEAN; +// } else if (klass == Long.class || klass == long.class) { +// return LONG; +// } else if (klass == Integer.class || klass == int.class) { +// return INTEGER; +// } else if (klass == BigInteger.class) { +// return BIG_INTEGER; +// } else if (klass == Short.class || klass == short.class) { +// return SHORT; +// } else if (klass == String.class) { +// return STRING; +// } else if (klass == LocalDate.class) { +// return LOCAL_DATE; +// } else if (klass == Date.class) { +// return DATE; +// } else if (klass == LocalDateTime.class) { +// return LOCAL_DATE_TIME; +// } else if (klass == Instant.class) { +// return INSTANT; +// } else if (klass == Float.class || klass == float.class) { +// return FLOAT; +// } else if (klass == Double.class || klass == double.class) { +// return DOUBLE; +// } else if (klass == BigDecimal.class) { +// return BIG_DECIMAL; +// } else if (klass == byte[].class) { +// return BYTE_ARRAY; +// } else if (klass == OffsetDateTime.class) { +// return OFFSET_DATE_TIME; +// } else if (klass == byte.class || klass == Byte.class) { +// return BYTE; +// } else if (klass == java.util.UUID.class) { +// return UUID; +// } else if (klass == char.class || klass == Character.class) { +// return CHAR; +// } else if (Enum.class.isAssignableFrom(klass)) { +// return ENUM_STRING; +// } else { +// throw new UnsupportedFieldTypeException("Unsupported field type: " + klass); +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToManyFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToManyFieldType.java new file mode 100644 index 0000000..fccfcd4 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToManyFieldType.java @@ -0,0 +1,39 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import jakarta.persistence.OneToMany; +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.DbAdminException; + +public class OneToManyFieldType extends DbFieldType { + @Override + public String getFragmentName() { + throw new UnsupportedOperationException(); + } + + @Override + public Object parseValue(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Class getJavaClass() { + return OneToMany.class; + } + + @Override + public boolean isRelationship() { + return true; + } + + @Override + public String toString() { + return "One to Many"; + } + + @Override + public List getCompareOperators() { + throw new DbAdminException(); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToOneFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToOneFieldType.java new file mode 100644 index 0000000..2b283b5 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/OneToOneFieldType.java @@ -0,0 +1,38 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.util.List; + +import jakarta.persistence.OneToOne; +import tech.ailef.dbadmin.external.dto.CompareOperator; +import tech.ailef.dbadmin.external.exceptions.DbAdminException; + +public class OneToOneFieldType extends DbFieldType { + @Override + public String getFragmentName() { + throw new UnsupportedOperationException(); + } + + @Override + public Object parseValue(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Class getJavaClass() { + return OneToOne.class; + } + + @Override + public boolean isRelationship() { + return true; + } + + @Override + public String toString() { + return "One to One"; + } + + @Override + public List getCompareOperators() { + throw new DbAdminException(); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ShortFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ShortFieldType.java new file mode 100644 index 0000000..1b4f1a6 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/ShortFieldType.java @@ -0,0 +1,28 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class ShortFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "number"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return Short.parseShort(value.toString()); + } + + @Override + public Class getJavaClass() { + return Short.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/StringFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/StringFieldType.java new file mode 100644 index 0000000..53719fb --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/StringFieldType.java @@ -0,0 +1,27 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class StringFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "text"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return value.toString(); + } + + @Override + public Class getJavaClass() { + return String.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.CONTAINS, CompareOperator.STRING_EQ); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/TextFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/TextFieldType.java new file mode 100644 index 0000000..be2a752 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/TextFieldType.java @@ -0,0 +1,28 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class TextFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "textarea"; + } + + @Override + public Object parseValue(Object value) { + if (value == null || value.toString().isBlank()) return null; + return value.toString(); + } + + @Override + public Class getJavaClass() { + return String.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.CONTAINS, CompareOperator.STRING_EQ); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/UUIDFieldType.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/UUIDFieldType.java new file mode 100644 index 0000000..12c13e0 --- /dev/null +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/fields/UUIDFieldType.java @@ -0,0 +1,27 @@ +package tech.ailef.dbadmin.external.dbmapping.fields; + +import java.util.List; + +import tech.ailef.dbadmin.external.dto.CompareOperator; + +public class UUIDFieldType extends DbFieldType { + @Override + public String getFragmentName() { + return "text"; + } + + @Override + public Object parseValue(Object value) { + return java.util.UUID.fromString(value.toString()); + } + + @Override + public Class getJavaClass() { + return java.util.UUID.class; + } + + @Override + public List getCompareOperators() { + return List.of(CompareOperator.STRING_EQ, CompareOperator.CONTAINS); + } +} diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/query/DbQueryOutputField.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/query/DbQueryOutputField.java index 3d1afb2..c082daa 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/query/DbQueryOutputField.java +++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/query/DbQueryOutputField.java @@ -20,12 +20,13 @@ package tech.ailef.dbadmin.external.dbmapping.query; +import java.lang.reflect.InvocationTargetException; import java.util.Objects; import tech.ailef.dbadmin.external.DbAdmin; -import tech.ailef.dbadmin.external.dbmapping.DbField; -import tech.ailef.dbadmin.external.dbmapping.DbFieldType; import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; +import tech.ailef.dbadmin.external.dbmapping.fields.DbFieldType; import tech.ailef.dbadmin.external.exceptions.DbAdminException; import tech.ailef.dbadmin.external.exceptions.UnsupportedFieldTypeException; @@ -127,9 +128,10 @@ public class DbQueryOutputField { // If the row this fields belongs to is defined if (result != null) { try { - DbFieldType type = DbFieldType.fromClass(result.get(this).getClass()); + DbFieldType type = DbFieldType.fromClass(result.get(this).getClass()).getConstructor().newInstance(); return type.toString(); - } catch (UnsupportedFieldTypeException e) { + } catch (UnsupportedFieldTypeException | InstantiationException | IllegalAccessException | + IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { return "-"; } } diff --git a/src/main/java/tech/ailef/dbadmin/external/dto/QueryFilter.java b/src/main/java/tech/ailef/dbadmin/external/dto/QueryFilter.java index 828cfa5..0e2e8b1 100644 --- a/src/main/java/tech/ailef/dbadmin/external/dto/QueryFilter.java +++ b/src/main/java/tech/ailef/dbadmin/external/dto/QueryFilter.java @@ -21,7 +21,7 @@ package tech.ailef.dbadmin.external.dto; import java.util.Objects; -import tech.ailef.dbadmin.external.dbmapping.DbField; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; import tech.ailef.dbadmin.external.exceptions.DbAdminException; /** diff --git a/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java b/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java index 37e267f..281e7eb 100644 --- a/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java +++ b/src/main/java/tech/ailef/dbadmin/external/misc/Utils.java @@ -26,8 +26,8 @@ import java.util.Set; import org.springframework.util.MultiValueMap; -import tech.ailef.dbadmin.external.dbmapping.DbField; import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema; +import tech.ailef.dbadmin.external.dbmapping.fields.DbField; import tech.ailef.dbadmin.external.dto.CompareOperator; import tech.ailef.dbadmin.external.dto.QueryFilter; import tech.ailef.dbadmin.external.exceptions.DbAdminException; diff --git a/src/main/resources/templates/fragments/inputs.html b/src/main/resources/templates/fragments/inputs.html index bac3049..3b1940b 100644 --- a/src/main/resources/templates/fragments/inputs.html +++ b/src/main/resources/templates/fragments/inputs.html @@ -77,6 +77,18 @@ > + + +