Docyrus

Docyrus Query Builder

Author Docyrus data-source queries on a phone — columns tree, nested filters, sort, pagination, calculations, formulas, child queries and pivots, with a live Run preview and the JSON payload.

iOSAndroid
Preview Docyrus Query Builder on your device

Scan with Expo Go

Download Expo Go, then scan the QR code to preview native components.

Installation

pnpm dlx @docyrus/cli add @docyrus/rn-docyrus-query-builder
Required Packages(5 packages)
pnpm add @react-querybuilder/core react-native-reanimated react-native-gesture-handler @shopify/flash-list tailwind-variants

DocyrusDataSourceQueryBuilder is the React Native port of the web component with the same name. It uses the same query model (ISelectQueryParams) and the same hook (useDocyrusQueryBuilder). Its section editors produce the same payload for the Docyrus items endpoint (/v1/apps/{app}/data-sources/{ds}/items), so a query written on a phone can be saved and run on the web without changes, and the other way round.

The layout is built for mobile:

  • Primary tabs: Configure, Preview and JSON.
  • Configure shows one row per section with a live summary, such as "Filters · 3 rules" or "Columns · 12 selected". Tapping a row opens that section in a full-height bottom sheet (presentation="sheet", the default) or inline with a back row ("stack"). You can also push your own screen from onSectionPress.
  • Preview calls runQuery() and shows the returned rows in a horizontally scrolling read-only table, with the row count, the total and any error.
  • JSON shows the cleaned payload read-only in a monospace font, in pretty or compact form. It has a Copy button when you pass onCopy. The component adds no clipboard dependency, so wire expo-clipboard or a similar library yourself.

Every section except Select Data Source stays disabled until a data source is selected.

Works without a client

When you pass dataSources, and optionally fields, but no client, every configure section still works offline. Only Run needs a client: without one, it reports that authentication is required. With a client, the builder:

  • discovers data sources (/v1/apps/data-sources)
  • loads the selected source's schema including enums (/v1/apps/{app}/data-sources/{ds}?expand=enums)
  • loads user, team, role and org-unit filter options (/v1/users, /v1/teams, /v1/users/acl/roles, /v1/users/acl/hierarchy-units)
  • loads relation filter pickers (…/items?columns=id,name)
  • loads parent and child field groups (/v1/dev/data-sources/:id/fields?expand=parent,child)
  • runs the query (/items)

Usage

import { useState } from 'react';

import * as Clipboard from 'expo-clipboard';

import { useDocyrusClient } from '@docyrus/signin/react-native';

import {
  DocyrusDataSourceQueryBuilder,
  type ISelectQueryParams
} from '@/components/docyrus-native/docyrus-query-builder';

export function QueryScreen() {
  const client = useDocyrusClient();
  const [value, setValue] = useState<Partial<ISelectQueryParams>>({});

  return (
    <DocyrusDataSourceQueryBuilder
      client={client}
      value={value}
      onChange={setValue}
      enableCalculations
      enableChildQueries
      onCopy={json => void Clipboard.setStringAsync(json)}
      className="flex-1" />
  );
}

Offline, with a fixed data source

<DocyrusDataSourceQueryBuilder
  value={{ dataSourceId: 'ds-contact', dataSourceFullSlug: 'crm.contact', limit: 25 }}
  onChange={setValue}
  dataSources={[contactDataSource]}
  lockDataSource
  presentation="stack" />

Pushing sections as screens

When onSectionPress returns true, the builder does not open the section itself. Render the matching section editor on your own screen inside a DSQBContext provider that holds the builder's hook result:

const dsqb = useDocyrusQueryBuilder({ value, onChange, client });

<DSQBContext value={dsqb}>
  <DSQBFiltersEditor />
</DSQBContext>

Sections

