Skip to content

Commit 337c4d2

Browse files
authored
Merge pull request #13 from react-querybuilder/v450
v4.5.0
2 parents 215f583 + bcda263 commit 337c4d2

File tree

4 files changed

+360
-474
lines changed

4 files changed

+360
-474
lines changed

docs/api/export.mdx

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ Use the `formatQuery` function to export queries in various formats. The functio
1313
function formatQuery(
1414
query: RuleGroupTypeAny,
1515
options?: ExportFormat | FormatQueryOptions
16-
): string | ParameterizedSQL | ParameterizedNamedSQL;
16+
): string | ParameterizedSQL | ParameterizedNamedSQL | RQBJsonLogic;
1717
```
1818

19-
`formatQuery` parses a given query into one of the following formats:
19+
`formatQuery` converts a given query into one of the following formats:
2020

2121
- JSON (with or without `id`s)
2222
- SQL `WHERE` clause
@@ -88,7 +88,7 @@ The output will be a multi-line string representation of the query using 2 space
8888

8989
### JSON without identifiers
9090

91-
To export the internal query representation without formatting (single-line, no indentation) and without the `id` attribute on each object, use the "json_without_ids" format. This is useful if you need to serialize the query for storage.
91+
To export the internal query representation without formatting (single-line, no indentation) and without the `id` or `path` attributes on each object, use the "json_without_ids" format. This is useful if you need to serialize the query for storage.
9292

9393
```ts
9494
formatQuery(query, 'json_without_ids');
@@ -255,7 +255,7 @@ formatQuery(query, { format: 'sql', parseNumbers: true });
255255

256256
:::info
257257

258-
To avoid information loss, this option is more strict about what qualifies as "numeric" than [the standard `parseFloat` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat). Put simply, `parseFloat` works with any string that _starts_ with a numeric sequence, ignoring the rest of the string beginning with the first non-numeric character. When `parseNumbers` is `true`, `formatQuery` will only convert a `value` to a `number` if it appears to be numeric _in its entirety_ (after trimming whitespace).
258+
To avoid information loss, this option is more strict about what qualifies as "numeric" than [the standard `parseFloat` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat). To oversimplify a bit, `parseFloat` works with any string that _starts_ with a numeric sequence, ignoring the rest of the string beginning with the first non-numeric character. In contrast, when `parseNumbers` is `true`, `formatQuery` will only convert a `value` to a `number` if it appears to be numeric _in its entirety_ (after trimming whitespace).
259259

260260
The following expressions all evaluate to `true`:
261261

