diff --git a/pom.xml b/pom.xml
index 3198ff9..61171a0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
tech.ailef
spring-boot-db-admin
- 0.0.1-SNAPSHOT
+ 0.0.2
spring-boot-db-admin
Srping Boot DB Admin Dashboard
diff --git a/src/main/java/tech/ailef/dbadmin/DbAdmin.java b/src/main/java/tech/ailef/dbadmin/DbAdmin.java
index f92e22d..c0c3427 100644
--- a/src/main/java/tech/ailef/dbadmin/DbAdmin.java
+++ b/src/main/java/tech/ailef/dbadmin/DbAdmin.java
@@ -95,7 +95,6 @@ public class DbAdmin {
field.setSchema(schema);
schema.addField(field);
- System.out.println(field);
}
return schema;
diff --git a/src/main/java/tech/ailef/dbadmin/annotations/Filterable.java b/src/main/java/tech/ailef/dbadmin/annotations/Filterable.java
new file mode 100644
index 0000000..5b72c56
--- /dev/null
+++ b/src/main/java/tech/ailef/dbadmin/annotations/Filterable.java
@@ -0,0 +1,11 @@
+package tech.ailef.dbadmin.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Filterable {
+}
\ No newline at end of file
diff --git a/src/main/java/tech/ailef/dbadmin/controller/DefaultDbAdminController.java b/src/main/java/tech/ailef/dbadmin/controller/DefaultDbAdminController.java
index 99942d1..f002e35 100644
--- a/src/main/java/tech/ailef/dbadmin/controller/DefaultDbAdminController.java
+++ b/src/main/java/tech/ailef/dbadmin/controller/DefaultDbAdminController.java
@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
@@ -12,6 +13,7 @@ import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
+import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -22,12 +24,17 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import tech.ailef.dbadmin.DbAdmin;
import tech.ailef.dbadmin.dbmapping.DbAdminRepository;
import tech.ailef.dbadmin.dbmapping.DbObject;
import tech.ailef.dbadmin.dbmapping.DbObjectSchema;
+import tech.ailef.dbadmin.dto.CompareOperator;
import tech.ailef.dbadmin.dto.PaginatedResult;
+import tech.ailef.dbadmin.dto.QueryFilter;
import tech.ailef.dbadmin.exceptions.InvalidPageException;
+import tech.ailef.dbadmin.misc.Utils;
@Controller
@RequestMapping("/dbadmin")
@@ -45,10 +52,15 @@ import tech.ailef.dbadmin.exceptions.InvalidPageException;
* - Pagination in one to many results?
* - BLOB upload (WIP: check edit not working)
* - AI console (PRO)
+ * - Action logs
+ * - Boolean icons
+ * - @Filterable
+ * - Boolean in create/edit is checkbox
* - SQL console (PRO)
* - JPA Validation (PRO)
* - Logging
- * - ERROR 500: http://localhost:8080/dbadmin/model/tech.ailef.dbadmin.test.models.Order?query=2021
+ * - TODO FIX: list model page crash
+ * EDIT error on table product
* - Logs in web ui
* - Tests: AutocompleteController, REST API, create/edit
*/
@@ -86,16 +98,55 @@ public class DefaultDbAdminController {
public String list(Model model, @PathVariable String className,
@RequestParam(required=false) Integer page, @RequestParam(required=false) String query,
@RequestParam(required=false) Integer pageSize, @RequestParam(required=false) String sortKey,
- @RequestParam(required=false) String sortOrder) {
+ @RequestParam(required=false) String sortOrder, @RequestParam MultiValueMap otherParams,
+ HttpServletRequest request,
+ HttpServletResponse response) {
+
if (page == null) page = 1;
if (pageSize == null) pageSize = 50;
+ Set queryFilters = Utils.computeFilters(otherParams);
+ if (otherParams.containsKey("remove_field")) {
+ List fields = otherParams.get("remove_field");
+
+ for (int i = 0; i < fields.size(); i++) {
+ QueryFilter toRemove =
+ new QueryFilter(
+ fields.get(i),
+ CompareOperator.valueOf(otherParams.get("remove_op").get(i).toUpperCase()),
+ otherParams.get("remove_value").get(i)
+ );
+ queryFilters.removeIf(f -> f.equals(toRemove));
+ }
+
+ MultiValueMap parameterMap = Utils.computeParams(queryFilters);
+
+ MultiValueMap filteredParams = new LinkedMultiValueMap<>();
+ request.getParameterMap().entrySet().stream()
+ .filter(e -> !e.getKey().startsWith("remove_") && !e.getKey().startsWith("filter_"))
+ .forEach(e -> {
+ filteredParams.putIfAbsent(e.getKey(), new ArrayList<>());
+ for (String v : e.getValue()) {
+ if (filteredParams.get(e.getKey()).isEmpty()) {
+ filteredParams.get(e.getKey()).add(v);
+ } else {
+ filteredParams.get(e.getKey()).set(0, v);
+ }
+ }
+ });
+
+ filteredParams.putAll(parameterMap);
+ String queryString = Utils.getQueryString(filteredParams);
+ String redirectUrl = request.getServletPath() + queryString;
+ return "redirect:" + redirectUrl.trim();
+ }
+
DbObjectSchema schema = dbAdmin.findSchemaByClassName(className);
try {
PaginatedResult result = null;
- if (query != null) {
- result = repository.search(schema, query, page, pageSize, sortKey, sortOrder);
+ if (query != null || !otherParams.isEmpty()) {
+ result = repository.search(schema, query, page, pageSize, sortKey, sortOrder, queryFilters);
} else {
result = repository.findAll(schema, page, pageSize, sortKey, sortOrder);
}
@@ -107,6 +158,7 @@ public class DefaultDbAdminController {
model.addAttribute("sortKey", sortKey);
model.addAttribute("query", query);
model.addAttribute("sortOrder", sortOrder);
+ model.addAttribute("activeFilters", queryFilters);
return "model/list";
} catch (InvalidPageException e) {
@@ -333,9 +385,12 @@ public class DefaultDbAdminController {
}
}
+
@GetMapping("/settings")
public String settings(Model model) {
model.addAttribute("activePage", "settings");
return "settings";
}
+
+
}
diff --git a/src/main/java/tech/ailef/dbadmin/controller/GlobalController.java b/src/main/java/tech/ailef/dbadmin/controller/GlobalController.java
new file mode 100644
index 0000000..c900079
--- /dev/null
+++ b/src/main/java/tech/ailef/dbadmin/controller/GlobalController.java
@@ -0,0 +1,27 @@
+package tech.ailef.dbadmin.controller;
+
+import java.util.Map;
+
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ModelAttribute;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * This class registers some ModelAttribute objects that are
+ * used in all templates.
+ */
+@ControllerAdvice
+public class GlobalController {
+
+ /**
+ * A multi valued map containing the query parameters. It is used primarily
+ * in building complex URL when performing faceted search with multiple filters.
+ * @param request the incoming request
+ * @return multi valued map of request parameters
+ */
+ @ModelAttribute("queryParams")
+ public Map getQueryParams(HttpServletRequest request) {
+ return request.getParameterMap();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/tech/ailef/dbadmin/dbmapping/AdvancedJpaRepository.java b/src/main/java/tech/ailef/dbadmin/dbmapping/AdvancedJpaRepository.java
index 6eb67c8..e5db4ba 100644
--- a/src/main/java/tech/ailef/dbadmin/dbmapping/AdvancedJpaRepository.java
+++ b/src/main/java/tech/ailef/dbadmin/dbmapping/AdvancedJpaRepository.java
@@ -1,17 +1,29 @@
package tech.ailef.dbadmin.dbmapping;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
+import org.springframework.web.multipart.MultipartFile;
import jakarta.persistence.EntityManager;
+import jakarta.persistence.Query;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
+import tech.ailef.dbadmin.dto.CompareOperator;
+import tech.ailef.dbadmin.dto.QueryFilter;
+import tech.ailef.dbadmin.exceptions.DbAdminException;
@SuppressWarnings("rawtypes")
public class AdvancedJpaRepository extends SimpleJpaRepository {
@@ -27,51 +39,151 @@ public class AdvancedJpaRepository extends SimpleJpaRepository {
this.schema = schema;
}
- public long count(String q) {
+ @SuppressWarnings("unchecked")
+ public long count(String q, Set queryFilters) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(Long.class);
Root root = query.from(schema.getJavaClass());
-
- List stringFields =
- schema.getSortedFields().stream().filter(f -> f.getType() == DbFieldType.STRING)
- .collect(Collectors.toList());
-
- System.out.println("STRING F = " + stringFields);
- List predicates = new ArrayList<>();
- for (DbField f : stringFields) {
- Path path = root.get(f.getJavaName());
- predicates.add(cb.like(cb.lower(cb.toString(path)), "%" + q.toLowerCase() + "%"));
- }
+ List finalPredicates = buildPredicates(q, queryFilters, cb, root);
+
query.select(cb.count(root.get(schema.getPrimaryKey().getName())))
- .where(cb.or(predicates.toArray(new Predicate[predicates.size()])));
+ .where(
+ cb.and(
+ finalPredicates.toArray(new Predicate[finalPredicates.size()])
+ )
+ );
Object o = entityManager.createQuery(query).getSingleResult();
return (Long)o;
}
@SuppressWarnings("unchecked")
- public List