Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 48 additions & 15 deletions docs/api/export.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ Use the `formatQuery` function to export queries in various formats. The functio
function formatQuery(
query: RuleGroupTypeAny,
options?: ExportFormat | FormatQueryOptions
): string | ParameterizedSQL | ParameterizedNamedSQL;
): string | ParameterizedSQL | ParameterizedNamedSQL | RQBJsonLogic;
```

`formatQuery` parses a given query into one of the following formats:
`formatQuery` converts a given query into one of the following formats:

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

### JSON without identifiers

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.
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.

```ts
formatQuery(query, 'json_without_ids');
Expand Down Expand Up @@ -255,7 +255,7 @@ formatQuery(query, { format: 'sql', parseNumbers: true });

:::info

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).
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).

The following expressions all evaluate to `true`:

Expand All @@ -277,7 +277,7 @@ formatQuery(

### Value processor

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).
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).

```ts
const query: RuleGroupType = {
Expand All @@ -297,24 +297,57 @@ const query: RuleGroupType = {
],
};

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

formatQuery(query, { format: 'sql', valueProcessor });
// Returns: "(instrument in ('Guitar','Vocals') and lastName = 'Vai')"
formatQuery(query, { format: 'sql', valueProcessor: customValueProcessor });
// Returns: "(instrument in ('Guitar', 'Vocals') and lastName = 'Vai')"
```

:::caution

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.
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.

:::

#### Enhanced `valueProcessor` behavior

`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.

If the `valueProcessor` function accepts fewer than three (3) arguments, it will be called like this:

```ts
valueProcessor(rule, { parseNumbers });
```

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">`).

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.

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:

- `defaultValueProcessorByRule` (for SQL-based formats)
- `defaultValueProcessorCELByRule`
- `defaultValueProcessorMongoDBByRule`
- `defaultValueProcessorSpELByRule`

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:

```ts
const valueProcessor = (field: string, operator = '=', value = '') => '...';
console.log(`length: ${valueProcessor.length}`);
```

Removing `= ...` from the `operator` and `value` argument declarations would increase the function's `length` to 3.

If you use TypeScript, these conditions will be enforced automatically.

### Quote field names

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

### Value sources

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.
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.

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

## Validation

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.
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.

Example:

Expand Down Expand Up @@ -431,8 +464,8 @@ formatQuery(query, {

### Automatic validation

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:
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:

- 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.
- 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).
- Rules where the following expression is true will be deemed invalid: `field === placeholderFieldName || operator === placeholderOperatorName`.
- 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).
- Rules where either the `field` or `operator` match their respective placeholder will be deemed invalid (`field === placeholderFieldName || operator === placeholderOperatorName`).
32 changes: 24 additions & 8 deletions docs/api/import.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
---
title: Import
description: Convert SQL to query builder objects
description: Convert SQL and other formats to query builder objects
---

import TypeScriptAdmonition from './_ts_admonition.md';

<TypeScriptAdmonition />

## SQL

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

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

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.

## Basic usage
### Basic usage

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

Expand Down Expand Up @@ -58,6 +60,20 @@ Output (`RuleGroupType`):
}
```

## Common Expression Language (CEL)

`parseCEL` takes a [CEL](https://github.com/google/cel-spec) string and converts it to `RuleGroupType`.

Click the "Import from CEL" button in [the demo](https://react-querybuilder.js.org/react-querybuilder) to try it out.

## JsonLogic

`parseJsonLogic` takes a [JsonLogic](https://jsonlogic.com/) object and converts it to `RuleGroupType`.

Click the "Import from JsonLogic" button in [the demo](https://react-querybuilder.js.org/react-querybuilder) to try it out.

## Configuration

### Lists as arrays

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

## Independent combinators
### Independent combinators

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

```ts
parseSQL(`SELECT * FROM t WHERE firstName = 'Steve' AND lastName = 'Vai'`, {
Expand Down Expand Up @@ -118,11 +134,11 @@ Output (`RuleGroupTypeIC`):
}
```

## Fields as value source
### Fields as value source

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.
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.

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".
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.

```ts
parseSQL(`SELECT * FROM t WHERE firstName = lastName`, {
Expand Down Expand Up @@ -152,6 +168,6 @@ Output:

:::note

`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.
`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.

:::
23 changes: 19 additions & 4 deletions docs/api/misc.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import TypeScriptAdmonition from './_ts_admonition.md';
### `defaultValidator`

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

```ts
function findPath(path: number[], query: RuleGroupType): RuleType | RuleGroupType;
function findPath(path: number[], query: RuleGroupTypeAny): RuleType | RuleGroupTypeAny;
```

`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.
Expand All @@ -42,6 +42,22 @@ function convertQuery(query: RuleGroupTypeIC): RuleGroupType;

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

### `transformQuery`

```ts
function transformQuery(query: RuleGroupTypeAny, options: QueryTransformerOptions): any;
```

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:

- `ruleGroupProcessor`: Custom processing for each rule group. (The `rules` property will be overwritten.)
- `propertyMap`: Keys in the rule or group objects that match keys in this object will be renamed to the corresponding value.
- `combinatorMap`: Best explained with an example: `{and: "&&", or: "||"}` would translate "and"/"or" combinators to "&&"/"||", respectively.
- `operatorMap`: Convert operators that match the keys in this object to the corresponding values, e.g. `{"=": "=="}`.
- `deleteRemappedProperties`: Defaults to `true`; pass `false` to leave the remapped properties _and_ the original properties in the resulting object.

See the [test suite](https://github.com/react-querybuilder/react-querybuilder/blob/main/packages/react-querybuilder/src/utils/transformQuery.test.ts) for example usage.

## Query tools

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

Expand Down
Loading