React-Awesome-Query-Builder

repository·master·Indexed 24 days ago

https://github.com/ukrbublik/react-awesome-query-builder

A highly configurable React library for building complex query builders (filters). It supports multiple UI frameworks including Ant Design, Bootstrap, Fluent UI, Material-UI v4, and MUI. The library includes a core package (@react-awesome-query-builder/core) for server-side query manipulation without a UI, providing utilities to export query trees into various formats such as SQL, MongoDB, JSONLogic, Elasticsearch, and SpEL.

Tokens
40.1K
Snippets
54
Records
219
Agent score
79%

What's inside react-awesome-query-builder

  1. Overview of React-Awesome-Query-Builder

    master

    React-Awesome-Query-Builder is a highly configurable, user-friendly React component designed to build complex queries (filters). It is inspired by jQuery QueryBuilder and supports various UI frameworks including Ant Design, Material-UI (MUI), Bootstrap, and Fluent UI.

    Key capabilities include:

    • Complex Data Types: Supports simple types (string, number, bool, date/time, list) and complex types (structs, arrays).
    • Advanced Query Logic: Supports aggregation (e.g., COUNT OF users WHERE ... > 5), field-to-field comparisons, and nested functions.
    • Flexible Operators: Supports binary, unary, 'between', and complex operators like 'proximity'.
    • Ternary Mode: Supports if-then-else logic.
    • Multi-format Export/Import: Export to MongoDB, SQL, JsonLogic, SpEL, or ElasticSearch; Import from JsonLogic, SpEL, or SQL.
    • UI Features: Drag-and-drop reordering for rules and groups, and support for saving/loading query values and configurations from a server.
  2. Use config.ctx to manage non-serializable logic

    master

    The config.ctx (Context) is a collection of JavaScript functions and React components used to isolate non-serializable parts of your configuration. This is essential when you want to serialize your configuration to JSON (creating a zipConfig).

    The Pattern:

    1. Instead of importing modules directly into your fields or widgets config, add them to ctx.
    2. In your configuration, refer to these items by their string name.
    3. Use Utils.ConfigUtils.decompressConfig(zipConfig, BaseConfig, ctx) to reconstruct the full configuration.

    Example Workflow:

    import { BasicConfig } from '@react-awesome-query-builder/ui';
    
    // 1. Define the serializable part (zipConfig)
    const zipConfig = {
      fields: {
        firstName: {
          type: "text",
          fieldSettings: {
            validateValue: "validateFirstName", // Reference by name
          }
        },
      },
      settings: {
        useConfigCompress: true,
      },
    };
    
    // 2. Define the non-serializable part (ctx)
    const ctx = {
      ...BasicConfig.ctx,
      validateFirstName: (val: string) => val.length < 10,
    };
    
    // 3. Reconstruct
    const config = Utils.ConfigUtils.decompressConfig(zipConfig, BasicConfig, ctx);
    import {BasicConfig} from '@react-awesome-query-builder/ui';
    
    const fields = {
      firstName: {
        type: "text",
        fieldSettings: {
          // use function `validateFirstName` from `ctx` by name
          validateValue: "validateFirstName",
        }
      },
    };
    
    const ctx = {
      ...BasicConfig.ctx,
      validateFirstName: (val: string) => {
        return (val.length < 10);
      },
    };
    
    // `zipConfig` can be passed to backend as JSON
    const zipConfig = {
      fields,
      settings: {
        useConfigCompress: true, // this is required to use Utils.ConfigUtils.decompressConfig()
      },
      // you can add here other sections like `widgets` or `types`, but don't add `ctx`
    };
    
    // Config can be loaded from backend with providing `ctx`
    const config = Utils.ConfigUtils.decompressConfig(zipConfig, BasicConfig, ctx);
  3. Understand the Config Context (ctx)

    master

    Starting from version 6.3.0, the ctx (Config Context) property is an obligatory part of the configuration.

    ctx is a collection of functions and React components used by other parts of the configuration via reference. Its primary purpose is to isolate non-serializable parts of the configuration (like functions or components) from the rest of the JSON-serializable config.

    When manually constructing a config object (instead of destructuring an existing one like MuiConfig), you must explicitly include ctx.

  4. Understand the package architecture

    master

    The library is modularized into several packages to allow for different use cases (frontend vs. backend) and UI preferences:

    • @react-awesome-query-builder/core: Contains core functionality for importing/exporting and storing queries, along with utility functions. Use this on the server-side (Node.js) to perform exports (e.g., to SQL) for security.
    • @react-awesome-query-builder/ui: Provides core React components like <Query> and <Builder>, CSS, and basic (vanilla) widgets. It re-exports from core.
    • Framework-specific packages: These provide configurations with specific UI widgets and re-export from ui. Use these on the frontend:
      • @react-awesome-query-builder/antd: Ant Design widgets.
      • @react-awesome-query-builder/mui: MUI widgets.
      • @react-awesome-query-builder/bootstrap: Bootstrap widgets.
      • @react-awesome-query-builder/fluent: Fluent UI widgets.
      • @react-awesome-query-builder/material: Material-UI v4 widgets (deprecated).

    Dependency Flow: core $\rightarrow$ ui $\rightarrow$ [framework-specific packages]

  5. Understand the @react-awesome-query-builder/sandbox-next architecture

    master

    The sandbox-next package is a Next.js demo application designed to demonstrate Server-Side Rendering (SSR) capabilities with @react-awesome-query-builder.

    Key Concepts

    SSR with Session Data

    To enable SSR, the application saves and loads two primary pieces of data from a session (using Redis or a local JSON file via lib/withSession.ts):

    • jsonTree: The query value in JSON format (obtained via Utils.getTree()).
    • zipConfig: A compressed query configuration in JSON format (obtained via Utils.ConfigUtils.compressConfig()).

    Server-Side API Endpoints

    The application uses several Next.js API routes to manage state and data conversion:

    • /api/tree: Manages the jsonTree. It can save the tree to the session via POST and load it via GET. It also performs server-side conversion of the tree into formats like JsonLogic, SQL, MongoDB, and SpEL.
    • /api/config: Manages the zipConfig. It can save the compressed config via POST and load it via GET.
    • /api/autocomplete: Provides autocomplete functionality (used by asyncFetch).

    Configuration Lifecycle

    The configuration (zipConfig) is generated on the server-side by:

    1. Starting with CoreConfig from @react-awesome-query-builder/core.
    2. Adding fields, functions, and overrides in lib/config_base.ts.
    3. Adding UI mixins (like asyncFetch, custom React components, and factory overrides) in lib/config.tsx.
    4. Compressing the result using Utils.ConfigUtils.compressConfig().
  6. Understand the React-Awesome-Query-Builder configuration format

    master

    The configuration object is the core of the library and is divided into 8 main sections: conjunctions, operators, widgets, types, funcs, settings, fields, and ctx.

    To implement a query builder, you typically start by reusing a base configuration (like BasicConfig, AntdConfig, or MuiConfig) and then overriding specific parts such as fields or settings. You can also extend the builder by adding your own custom types, widgets, or operators (including logical conjunctions like XOR or NOR).

    {
      conjunctions, 
      operators, 
      widgets, 
      types, 
      funcs, 
      settings, 
      fields, 
      ctx
    }
  7. Install @react-awesome-query-builder/mui

    master

    To use MUI widgets with React Awesome Query Builder, you must install the package along with its required MUI peer dependencies. Ensure you have @mui/material, @emotion/react, @emotion/styled, @mui/icons-material, @mui/x-date-pickers, and @mui/base installed in your project.

    npm i @mui/material @emotion/react @emotion/styled @mui/icons-material @mui/x-date-pickers @mui/base --save
    npm i @react-awesome-query-builder/mui --save
  8. Run the @react-awesome-query-builder/sandbox-simple demo locally

    master

    You can run the sandbox-simple demo app locally using two different methods depending on whether you want to use the local repository packages or the published NPM packages.

    Method 1: Using local repository packages

    If you have cloned the entire react-awesome-query-builder repository, run this command from the root of the repository to use the local @react-awesome-query-builder/* packages:

    pnpm sandbox-js

    Method 2: Using NPM packages

    If you only want to run the sandbox_simple directory, navigate into it and run:

    npm run preinstall
    npm i
    npm start

    After running either method, open http://localhost:5174 in your browser. You can experiment with the code located in the src/demo directory.

  9. Install @react-awesome-query-builder/material

    master

    To use the Material-UI v4 widgets, you must install the package along with its required peer dependencies from the @material-ui ecosystem.

    First, install the peer dependencies:

    npm i @material-ui/core @material-ui/lab @material-ui/icons @material-ui/pickers --save

    Then, install the package itself:

    npm i @react-awesome-query-builder/material --save
    npm i @material-ui/core @material-ui/lab @material-ui/icons @material-ui/pickers --save
    npm i @react-awesome-query-builder/material --save
  10. Migrate Config Context (v6.3.0+)

    master

    Version 6.3.0 introduced the ctx property.

    If you destructure a base config:

    const config = { ...MuiConfig, fields: { ... } };

    No changes are needed because ctx is copied automatically.

    If you define a config manually: You must explicitly add ctx from the base config:

    const config = {
      ctx: MuiConfig.ctx, // Required
      conjunctions,
      operators,
      // ...
    };

    Note on overriding render* functions: If you override a render* function in settings and call the original function from the imported config, you must pass ctx as the second argument.

    config = {
      ...MuiConfig,
      settings: {
        ...MuiConfig.settings,
        renderField: (props) => (
          <WithTheme theme={theme}>
            { MuiConfig.settings.renderField?.(props, MuiConfig.ctx) }  // Pass ctx here
          </WithTheme>
        ),
      }
    };