trabajando en usuarios

This commit is contained in:
2025-09-26 15:13:11 +02:00
parent 062a20c26a
commit 01a1ac4b71
30 changed files with 937 additions and 139 deletions

View File

@ -0,0 +1,98 @@
package com.imprimelibros.erp.datatables;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
public class DataTable<T> {
public interface FilterHook<T> extends BiConsumer<SpecBuilder<T>, DataTablesRequest> {}
public interface SpecBuilder<T> { void add(Specification<T> extra); }
private final JpaSpecificationExecutor<T> repo;
private final Class<T> entityClass;
private final DataTablesRequest dt;
private final List<String> searchable;
private final List<Function<T, Map<String,Object>>> adders = new ArrayList<>();
private final List<Function<Map<String,Object>, Map<String,Object>>> editors = new ArrayList<>();
private final List<FilterHook<T>> filters = new ArrayList<>();
private Specification<T> baseSpec = (root,q,cb) -> cb.conjunction();
private final ObjectMapper om = new ObjectMapper();
private DataTable(JpaSpecificationExecutor<T> repo, Class<T> entityClass, DataTablesRequest dt, List<String> searchable) {
this.repo = repo; this.entityClass = entityClass; this.dt = dt; this.searchable = searchable;
}
public static <T> DataTable<T> of(JpaSpecificationExecutor<T> repo, Class<T> entityClass, DataTablesRequest dt, List<String> searchable) {
return new DataTable<>(repo, entityClass, dt, searchable);
}
/** Equivalente a tu $q->where(...): establece condición base */
public DataTable<T> where(Specification<T> spec) { this.baseSpec = this.baseSpec.and(spec); return this; }
/** add("campo", fn(entity)->valor|Map) */
public DataTable<T> add(String field, Function<T, Object> fn) {
adders.add(entity -> {
Map<String,Object> m = new HashMap<>();
m.put(field, fn.apply(entity));
return m;
});
return this;
}
/** add(fn(entity)->Map<String,Object>) para devolver objetos anidados como tu "logo" */
public DataTable<T> add(Function<T, Map<String,Object>> fn) { adders.add(fn); return this; }
/** edit("campo", fn(entity)->valor) sobreescribe un campo existente o lo crea si no existe */
public DataTable<T> edit(String field, Function<T, Object> fn) {
editors.add(row -> { row.put(field, fn.apply((T)row.get("__entity"))); return row; });
return this;
}
/** filter((builder, req) -> builder.add(miExtraSpec(req))) */
public DataTable<T> filter(FilterHook<T> hook) { filters.add(hook); return this; }
public DataTablesResponse<Map<String,Object>> toJson(long totalCount) {
// Construye spec con búsqueda global + base + filtros custom
Specification<T> spec = baseSpec.and(DataTablesSpecification.build(dt, searchable));
final Specification<T>[] holder = new Specification[]{ spec };
filters.forEach(h -> h.accept(extra -> holder[0] = holder[0].and(extra), dt));
spec = holder[0];
// Sort
Sort sort = Sort.unsorted();
if (!dt.order.isEmpty() && !dt.columns.isEmpty()) {
List<Sort.Order> orders = new ArrayList<>();
for (var o : dt.order) {
String field = dt.columns.get(o.column).name;
orders.add(new Sort.Order("desc".equalsIgnoreCase(o.dir) ? Sort.Direction.DESC : Sort.Direction.ASC, field));
}
sort = Sort.by(orders);
}
// Page
int page = dt.length > 0 ? dt.start / dt.length : 0;
Pageable pageable = dt.length > 0 ? PageRequest.of(page, dt.length, sort) : Pageable.unpaged();
var p = repo.findAll(holder[0], pageable);
long filtered = p.getTotalElements();
// Mapear entidad -> Map base (via Jackson) + add/edit
List<Map<String,Object>> data = new ArrayList<>();
for (T e : p.getContent()) {
Map<String,Object> row = om.convertValue(e, Map.class);
row.put("__entity", e); // para editores que necesiten la entidad
for (var ad : adders) row.putAll(ad.apply(e));
for (var ed : editors) ed.apply(row);
row.remove("__entity");
data.add(row);
}
return new DataTablesResponse<>(dt.draw, totalCount, filtered, data);
}
}