@@ -277,7 +277,7 @@ formatQuery(
277277

278278
### Value processor
279279

280-
If you need to control the way the value portion of the output is processed, you can specify a custom `valueProcessor` (only applicable for "sql" format).
280+
If you need to control the way the value portion of the output is processed, you can specify a custom `valueProcessor` (only applicable for certain formats).
281281

282282
```ts
283283
const query: RuleGroupType = {
@@ -297,24 +297,57 @@ const query: RuleGroupType = {
297297
],
298298
};
299299

300-
const valueProcessor = (field, operator, value) => {
300+
const customValueProcessor = (field, operator, value) => {
301301
if (operator === 'in') {
302302
// Assuming `value` is an array, such as from a multi-select
303-
return `(${value.map(v => `"${v.trim()}"`).join(',')})`;
303+
return `(${value.map(v => `"${v.trim()}"`).join(', ')})`;
304304
}
305+
// Fall back to the default value processor for other operators
305306
return defaultValueProcessor(field, operator, value);
306307
};
307308

308-
formatQuery(query, { format: 'sql', valueProcessor });
309-
// Returns: "(instrument in ('Guitar','Vocals') and lastName = 'Vai')"
309+
formatQuery(query, { format: 'sql', valueProcessor: customValueProcessor });
310+
// Returns: "(instrument in ('Guitar', 'Vocals') and lastName = 'Vai')"
310311
```
311312

312313
:::caution
313314

314-
When using the "mongodb" export format, `valueProcessor` functions must produce the entire MongoDB rule object and not just the value portion like with other formats.
315+
When using the "mongodb", "cel", or "spel" export formats, `valueProcessor` functions must produce the entire MongoDB rule object or CEL/SpEL rule string, not just the expression on the right-hand side of the operator like with SQL-based formats.
315316

316317
:::
317318

319+
#### Enhanced `valueProcessor` behavior
320+
321+
`formatQuery` will invoke custom `valueProcessor` functions with different arguments based on the function's `length` property, which is the number of arguments a function accepts excluding those with default values.
322+
323+
If the `valueProcessor` function accepts fewer than three (3) arguments, it will be called like this:
324+
325+
```ts
326+
valueProcessor(rule, { parseNumbers });
327+
```
328+
329+
The first argument is the `RuleType` object directly from the query. The second argument is of type `ValueProcessorOptions`, which is equivalent to `Pick<FormatQueryOptions, "parseNumbers">`).
330+
331+
Invoking `valueProcessor` with the full `RuleType` object provides access to much more information about each rule. Standard properties that were previously unavailable include `path`, `id`, and `disabled`, but any custom properties will also be accessible.
332+
333+
The default value processors have not changed from the legacy function signature, but alternate functions using the new `fn(rule, options)` signature are now available:
334+
335+
- `defaultValueProcessorByRule` (for SQL-based formats)
336+
- `defaultValueProcessorCELByRule`
337+
- `defaultValueProcessorMongoDBByRule`
338+
- `defaultValueProcessorSpELByRule`
339+
340+
To maintain the legacy signature (`valueProcessor(field, operator, value, valueSource)`), make sure your custom `valueProcessor` function accepts at least three arguments _with no default values_ (i.e. do not use `=` for the first three arguments). For example, the following code will log `length: 1` and the function would be called with the `(rule, options)` arguments:
341+
342+
```ts
343+
const valueProcessor = (field: string, operator = '=', value = '') => '...';
344+
console.log(`length: ${valueProcessor.length}`);
345+
```
346+
347+
Removing `= ...` from the `operator` and `value` argument declarations would increase the function's `length` to 3.
348+
349+
If you use TypeScript, these conditions will be enforced automatically.
350+
318351
### Quote field names
319352

