@adiba-banking-cloud/filter-builder
v0.1.1
Published
Framework-agnostic OData filter builder utilities for ADIBA SDKs and apps
Downloads
317
Readme
@adiba-banking-cloud/filter-builder
Framework-agnostic OData filter builder utilities for ADIBA SDKs and apps.
This package helps you build OData-style filter expressions such as:
partyName eq 'Patrica' and status eq 'ACTIVE' and age ge 10It is intentionally small:
- no React dependencies
- no SDK-specific assumptions
- no built-in URL construction
The package builds the filter expression only. The calling package is responsible for encoding it and attaching it to a request.
Install
npm install @adiba-banking-cloud/filter-builderExports
buildODataFilter(...)and(...)or(...)
When To Use
Use this package when:
- your backend expects OData-style filter expressions
- you want a typed way to build rules like
eq,ge,contains, and grouped conditions - you want to reuse filter-building logic across SDKs and apps
Do not use this package when:
- your backend expects plain query params like
status=ACTIVE&type=Organization - your backend uses a different filter syntax
- you want a package that constructs the full request URL for you
Core API
buildODataFilter(input, options?)
Builds an OData filter expression from either:
- an array of rules
- a grouped condition created with
and(...)oror(...)
Top-level arrays use and by default.
buildODataFilter(rules);
buildODataFilter(rules, { topLevelLogic: "or" });and(...filters)
Creates a grouped and expression.
or(...filters)
Creates a grouped or expression.
Quick Start
import { buildODataFilter } from "@adiba-banking-cloud/filter-builder";
const filter = buildODataFilter([
{ field: "partyName", operator: "eq", value: "Patrica" },
{ field: "status", operator: "eq", value: "ACTIVE" },
{ field: "age", operator: "ge", value: 10 },
]);
// partyName eq 'Patrica' and status eq 'ACTIVE' and age ge 10Returned value:
"partyName eq 'Patrica' and status eq 'ACTIVE' and age ge 10"Using In A URL
This package returns a plain filter expression. If you are sending it in a URL, encode it yourself:
import { buildODataFilter } from "@adiba-banking-cloud/filter-builder";
const expression = buildODataFilter([
{ field: "status", operator: "eq", value: "ACTIVE" },
{ field: "type", operator: "eq", value: "Organization" },
]);
const url = `/re/clients?filter=${encodeURIComponent(expression)}`;Resulting expression:
"status eq 'ACTIVE' and type eq 'Organization'"Nested Groups
import { and, buildODataFilter, or } from "@adiba-banking-cloud/filter-builder";
const filter = buildODataFilter(
and(
{ field: "status", operator: "eq", value: "ACTIVE" },
or(
{ field: "partyName", operator: "contains", value: "pat" },
{ field: "partyName", operator: "startswith", value: "tri" },
),
),
);
// status eq 'ACTIVE' and (contains(partyName,'pat') or startswith(partyName,'tri'))Top-Level OR Example
import { buildODataFilter } from "@adiba-banking-cloud/filter-builder";
const filter = buildODataFilter(
[
{ field: "status", operator: "eq", value: "ACTIVE" },
{ field: "status", operator: "eq", value: "PENDING" },
],
{ topLevelLogic: "or" },
);
// status eq 'ACTIVE' or status eq 'PENDING'Supported Operators
Comparison operators:
eqnegtgeltle
Function operators:
containsstartswithendswith
Value Handling
- strings are wrapped in single quotes
- single quotes inside strings are escaped
- booleans become
true/false - numbers are emitted as-is
nullbecomesnullDatevalues become ISO strings wrapped in single quotes
Example:
import { buildODataFilter } from "@adiba-banking-cloud/filter-builder";
const filter = buildODataFilter([
{ field: "partyName", operator: "eq", value: "O'Brian" },
{ field: "isFavorite", operator: "eq", value: true },
{
field: "createdAt",
operator: "ge",
value: new Date("2024-01-02T03:04:05.000Z"),
},
{ field: "deletedAt", operator: "eq", value: null },
]);
// partyName eq 'O''Brian' and isFavorite eq true and createdAt ge '2024-01-02T03:04:05.000Z' and deletedAt eq nullFlat Object Mapping Example
Many SDKs start with a flat filter object like this:
const filters = {
status: "ACTIVE",
type: "Organization",
};That object does not describe operators by itself, so the consuming package needs to decide how to map it.
For example, if every field should be treated as eq:
import { buildODataFilter, type ODataRule } from "@adiba-banking-cloud/filter-builder";
const filters = {
status: "ACTIVE",
type: "Organization",
};
const rules: ODataRule[] = Object.entries(filters).map(([field, value]) => ({
field,
operator: "eq",
value,
}));
const expression = buildODataFilter(rules);
// status eq 'ACTIVE' and type eq 'Organization'That mapping step is intentionally left to the consuming SDK or app, because different APIs may want different defaults.
SDK Example
import { buildODataFilter, type ODataRule } from "@adiba-banking-cloud/filter-builder";
type ClientFilters = {
status?: string;
type?: string;
partyName?: string;
};
export const buildClientFilter = (filters: ClientFilters): string => {
const rules: ODataRule[] = Object.entries(filters)
.filter(([, value]) => value !== undefined && value !== "")
.map(([field, value]) => ({
field,
operator: "eq",
value: value!,
}));
return buildODataFilter(rules);
};Then:
const expression = buildClientFilter({
status: "ACTIVE",
type: "Organization",
});
const url = `/re/clients?filter=${encodeURIComponent(expression)}`;Types
The package exports typed filter structures:
ODataRuleODataGroupODataNodeODataOperatorODataLogicODataFilterValue
Notes
- OData uses
geandle, notgteandlte buildODataFilter([...])uses top-levelandby default- this package returns only the filter expression, not the final URL
- callers should use
encodeURIComponent(...)before placing the expression in a query string - if you need custom SDK-specific mapping from flat objects to filter rules, build that in the consuming package and pass the resulting rules into
buildODataFilter(...)
