UNPKG

react-querybuilder

Version:

React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts

378 lines (377 loc) 13.9 kB
import type { FullField, FullOperator, ParseNumbersPropConfig, ValueSource, ValueSources } from "./basic"; import type { RulesLogic } from "json-logic-js"; import type { FlexibleOptionList, OptionList } from "./options"; import type { RuleGroupType, RuleType } from "./ruleGroups"; import type { RuleGroupTypeAny } from "./ruleGroupsIC"; import type { QueryValidator } from "./validation"; /** * Available export formats for {@link formatQuery}. */ export type ExportFormat = "json" | "sql" | "json_without_ids" | "parameterized" | "parameterized_named" | "mongodb" | "mongodb_query" | "cel" | "jsonlogic" | "spel" | "elasticsearch" | "jsonata" | "natural_language"; export type ExportObjectFormats = "parameterized" | "parameterized_named" | "jsonlogic" | "elasticsearch" | "jsonata" | "mongodb_query"; export type SQLPreset = "ansi" | "sqlite" | "postgresql" | "mysql" | "mssql" | "oracle"; /** * Options object shape for {@link formatQuery}. */ export interface FormatQueryOptions { /** * The {@link ExportFormat}. */ format?: ExportFormat; /** * This function will be used to process the `operator` from each rule * for query language formats. If not defined, the appropriate * `defaultOperatorProcessor*` for the format will be used. */ operatorProcessor?: RuleProcessor; /** * This function will be used to process the `value` from each rule * for query language formats. If not defined, the appropriate * `defaultValueProcessor*` for the format will be used. */ valueProcessor?: ValueProcessorLegacy | ValueProcessorByRule; /** * This function will be used to process each rule for query language * formats. If not defined, the appropriate `defaultRuleProcessor*` * for the format will be used. */ ruleProcessor?: RuleProcessor; /** * In the "sql", "parameterized", "parameterized_named", and "jsonata" export * formats, field names will be bracketed by this string. If an array of strings * is passed, field names will be preceded by the first element and * succeeded by the second element. * * Tip: Use `fieldIdentifierSeparator` to bracket identifiers individually within field names. * * @default '' // the empty string * * @example * formatQuery(query, { format: 'sql', quoteFieldNamesWith: '"' }) * // `"First name" = 'Steve'` * * @example * formatQuery(query, { format: 'sql', quoteFieldNamesWith: ['[', ']'] }) * // "[First name] = 'Steve'" */ quoteFieldNamesWith?: string | [string, string]; /** * When used in conjunction with the `quoteFieldNamesWith` option, field names will * be split by this string, each part being individually processed as per the rules * of the `quoteFieldNamesWith` configuration. The parts will then be re-joined * by the same string. * * A common value for this option is `'.'`. * * A value of `''` (the empty string) will disable splitting/rejoining. * * @default '' * * @example * formatQuery(query, { * format: 'sql', * quoteFieldNamesWith: ['[', ']'], * fieldIdentifierSeparator: '.', * }) * // "[dbo].[Musicians].[First name] = 'Steve'" */ fieldIdentifierSeparator?: string; /** * Character to use for quoting string values in the SQL format. * @default `'` */ quoteValuesWith?: string; /** * Validator function for the entire query. Can be the same function passed * as `validator` prop to {@link QueryBuilder}. */ validator?: QueryValidator; /** * This can be the same {@link FullField} array passed to {@link QueryBuilder}, but * really all you need to provide is the `name` and `validator` for each field. * * The full field object from this array, where the field's identifying property * matches the rule's `field`, will be passed to the rule processor. */ fields?: FlexibleOptionList<FullField>; /** * This can be the same `getOperators` function passed to {@link QueryBuilder}. * * The full operator object from this array, where the operator's identifying property * matches the rule's `operator`, will be passed to the rule processor. */ getOperators?(field: string, misc: { fieldData: FullField }): FlexibleOptionList<FullOperator> | null; /** * This string will be inserted in place of invalid groups for non-JSON formats. * Defaults to `'(1 = 1)'` for "sql"/"parameterized"/"parameterized_named" and * `'$and:[{$expr:true}]'` for "mongodb". */ fallbackExpression?: string; /** * This string will be placed in front of named parameters (aka bind variables) * when using the "parameterized_named" export format. * * @default ":" */ paramPrefix?: string; /** * Maintains the parameter prefix in the `params` object keys when using the * "parameterized_named" export format. Recommended when using SQLite. * * @default false * * @example * console.log(formatQuery(query, { * format: "parameterized_named", * paramPrefix: "$", * paramsKeepPrefix: true * }).params) * // { $firstName: "Stev" } * // Default (`paramsKeepPrefix` is `false`): * // { firstName: "Stev" } */ paramsKeepPrefix?: boolean; /** * Renders parameter placeholders as a series of sequential numbers * instead of '?' like the default. This option will respect the * `paramPrefix` option like the 'parameterized_named' format. * * @default false */ numberedParams?: boolean; /** * Preserves the order of values for "between" and "notBetween" rules, even if a larger * value comes before a smaller value (which will always evaluate to false). */ preserveValueOrder?: boolean; /** * Renders values as either `number`-types or unquoted strings, as * appropriate and when possible. Each `string`-type value is evaluated * against {@link numericRegex} to determine if it can be represented as a * plain numeric value. If so, `parseFloat` is used to convert it to a number. */ parseNumbers?: ParseNumbersPropConfig; /** * Any rules where the field is equal to this value will be ignored. * * @default '~' */ placeholderFieldName?: string; /** * Any rules where the operator is equal to this value will be ignored. * * @default '~' */ placeholderOperatorName?: string; /** * Operator to use when concatenating wildcard characters and field names in "sql" format. * The ANSI standard is `||`, while SQL Server uses `+`. MySQL does not implement a concatenation * operator by default, and therefore requires use of the `CONCAT` function. * * If `concatOperator` is set to `"CONCAT"` (case-insensitive), the `CONCAT` function will be * used. Note that Oracle SQL does not support more than two values in the `CONCAT` function, * so this option should not be used in that context. The default setting (`"||"`) is already * compatible with Oracle SQL. * * @default '||' */ concatOperator?: "||" | "+" | "CONCAT" | (string & {}); /** * Option presets to maximize compatibility with various SQL dialects. */ preset?: SQLPreset; context?: Record<string, any>; } /** * Options object for {@link ValueProcessorByRule} functions. */ export interface ValueProcessorOptions extends FormatQueryOptions { valueProcessor?: ValueProcessorByRule; escapeQuotes?: boolean; /** * The full field object, if `fields` was provided in the * {@link formatQuery} options parameter. */ fieldData?: FullField; /** * Included for the "parameterized_named" format only. Keys of this object represent * field names and values represent the current list of parameter names for that * field based on the query rules processed up to that point. Use this list to * ensure that parameter names generated by the custom rule processor are unique. */ fieldParamNames?: Record<string, string[]>; /** * Included for the "parameterized_named" format only. Call this function with a * field name to get a unique parameter name, as yet unused during query processing. */ getNextNamedParam?: (field: string) => string; /** * Additional prefix and suffix characters to wrap the value in. Useful for augmenting * the default value processor results with special syntax (e.g., for dates or function * calls). */ wrapValueWith?: [string, string]; /** * Parse numbers in the rule value. * * @default false */ parseNumbers?: boolean; } /** * Function that produces a processed value for a given {@link RuleType}. */ export type ValueProcessorByRule = (rule: RuleType, options?: ValueProcessorOptions) => string; /** * Function that produces a processed value for a given `field`, `operator`, `value`, * and `valueSource`. */ export type ValueProcessorLegacy = (field: string, operator: string, value: any, valueSource?: ValueSource) => string; export type ValueProcessor = ValueProcessorLegacy; /** * Function to produce a result that {@link formatQuery} uses when processing a * {@link RuleType} object. * * See the default rule processor for each format to know what type to return. * | Format | Default rule processor | * | ------------------------ | ----------------------------------------- | * | `sql` | {@link defaultRuleProcessorSQL} | * | `parameterized` | {@link defaultRuleProcessorParameterized} | * | `parameterized_named` | {@link defaultRuleProcessorParameterized} | * | `mongodb` _(deprecated)_ | {@link defaultRuleProcessorMongoDB} | * | `mongodb_query` | {@link defaultRuleProcessorMongoDBQuery} | * | `cel` | {@link defaultRuleProcessorCEL} | * | `spel` | {@link defaultRuleProcessorSpEL} | * | `jsonlogic` | {@link defaultRuleProcessorJsonLogic} | * | `elasticsearch` | {@link defaultRuleProcessorElasticSearch} | * | `jsonata` | {@link defaultRuleProcessorJSONata} | */ export type RuleProcessor = (rule: RuleType, options?: ValueProcessorOptions, meta?: { processedParams?: Record<string, any> | any[] context?: Record<string, any> }) => any; /** * Object produced by {@link formatQuery} for the `"parameterized"` format. */ export interface ParameterizedSQL { /** The SQL `WHERE` clause fragment with `?` placeholders for each value. */ sql: string; /** * Parameter values in the same order their respective placeholders * appear in the `sql` string. */ params: any[]; } /** * Object produced by {@link formatQuery} for the `"parameterized_named"` format. */ export interface ParameterizedNamedSQL { /** The SQL `WHERE` clause fragment with bind variable placeholders for each value. */ sql: string; /** * Map of bind variable names from the `sql` string to the associated values. */ params: Record<string, any>; } export interface RQBJsonLogicStartsWith { startsWith: [RQBJsonLogic, RQBJsonLogic, ...RQBJsonLogic[]]; } export interface RQBJsonLogicEndsWith { endsWith: [RQBJsonLogic, RQBJsonLogic, ...RQBJsonLogic[]]; } export interface RQBJsonLogicVar { var: string; } /** * JsonLogic rule object with additional operators generated by {@link formatQuery} * and accepted by {@link parseJsonLogic!parseJsonLogic}. */ export type RQBJsonLogic = RulesLogic<RQBJsonLogicStartsWith | RQBJsonLogicEndsWith>; /** * Options common to all parsers. */ interface ParserCommonOptions { fields?: OptionList<FullField> | Record<string, FullField>; getValueSources?: (field: string, operator: string) => ValueSources; listsAsArrays?: boolean; independentCombinators?: boolean; } /** * Options object for {@link parseSQL!parseSQL}. */ export interface ParseSQLOptions extends ParserCommonOptions { paramPrefix?: string; params?: any[] | Record<string, any>; } /** * Options object for {@link parseCEL!parseCEL}. */ export interface ParseCELOptions extends ParserCommonOptions {} /** * Options object for {@link parseSpEL!parseSpEL}. */ export interface ParseSpELOptions extends ParserCommonOptions {} /** * Options object for {@link parseJSONata!parseJSONata}. * * Note: `listsAsArrays` is ignored by `parseJSONata`; lists are _always_ arrays. */ export interface ParseJSONataOptions extends ParserCommonOptions {} /** * Options object for {@link parseJsonLogic!parseJsonLogic}. */ export interface ParseJsonLogicOptions extends ParserCommonOptions { jsonLogicOperations?: Record<string, (value: any) => RuleType | RuleGroupTypeAny | false>; } /** * Options object for {@link parseMongoDB!parseMongoDB}. */ export interface ParseMongoDbOptions extends ParserCommonOptions { /** * When `true`, MongoDB rules in the form of `{ fieldName: { $not: { <...rule> } } }` * will be parsed into a rule group with the `not` attribute set to `true`. By default * (i.e., when this attribute is `false`), such "`$not`" rules will be parsed into a * rule with a negated operator. * * For example, with `preventOperatorNegation` set to `true`, a MongoDB rule like this... * * ```ts * { fieldName: { $not: { $eq: 1 } } } * ``` * * ...would yield a rule group like this: * * ```ts * { * combinator: 'and', * not: true, * rules: [{ field: 'fieldName', operator: '=', value: 1 }] * } * ``` * * By default, the same MongoDB rule would yield a rule like this: * * ```ts * { field: 'fieldName', operator: '!=', value: 1 } * // negated operator ^ * ``` * * @default false */ preventOperatorNegation?: boolean; /** * Map of additional operators to their respective processing functions. Operators * must begin with `"$"`. Processing functions should return either a {@link index!RuleType RuleType} * or {@link index!RuleGroupType RuleGroupType}. * * (The functions should _not_ return {@link index!RuleGroupTypeIC RuleGroupTypeIC}, even if using independent * combinators. If the `independentCombinators` option is `true`, `parseMongoDB` * will convert the final query to {@link index!RuleGroupTypeIC RuleGroupTypeIC} before returning it.) * * @default {} */ additionalOperators?: Record<`$${string}`, (field: string, operator: string, value: any, options: ParserCommonOptions) => RuleType | RuleGroupType>; } export {};