This commit is contained in:
Francesco 2023-09-30 08:38:07 +02:00
parent 9c15bb33e7
commit 5c5df5e2ba
3 changed files with 143 additions and 19 deletions

View File

@ -59,6 +59,13 @@ public class DbObjectSchema {
*/
private String tableName;
/**
* Initializes this schema for the specific `@Entity` class.
* Determines the table name from the `@Table` annotation and also
* which methods are `@ComputedColumn`s
* @param klass the `@Entity` class
* @param dbAdmin the DbAdmin instance
*/
public DbObjectSchema(Class<?> klass, DbAdmin dbAdmin) {
this.dbAdmin = dbAdmin;
this.entityClass = klass;
@ -88,48 +95,103 @@ public class DbObjectSchema {
}
}
/**
* Returns the DbAdmin instance
* @return the DbAdmin instance
*/
public DbAdmin getDbAdmin() {
return dbAdmin;
}
/**
* Returns the Java class for the underlying `@Entity` this schema
* corresponds to
* @return the Java class for the `@Entity` this schema corresponds to
*/
@JsonIgnore
public Class<?> getJavaClass() {
return entityClass;
}
/**
* Returns the name of the Java class for the underlying `@Entity` this schema
* corresponds to
* @return the name of the Java class for the `@Entity` this schema corresponds to
*/
@JsonIgnore
public String getClassName() {
return entityClass.getName();
}
/**
* Returns an unmodifiable list of all the fields in the schema
* @return an unmodifiable list of all the fields in the schema
*/
public List<DbField> getFields() {
return Collections.unmodifiableList(fields);
}
/**
* Get a field by its Java name, i.e. the name of the instance variable
* in the `@Entity` class
* @param name name of the instance variable
* @return the DbField if found, null otherwise
*/
public DbField getFieldByJavaName(String name) {
return fields.stream().filter(f -> f.getJavaName().equals(name)).findFirst().orElse(null);
}
/**
* Get a field by its database name, i.e. the name of the column corresponding
* to the field
* @param name name of the column
* @return the DbField if found, null otherwise
*/
public DbField getFieldByName(String name) {
return fields.stream().filter(f -> f.getName().equals(name)).findFirst().orElse(null);
}
/**
* Adds a field to this schema. This is used by the DbAdmin instance
* during initialization and it's not supposed to be called afterwards
* @param f the DbField to add
*/
public void addField(DbField f) {
fields.add(f);
}
/**
* Returns the underlying CustomJpaRepository
* @return
*/
public CustomJpaRepository getJpaRepository() {
return jpaRepository;
}
/**
* Sets the underlying CustomJpaRepository
* @param jpaRepository
*/
public void setJpaRepository(CustomJpaRepository jpaRepository) {
this.jpaRepository = jpaRepository;
}
/**
* Returns the inferred table name for this schema
* @return
*/
public String getTableName() {
return tableName;
}
/**
* Returns a sorted list of physical fields (i.e., fields that correspond to
* a column in the table as opposed to fields that are just present as
* instance variables, like relationship fields). Sorted alphabetically
* with priority to the primary key.
*
* @return
*/
@JsonIgnore
public List<DbField> getSortedFields() {
return getFields().stream()
@ -151,6 +213,10 @@ public class DbObjectSchema {
}).collect(Collectors.toList());
}
/**
* Returns the list of relationship fields
* @return
*/
public List<DbField> getRelationshipFields() {
List<DbField> res = getFields().stream().filter(f -> {
return f.getPrimitiveField().getAnnotation(OneToMany.class) != null
@ -159,6 +225,11 @@ public class DbObjectSchema {
return res;
}
/**
* Returns the list of ManyToMany fields owned by this class (i.e. they
* do not have "mappedBy")
* @return
*/
public List<DbField> getManyToManyOwnedFields() {
List<DbField> res = getFields().stream().filter(f -> {
ManyToMany anno = f.getPrimitiveField().getAnnotation(ManyToMany.class);
@ -167,6 +238,10 @@ public class DbObjectSchema {
return res;
}
/**
* Returns the DbField which serves as the primary key for this schema
* @return
*/
@JsonIgnore
public DbField getPrimaryKey() {
Optional<DbField> pk = fields.stream().filter(f -> f.isPrimaryKey()).findFirst();
@ -176,21 +251,37 @@ public class DbObjectSchema {
throw new RuntimeException("No primary key defined on " + entityClass.getName() + " (table `" + tableName + "`)");
}
/**
* Returns the names of the `@ComputedColumn`s in this schema
* @return
*/
public List<String> getComputedColumnNames() {
return computedColumns.keySet().stream().sorted().toList();
}
/**
* Returns the method for the given `@ComputedColumn` name
* @param name the name of the `@ComputedColumn`
* @return the corresponding instance method if found, null otherwise
*/
public Method getComputedColumn(String name) {
return computedColumns.get(name);
}
/**
* Returns the list of fields that are `@Filterable`
* @return
*/
public List<DbField> getFilterableFields() {
return getSortedFields().stream().filter(f -> {
return !f.isBinary() && !f.isPrimaryKey()
&& f.isFilterable();
return !f.isBinary() && !f.isPrimaryKey() && f.isFilterable();
}).toList();
}
/**
* Returns all the data in this schema, as `DbObject`s
* @return
*/
public List<DbObject> findAll() {
List<?> r = jpaRepository.findAll();
return r.stream().map(o -> new DbObject(o, this)).toList();

View File

@ -1,5 +1,9 @@
package tech.ailef.dbadmin.external.exceptions;
/**
* Generic top-level exception for everything thrown by us
*
*/
public class DbAdminException extends RuntimeException {
private static final long serialVersionUID = 8120227031645804467L;

View File

@ -1,6 +1,7 @@
package tech.ailef.dbadmin.external.misc;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -13,7 +14,38 @@ import tech.ailef.dbadmin.external.dto.CompareOperator;
import tech.ailef.dbadmin.external.dto.QueryFilter;
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
/**
* Collection of utility functions used across the project
*
*/
public interface Utils {
/**
* Converts snake case to camel case
* @param text
* @return
*/
public static String snakeToCamel(String text) {
boolean shouldConvertNextCharToLower = true;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char currentChar = text.charAt(i);
if (currentChar == '_') {
shouldConvertNextCharToLower = false;
} else if (shouldConvertNextCharToLower) {
builder.append(Character.toLowerCase(currentChar));
} else {
builder.append(Character.toUpperCase(currentChar));
shouldConvertNextCharToLower = true;
}
}
return builder.toString();
}
/**
* Convers camel case to snake case
* @param v
* @return
*/
public static String camelToSnake(String v) {
if (Character.isUpperCase(v.charAt(0))) {
v = Character.toLowerCase(v.charAt(0)) + v.substring(1);
@ -23,6 +55,12 @@ public interface Utils {
}
/**
* Converts a set of query filters applied with the faceted search feature
* to a multi value map
* @param filters
* @return
*/
public static MultiValueMap<String, String> computeParams(Set<QueryFilter> filters) {
MultiValueMap<String, String> r = new LinkedMultiValueMap<>();
if (filters == null)
@ -41,6 +79,13 @@ public interface Utils {
return r;
}
/**
* Converts a multi value map of parameters containing query filters applied
* with the faceted search feature into a set of QueryFilter objects
* @param schema
* @param params
* @return
*/
public static Set<QueryFilter> computeFilters(DbObjectSchema schema, MultiValueMap<String, String> params) {
if (params == null)
return new HashSet<>();
@ -85,20 +130,4 @@ public interface Utils {
return "?" + String.join("&", paramValues);
}
public static String snakeToCamel(String text) {
boolean shouldConvertNextCharToLower = true;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char currentChar = text.charAt(i);
if (currentChar == '_') {
shouldConvertNextCharToLower = false;
} else if (shouldConvertNextCharToLower) {
builder.append(Character.toLowerCase(currentChar));
} else {
builder.append(Character.toUpperCase(currentChar));
shouldConvertNextCharToLower = true;
}
}
return builder.toString();
}
}