UNPKG

@bitrix24/b24jssdk

Version:

Bitrix24 REST API JavaScript SDK

1 lines 10.4 kB
{"version":3,"file":"filter-v3.mjs","sources":["../../../src/tools/filter-v3.ts"],"sourcesContent":["import { SdkError } from '../core/sdk-error'\n\n/**\n * The eight — and only eight — comparison operators the Bitrix24 REST API v3\n * filter grammar accepts. Anything else is rejected server-side with\n * `UNKNOWNFILTEROPERATOREXCEPTION`.\n */\nexport type FilterV3Operator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'in' | 'between'\n\nconst FILTER_V3_OPERATORS: readonly FilterV3Operator[] = ['=', '!=', '>', '>=', '<', '<=', 'in', 'between']\n\n/**\n * A single condition in short-form: `[field, operator, value]`.\n */\nexport type FilterV3Condition = [string, FilterV3Operator, unknown]\n\n/**\n * A logical group of conditions / nested groups. `logic` defaults to `'and'`;\n * `negative: true` wraps the whole group in a NOT.\n */\nexport interface FilterV3Group {\n logic?: 'and' | 'or'\n negative?: boolean\n conditions: FilterV3Node[]\n}\n\nexport type FilterV3Node = FilterV3Condition | FilterV3Group\n\nfunction condition(field: string, operator: FilterV3Operator, value: unknown): FilterV3Condition {\n if (typeof field !== 'string' || field.length === 0) {\n throw new SdkError({\n code: 'JSSDK_FILTER_V3_INVALID_FIELD',\n description: `FilterV3: field name must be a non-empty string, got ${JSON.stringify(field)}.`,\n status: 400\n })\n }\n if (!FILTER_V3_OPERATORS.includes(operator)) {\n throw new SdkError({\n code: 'JSSDK_FILTER_V3_INVALID_OPERATOR',\n description: `FilterV3: operator \"${operator}\" is not one of ${FILTER_V3_OPERATORS.join(' ')}.`,\n status: 400\n })\n }\n return [field, operator, value]\n}\n\n/**\n * Typed builder for Bitrix24 REST API **v3** filters (the array-of-triples\n * dialect with AND/OR/NOT groups — see the v3 reference §3). Produces exactly\n * the structures the server accepts, so a bad operator or a malformed\n * `in` / `between` value fails fast on the client instead of as a server 400.\n *\n * @example\n * import { FilterV3 as F } from '@bitrix24/b24jssdk'\n *\n * // status = NEW AND (id in [1,2] OR id > 100)\n * const filter = F.build(\n * F.eq('status', 'NEW'),\n * F.or(\n * F.in('id', [1, 2]),\n * F.gt('id', 100)\n * )\n * )\n * await b24.actions.v3.call.make({ method: 'tasks.task.list', params: { filter } })\n */\nexport const FilterV3 = Object.freeze({\n /** `field = value` */\n eq(field: string, value: unknown): FilterV3Condition {\n return condition(field, '=', value)\n },\n /** `field != value` */\n ne(field: string, value: unknown): FilterV3Condition {\n return condition(field, '!=', value)\n },\n /** `field > value` */\n gt(field: string, value: unknown): FilterV3Condition {\n return condition(field, '>', value)\n },\n /** `field >= value` */\n ge(field: string, value: unknown): FilterV3Condition {\n return condition(field, '>=', value)\n },\n /** `field < value` */\n lt(field: string, value: unknown): FilterV3Condition {\n return condition(field, '<', value)\n },\n /** `field <= value` */\n le(field: string, value: unknown): FilterV3Condition {\n return condition(field, '<=', value)\n },\n /** `field in [values]` — `values` must be a non-empty array. */\n in(field: string, values: unknown[]): FilterV3Condition {\n if (!Array.isArray(values) || values.length === 0) {\n throw new SdkError({\n code: 'JSSDK_FILTER_V3_INVALID_IN',\n description: `FilterV3.in(\"${field}\"): value must be a non-empty array.`,\n status: 400\n })\n }\n return condition(field, 'in', values)\n },\n /** `field between [from, to]` — inclusive range of exactly two defined operands. */\n between(field: string, from: unknown, to: unknown): FilterV3Condition {\n if (from === undefined || from === null || to === undefined || to === null) {\n throw new SdkError({\n code: 'JSSDK_FILTER_V3_INVALID_BETWEEN',\n description: `FilterV3.between(\"${field}\"): both range operands must be defined (got [${String(from)}, ${String(to)}]).`,\n status: 400\n })\n }\n return condition(field, 'between', [from, to])\n },\n\n /** Combine nodes with AND (for nesting inside an OR; the top level is already AND). */\n and(...conditions: FilterV3Node[]): FilterV3Group {\n return { logic: 'and', conditions }\n },\n /** Combine nodes with OR. */\n or(...conditions: FilterV3Node[]): FilterV3Group {\n return { logic: 'or', conditions }\n },\n /**\n * Negate a condition or group (wraps it in a NOT). A bare condition is wrapped\n * in a single-item AND group so the `negative` flag has somewhere to live.\n * Returns a fresh group (the input's `conditions` array is copied, not shared).\n */\n not(node: FilterV3Node): FilterV3Group {\n if (isGroup(node)) {\n return { ...node, conditions: [...node.conditions], negative: true }\n }\n return { logic: 'and', negative: true, conditions: [node] }\n },\n\n /**\n * Assemble the top-level filter array (its elements are AND-joined) ready to\n * pass as `params.filter`. Falsy nodes are skipped, so you can inline\n * conditionals: `F.build(F.eq('a', 1), flag && F.gt('b', 2))`.\n *\n * Always wrap with `build` (or an array) even for a single condition —\n * `params.filter` must be an array, so pass `build(F.eq('a', 1))`, not the bare\n * `F.eq('a', 1)`. Each surviving node is shape-checked, so a forgotten spread\n * (`build([F.eq(...)])`) or a hand-rolled malformed triple fails fast here\n * instead of as an opaque server error.\n */\n build(...nodes: Array<FilterV3Node | false | null | undefined>): FilterV3Node[] {\n const result = nodes.filter(Boolean) as FilterV3Node[]\n for (const node of result) {\n assertNode(node)\n }\n return result\n }\n})\n\nfunction isGroup(node: unknown): node is FilterV3Group {\n return !Array.isArray(node) && typeof node === 'object' && node !== null && 'conditions' in node\n}\n\nfunction assertNode(node: FilterV3Node): void {\n if (isGroup(node)) {\n return\n }\n const ok = Array.isArray(node)\n && node.length === 3\n && typeof node[0] === 'string'\n && FILTER_V3_OPERATORS.includes(node[1] as FilterV3Operator)\n if (!ok) {\n throw new SdkError({\n code: 'JSSDK_FILTER_V3_INVALID_NODE',\n description: `FilterV3.build: each node must be a [field, operator, value] condition or a group — got ${JSON.stringify(node)}. Did you forget to spread (build(...nodes)) or build a condition with FilterV3 helpers?`,\n status: 400\n })\n }\n}\n"],"names":[],"mappings":"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"}