Fields and operators
Enhancing the query builder with fields from the sample sales data set
Fields#
Now we'll add fields from the sample sales data set. This is a randomized data set with columns for location, item type, dates, quantities and totals. Each field will need name
and label
attributes. We'll come back to that later and augment the field names and labels with some other attributes to configure the behavior of the query builder in a later lesson.
Let's split this out into a separate file, fields.ts
, because it can get quite large. Create a new file called fields.ts
in the client/src/
folder.
import { Field } from "react-querybuilder";
const fields: Field[] = [
{
name: "order_id",
label: "Order ID",
},
{
name: "region",
label: "Region",
},
{
name: "country",
label: "Country",
},
{
name: "item_type",
label: "Item Type",
},
{
name: "sales_channel",
label: "Sales Channel",
},
{
name: "order_priority",
label: "Order Priority",
},
{
name: "order_date",
label: "Order Date",
},
{
name: "ship_date",
label: "Ship Date",
},
{
name: "units_sold",
label: "Units Sold",
},
{
name: "unit_price",
label: "Unit Price",
},
{
name: "unit_cost",
label: "Unit Cost",
},
{
name: "total_revenue",
label: "Total Revenue",
},
{
name: "total_cost",
label: "Total Cost",
},
{
name: "total_profit",
label: "Total Profit",
},
];
export default fields;
Make sure you include them in the query builder props in App.tsx
by changing the fields
assignment and adding the following import:
// App.tsx
import fields from "./fields";
// ...
<QueryBuilder fields={fields} { } />
View the application and check that all the new fields are available to choose from the drop-down list.
We have a working query builder now, but all the fields have the same options (meaning the operators and value editors are the defaults). What we really want to do is tailor the operators and value editors to each specific field so that users get an optimal experience.
Operators#
There are two ways to configure operators in React Query Builder:
the
getOperators
prop at query levelthe
operators
attribute at field level
We're going to use the getOperators
method in order to keep all our operator configuration in the same place. To configure the operators with the getOperators
prop, we will again split this out into a separate file to keep things nice and tidy in our App.tsx
file.
Create a new file called getOperators.ts
in the client/src/
folder.
import { defaultOperators, NameLabelPair } from "react-querybuilder";
const getOperators = (field: string): NameLabelPair[] => {
switch (field) {
case "order_date":
case "ship_date":
return [
{ name: "=", label: "is" },
{ name: "!=", label: "is not" },
{ name: "<", label: "is before" },
{ name: ">", label: "is after" },
{ name: "<=", label: "is on or before" },
{ name: ">=", label: "is on or after" },
{ name: "null", label: "is blank" },
{ name: "notNull", label: "is not blank" },
];
case "order_id":
case "units_sold":
case "unit_price":
case "unit_cost":
case "total_revenue":
case "total_cost":
case "total_profit":
return [
{ name: "=", label: "is" },
{ name: "!=", label: "is not" },
{ name: "<", label: "is less than" },
{ name: ">", label: "is greater than" },
{ name: "<=", label: "is less than or equal to" },
{ name: ">=", label: "is greater than or equal to" },
{ name: "null", label: "is blank" },
{ name: "notNull", label: "is not blank" },
];
default:
return defaultOperators;
}
};
export default getOperators;
The date fields in our data set, order_date
and ship_date
, will get date-related operators ("is before", "is after", etc), while numeric fields will get number-related operators ("is greater than", "is less than", etc). The remaining fields will get the default operators, which we can import from react-querybuilder
.
And once again, include the new function in the query builder props.
// App.tsx
import getOperators from "./getOperators";
// ...
<QueryBuilder getOperators={getOperators} { } />
View the application and make sure the correct operators are available when you choose specific fields.
Let's take a look at the App.tsx
file as it stands now.
import React, { useState } from "react";
import QueryBuilder, { formatQuery, RuleGroupType } from "react-querybuilder";
import fields from "./fields";
import getOperators from "./getOperators";
function App() {
const [query, setQuery] = useState<RuleGroupType>({
id: "root",
combinator: "and",
rules: [],
});
return (
<>
<QueryBuilder
fields={fields}
getOperators={getOperators}
query={query}
onQueryChange={(q) => setQuery(q)}
/>
<pre>{formatQuery(query, "sql")}</pre>
<pre>{formatQuery(query, "json")}</pre>
</>
);
}
export default App;