vertx-gaia/vertx-up/src/main/java/io/vertx/up/unity/Query.java
package io.vertx.up.unity;
import io.horizon.atom.common.Kv;
import io.horizon.eon.VString;
import io.horizon.uca.log.Annal;
import io.horizon.uca.qr.syntax.Ir;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.up.eon.KWeb;
import io.vertx.up.util.Ut;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/*
* 查询条件专用算法,用来合并两个维度的条件
* 1. irV: 合并 projection
* 2. irH: 合并 criteria
*/
final class Query {
private static final Annal LOGGER = Annal.get(Query.class);
/*
* Move `RibIr` code to current method, complex algorithm to combine qr parts directly
* 1. irV / irH: 3 arguments -> Qr Full
* 2. irV / irH: 2 arguments -> Qr Node ( criteria, projection )
*/
// ------------------- H ----------------------
static JsonObject irQH(final JsonObject query, final String field, final Object value) {
Objects.requireNonNull(query);
final JsonObject original = Ut.valueJObject(query, Ir.KEY_CRITERIA);
query.put(Ir.KEY_CRITERIA, irH(original, field, value));
return query;
}
static JsonObject irH(final JsonObject original, final String field, final Object value) {
final JsonObject originalJ = Ut.valueJObject(original);
// 如果 value 本身是 JsonObject
if (value instanceof JsonObject) {
// 左右合并
final Kv<String, String> kv = Kv.create(KWeb.ARGS.TREE_L, field);
return ir(originalJ, (JsonObject) value, Ir.Connector.AND, kv);
} else {
// 直接合并(加 And)
if (!originalJ.containsKey(VString.EMPTY)) {
originalJ.put(VString.EMPTY, Boolean.TRUE);
}
originalJ.put(field, value);
return originalJ;
}
}
static JsonObject irH(final JsonObject original, final JsonObject criteria) {
// 此处必须使用副本
final JsonObject originalJ = Ut.valueJObject(original, true);
final JsonObject criteriaJ = Ut.valueJObject(criteria);
// Combine Result
final JsonObject result = new JsonObject();
if (irNil(original) && irNil(criteria)) {
// 左右都不包含条件
return result;
}
if (irNil(originalJ)) {
// 直接取新条件
return result.mergeIn(criteriaJ, true);
}
if (irNil(criteriaJ)) {
// 直接取旧条件
return result.mergeIn(originalJ, true);
}
// 新旧都不为空
final Kv<String, String> kv = Kv.create(KWeb.ARGS.TREE_L, KWeb.ARGS.TREE_R);
return irAnd(originalJ, criteriaJ, kv);
}
static JsonObject irQH(final JsonObject query, final JsonObject criteria, final boolean clear) {
Objects.requireNonNull(query);
if (clear) {
/* Overwrite Mode */
query.put(Ir.KEY_CRITERIA, criteria);
} else {
/* Combine Mode */
final JsonObject originalJ = Ut.valueJObject(query, Ir.KEY_CRITERIA);
query.put(Ir.KEY_CRITERIA, irH(originalJ, criteria));
}
LOGGER.info("[Qr] Criteria: \n{0}", query.encodePrettily());
return query;
}
private static JsonObject irAnd(final JsonObject originalJ, final JsonObject criteriaJ,
final Kv<String, String> nodes) {
return ir(originalJ, criteriaJ, Ir.Connector.AND, nodes);
}
private static JsonObject irOr(final JsonObject originalJ, final JsonObject criteriaJ,
final Kv<String, String> nodes) {
return ir(originalJ, criteriaJ, Ir.Connector.OR, nodes);
}
private static JsonObject ir(final JsonObject originalJ, final JsonObject criteriaJ,
final Ir.Connector connectorL, final Kv<String, String> kv) {
// 在 originalJ 中追加条件:AND
originalJ.put(VString.EMPTY, Ir.Connector.AND == connectorL);
if (irOne(criteriaJ)) {
// 单条件,直接将条件追加(此时不论符号)
criteriaJ.fieldNames()
.forEach(field -> originalJ.put(field, criteriaJ.getValue(field)));
return originalJ;
} else {
// 多条件,需检查对端符号
final Boolean isAnd = criteriaJ.getBoolean(VString.EMPTY, Boolean.FALSE);
final Ir.Connector connectorR = isAnd ? Ir.Connector.AND : Ir.Connector.OR;
if (connectorL == connectorR) {
// 两边符号相同,Linear合并
// L AND R ( r1 = v1, r2 = v2 )
criteriaJ.fieldNames()
.forEach(field -> originalJ.put(field, criteriaJ.getValue(field)));
return originalJ;
} else {
// 符号不同,Tree合并
// L AND R
final JsonObject result = new JsonObject();
result.put(VString.EMPTY, Boolean.TRUE);
result.put(kv.key(), originalJ);
result.put(kv.value(), criteriaJ);
return result;
}
}
}
// ------------------- V ----------------------
static JsonObject irQV(final JsonObject query, final JsonArray projection, final boolean clear) {
Objects.requireNonNull(query);
if (clear) {
/* Overwrite Mode */
query.put(Ir.KEY_PROJECTION, projection.copy());
} else {
/* Combine */
final JsonArray original = Ut.valueJArray(query, Ir.KEY_PROJECTION);
query.put(Ir.KEY_PROJECTION, irV(original, projection));
}
LOGGER.info("[Qr] Projection: \n{0}", query.encodePrettily());
return query;
}
/*
* Combine ( original, updated )
*/
static JsonArray irV(final JsonArray original, final JsonArray projection) {
final JsonArray originalA = Ut.valueJArray(original);
final JsonArray projectionA = Ut.valueJArray(projection);
// Original Set Conversation
final Set<String> originalSet = originalA.stream()
.filter(item -> item instanceof String)
.map(item -> (String) item)
.collect(Collectors.toSet());
// Add New from
projectionA.stream()
.filter(item -> item instanceof String)
.map(item -> (String) item)
.forEach(originalSet::add);
// Returned to Combined
return Ut.toJArray(originalSet);
}
static boolean irOne(final JsonObject condition) {
final JsonObject normalized = condition.copy();
normalized.remove(VString.EMPTY);
return 1 == normalized.fieldNames().size();
}
static boolean irNil(final JsonObject condition) {
if (Ut.isNil(condition)) {
return true;
} else {
final JsonObject normalized = condition.copy();
normalized.remove(VString.EMPTY);
return Ut.isNil(normalized);
}
}
static boolean irAnd(final JsonObject condition) {
if (!condition.containsKey(VString.EMPTY)) {
// Default: OR
return false;
}
// true for AND
// false for OR
return condition.getBoolean(VString.EMPTY, Boolean.FALSE);
}
}