дополнительные скрипты

This commit is contained in:
Рауф Латыпов 2025-04-21 00:18:55 +03:00
parent 92050674b1
commit 2696f438e4
4 changed files with 118 additions and 239 deletions

View file

@ -0,0 +1,81 @@
package ru.micord.ervu_dashboard.dao;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.stream.Collectors;
import database.dao.DefaultLoadDao;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.springframework.beans.factory.annotation.Autowired;
import ru.cg.webbpm.modules.database.api.utils.QueryUtils;
import ru.cg.webbpm.modules.database.bean.entity_graph.condition.Operator;
import ru.cg.webbpm.modules.database.bean.filter.EntityFilter;
import ru.cg.webbpm.modules.database.bean.filter.FilterOperation;
/**
* @author r.latypov
*/
public class CustomCoalesceDao extends DefaultLoadDao {
@Autowired
private DSLContext dsl;
@Override
public Condition getFilterCondition(EntityFilter entityFilter) {
Field<Object> field = QueryUtils.toJooqField(
entityFilter.getEntityColumn(), dsl.dialect(), false
);
return condition(entityFilter, field);
}
@Override
public Condition getFilterCondition(EntityFilter entityFilter, String tableName) {
Field<Object> field = toJooqField(entityFilter.getEntityColumn(), tableName);
return condition(entityFilter, field);
}
private Condition condition(EntityFilter entityFilter, Field<Object> field) {
FilterOperation operation = entityFilter.getFilterOperation();
Operator multiValueOperator = entityFilter.getMultiValueOperator();
Object value = entityFilter.getValue();
// todo this is KOSTIL
if (value instanceof String && field.getDataType().isDateTime()) {
if (java.sql.Date.class.isAssignableFrom(field.getType())) {
value = java.sql.Date.valueOf(
LocalDate.parse(String.valueOf(value), DateTimeFormatter.ISO_DATE_TIME));
}
else if (Timestamp.class.isAssignableFrom(field.getType())) {
value = Timestamp.valueOf(
LocalDateTime.parse(String.valueOf(value), DateTimeFormatter.ISO_DATE_TIME));
}
}
return switch (operation) {
case EQUAL -> getEqualCondition(field, value, multiValueOperator);
case NOT_EQUAL -> getNotEqualCondition(field, value, multiValueOperator);
case EQUAL_IGNORE_CASE -> getEqualIgnoreCaseCondition(field, value, multiValueOperator);
case GREATER_THAN -> getGreaterThanCondition(field, value, multiValueOperator);
case LESS_THAN -> getLessThanCondition(field, value, multiValueOperator);
case GREATER_OR_EQUAL -> getGreaterOrEqualCondition(field, value, multiValueOperator);
case LESS_OR_EQUAL -> getLessOrEqualCondition(field, value, multiValueOperator);
case CONTAINS -> getContainsCondition(field, value, multiValueOperator);
case NOT_CONTAINS -> getNotContainsCondition(field, value, multiValueOperator);
case START_WITH -> getStartsWithCondition(field, value, multiValueOperator);
case ENDS_WITH -> getEndsWithCondition(field, value, multiValueOperator);
case IS_NULL -> field.isNull();
case IS_NOT_NULL -> field.isNotNull();
case IN -> field.in(value instanceof String
? Arrays.stream(((String) value).split(","))
.collect(Collectors.toUnmodifiableSet())
: value)
.or(field.isNull());
case NOT_IN -> field.notIn(value);
};
}
}

View file

