|
@@ -0,0 +1,180 @@
|
|
|
|
+import { get, head, last, isArray } from 'lodash';
|
|
|
|
+import { Opera } from './dbOpera';
|
|
|
|
+
|
|
|
|
+ *
|
|
|
|
+ * @param builder model的createQueryBuilder,只有到最后要查数据的时候才是异步的
|
|
|
|
+ * @param {object} query 查询条件
|
|
|
|
+ * @param {object} operas 指定查询方式
|
|
|
|
+ * @param {any} model 存在的情况,default会调用columnIsString 判断是否是字符串字段的函数或其他任何形式的参数
|
|
|
|
+ */
|
|
|
|
+export const completeBuilderCondition = (builder, query = {}, operas = {}, model?) => {
|
|
|
|
+
|
|
|
|
+ if (!query) return;
|
|
|
|
+ const searchColumns = Object.keys(query);
|
|
|
|
+ if (searchColumns.length <= 0) return;
|
|
|
|
+ for (let i = 0; i < searchColumns.length; i++) {
|
|
|
|
+ const key = searchColumns[i];
|
|
|
|
+ const value = query[key];
|
|
|
|
+ if (!value) continue;
|
|
|
|
+
|
|
|
|
+ const opera = get(operas, key);
|
|
|
|
+
|
|
|
|
+ let method = 'where';
|
|
|
|
+ if (i === 0) method = 'where';
|
|
|
|
+ else method = 'andWhere';
|
|
|
|
+ let str;
|
|
|
|
+ let params;
|
|
|
|
+
|
|
|
|
+ const valueStr = `value${i}`;
|
|
|
|
+ let valueArr = [];
|
|
|
|
+ const strArr = [];
|
|
|
|
+ switch (opera) {
|
|
|
|
+ case Opera.Between:
|
|
|
|
+ str = `"${key}" Between :${valueStr}_1 AND :${valueStr}_2`;
|
|
|
|
+ params = { [`${valueStr}_1`]: head(value), [`${valueStr}_2`]: last(value) };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.Not:
|
|
|
|
+ str = `"${key}" != :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.Like:
|
|
|
|
+ str = `"${key}" Like :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: `%${value}%` };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.LikeLeft:
|
|
|
|
+ str = `"${key}" Like :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: `%${value}` };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.LikeRight:
|
|
|
|
+ str = `"${key}" Like :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: `${value}%` };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.ILike:
|
|
|
|
+ str = `"${key}" Not Like :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: `%${value}%` };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.ILikeLeft:
|
|
|
|
+ str = `"${key}" Not Like :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: `%${value}` };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.ILikeRight:
|
|
|
|
+ str = `"${key}" Not Like :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: `${value}%` };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.LessThan:
|
|
|
|
+ str = `"${key}" < :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.LessThanOrEqual:
|
|
|
|
+ str = `"${key}" <= :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.MoreThan:
|
|
|
|
+ str = `"${key}" > :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.MoreThanOrEqual:
|
|
|
|
+ str = `"${key}" >= :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.In:
|
|
|
|
+ if (!isArray(value)) str = `"${key}" IN (:${valueStr})`;
|
|
|
|
+ else str = `"${key}" IN (:...${valueStr})`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.IsNull:
|
|
|
|
+ str = `"${key}" IS NULL`;
|
|
|
|
+ break;
|
|
|
|
+ case Opera.IsNotNull:
|
|
|
|
+ str = `"${key}" IS NOT NULL`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.Json:
|
|
|
|
+ params = {};
|
|
|
|
+ if (isArray(value)) valueArr = value;
|
|
|
|
+ else valueArr = [value];
|
|
|
|
+ for (let vi = 0; vi < valueArr.length; vi++) {
|
|
|
|
+ const v = valueArr[vi];
|
|
|
|
+ const mvalKey = `${valueStr}${vi}`;
|
|
|
|
+ const mstr = `JSONB_EXISTS("${key}", :${mvalKey})`;
|
|
|
|
+ strArr.push(mstr);
|
|
|
|
+ params[mvalKey] = v;
|
|
|
|
+ }
|
|
|
|
+ str = `(${strArr.join(' OR ')})`;
|
|
|
|
+ break;
|
|
|
|
+ case Opera.JsonObject:
|
|
|
|
+ const jokeys = key.split('.');
|
|
|
|
+ const jorootCol = head(jokeys);
|
|
|
|
+ const jolastKey = last(jokeys);
|
|
|
|
+ const jopath = jokeys.filter(f => f !== jorootCol && f !== jolastKey);
|
|
|
|
+ str = `"${jorootCol}" `;
|
|
|
|
+ for (const jok of jopath) {
|
|
|
|
+ str = `${str} -> ${jok}`;
|
|
|
|
+ }
|
|
|
|
+ str = `${str} ->> '${jolastKey}' = :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ case Opera.JsonArrayObject:
|
|
|
|
+
|
|
|
|
+ * 1.分割key,过来的属性默认以 x.y.z... 形式
|
|
|
|
+ * x:根子段;后面,数组中依次往下的属性名
|
|
|
|
+ */
|
|
|
|
+ const keys = key.split('.');
|
|
|
|
+ let numberValue;
|
|
|
|
+ if (isFinite(parseInt(value))) numberValue = parseInt(value);
|
|
|
|
+ let rootCol = head(keys);
|
|
|
|
+ let lastKey = last(keys);
|
|
|
|
+ let path = keys.filter(f => f !== rootCol && f !== lastKey);
|
|
|
|
+ const getObject = (path, lastKey, value) => {
|
|
|
|
+ let obj = {};
|
|
|
|
+ let mid = obj;
|
|
|
|
+ for (const k of path) {
|
|
|
|
+ mid[k] = {};
|
|
|
|
+ mid = mid[k];
|
|
|
|
+ }
|
|
|
|
+ mid[lastKey] = value;
|
|
|
|
+ return obj;
|
|
|
|
+ };
|
|
|
|
+ const obj = getObject(path, lastKey, value);
|
|
|
|
+ let newVal = JSON.stringify([obj]);
|
|
|
|
+ str = `"${rootCol}" @> :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: newVal };
|
|
|
|
+ if (numberValue) {
|
|
|
|
+ const numObj = getObject(path, lastKey, numberValue);
|
|
|
|
+ let numVal = JSON.stringify([numObj]);
|
|
|
|
+ const valueStrNum = `${valueStr}Num`;
|
|
|
|
+ str = `(${str} OR "${rootCol}" @> :${valueStrNum})`;
|
|
|
|
+ params[valueStrNum] = numVal;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case Opera.Equal:
|
|
|
|
+ str = `"${key}" = :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ let isString = false;
|
|
|
|
+ if (model) isString = columnIsString(key, model);
|
|
|
|
+ if (isString) {
|
|
|
|
+
|
|
|
|
+ str = `"${key}" Like :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: `%${value}%` };
|
|
|
|
+ } else {
|
|
|
|
+ str = `"${key}" = :${valueStr}`;
|
|
|
|
+ params = { [`${valueStr}`]: value };
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (!str) continue;
|
|
|
|
+ builder[method](str, params);
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const columnIsString = (columnName: string, model?) => {
|
|
|
|
+ if (!model) return false;
|
|
|
|
+ const columns = model.metadata.columns;
|
|
|
|
+ const colSetting = columns.find(f => get(f, 'propertyName') === columnName);
|
|
|
|
+ if (!colSetting) return false;
|
|
|
|
+ const type = get(colSetting, 'type');
|
|
|
|
+ if (!type) return false;
|
|
|
|
+ return type === 'character varying' || type === 'text';
|
|
|
|
+};
|