@react-awesome-query-builder/sql
Version:
User-friendly query builder for React. SQL support
122 lines (110 loc) • 4.03 kB
text/typescript
/* eslint-disable @typescript-eslint/no-redundant-type-constituents, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
import type { Conv, Meta, OutLogic } from "./types";
import {
Config, SqlImportFunc, Utils, ConfigContext, DateTimeWidget,
BaseWidget, MomentInput, SqlDialect, Widget
} from "@react-awesome-query-builder/core";
import { ValueExpr } from "node-sql-parser";
const logger = Utils.OtherUtils.logger;
export const manuallyImportedOps: string[] = [
];
export const unsupportedOps: string[] = [
"some", "all", "none",
];
// sql type => raqb type
export const SqlPrimitiveTypes: Record<string, string> = {
single_quote_string: "text",
double_quote_string: "text",
backticks_quote_string: "text",
var_string: "text",
natural_string: "text",
hex_string: "text",
full_hex_string: "text",
bit_string: "text",
string: "text",
regex_string: "text", // ?
number: "number",
null: "null",
bool: "boolean",
boolean: "boolean",
};
export const buildConv = (config: Config, meta: Meta): Conv => {
const operators: Record<string, string[]> = {};
const opFuncs: Record<string, SqlImportFunc[]> = {};
const valueFuncs: Record<string, SqlImportFunc[]> = {
datetime: [sqlImportDate],
date: [sqlImportDate],
time: [sqlImportDate],
};
for (const opKey in config.operators) {
const opConfig = config.operators[opKey];
// const isGroupOp = config.settings.groupOperators?.includes(opKey);
const sqlOps = opConfig.sqlOps ? opConfig.sqlOps : opConfig.sqlOp ? [opConfig.sqlOp] : undefined;
if (opConfig.sqlImport) {
if (!opFuncs[opKey])
opFuncs[opKey] = [] as SqlImportFunc[];
opFuncs[opKey].push(opConfig.sqlImport as SqlImportFunc);
}
if (sqlOps) {
// examples of 2+: "==", "eq", ".contains", "matches" (can be used for starts_with, ends_with)
sqlOps?.forEach(sqlOp => {
if (!operators[sqlOp])
operators[sqlOp] = [];
operators[sqlOp].push(opKey);
});
} else {
const revOpConfig = config.operators?.[opConfig.reversedOp!];
const canUseRev = revOpConfig?.sqlOp || revOpConfig?.sqlOps || revOpConfig?.sqlImport;
const canIgnore = canUseRev || opConfig.sqlImport
|| manuallyImportedOps.includes(opKey) || manuallyImportedOps.includes(opConfig.reversedOp!)
|| unsupportedOps.includes(opKey);
if (!canIgnore) {
logger.warn(`[sql] No sqlOp/sqlImport for operator ${opKey}`);
}
}
}
const conjunctions: Record<string, string> = {};
for (const conjKey in config.conjunctions) {
const conjunctionDefinition = config.conjunctions[conjKey];
const ck = conjunctionDefinition.sqlConj || conjKey.toLowerCase();
conjunctions[ck] = conjKey;
}
for (const w in config.widgets) {
const widgetDef = config.widgets[w] as BaseWidget;
const {sqlImport} = widgetDef;
if (sqlImport) {
if (!valueFuncs[w])
valueFuncs[w] = [] as SqlImportFunc[];
valueFuncs[w].push(sqlImport);
}
}
return {
operators,
conjunctions,
opFuncs,
valueFuncs,
};
};
const sqlImportDate: SqlImportFunc = function (this: ConfigContext, sqlObj: OutLogic, wgtDef?: Widget, sqlDialect?: SqlDialect) {
if (sqlObj?.children && [
"TO_DATE", "TO_TIMESTAMP", "TO_TIMESTAMP_TZ", "TO_UTC_TIMESTAMP_TZ"
].includes(sqlObj.func!) && sqlObj.children.length >= 1) {
const [valArg, _patternArg] = sqlObj!.children!;
if (valArg?.valueType?.endsWith("_quote_string")) {
const dateWidgetDef = wgtDef as DateTimeWidget;
// tip: moment doesn't support SQL date format, so ignore patternArg
const dateVal = this.utils.moment(valArg.value as MomentInput);
if (dateVal.isValid()) {
return {
value: dateVal.format(dateWidgetDef?.valueFormat),
};
} else {
return {
value: null,
error: "Invalid date",
};
}
}
}
return undefined;
};