@dudousxd/nestjs-filter-clickhouse
Version:
ClickHouse adapter for @dudousxd/nestjs-filter: compiles structured filter input to parameterized ClickHouse SQL.
122 lines • 5.02 kB
TypeScript
import type { SchemaEntity } from '@dudousxd/nestjs-filter';
/**
* A field of a ClickHouse table: a trusted SQL expression plus its ClickHouse type.
*
* - `type` — the ClickHouse type of the expression (`String`, `UInt64`, `Float64`,
* `DateTime64(3, 'UTC')`, `LowCardinality(String)`, `Nullable(Int32)`, `Array(String)`, …). It
* types every bound parameter (`{p0:UInt64}`) and decides coercion, LIKE casts and `isEmpty`.
* - `expr` — the SQL expression (developer-written, never client input). Defaults to the quoted
* field name, i.e. the column of that name.
* - `measure` — an aggregate expression (`sum(count)`, `uniqMerge(users)`). A table with measures
* is an **aggregated** table: rows are grouped by the requested dimensions (`select`, or the
* table's `groupBy`), measures are projected per group, and a filter on a measure goes to HAVING.
* - `searchable` — included in `search` when the filter class declares no `static search` list
* (dynamic mode searches every searchable field). Defaults to true for String types.
*/
export interface ClickHouseFieldDefinition {
type: string;
expr?: string;
measure?: boolean;
searchable?: boolean;
}
export interface ClickHouseTableDefinition {
/**
* The FROM target — a table name, `db.table`, or any trusted table expression
* (`events FINAL`, a subquery in parentheses). Emitted verbatim.
*/
table: string;
/** Display name (errors, the `alias` computed sources receive). Defaults to `table`. */
name?: string;
/**
* The fields a client may filter, sort, search, group and project by — the allowlist. A bare
* string is the type of the column of that name.
*/
fields: Record<string, string | ClickHouseFieldDefinition>;
/** Unique row key — the cursor-pagination tiebreaker, and what `select` keeps. */
primaryKey?: string;
/** Aggregated tables: the dimensions rows are grouped by when the request selects none. */
groupBy?: string[];
/**
* A condition always applied (trusted SQL), e.g. a time bound on a raw events table:
* `at >= now64(3) - toIntervalDay(30)`.
*/
where?: string;
}
/** The type family a ClickHouse type belongs to, for coercion and operator shapes. */
export type ClickHouseTypeKind = 'string' | 'int' | 'float' | 'bool' | 'date' | 'datetime' | 'array' | 'other';
export interface ResolvedClickHouseField {
name: string;
/** The declared type. */
type: string;
/** The type with `Nullable(…)` / `LowCardinality(…)` unwrapped — what parameters are typed as. */
baseType: string;
kind: ClickHouseTypeKind;
/** For `Array(T)`: the resolved element type. */
element?: {
baseType: string;
kind: ClickHouseTypeKind;
};
nullable: boolean;
expr: string;
measure: boolean;
searchable: boolean;
}
declare const TABLE: unique symbol;
/** `Nullable(LowCardinality(String))` → `{ base: 'String', nullable: true }`. */
export declare function unwrapType(type: string): {
base: string;
nullable: boolean;
};
export declare function typeKind(base: string): ClickHouseTypeKind;
/**
* A declared ClickHouse table — the adapter's "entity", used wherever a Drizzle table or an entity
* class goes: `@Filterable({ entity: events })`, `runner.findAndCount(events, input)`.
*/
export declare class ClickHouseTable<T = Record<string, unknown>> implements SchemaEntity<T> {
/** Type-only: the row type. */
readonly $inferSelect: T;
readonly [TABLE] = true;
readonly table: string;
readonly name: string;
readonly primaryKey: string | undefined;
readonly groupBy: string[];
readonly where: string | undefined;
private readonly fieldMap;
constructor(definition: ClickHouseTableDefinition);
field(name: string): ResolvedClickHouseField | undefined;
fields(): ResolvedClickHouseField[];
/** Whether the table has measures (rows are groups, measures aggregate per group). */
get aggregated(): boolean;
}
/**
* Declares a ClickHouse table.
*
* ```ts
* export const events = defineClickHouseTable({
* table: 'events',
* primaryKey: 'id',
* fields: {
* id: 'UUID',
* at: "DateTime64(3, 'UTC')",
* event: { type: 'LowCardinality(String)', expr: 'name' },
* day: { type: 'Date', expr: 'toDate(at)' },
* durationMs: 'UInt64',
* },
* });
*
* export const errorsDaily = defineClickHouseTable({
* table: 'errors_daily',
* groupBy: ['event', 'provider'],
* fields: {
* day: 'Date',
* event: { type: 'String', expr: 'name' },
* provider: 'String',
* count: { type: 'UInt64', expr: 'sum(count)', measure: true },
* },
* });
* ```
*/
export declare function defineClickHouseTable<T = Record<string, unknown>>(definition: ClickHouseTableDefinition): ClickHouseTable<T>;
export declare function isClickHouseTable(value: unknown): value is ClickHouseTable<unknown>;
export {};
//# sourceMappingURL=table.d.ts.map