npm.io
2.2.0 • Published 1 week ago

@rapiq/core

Licence
MIT
Version
2.2.0
Deps
3
Size
738 kB
Vulns
0
Weekly
0
Stars
33

rapiq

@rapiq/core

The foundation of rapiq: the query AST, the typed build layer & the schema system.
Every other @rapiq/* package builds on the interfaces defined here.

npm version types License: MIT

Documentation · Monorepo · npm


Part of rapiq. Typed REST queries: build, transport, validate, execute. @rapiq/core owns the intermediate representation the whole pipeline revolves around: a typed Query AST (fields, filters, pagination, relations, sorts), the defineQuery build layer, the Schema allow-list system, and the visitor interfaces parsers, codecs and backend adapters implement.

  • Typed end to end: every field path in defineQuery<User> is checked against the record type; condition helpers (eq, gte, and, or, …) replace magic value strings.
  • One AST, many consumers: the same Query node graph is walked into SQL, a TypeORM builder or in-memory predicates through the visitor pattern; core never changes when a backend is added.
  • Schema = the receiving side's allow-list: declare per-parameter allowed / default / mapping; parsers and codecs validate against it and drop or throw per policy.
  • Composable & immutable: mergeQueries uses keyed left priority for fields, relations and sorts, per-property left priority for pagination, and ordered logical AND for filters. The Filters combinators (merge, and, or) let a gateway add scope without losing predicates.

Installation

npm install @rapiq/core

Usage

Build a query

defineQuery builds the AST directly from typed input; every field path is checked against the record generic:

import { defineQuery, gte, or, eq } from '@rapiq/core';

const query = defineQuery<User>({
    fields: ['id', 'name'],
    filters: or(gte('age', 18), eq('deleted_at', null)),
    relations: ['realm'],
    sorts: '-created_at',
    pagination: { limit: 10 },
});

Filters accept scalars ({ name: 'John' }), bare arrays (in, null is a legal element), $-operator objects ({ age: { $gte: 18 } }) and condition helpers (eq, gte, inArray, and, or, …). Queries compose immutably with mergeQueries: filters are ordered logical AND, while keyed parameters use left priority. Use or(...) inside a filter tree for alternatives.

Declare what a caller may request

A Schema is the receiving side's allow-list: parsers and decoders validate incoming input against it:

import { SchemaRegistry, defineSchema } from '@rapiq/core';

const registry = new SchemaRegistry();

registry.add(defineSchema<User>({
    name: 'user',
    fields: { allowed: ['id', 'name', 'age'] },
    filters: { allowed: ['id', 'name', 'age'] },
    relations: { allowed: ['realm'] },
    sorts: { allowed: ['id', 'age'] },
    pagination: { maxLimit: 50 },
    schemaMapping: { realm: 'realm' },
}));
Consume the AST

Every node implements accept(visitor). Backends implement the visitor interfaces (IQueryVisitor, IFiltersVisitor, …) to walk a query into whatever they target. Ready-made adapters exist for SQL, TypeORM and in-memory data; parsers and URL codecs live in their own packages as well.

The rapiq family

Package Purpose
@rapiq/core Query AST, typed build layer & schema system (the shared foundation)
@rapiq/parser-simple Parse plain object/array input (the "simple" dialect)
@rapiq/parser-expression Parse filter expressions like and(eq(name,'John'), gte(age,'18'))
@rapiq/parser-mongo Parse MongoDB-style filter documents like { age: { $gte: 18 } }
@rapiq/codec-url URL query-string transport codec
@rapiq/adapter-sql Dialect-agnostic SQL fragment adapter (pg, mysql, sqlite, mssql, oracle)
@rapiq/adapter-typeorm Apply a query to a TypeORM SelectQueryBuilder
@rapiq/adapter-prisma Serialize a query into a Prisma argument object
@rapiq/adapter-drizzle Serialize a query into a Drizzle relational query config
@rapiq/adapter-memory Evaluate a query against in-memory objects & arrays

Documentation

Full guide: rapiq.tada5hi.net. See Building Queries, Schemas and Merging Queries.

License

Published under the MIT License.

Keywords