Skip to content

Commit b7da5d9

Browse files
authored
Merge pull request #9 from react-querybuilder/rqb-298
Add documentation on `parseNumbers` and `debugMode` (RQB v4.2.4)
2 parents b3f0c88 + 6091a42 commit b7da5d9

File tree

11 files changed

+1785
-1746
lines changed

11 files changed

+1785
-1746
lines changed

docs/api/export.mdx

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ function formatQuery(
2424
- MongoDB
2525
- Common Expression Language (CEL)
2626

27-
:::info
28-
29-
The inversion operator (setting `not: true` for a rule group) is currently unsupported for the MongoDB format, but rules can be created using the `"!="` operator.
30-
31-
:::
32-
3327
For the next few sections, assume the `query` variable has been defined as:
3428

3529
```ts
@@ -169,6 +163,12 @@ Output:
169163
`{"$and":[{"firstName":{"$eq":"Steve"}},{"lastName":{"$eq":"Vai"}}]}`;
170164
```
171165

166+
:::info
167+
168+
For now, the MongoDB export format has two major shortcomings. For one, it does not support the inversion operator (setting `not: true` for a rule group), however rules _can_ be created using the `"!="` operator. Also, if the query uses [independent combinators](./querybuilder#independentcombinators), it will not be processed and `formatQuery(query, 'mongodb')` will always return the [fallback expression](#fallback-expression).
169+
170+
:::
171+
172172
### Common Expression Language
173173

174174
For Common Expression Language (CEL) output, use the "cel" format.
@@ -185,7 +185,65 @@ Output:
185185

186186
## Configuration
187187

188-
An object can be passed as the second argument instead of a string in order to have more detailed control over the output.
188+
An object can be passed as the second argument instead of a string to have more fine-grained control over the output.
189+
190+
### Parse numbers
191+
192+
Since HTML `<input>` controls store values as strings (even when `type="number"`), exporting a query to various formats may produce a string representation of a value when a true numeric value is required or more appropriate. Set the `parseNumbers` option to `true` and `formatQuery` will attempt to convert all values to numbers, falling back to the original value if `parseFloat(value)` returns `NaN` (not a number).
193+
194+
```ts
195+
const query: RuleGroupType = {
196+
combinator: 'and',
197+
not: false,
198+
rules: [
199+
{
200+
field: 'digits',
201+
operator: '=',
202+
value: '20',
203+
},
204+
{
205+
field: 'age',
206+
operator: 'between',
207+
value: '26, 52',
208+
},
209+
{
210+
field: 'lastName',
211+
operator: '=',
212+
value: 'Vai',
213+
},
214+
],
215+
};
216+
217+
// Default configuration - all values are strings:
218+
formatQuery(query, { format: 'sql' });
219+
// Returns: "(digits = '20' and age between '26' and '52' and lastName = 'Vai')"
220+
221+
// `parseNumbers: true` - numeric strings converted to actual numbers:
222+
formatQuery(query, { format: 'sql', parseNumbers: true });
223+
// Returns: "(digits = 20 and age between 26 and 52 and lastName = 'Vai')"
224+
```
225+
226+
:::info
227+
228+
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).
229+
230+
The following expressions all evaluate to `true`:
231+
232+
```ts
233+
parseFloat('000111abcdef') === 111;
234+
235+
formatQuery(
236+
{ rules: [{ field: 'f', operator: '=', value: '000111abcdef' }] },
237+
{ format: 'sql', parseNumbers: true }
238+
) === "(f = '000111abcdef')";
239+
240+
formatQuery(
241+
{ rules: [{ field: 'f', operator: '=', value: ' 000111 ' }] },
242+
{ format: 'sql', parseNumbers: true }
243+
) === '(f = 111)';
244+
```
245+
246+
:::
189247

190248
### Value processor
191249

@@ -198,13 +256,13 @@ const query: RuleGroupType = {
198256
rules: [
199257
{
200258
field: 'instrument',
201-
value: ['Guitar', 'Vocals'],
202259
operator: 'in',
260+
value: ['Guitar', 'Vocals'],
203261
},
204262
{
205263
field: 'lastName',
206-
value: 'Vai',
207264
operator: '=',
265+
value: 'Vai',
208266
},
209267
],
210268
};
@@ -218,7 +276,7 @@ const valueProcessor = (field, operator, value) => {
218276
};
219277

220278
formatQuery(query, { format: 'sql', valueProcessor });
221-
// Output: "(instrument in ('Guitar','Vocals') and lastName = 'Vai')"
279+
// Returns: "(instrument in ('Guitar','Vocals') and lastName = 'Vai')"
222280
```
223281

224282
### Quote field names
@@ -227,7 +285,7 @@ Some database engines wrap field names in backticks. This can be configured with
227285

228286
```ts
229287
formatQuery(query, { format: 'sql', quoteFieldNamesWith: '`' });
230-
// Output: "(`firstName` = 'Steve' and `lastName` = 'Vai')"
288+
// Returns: "(`firstName` = 'Steve' and `lastName` = 'Vai')"
231289
```
232290

233291
### Parameter prefix
@@ -306,21 +364,21 @@ formatQuery(query, {
306364
format: 'sql',
307365
validator: () => false,
308366
});
309-
// Output: "(1 = 1)" <-- see `fallbackExpression` option
367+
// Returns: "(1 = 1)" <-- see `fallbackExpression` option
310368

311369
// Rule "r1" is invalid based on the validation map
312370
formatQuery(query, {
313371
format: 'sql',
314372
validator: () => ({ r1: false }),
315373
});
316-
// Output: "(lastName = 'Vai')" <-- skipped `firstName` rule with `id === 'r1'`
374+
// Returns: "(lastName = 'Vai')" <-- skipped `firstName` rule with `id === 'r1'`
317375

318376
// Rule "r1" is invalid based on the field validator for `firstName`
319377
formatQuery(query, {
320378
format: 'sql',
321379
fields: [{ name: 'firstName', validator: () => false }],
322380
});
323-
// Output: "(lastName = 'Vai')" <-- skipped `firstName` rule because field validator returned `false`
381+
// Returns: "(lastName = 'Vai')" <-- skipped `firstName` rule because field validator returned `false`
324382
```
325383

326384
### Automatic validation

docs/api/import.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Use the `parseSQL` function to convert SQL `SELECT` statements into a format sui
1313
function parseSQL(sql: string, options?: ParseSQLOptions): RuleGroupTypeAny;
1414
```
1515

16-
`parseSQL` takes a SQL `SELECT` statement (either the full statement or the `WHERE` clause by itself). Try it out in the [demo](https://react-querybuilder.github.io/react-querybuilder/) by clicking the "Load from SQL" button.
16+
`parseSQL` takes a SQL `SELECT` statement (either the full statement or the `WHERE` clause by itself). Try it out in the [demo](https://react-querybuilder.js.org/react-querybuilder/) by clicking the "Load from SQL" button.
1717

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

docs/api/misc.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function defaultValidator(query: RuleGroupType): {
2020

2121
Pass `validator={defaultValidator}` to automatically validate groups (rules will be ignored). A group will be marked invalid if either 1) it has no child rules or groups (`query.rules.length === 0`), or 2) it has a missing/invalid `combinator` and more than one child rule or group (`rules.length >= 2`).
2222

23-
You can see an example of the default validator in action in the [demo](https://react-querybuilder.github.io/react-querybuilder/) if you check the ["Use validation" option](https://react-querybuilder.github.io/react-querybuilder/#validateQuery=true). Empty groups will have bold text on their "+Rule" button and a description of the situation where the rules normally appear.
23+
You can see an example of the default validator in action in the [demo](https://react-querybuilder.js.org/react-querybuilder/) if you check the ["Use validation" option](https://react-querybuilder.js.org/react-querybuilder/#validateQuery=true). Empty groups will have bold text on their "+Rule" button and a description of the situation where the rules normally appear.
2424

2525
### `findPath`
2626

docs/api/querybuilder.mdx

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -661,35 +661,35 @@ The `translations` prop is optional, and each top-level property in the `transla
661661

662662
### `showCombinatorsBetweenRules`
663663

664-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#showCombinatorsBetweenRules=true)
664+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#showCombinatorsBetweenRules=true)
665665

666666
Pass `true` to show the combinators (and/or) between rules and rule groups instead of at the top of rule groups. This can make some queries easier to understand as it encourages a more natural style of reading.
667667

668668
### `showNotToggle`
669669

670-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#showNotToggle=true)
670+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#showNotToggle=true)
671671

672672
Pass `true` to show the "Not" (aka inversion) toggle switch for each rule group.
673673

674674
### `showCloneButtons`
675675

676-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#showCloneButtons=true)
676+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#showCloneButtons=true)
677677

678678
### `showLockButtons`
679679

680-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#showLockButtons=true)
680+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#showLockButtons=true)
681681

682682
Pass `true` to show the "Lock rule" and "Lock group" buttons. When a rule is locked, all elements within the rule will be disabled (except for the lock button, so the user can unlock it). When a group is locked, all elements within the group header (except the lock button), as well as all child rule/group elements, will be disabled.
683683

684684
### `resetOnFieldChange`
685685

686-
`boolean` (default `true`) [_Click for demo with this feature disabled_](https://react-querybuilder.github.io/react-querybuilder/#resetOnFieldChange=false)
686+
`boolean` (default `true`) [_Click for demo with this feature disabled_](https://react-querybuilder.js.org/react-querybuilder/#resetOnFieldChange=false)
687687

688688
Pass `false` to avoid resetting the operator and value when the field changes.
689689

690690
### `resetOnOperatorChange`
691691

692-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#resetOnOperatorChange=true)
692+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#resetOnOperatorChange=true)
693693

694694
Pass `true` to reset the value when the operator changes.
695695

@@ -701,25 +701,25 @@ Pass `false` to disable the `onQueryChange` call on mount of the component which
701701

702702
### `autoSelectField`
703703

704-
`boolean` (default `true`) [_Click for demo with this feature disabled_](https://react-querybuilder.github.io/react-querybuilder/#autoSelectField=false)
704+
`boolean` (default `true`) [_Click for demo with this feature disabled_](https://react-querybuilder.js.org/react-querybuilder/#autoSelectField=false)
705705

706706
Pass `false` to add an empty option (`"------"`) to the `fields` array as the first element (which will be selected by default for new rules). When the empty field option is selected, the operator and value components will not display for that rule.
707707

708708
### `addRuleToNewGroups`
709709

710-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#addRuleToNewGroups=true)
710+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#addRuleToNewGroups=true)
711711

712712
Pass `true` to automatically add a rule to new groups. If a `query` prop is not passed in, a rule will be added to the root group when the component is mounted. If a `query` prop is passed in with an empty `rules` array, no rule will be added automatically.
713713

714714
### `independentCombinators`
715715

716-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#independentCombinators=true)
716+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#independentCombinators=true)
717717

718718
Pass `true` to insert an independent combinator selector between each rule/group in a rule group. The combinator selector at the group level will not be available. Visually, this is similar to the [`showCombinatorsBetweenRules`](#showcombinatorsbetweenrules) option, except that each combinator selector is independently controlled. You may find that users take to this configuration more easily, as it can allow them to express queries more like they would in natural language.
719719

720720
### `enableDragAndDrop`
721721

722-
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#enableDragAndDrop=true)
722+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#enableDragAndDrop=true)
723723

724724
Pass `true` to display a drag handle to the left of each group header and rule. Clicking and dragging the handle element allows visual reordering of rules and groups.
725725

@@ -731,12 +731,18 @@ Pass `true` to display a drag handle to the left of each group header and rule.
731731

732732
### `disabled`
733733

734-
`boolean | number[][]` (default `false`) [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#disabled=true)
734+
`boolean | number[][]` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#disabled=true)
735735

736736
Pass `true` to disable all subcomponents and prevent changes to the query. Pass an array of paths to disable specific rules and/or groups, e.g. `disabled={[[0]]}` will disable the first rule and its subcomponents but nothing else.
737737

738+
### `debugMode`
739+
740+
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#debugMode=true)
741+
742+
Pass `true` to log debugging information to the console.
743+
738744
### `validator`
739745

740-
`QueryValidator` [_Click for demo_](https://react-querybuilder.github.io/react-querybuilder/#validateQuery=true)
746+
`QueryValidator` [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#validateQuery=true)
741747

742748
This is a callback function that is executed each time `QueryBuilder` renders. The return value should be a boolean (`true` for valid queries, `false` for invalid) or an object whose keys are the `id`s of each rule and group in the query tree. If such an object is returned, the values associated to each key should be a boolean (`true` for valid rules/groups, `false` for invalid) or an object with a `valid` boolean property and an optional `reasons` array. The full object will be passed to each rule and group component, and all sub-components of each rule/group will receive the value associated with the rule's or group's `id`. See the [Validation](./validation) documentation for more information.

docs/api/validation.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ If you provide a query- or field-level validator function then the wrapper `<div
110110

111111
:::tip See it in action
112112

113-
In the [demo](https://react-querybuilder.github.io/react-querybuilder/), check the "Use validation" option and create an empty group or a text input without a value. Empty groups will show a message where the rules usually appear (using the `:after` pseudo-selector), and text fields without values will have a [purple](https://meyerweb.com/eric/thoughts/2014/06/19/rebeccapurple/) outline.
113+
In the [demo](https://react-querybuilder.js.org/react-querybuilder/), check the "Use validation" option and create an empty group or a text input without a value. Empty groups will show a message where the rules usually appear (using the `:after` pseudo-selector), and text fields without values will have a [purple](https://meyerweb.com/eric/thoughts/2014/06/19/rebeccapurple/) outline.
114114

115115
:::
116116

@@ -120,4 +120,4 @@ See the [validation section on the Export page](./export#validation) for more in
120120

121121
## Default validator
122122

123-
You can pass the provided [`defaultValidator`](./misc#defaultvalidator) to the `validator` prop to check for invalid combinators, empty groups, or (if `independentCombinators` is true) out-of-sequence `rules` arrays. The [demo](https://react-querybuilder.github.io/react-querybuilder/) uses the default validator.
123+
You can pass the provided [`defaultValidator`](./misc#defaultvalidator) to the `validator` prop to check for invalid combinators, empty groups, or (if `independentCombinators` is true) out-of-sequence `rules` arrays. The [demo](https://react-querybuilder.js.org/react-querybuilder/) uses the default validator.

docs/api/valueeditor.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This query builder has been specially configured in two ways:
1616

1717
:::tip
1818

19-
The [compatibility packages](../compat) also implement these options using appropriate components from the associated style library ([see the demo](https://react-querybuilder.github.io/react-querybuilder/)).
19+
The [compatibility packages](../compat) also implement these options using appropriate components from the associated style library ([see the demo](https://react-querybuilder.js.org/react-querybuilder/)).
2020

2121
:::
2222

docs/intro.mdx

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ In the query builder below, click the "+Rule" button and then the fields selecto
3535
<SandpackRQB options={{ editorHeight: 240 }}>
3636

3737
```tsx
38-
import QueryBuilder from 'react-querybuilder';
38+
import { QueryBuilder } from 'react-querybuilder';
3939
import 'react-querybuilder/dist/query-builder.scss';
4040

4141
const fields: Field[] = [
@@ -56,7 +56,7 @@ The state variable `query` will be passed to the `query` prop, and the setter me
5656

5757
```tsx
5858
import { useState } from 'react';
59-
import QueryBuilder, { Field, RuleGroupType } from 'react-querybuilder';
59+
import { QueryBuilder, Field, RuleGroupType } from 'react-querybuilder';
6060
import 'react-querybuilder/dist/query-builder.scss';
6161

6262
const fields: Field[] = [
@@ -84,7 +84,7 @@ export default () => {
8484

8585
```jsx
8686
import { useState } from 'react';
87-
import QueryBuilder from 'react-querybuilder';
87+
import { QueryBuilder } from 'react-querybuilder';
8888
import 'react-querybuilder/dist/query-builder.scss';
8989

9090
const fields = [
@@ -113,9 +113,48 @@ This documentation primarily demonstrates use of the ESM and CommonJS builds of
113113

114114
:::
115115

116+
## Exporting queries
117+
118+
To convert a query object into other formats like [SQL](https://en.wikipedia.org/wiki/SQL), [MongoDB](https://www.mongodb.com/), and [CEL](https://github.com/google/cel-spec), you can use the `formatQuery` function ([full documentation here](./api/export)). The example below demonstrates the conversion of a query to its equivalent SQL form. Modify the query by manipulating the form elements and the SQL will update accordingly.
119+
120+
<SandpackRQB options={{ editorHeight: 480 }}>
121+
122+
```tsx
123+
import { useState } from 'react';
124+
import { QueryBuilder, Field, formatQuery, RuleGroupType } from 'react-querybuilder';
125+
import 'react-querybuilder/dist/query-builder.scss';
126+
127+
const fields: Field[] = [
128+
{ name: 'firstName', label: 'First Name' },
129+
{ name: 'lastName', label: 'Last Name' },
130+
];
131+
132+
export default () => {
133+
const [query, setQuery] = useState<RuleGroupType>({
134+
combinator: 'and',
135+
rules: [
136+
{ field: 'firstName', operator: 'beginsWith', value: 'Stev' },
137+
{ field: 'lastName', operator: 'in', value: 'Vai,Vaughan' },
138+
],
139+
});
140+
141+
return (
142+
<>
143+
<QueryBuilder fields={fields} query={query} onQueryChange={q => setQuery(q)} />
144+
<h4>
145+
SQL as result of <code>formatQuery(query, 'sql')</code>:
146+
</h4>
147+
<pre>{formatQuery(query, 'sql')}</pre>
148+
</>
149+
);
150+
};
151+
```
152+
153+
</SandpackRQB>
154+
116155
## Onward and upward!
117156

118-
To discover all the options of React Query Builder, check out the [API documentation](./api/querybuilder). To play around with various configurations, check out the ["kitchen sink" demo](https://react-querybuilder.github.io/react-querybuilder/).
157+
To discover all the options of React Query Builder, check out the [API documentation](./api/querybuilder). To play around with various configurations, including other export formats and [importing from SQL](./api/import), check out the ["kitchen sink" demo](https://react-querybuilder.js.org/react-querybuilder/).
119158

120159
## Training
121160

0 commit comments

Comments
 (0)