SectionWeb counterpartNative editor
Select Data SourceTwo panes: grouped list and field tableA searchable list grouped by app, with collapsible groups (search opens every group), plus a card for the selected source whose field list you can expand. Hidden by lockDataSource. Picking a source closes the sheet.
ColumnsTreeView multi-selectThe native TreeView with checkboxes. Leaf ids are paths (status|id → status(id), company|owner|email → company(owner(email))). User and enum fields expand into fixed sub-field folders. The Parent Data Sources switch nests a parent's fields under the relation column that points to it. Shows the generated columns string.
Filtersreact-querybuilder QueryBuilderDocyrusThe native QueryBuilderDocyrus, driven by getOperatorsForFieldType, user / team / role / unit option sources (createDocyrusOperatorValueConfig) and relation record pickers, plus the full-text filterKeyword. The id-bearing rule tree is kept locally and rebuilt only when value.filters changes from outside (web #238).
SortField selector, ASC/DESC, drag handleField selector sheet, ASC/DESC toggle, Move up / Move down and remove
PaginationLimit (with presets), offset, full countSame controls: number inputs, preset chips and a fullCount switch
Calculations (enableCalculations)Aggregate rows with an Advanced collapsibleAggregate Select, field, alias, and an Advanced section (distinct, min/max, number type), with move up/down
Formulas (enableFormulas)Nested block cards with dragNested block cards with a colour chip per kind and a coloured left border. Each card has kind, cast and tz controls. Add / insert first / remove / move up / move down replace drag. Inline or subquery formulas (from / with). Formula keys are renamed when editing ends.
Child Queries (enableChildQueries)Child data-source picker and per-entry cardsSame flow. Opening the section turns on relatedExpand.child. value.childQueries is an array, and each entry's alias is injected into the parent columns (the items endpoint drops the child block without it) and removed from them again when the entry is deleted. Each card shows from / using read-only, a columns tree, order by, direction and limit.
Pivot (enablePivot)Matrix entriesMatrix entry cards (using, columns, spread, and an optional date range typed as ISO text), move up/down, plus hideEmptyRows / limit

API Reference

DocyrusDataSourceQueryBuilderProps

PropTypeDefaultDescription
valuePartial<ISelectQueryParams>-Required. The current query payload (controlled).
onChange(value: Partial<ISelectQueryParams>) => void-Required. Receives the next payload. dataSourceId, dataSourceFullSlug and showGroupSummaries are removed from it.
clientDocyrusDataSourceQueryBuilderClient | nullnullAn authenticated client, which only needs get. It enables discovery, filter option sources, related fields and Run.
fieldsIField[][]Fallback field list, used when the selected source has no fields.
dataSourcesIDataSourceReference[][]Static data sources. Used when there is no client, and as a fallback when discovery fails.
localeUiI18nLocale'en'Locale exposed on the context.
size'sm' | 'default' | 'lg''default'Text size of section titles and summaries.
variant'default' | 'bordered' | 'compact''default'Visual style.
classNamestring-Root container className. The root is flex-1, so give it a height.
defaultSectionDSQBSection-Section to open on mount (as a sheet or inline). Leave it out to start on the section list.
lockDataSourcebooleanfalseFixes the data source to the one in value: hides the data-source section and the clear button.
enableCalculationsbooleanfalseShows the Calculations section.
enableFormulasbooleanfalseShows the Formulas section.
enableChildQueriesbooleanfalseShows the Child Queries section.
enablePivotbooleanfalseShows the Pivot section.
presentation'stack' | 'sheet''sheet''sheet' opens a tapped section in a full-height bottom sheet. 'stack' shows it inline, in place of the list, with a back row.
onSectionPress(section: DSQBSection) => boolean | void-Called when a section row is tapped. Return true to handle navigation yourself.
onCopy(json: string) => void-Copy handler for the JSON tab. The Copy button is hidden when this is omitted.
filterControlElementsPartial<QBControlElements>-Control-element overrides for the Filters QueryBuilderDocyrus. They are merged over the defaults. Pass a stable reference.
renderFilterValueEditor(props: ValueEditorProps, context: unknown) => ReactNode | undefined-Replaces the value editor of a rule. Return undefined to keep the default editor. Ignored when filterControlElements.valueEditor is set.
filterContextunknown-Passed to renderFilterValueEditor as its second argument.

DSQBFieldSelector

PropTypeDefaultDescription
fieldsIField[]-Fields to pick from. They are grouped by category (text, numeric, date, select, relation, user, boolean, other).
valuestring-Slug of the selected field.
onSelect(slug: string) => void-Called when a field is picked.
placeholderstring'Select field...'Text on the trigger when nothing is selected.
titlestringplaceholderTitle of the sheet.
size'sm' | 'default' | 'lg''default'Size of the trigger.
showTypeIconbooleantrueShows the columns icon on the trigger.
disabledbooleanfalseDisables the trigger.
classNamestring-className for the trigger.

DSQBJsonPreview

PropTypeDefaultDescription
valuePartial<ISelectQueryParams>-Query payload. It is cleaned with sanitizeSelectQueryParams and cleanPayload before display.
onCopy(json: string) => void-Shows the Copy button.
classNamestring'flex-1 gap-2'Container className.

DSQBFormulaBlock

PropTypeDefaultDescription
blockIQueryFormulaBlock-The block node.
onChange(block: IQueryFormulaBlock) => void-Replaces the node.
onRemove() => void-Shows the remove button.
onMoveUp / onMoveDown() => void-Native only. Shows the move buttons, which replace drag.
fieldsArray<{ slug: string; name: string }>-Fields offered by column blocks.
depthnumber0Nesting depth, used for indentation.

The other section editors take no props. They read everything through useDSQB().

useDocyrusQueryBuilder(options)

It takes UseDocyrusQueryBuilderOptions: value, onChange, client, fields, dataSources, locale and size. It returns UseDocyrusQueryBuilderResult. The hook uses no React Query.

FieldTypeDescription
value / updateValue(patch)Partial<ISelectQueryParams> / (patch) => voidCurrent payload, and a patch writer that sanitizes the result.
fieldsIField[]The selected source's fields, or the fields option as a fallback.
filterOptionSourcesDocyrusQueryBuilderOptionSourcesUsers, teams, roles and units for filter pickers.
relationValuesByFieldRecord<string, DocyrusQueryBuilderOption[]>Related records (id and name) for each relation field slug.
dataSources, dataSourcesStatus, dataSourcesError, reloadDataSources()—Discovery state.
selectedDataSource, selectDataSource(ds), unselectDataSource()—Selection. Selecting a source replaces the payload with { dataSourceId, dataSourceFullSlug, limit: 25 }. Unselecting clears it.
dataSourceDetailStatus, dataSourceDetailError, reloadSelectedDataSource()—Detail fetch with enums.
ensureDataSourceFields(id)(id: string) => Promise<IField[]>Lazy-loads the schema of a related source.
fetchRelatedFields(expand)(expand: Array<'parent' | 'child'>) => Promise<DSQBRelatedFields>Parent and child field groups.
relatedExpand / setRelatedExpandDSQBRelatedExpand / Dispatch<SetStateAction<…>>Expansion state kept in the hook. The fetch is de-duplicated on a <dataSourceId>::<expand> key, and a failed attempt stays pinned to that key.
relatedFields, relatedFieldsLoading—The resolved groups.
preview, runQuery()DSQBPreviewState / () => Promise<void>Run state.
locale, size—Echoed from the options.

Context

DSQBContext and useDSQB() hold a DSQBContextValue: the hook result plus filterControlElements, renderFilterValueEditor and filterContext. useDSQB() throws when it is called outside the builder.

Components

ComponentDescription
DocyrusDataSourceQueryBuilderRoot: the Configure / Preview / JSON tabs, the section list and the sheets
DSQBDataSourceSelectorData-source section
DSQBColumnsEditorColumns tree section
DSQBFiltersEditorFilters section (keyword and QueryBuilderDocyrus)
DSQBOrderByEditorSort section
DSQBPaginationEditorPagination section
DSQBCalculationsEditorCalculations section
DSQBFormulaEditor / DSQBFormulaBlockFormulas section and a single block node
DSQBChildQueriesEditorChild Queries section
DSQBPivotEditorPivot section
DSQBRunPreviewRun and result table
DSQBJsonPreviewJSON payload view
DSQBFieldSelectorSearchable field picker in a sheet

Hooks, constants & utilities

ExportDescription
useDocyrusQueryBuilder, useDSQB, DSQBContextHook and context
createDocyrusOperatorValueConfig(fieldType, sources)Per-operator value options and editor types for user and follower fields
loadDocyrusQueryBuilderOptionSources(client)Fetches users, teams, roles and units
docyrusQueryBuilderVariantstv() slot styles (variant / size)
FILTER_OPERATOR_CATEGORIES, ALL_FILTER_OPERATORSFilter operator catalog
FUNCTION_CATEGORIES, ALL_ALLOWED_FUNCTIONS, ALLOWED_AGGREGATES, ALLOWED_CAST_TYPES, DATE_FORMULASAllowed functions, aggregates, casts and date formulas
BUILTIN_NAMES, EXTRACT_PARTS, MATH_OPS, COMPARE_OPS, BOOLEAN_OPSFormula operators
BLOCK_KINDS, BLOCK_KIND_LABELS, BLOCK_KIND_COLORSFormula block kinds
QUERY_MODES, QUERY_MODE_DESCRIPTIONS, FILTER_TYPES, NUMBER_TYPES, DATE_RANGE_INTERVALSEnumerations
parseColumnString, serializeColumnsColumn DSL parser and serializer (alias:func[args]@field(sub), ...spread)
normalizeOrderBy, serializeOrderByOrder-by normalization
buildDefaultColumns, cleanPayloadPayload helpers
getFieldTypeCategory, getOperatorsForFieldTypeField-type helpers
validateQuery(params, fields)Validation errors and warnings. On native, a filter rule on a field that is not in a non-empty fields list is reported as a warning.
countFilterRulesCounts leaf rules
createBlock, updateBlockAt, removeBlockAt, insertBlockAt, getBlockLabelFormula-block tree helpers
prepareRuleGroup, toRuleGroup, fromRuleGroupNative only. Local id-stamping and the IQueryFilterGroup ⇄ rule-tree bridge, so the component does not import react-querybuilder

Type Exports

TypeDescription
DocyrusDataSourceQueryBuilderPropsRoot props
DocyrusDataSourceQueryBuilderClient{ get(path, params?) }
UseDocyrusQueryBuilderOptions / UseDocyrusQueryBuilderResult / DSQBContextValueHook and context
DSQBPrimaryTab / DSQBSection / DSQBPresentation'configure' | 'preview' | 'json', the section ids, 'stack' | 'sheet'
DSQBFilterValueEditorRendererType of renderFilterValueEditor
DSQBPreviewState{ status, rows, columns, total?, error?, raw? }
DocyrusQueryBuilderOption / DocyrusQueryBuilderOptionSourcesFilter picker options
ISelectQueryParamsFull query payload
IQueryFilterGroup / IQueryFilterRule / QueryFilterTypeFilters
ISelectQueryOrderBy / ISelectQueryCalculationRule / AggregateFunction / NumberTypeSort and calculations
IQueryFormula / IQueryBlockInlineFormula / IQueryBlockSubqueryFormula / IQueryFormulaBlock / BlockKindFormulas
IBlockLiteral … IBlockBoolean, BuiltinName, ExtractPart, MathOp, CompareOp, BooleanOpBlock AST
IQueryChildQueryParamsA child query entry (alias, from, using, columns?, filters?, calculations?, orderBy?, limit?)
ISelectPivot / ISelectPivotMatrixQuery / DateRangeIntervalPivot
QueryMode / ExpandTypeEnumerations
IDataSourceReferenceA data source with fields
DSQBParentFieldGroup / DSQBChildFieldGroup / DSQBRelatedFields / DSQBRelatedExpandRelated field groups
IQueryValidationError / ParsedColumnValidation and column DSL
IField / IFieldType / UiI18nLocaleField model
ValueEditorType / DSQBRuleType / DSQBRuleGroupTypeNative only. Local structural react-querybuilder types

Differences from web

  • Removed: aiAssistantOpen, onAiAssistantOpenChange, renderAiAssistant, useApplyQuery, IQueryBuilderAiAssistantRenderContext and the Cody agent toggle.
  • Added: presentation, onSectionPress, onCopy, renderFilterValueEditor.
  • Changed: filterControlElements uses the native QBControlElements slot map. The web version uses react-querybuilder's ControlElementsProp. filterContext goes to renderFilterValueEditor, because the native builder has no context prop.
  • Changed: defaultSection defaults to no open section. The web version always shows one section.
  • Replaced interactions: Drag handles in Sort and Formulas become move up / move down buttons. Pivot date-range bounds are ISO text inputs instead of datetime-local.

Translations

All copy goes through useUiTranslation() under ui.docyrusQueryBuilder.*, with English fallbacks. The web component hard-codes English, so these keys are new: selectDataSource, columns, filters, sort, pagination, calculations, formulas, childQueries, pivot and their *Description keys, configure, preview, run, runQuery, running, searchFields, selectField, parentDataSources, allColumnsReturned, selected, keyword, filterRules, addSortRule, limit, offset, fullCount, addCalculation, advanced, distinct, addFormula, addInput, addWhen, addChildDataSource, addMatrixEntry, moveUp, moveDown, remove, copy, copied, pretty, compact, jsonOutput, noRows, runError, selectDataSourceFirst, the category* field-group labels and the empty or loading state messages.

On this page