320353
Some database engines wrap field names in backticks (`` ` ``). This can be configured with the `quoteFieldNamesWith` option.
@@ -352,7 +385,7 @@ The `fallbackExpression` is a string that will be part of the output when `forma
352385

353386
### Value sources
354387

355-
When the `valueSource` property for a rule is set to "field", `formatQuery` will place the bare, unquoted value (which should be a valid field name) in the result for the "sql", "parameterized", "parameterized_named", "mongodb", and "cel" formats. No parameters will be generated for such rules.
388+
When the `valueSource` property for a rule is set to "field", `formatQuery` will place the bare, unquoted value (which should be a valid field name) in the result for the "sql", "parameterized", "parameterized_named", "mongodb", "cel", and "spel" formats. No parameters will be generated for such rules.
356389

357390
```ts
358391
const pf = formatQuery(
@@ -382,7 +415,7 @@ Any rule where the `field` or `operator` matches the placeholder value (default
382415

383416
## Validation
384417

385-
The validation options (`validator` and `fields` – see [Validation](./validation) for more information) only affect the output when `format` is "sql", "parameterized", "parameterized_named", "mongodb", or "cel". If the `validator` function returns `false`, the `fallbackExpression` will be returned. Otherwise, groups and rules marked as invalid (either by the validation map produced by the `validator` function or the result of the field-based `validator` function) will be ignored.
418+
The validation options (`validator` and `fields` – see [Validation](./validation) for more information) only affect the output when `format` is not "json" or "json_without_ids". If the `validator` function returns `false`, the `fallbackExpression` will be returned. Otherwise, groups and rules marked as invalid (either by the validation map produced by the `validator` function or the result of the field-based `validator` function) will be ignored.
386419

387420
Example:
388421

@@ -431,8 +464,8 @@ formatQuery(query, {
431464

432465
### Automatic validation
433466

434-
A basic form of validation will be used by `formatQuery` for the "in", "notIn", "between", and "notBetween" operators when the output format is "sql", "parameterized", "parameterized_named", "mongodb", or "cel". This validation is used regardless of the presence of any `validator` options either at the query or field level:
467+
A basic form of validation will be used by `formatQuery` for the "in", "notIn", "between", and "notBetween" operators when the output format is not "json" or "json_without_ids". This validation is used regardless of the presence of any `validator` options at either the query level or field level:
435468

436469
- Rules that specify an "in" or "notIn" `operator` will be deemed invalid if the rule's `value` is neither an array with at least one element (i.e. `value.length > 0`) nor a non-empty string.
437-
- Rules that specify a "between" or "notBetween" `operator` will be deemed invalid if the rule's `value` is neither an array of length two (`value.length === 2`) nor a string with exactly one comma that isn't the first or last character (i.e. `value.split(',').length === 2` and neither element is an empty string).
438-
- Rules where the following expression is true will be deemed invalid: `field === placeholderFieldName || operator === placeholderOperatorName`.
470+
- Rules that specify a "between" or "notBetween" `operator` will be deemed invalid if the rule's `value` is neither an array with length of at least two (`value.length >= 2`) nor a string with at least one comma that isn't the first or last character (i.e. `value.split(',').length >= 2`, and neither element is an empty string).
471+
- Rules where either the `field` or `operator` match their respective placeholder will be deemed invalid (`field === placeholderFieldName || operator === placeholderOperatorName`).

docs/api/import.mdx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
---
22
title: Import
3-
description: Convert SQL to query builder objects
3+
description: Convert SQL and other formats to query builder objects
44
---
55

66
import TypeScriptAdmonition from './_ts_admonition.md';
77

88
<TypeScriptAdmonition />
99

10+
## SQL
11+
1012
Use the `parseSQL` function to convert SQL `SELECT` statements into a format suitable for the `<QueryBuilder />` component's `query` prop. The function signature is:
1113

1214
```ts
@@ -17,7 +19,7 @@ function parseSQL(sql: string, options?: ParseSQLOptions): RuleGroupTypeAny;
1719

1820
The optional second parameter to `parseSQL` is an options object that configures how the function handles named or anonymous bind variables within the SQL string.
1921

20-
## Basic usage
22+
### Basic usage
2123

2224
Running any of the following statements will produce the same result (see below):
2325

@@ -58,6 +60,20 @@ Output (`RuleGroupType`):
5860
}
5961
```
6062

63+
## Common Expression Language (CEL)
64+
65+
`parseCEL` takes a [CEL](https://github.com/google/cel-spec) string and converts it to `RuleGroupType`.
66+
67+
Click the "Import from CEL" button in [the demo](https://react-querybuilder.js.org/react-querybuilder) to try it out.
68+
69+
## JsonLogic
70+
71+
`parseJsonLogic` takes a [JsonLogic](https://jsonlogic.com/) object and converts it to `RuleGroupType`.
72+
73+
Click the "Import from JsonLogic" button in [the demo](https://react-querybuilder.js.org/react-querybuilder) to try it out.
74+
75+
## Configuration
76+
6177
### Lists as arrays
6278

6379
To generate actual arrays instead of comma-separated strings for lists of values following `IN` and `BETWEEN` operators, use the `listsAsArrays` option.
@@ -88,9 +104,9 @@ Output:
88104
}
89105
```
90106

91-
## Independent combinators
107+
### Independent combinators
92108

93-
When the `independentCombinators` option is `true`, `parseSQL` will output a query with combinator identifiers between sibling rules/groups.
109+
When the `independentCombinators` option is `true`, `parse*` functions will output a query with combinator identifiers between sibling rules/groups.
94110

95111
```ts
96112
parseSQL(`SELECT * FROM t WHERE firstName = 'Steve' AND lastName = 'Vai'`, {
@@ -118,11 +134,11 @@ Output (`RuleGroupTypeIC`):
118134
}
119135
```
120136

121-
## Fields as value source
137+
### Fields as value source
122138