@ -6,7 +6,6 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import database.dao.DefaultLoadDao;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.Record;
@ -31,7 +30,7 @@ import ru.cg.webbpm.modules.database.bean.filter.EntityFilter;
/**
* @author r.latypov
*/
public class LessJoinsDao extends DefaultLoadDao {
public class LessJoinsDao extends CustomCoalesceDao {
@Override
public List<TableRow> load(Set<EntityColumn> columns, LoadOptions loadOptions,
boolean withGraphConditions) {

View file

@ -1,237 +0,0 @@
package ru.micord.ervu_dashboard.dao;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import database.dao.DefaultLoadDao;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.SelectConnectByStep;
import org.jooq.SelectForUpdateStep;
import org.jooq.SelectJoinStep;
import org.jooq.SelectLimitStep;
import org.jooq.SelectSelectStep;
import org.jooq.Table;
import org.jooq.impl.DSL;
import ru.cg.webbpm.modules.database.api.bean.TableRow;
import ru.cg.webbpm.modules.database.api.dao.option.LoadOptions;
import ru.cg.webbpm.modules.database.api.utils.QueryUtils;
import ru.cg.webbpm.modules.database.bean.entity_graph.DefaultGraphBinding;
import ru.cg.webbpm.modules.database.bean.entity_graph.DefaultGraphNode;
import ru.cg.webbpm.modules.database.bean.entity_graph.EntityColumn;
import ru.cg.webbpm.modules.database.bean.entity_graph.condition.ConditionGroup;
import ru.cg.webbpm.modules.database.bean.filter.EntityFilter;
/**
* @author r.latypov
*/
public class SubqueriesJoinsDao extends DefaultLoadDao {
@Override
public List<TableRow> load(Set<EntityColumn> columns, LoadOptions loadOptions,
boolean withGraphConditions) {
DefaultGraphNode mainNode = graph.getMainNode();
EntityColumn[] mainNodePkColumns = getGraphNodeTablePkFields(mainNode);
if (mainNodePkColumns == null || mainNodePkColumns.length == 0) {
throw new RuntimeException("Primary key does not exist in " + mainNode.getAlias() + " : "
+ mainNode.getSchemaName() + "." + mainNode.getTableName());
}
if (loadOptions.isLoadPK()) {
Collections.addAll(columns, mainNodePkColumns);
}
// presume only one pk column
EntityColumn mainNodePkColumn = mainNodePkColumns[0];
Set<String> fieldsEntityNames = columns.stream()
.map(EntityColumn::getEntity)
.collect(Collectors.toUnmodifiableSet());
// filters without groups
List<EntityFilter> allEntityFilters = loadOptions.getEntityFilterGroup().getEntityFilters();
Set<String> conditionsEntityNames = allEntityFilters.stream()
.map(entityFilter -> entityFilter.getEntityColumn().getEntity())
.collect(Collectors.toUnmodifiableSet());
// push entity filters into map
Map<String, List<Condition>> entitiesConditionsMap = conditionsEntityNames.stream()
.collect(Collectors.toMap(
entityName -> entityName,
entityName -> getFilterConditions(
allEntityFilters.stream()
.filter(entityFilter -> entityFilter.getEntityColumn()
.getEntity()
.equals(entityName))
.toList()
)
));
// queries for define main table ids condition
Set<?> mainTableIds = null;
Set<String> otherEntitiesNames = conditionsEntityNames.stream()
.filter(entityName -> !fieldsEntityNames.contains(entityName))
.collect(Collectors.toUnmodifiableSet());
if (!otherEntitiesNames.isEmpty()) {
mainTableIds = otherEntitiesNames.stream()
.map(entityName -> {
DefaultGraphNode graphNode = graph.getNodesByEntityNames().get(entityName);
DefaultGraphBinding binding = graph.getBindingByEndNode(graphNode);
if (binding == null) {
throw new RuntimeException("Entity " + entityName + " is not bound");
}
else {
EntityColumn refEntityColumn = null;
if (binding.getRefOnEntityName().equals(entityName)) {
refEntityColumn = binding.getRefOnColumns()[0];
}
if (binding.getRefToEntityName().equals(entityName)) {
refEntityColumn = binding.getRefToColumns()[0];
}
if (refEntityColumn == null) {
throw new RuntimeException("Binding for entity " + entityName + " is not valid");
}
else {
Field<?> selectField = QueryUtils.toJooqField(
refEntityColumn, this.getDsl().dialect(), true
);
return getDsl()
.select(selectField)
.from(getTableWithAlias(graphNode))
.where(entitiesConditionsMap.get(entityName))
.fetch(selectField);
}
}
})
// collect only intersection of all lists of ids
.collect(intersecting());
}
List<Condition> mainConditions = getFilterConditions(
allEntityFilters.stream()
.filter(entityFilter -> fieldsEntityNames.contains(
entityFilter.getEntityColumn().getTable()))
.collect(Collectors.toList())
);
Field<?> pkField = QueryUtils.toJooqField(mainNodePkColumn, this.getDsl().dialect(), true);
mainConditions.add(mainTableIds == null ? DSL.trueCondition() : pkField.in(mainTableIds));
List<Field<?>> fieldList = convertEntityColumnsToJooqFields(columns);
SelectJoinStep<Record> selectStep = selectByJooqColumns(fieldsEntityNames, fieldList);
SelectConnectByStep<Record> joinStep = buildWhereStep(selectStep, mainConditions,
withGraphConditions
);
SelectLimitStep<Record> limitStep = getOrderByStep(joinStep, loadOptions.getSortFields(), true);
SelectForUpdateStep<Record> selectForUpdateStep = getSelectForUpdateStep(limitStep,
loadOptions.getOffset(), loadOptions.getLimit()
);
return recordListToTableFieldDataList(selectForUpdateStep.fetch(), columns);
}
private SelectJoinStep<Record> selectByJooqColumns(Set<String> fieldsEntityNames,
List<Field<?>> fieldList) {
SelectSelectStep<Record> select = uniqueResult
? getDsl().selectDistinct(fieldList)
: getDsl().select(fieldList);
DefaultGraphNode mainNode = graph.getMainNode();
SelectJoinStep<Record> selectJoinStep = select.from(getTableWithAlias(mainNode));
addJoins(
fieldsEntityNames, selectJoinStep, graph.getMainNodeIndex(), -1, getMatrix()
);
return selectJoinStep;
}
private void addJoins(Set<String> fieldsEntityNames, SelectJoinStep<Record> selectJoinStep,
int currentIndex, int parentIndex, DefaultGraphBinding[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
if (matrix[currentIndex][i] == null || matrix[currentIndex][i].isCyclic()
|| (parentIndex >= 0 && i == parentIndex)) {
continue;
}
DefaultGraphNode endNode = graph.getNodeByIndex(i);
Table<?> endNodeTable = getTableWithAlias(endNode);
String tableAlias = endNode.getAlias();
if (!fieldsEntityNames.contains(tableAlias)) {
continue;
}
DefaultGraphBinding binding = matrix[currentIndex][i];
if (binding.getRefToColumns() != null && binding.getRefOnColumns() != null) {
EntityColumn refOnColumnsEntityColumn = binding.getRefOnColumns()[0];
refOnColumnsEntityColumn.setEntity(binding.getRefOnEntityName());
EntityColumn refToColumnsEntityColumn = binding.getRefToColumns()[0];
refToColumnsEntityColumn.setEntity(binding.getRefToEntityName());
Field startNodeCol = QueryUtils.toJooqField(refOnColumnsEntityColumn);
Field endNodeCol = QueryUtils.toJooqField(refToColumnsEntityColumn);
@SuppressWarnings("unchecked")
Condition bindingCondition = startNodeCol.equal(endNodeCol);
for (int j = 1; j < binding.getRefOnColumns().length; j++) {
startNodeCol = QueryUtils.toJooqField(binding.getRefOnColumns()[j]);
endNodeCol = QueryUtils.toJooqField(binding.getRefToColumns()[j]);
@SuppressWarnings("unchecked")
Condition condition = startNodeCol.equal(endNodeCol);
bindingCondition = bindingCondition.and(condition);
}
ConditionGroup conditionGroup = binding.getConditionGroup();
if (conditionGroup != null) {
Condition condition = conditionBuilder.build(conditionGroup);
if (condition != null) {
bindingCondition = bindingCondition.and(condition);
}
}
if (binding.isRequired()) {
selectJoinStep.join(endNodeTable).on(bindingCondition);
}
else {
selectJoinStep.leftOuterJoin(endNodeTable).on(bindingCondition);
}
}
addJoins(fieldsEntityNames, selectJoinStep, i, currentIndex, matrix);
}
}
private static <T, S extends Collection<T>> Collector<S, ?, Set<T>> intersecting() {
class Accumulator {
Set<T> result;
void accumulate(S collection) {
if (result == null) {
result = new HashSet<>(collection);
}
else {
result.retainAll(collection);
}
}
Accumulator combine(Accumulator other) {
if (result == null) {
return other;
}
if (other.result != null) {
result.retainAll(other.result);
}
return this;
}
}
return Collector.of(Accumulator::new, Accumulator::accumulate, Accumulator::combine,
acc -> acc.result == null ? Collections.emptySet() : acc.result,
Collector.Characteristics.UNORDERED
);
}
}

View file

@ -0,0 +1,36 @@
import {AdvancedProperty, AnalyticalScope, Behavior, Visible} from "@webbpm/base-package";
import {DropdownTreeViewComponent} from "../../../component/field/DropdownTreeViewComponent";
import {TreeItemDto} from "../../../generated/component/model/TreeItemDto";
@AnalyticalScope(DropdownTreeViewComponent)
export class DropdownTreeViewModelFilterValue extends Behavior {
public isBusinessId: boolean;
@AdvancedProperty()
public separator: string;
@Visible()
public getIds(): string {
const treeViewComponent = this.getScript(
DropdownTreeViewComponent) as DropdownTreeViewComponent;
let model: TreeItemDto = treeViewComponent.value;
const dtos: TreeItemDto[] = [];
if (!model && treeViewComponent.cachedValue) {
model = treeViewComponent.cachedValue;
}
if (model) {
dtos.push(model);
this.fillArray(dtos, model);
}
const ids: string[] = dtos.map(value => this.isBusinessId ? value.businessId : value.id);
return this.separator ? ids.join(this.separator) : ids.join();
}
private fillArray(dtos: TreeItemDto[], dto: TreeItemDto): void {
if (dto.children) {
dtos.push(...dto.children);
dto.children.forEach(value => this.fillArray(dtos, value));
}
}
}