feat: 在查询元数据键中添加 _where 支持,并实现自定义过滤器功能
This commit is contained in:
parent
756213f9af
commit
121a46ce33
@ -479,7 +479,6 @@ function mapOutpatientVisit(row, options = {}) {
|
|||||||
const registerType = pick(row, ["ST_REG_TYPE_NAME", "ST_REG_CATEGORY_NAME"]);
|
const registerType = pick(row, ["ST_REG_TYPE_NAME", "ST_REG_CATEGORY_NAME"]);
|
||||||
const visitType = pick(row, ["VISIT_TYPE", "ST_VISIT_TYPE"]);
|
const visitType = pick(row, ["VISIT_TYPE", "ST_VISIT_TYPE"]);
|
||||||
const chargeType = pick(row, ["ST_CHARGE_TYPE", "SC_CHARGE_TYPE"]);
|
const chargeType = pick(row, ["ST_CHARGE_TYPE", "SC_CHARGE_TYPE"]);
|
||||||
const serviceItems = joinPicked(row, ["ST_REG_TYPE_NAME", "ST_REG_CATEGORY_NAME", "ST_VISIT_TYPE", "VISIT_TYPE", "ST_CHARGE_TYPE"]);
|
|
||||||
const amount = pick(row, [
|
const amount = pick(row, [
|
||||||
"TREATMENT_COST",
|
"TREATMENT_COST",
|
||||||
"REGISTER_TOTAL_COST",
|
"REGISTER_TOTAL_COST",
|
||||||
@ -522,8 +521,6 @@ function mapOutpatientVisit(row, options = {}) {
|
|||||||
visitType,
|
visitType,
|
||||||
chargeType,
|
chargeType,
|
||||||
insuranceType: pick(row, ["INSURANCE_TYPE"]),
|
insuranceType: pick(row, ["INSURANCE_TYPE"]),
|
||||||
serviceItems,
|
|
||||||
serviceItem: serviceItems,
|
|
||||||
amount,
|
amount,
|
||||||
treatmentCost: pick(row, ["TREATMENT_COST"]),
|
treatmentCost: pick(row, ["TREATMENT_COST"]),
|
||||||
registerCost: pick(row, ["REGISTER_COST"]),
|
registerCost: pick(row, ["REGISTER_COST"]),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const sql = require("mssql");
|
|||||||
const { getConfig, parsePositiveInteger } = require("../../core/config");
|
const { getConfig, parsePositiveInteger } = require("../../core/config");
|
||||||
|
|
||||||
const pools = new Map();
|
const pools = new Map();
|
||||||
const QUERY_META_KEYS = new Set(["page", "pageSize", "saveSnapshot"]);
|
const QUERY_META_KEYS = new Set(["page", "pageSize", "saveSnapshot", "_where"]);
|
||||||
const RANGE_FILTERS = {
|
const RANGE_FILTERS = {
|
||||||
startCreateTime: { field: "create_time", op: ">=" },
|
startCreateTime: { field: "create_time", op: ">=" },
|
||||||
endCreateTime: { field: "create_time", op: "<=" },
|
endCreateTime: { field: "create_time", op: "<=" },
|
||||||
@ -97,6 +97,7 @@ function buildWhereClause({ query, fields, fieldMapping, resourceConfig }) {
|
|||||||
const standardFields = new Set(fields);
|
const standardFields = new Set(fields);
|
||||||
const inputs = [];
|
const inputs = [];
|
||||||
const clauses = [];
|
const clauses = [];
|
||||||
|
addCustomFilters({ clauses, inputs, where: query && query._where, standardFields, fieldMapping });
|
||||||
|
|
||||||
for (const [key, rawValue] of Object.entries(query || {})) {
|
for (const [key, rawValue] of Object.entries(query || {})) {
|
||||||
if (QUERY_META_KEYS.has(key) || isEmpty(rawValue)) continue;
|
if (QUERY_META_KEYS.has(key) || isEmpty(rawValue)) continue;
|
||||||
@ -123,6 +124,14 @@ function buildWhereClause({ query, fields, fieldMapping, resourceConfig }) {
|
|||||||
function addFilter({ clauses, inputs, standardField, value, fieldMapping, op }) {
|
function addFilter({ clauses, inputs, standardField, value, fieldMapping, op }) {
|
||||||
const sourceField = assertIdentifier(fieldMapping[standardField] || standardField, `filter.${standardField}`);
|
const sourceField = assertIdentifier(fieldMapping[standardField] || standardField, `filter.${standardField}`);
|
||||||
const paramName = `p${inputs.length}`;
|
const paramName = `p${inputs.length}`;
|
||||||
|
if (op === "notEmpty") {
|
||||||
|
clauses.push(`(${quoteName(sourceField)} IS NOT NULL AND LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), ${quoteName(sourceField)}))) <> '')`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (op === "isEmpty") {
|
||||||
|
clauses.push(`(${quoteName(sourceField)} IS NULL OR LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), ${quoteName(sourceField)}))) = '')`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (op === "like") {
|
if (op === "like") {
|
||||||
clauses.push(`${quoteName(sourceField)} LIKE @${paramName}`);
|
clauses.push(`${quoteName(sourceField)} LIKE @${paramName}`);
|
||||||
inputs.push({ name: paramName, value: `%${String(value).trim()}%` });
|
inputs.push({ name: paramName, value: `%${String(value).trim()}%` });
|
||||||
@ -132,6 +141,28 @@ function addFilter({ clauses, inputs, standardField, value, fieldMapping, op })
|
|||||||
inputs.push({ name: paramName, value });
|
inputs.push({ name: paramName, value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addCustomFilters({ clauses, inputs, where, standardFields, fieldMapping }) {
|
||||||
|
if (!Array.isArray(where)) return;
|
||||||
|
for (const item of where) {
|
||||||
|
const standardField = item && String(item.field || item.column || "").trim();
|
||||||
|
if (!standardField || !standardFields.has(standardField)) continue;
|
||||||
|
const op = normalizeCustomOperator(item.op || item.operator || item.type);
|
||||||
|
if (!op) continue;
|
||||||
|
if (op !== "notEmpty" && op !== "isEmpty" && isEmpty(item.value)) continue;
|
||||||
|
addFilter({ clauses, inputs, standardField, value: item.value, fieldMapping, op });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCustomOperator(op) {
|
||||||
|
const text = String(op || "eq").trim().toLowerCase();
|
||||||
|
if (["notempty", "not_empty", "isnotempty", "is_not_empty"].includes(text)) return "notEmpty";
|
||||||
|
if (["isempty", "is_empty", "empty"].includes(text)) return "isEmpty";
|
||||||
|
if (["like", "contains"].includes(text)) return "like";
|
||||||
|
if (["ne", "neq", "!=", "<>"].includes(text)) return "<>";
|
||||||
|
if (["eq", "="].includes(text)) return "=";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
function getFilterOperator(resourceConfig, standardField) {
|
function getFilterOperator(resourceConfig, standardField) {
|
||||||
const configured = resourceConfig.filterOperators && resourceConfig.filterOperators[standardField];
|
const configured = resourceConfig.filterOperators && resourceConfig.filterOperators[standardField];
|
||||||
if (!configured) return "=";
|
if (!configured) return "=";
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const { spawn } = require("child_process");
|
|||||||
const iconv = require("iconv-lite");
|
const iconv = require("iconv-lite");
|
||||||
const { getConfig, parsePositiveInteger } = require("../../core/config");
|
const { getConfig, parsePositiveInteger } = require("../../core/config");
|
||||||
|
|
||||||
const QUERY_META_KEYS = new Set(["page", "pageSize", "saveSnapshot"]);
|
const QUERY_META_KEYS = new Set(["page", "pageSize", "saveSnapshot", "_where"]);
|
||||||
const RANGE_FILTERS = {
|
const RANGE_FILTERS = {
|
||||||
startCreateTime: { field: "create_time", op: ">=" },
|
startCreateTime: { field: "create_time", op: ">=" },
|
||||||
endCreateTime: { field: "create_time", op: "<=" },
|
endCreateTime: { field: "create_time", op: "<=" },
|
||||||
@ -182,6 +182,7 @@ function parseSqlplusOutput(output, fields) {
|
|||||||
function buildWhereClause({ query, fields, fieldMapping, resourceConfig }) {
|
function buildWhereClause({ query, fields, fieldMapping, resourceConfig }) {
|
||||||
const standardFields = new Set(fields);
|
const standardFields = new Set(fields);
|
||||||
const clauses = [];
|
const clauses = [];
|
||||||
|
addCustomFilters({ clauses, where: query && query._where, standardFields, fieldMapping });
|
||||||
for (const [key, rawValue] of Object.entries(query || {})) {
|
for (const [key, rawValue] of Object.entries(query || {})) {
|
||||||
if (QUERY_META_KEYS.has(key) || isEmpty(rawValue)) continue;
|
if (QUERY_META_KEYS.has(key) || isEmpty(rawValue)) continue;
|
||||||
|
|
||||||
@ -202,10 +203,34 @@ function buildWhereClause({ query, fields, fieldMapping, resourceConfig }) {
|
|||||||
|
|
||||||
function buildFilterSql({ standardField, value, fieldMapping, op }) {
|
function buildFilterSql({ standardField, value, fieldMapping, op }) {
|
||||||
const sourceField = assertIdentifier(fieldMapping[standardField] || standardField, `filter.${standardField}`);
|
const sourceField = assertIdentifier(fieldMapping[standardField] || standardField, `filter.${standardField}`);
|
||||||
|
if (op === "notEmpty") return `${cleanSqlValue(identifier(sourceField))} <> ''`;
|
||||||
|
if (op === "isEmpty") return `${cleanSqlValue(identifier(sourceField))} = ''`;
|
||||||
if (op === "like") return `${cleanSqlValue(identifier(sourceField))} LIKE ${literal(`%${String(value).trim()}%`)}`;
|
if (op === "like") return `${cleanSqlValue(identifier(sourceField))} LIKE ${literal(`%${String(value).trim()}%`)}`;
|
||||||
return `${cleanSqlValue(identifier(sourceField))} ${op || "="} ${literal(value)}`;
|
return `${cleanSqlValue(identifier(sourceField))} ${op || "="} ${literal(value)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addCustomFilters({ clauses, where, standardFields, fieldMapping }) {
|
||||||
|
if (!Array.isArray(where)) return;
|
||||||
|
for (const item of where) {
|
||||||
|
const standardField = item && String(item.field || item.column || "").trim();
|
||||||
|
if (!standardField || !standardFields.has(standardField)) continue;
|
||||||
|
const op = normalizeCustomOperator(item.op || item.operator || item.type);
|
||||||
|
if (!op) continue;
|
||||||
|
if (op !== "notEmpty" && op !== "isEmpty" && isEmpty(item.value)) continue;
|
||||||
|
clauses.push(buildFilterSql({ standardField, value: item.value, fieldMapping, op }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCustomOperator(op) {
|
||||||
|
const text = String(op || "eq").trim().toLowerCase();
|
||||||
|
if (["notempty", "not_empty", "isnotempty", "is_not_empty"].includes(text)) return "notEmpty";
|
||||||
|
if (["isempty", "is_empty", "empty"].includes(text)) return "isEmpty";
|
||||||
|
if (["like", "contains"].includes(text)) return "like";
|
||||||
|
if (["ne", "neq", "!=", "<>"].includes(text)) return "<>";
|
||||||
|
if (["eq", "="].includes(text)) return "=";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
function getFilterOperator(resourceConfig, standardField) {
|
function getFilterOperator(resourceConfig, standardField) {
|
||||||
const configured = resourceConfig.filterOperators && resourceConfig.filterOperators[standardField];
|
const configured = resourceConfig.filterOperators && resourceConfig.filterOperators[standardField];
|
||||||
if (!configured) return "=";
|
if (!configured) return "=";
|
||||||
|
|||||||
@ -4,7 +4,7 @@ const { getConfig, parsePositiveInteger } = require("../../core/config");
|
|||||||
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
|
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
|
||||||
|
|
||||||
const pools = new Map();
|
const pools = new Map();
|
||||||
const QUERY_META_KEYS = new Set(["page", "pageSize", "saveSnapshot"]);
|
const QUERY_META_KEYS = new Set(["page", "pageSize", "saveSnapshot", "_where"]);
|
||||||
const RANGE_FILTERS = {
|
const RANGE_FILTERS = {
|
||||||
startCreateTime: { field: "create_time", op: ">=" },
|
startCreateTime: { field: "create_time", op: ">=" },
|
||||||
endCreateTime: { field: "create_time", op: "<=" },
|
endCreateTime: { field: "create_time", op: "<=" },
|
||||||
@ -96,6 +96,7 @@ function buildWhereClause({ query, fields, fieldMapping, resourceConfig }) {
|
|||||||
const standardFields = new Set(fields);
|
const standardFields = new Set(fields);
|
||||||
const binds = {};
|
const binds = {};
|
||||||
const clauses = [];
|
const clauses = [];
|
||||||
|
addCustomFilters({ clauses, binds, where: query && query._where, standardFields, fieldMapping });
|
||||||
|
|
||||||
for (const [key, rawValue] of Object.entries(query || {})) {
|
for (const [key, rawValue] of Object.entries(query || {})) {
|
||||||
if (QUERY_META_KEYS.has(key) || isEmpty(rawValue)) continue;
|
if (QUERY_META_KEYS.has(key) || isEmpty(rawValue)) continue;
|
||||||
@ -122,6 +123,14 @@ function buildWhereClause({ query, fields, fieldMapping, resourceConfig }) {
|
|||||||
function addFilter({ clauses, binds, standardField, value, fieldMapping, op }) {
|
function addFilter({ clauses, binds, standardField, value, fieldMapping, op }) {
|
||||||
const sourceField = assertIdentifier(fieldMapping[standardField] || standardField, `filter.${standardField}`);
|
const sourceField = assertIdentifier(fieldMapping[standardField] || standardField, `filter.${standardField}`);
|
||||||
const paramName = `p${Object.keys(binds).length}`;
|
const paramName = `p${Object.keys(binds).length}`;
|
||||||
|
if (op === "notEmpty") {
|
||||||
|
clauses.push(`((${identifier(sourceField)} IS NOT NULL) AND TRIM(TO_CHAR(${identifier(sourceField)})) <> '')`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (op === "isEmpty") {
|
||||||
|
clauses.push(`((${identifier(sourceField)} IS NULL) OR TRIM(TO_CHAR(${identifier(sourceField)})) = '')`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (op === "like") {
|
if (op === "like") {
|
||||||
clauses.push(`${identifier(sourceField)} LIKE :${paramName}`);
|
clauses.push(`${identifier(sourceField)} LIKE :${paramName}`);
|
||||||
binds[paramName] = `%${String(value).trim()}%`;
|
binds[paramName] = `%${String(value).trim()}%`;
|
||||||
@ -131,6 +140,28 @@ function addFilter({ clauses, binds, standardField, value, fieldMapping, op }) {
|
|||||||
binds[paramName] = value;
|
binds[paramName] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addCustomFilters({ clauses, binds, where, standardFields, fieldMapping }) {
|
||||||
|
if (!Array.isArray(where)) return;
|
||||||
|
for (const item of where) {
|
||||||
|
const standardField = item && String(item.field || item.column || "").trim();
|
||||||
|
if (!standardField || !standardFields.has(standardField)) continue;
|
||||||
|
const op = normalizeCustomOperator(item.op || item.operator || item.type);
|
||||||
|
if (!op) continue;
|
||||||
|
if (op !== "notEmpty" && op !== "isEmpty" && isEmpty(item.value)) continue;
|
||||||
|
addFilter({ clauses, binds, standardField, value: item.value, fieldMapping, op });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCustomOperator(op) {
|
||||||
|
const text = String(op || "eq").trim().toLowerCase();
|
||||||
|
if (["notempty", "not_empty", "isnotempty", "is_not_empty"].includes(text)) return "notEmpty";
|
||||||
|
if (["isempty", "is_empty", "empty"].includes(text)) return "isEmpty";
|
||||||
|
if (["like", "contains"].includes(text)) return "like";
|
||||||
|
if (["ne", "neq", "!=", "<>"].includes(text)) return "<>";
|
||||||
|
if (["eq", "="].includes(text)) return "=";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
function getFilterOperator(resourceConfig, standardField) {
|
function getFilterOperator(resourceConfig, standardField) {
|
||||||
const configured = resourceConfig.filterOperators && resourceConfig.filterOperators[standardField];
|
const configured = resourceConfig.filterOperators && resourceConfig.filterOperators[standardField];
|
||||||
if (!configured) return "=";
|
if (!configured) return "=";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user