123-
When the `fields` option (which accepts the same types as the [`fields` prop](./querybuilder#fields)) is provided, and _only_ if it is provided, then `parseSQL` will validate clauses that have a field identifier to the right of the operator instead of a primitive value. A `getValueSources` function can also be provided to help validate rules.
139+
When the `fields` option (which accepts the same types as the [`fields` prop](./querybuilder#fields)) is provided, and _only_ if it is provided, then `parse*` functions will validate clauses that have a field identifier to the right of the operator instead of a primitive value. A `getValueSources` function (with the same signature as the [prop of the same name](./querybuilder#getvaluesources)) can also be provided to help validate rules.
124140

125-
In order for such a rule to be considered valid, either the `getValueSources` return value, the field's `valueSources` property return value, or the field's `valueSources` property itself must be an array that includes the string "field".
141+
In order for such a rule to be considered valid, one of the following must be an array that includes the string "field": 1) the `getValueSources` return value, 2) the field's `valueSources` property return value, or 3) the field's `valueSources` property itself.
126142

127143
```ts
128144
parseSQL(`SELECT * FROM t WHERE firstName = lastName`, {
@@ -152,6 +168,6 @@ Output:
152168

153169
:::note
154170

155-
`parseSQL` will only validate clauses where "field" is the _only_ value source. Operators that take multiple values, like "between" and "in", must only have field names to the right of the operator, not a mix of field names and primitive values.
171+
`parse*` functions will only validate clauses where "field" is the _only_ value source. Operators that take multiple values, like "between" and "in", must only have field names to the right of the operator, not a mix of field names and primitive values.
156172

157173
:::

docs/api/misc.mdx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import TypeScriptAdmonition from './_ts_admonition.md';
1313
### `defaultValidator`
1414

1515
```ts
16-
function defaultValidator(query: RuleGroupType): {
16+
function defaultValidator(query: RuleGroupTypeAny): {
1717
[id: string]: { valid: boolean; reasons?: string[] };
1818
};
1919
```
@@ -25,7 +25,7 @@ You can see an example of the default validator in action in the [demo](https://
2525
### `findPath`
2626

2727
```ts
28-
function findPath(path: number[], query: RuleGroupType): RuleType | RuleGroupType;
28+
function findPath(path: number[], query: RuleGroupTypeAny): RuleType | RuleGroupTypeAny;
2929
```
3030

3131
`findPath` is a utility function for finding the rule or group within the query hierarchy that has a given `path`. Useful in custom [`onAddRule`](./querybuilder#onaddrule) and [`onAddGroup`](./querybuilder#onaddgroup) functions.
@@ -42,6 +42,22 @@ function convertQuery(query: RuleGroupTypeIC): RuleGroupType;
4242

4343
`convertToIC` and `convertFromIC` do the same thing as `convertQuery`, but only in one direction.
4444

45+
### `transformQuery`
46+
47+
```ts
48+
function transformQuery(query: RuleGroupTypeAny, options: QueryTransformerOptions): any;
49+
```
50+
51+
This function recursively steps through nested `rules` arrays in a `RuleGroupType` or `RuleGroupTypeIC`, passing each `RuleType` object to a provided `ruleProcessor` function. Several other options are also available:
52+
53+
- `ruleGroupProcessor`: Custom processing for each rule group. (The `rules` property will be overwritten.)
54+
- `propertyMap`: Keys in the rule or group objects that match keys in this object will be renamed to the corresponding value.
55+
- `combinatorMap`: Best explained with an example: `{and: "&&", or: "||"}` would translate "and"/"or" combinators to "&&"/"||", respectively.
56+
- `operatorMap`: Convert operators that match the keys in this object to the corresponding values, e.g. `{"=": "=="}`.
57+
- `deleteRemappedProperties`: Defaults to `true`; pass `false` to leave the remapped properties _and_ the original properties in the resulting object.
58+
59+
See the [test suite](https://github.com/react-querybuilder/react-querybuilder/blob/main/packages/react-querybuilder/src/utils/transformQuery.test.ts) for example usage.
60+
4561
## Query tools
4662

4763
Several methods are available to assist with manipulation of query objects outside the context of the `<QueryBuilder />` component:
@@ -60,8 +76,7 @@ The following default configuration objects are exported for convenience.
6076
- `defaultCombinators` (see [`combinators` prop](./querybuilder#combinators))
6177
- `defaultOperators` (see [`operators` prop](./querybuilder#operators))
6278
- `defaultTranslations` (see [`translations` prop](./querybuilder#translations))
63-
- `defaultValueProcessor` (see [Export](./export) > [Value processor](./export#value-processor))
64-
- `defaultMongoDBValueProcessor` (see [Export](./export) > [Value processor](./export#value-processor))
79+
- `defaultValueProcessor` and variants for non-SQL formats (see [Export](./export) > [Value processor](./export#value-processor))
6580
- `defaultFields` (see [`fields` prop](./querybuilder#fields))
6681
- `standardClassnames` (see [CSS classes](./classnames))
6782

0 commit comments

Comments
 (0)