/** * Type inference utilities for extracting TypeScript types from Tinybird definitions */ import type { TypeValidator, TypeModifiers } from "../schema/types.js"; import type { ParamValidator } from "../schema/params.js"; import type { DatasourceDefinition, SchemaDefinition, ColumnDefinition } from "../schema/datasource.js"; import type { PipeDefinition, ParamsDefinition, OutputDefinition } from "../schema/pipe.js"; /** * Extract the TypeScript type from a type validator * * @example * ```ts * import { t, Infer } from '@tinybirdco/sdk'; * * const myType = t.string(); * type MyType = Infer; // string * * const myArray = t.array(t.int32()); * type MyArray = Infer; // number[] * ``` */ export type Infer = T extends TypeValidator ? U : T extends ParamValidator ? U : never; /** * Infer a single column type, handling both raw validators and column definitions */ type InferColumn = T extends TypeValidator ? U : T extends { type: TypeValidator } ? U : never; /** * Extract a row type from a datasource definition * * @example * ```ts * import { defineDatasource, t, InferRow } from '@tinybirdco/sdk'; * * const events = defineDatasource('events', { * schema: { * id: t.string(), * count: t.int32(), * timestamp: t.dateTime(), * }, * }); * * type EventRow = InferRow; * // { id: string; count: number; timestamp: string } * ``` */ export type InferRow = T extends DatasourceDefinition ? { [K in keyof S]: InferColumn } : never; /** * Infer a single parameter type, respecting required/optional */ type InferSingleParam = T extends ParamValidator ? R extends true ? U : U | undefined : never; /** * Extract the required parameter keys from a params definition */ type RequiredParamKeys = { [K in keyof T]: T[K] extends ParamValidator ? K : never; }[keyof T]; /** * Extract the optional parameter keys from a params definition */ type OptionalParamKeys = { [K in keyof T]: T[K] extends ParamValidator ? K : never; }[keyof T]; /** * Extract the required output keys from an output definition */ type RequiredOutputKeys = { [K in keyof T]: T[K] extends TypeValidator ? M extends { optional: true } ? never : K : K; }[keyof T]; /** * Extract the optional output keys from an output definition */ type OptionalOutputKeys = { [K in keyof T]: T[K] extends TypeValidator ? M extends { optional: true } ? K : never : never; }[keyof T]; /** * Extract a single output row type from an output definition */ type InferOutputObject = { [K in RequiredOutputKeys]: InferColumn; } & { [K in OptionalOutputKeys]?: InferColumn; }; /** * Extract the params type from a pipe definition * * @example * ```ts * import { definePipe, p, InferParams } from '@tinybirdco/sdk'; * * const myPipe = definePipe('my_pipe', { * params: { * userId: p.string(), * limit: p.int32().optional(10), * }, * nodes: [...], * output: {...}, * }); * * type MyParams = InferParams; * // { userId: string; limit?: number } * ``` */ export type InferParams = T extends PipeDefinition ? { [K in RequiredParamKeys

]: InferSingleParam; } & { [K in OptionalParamKeys

]?: InferSingleParam; } : never; /** * Extract the output type (single row) from a pipe definition * * @example * ```ts * import { definePipe, t, InferOutput } from '@tinybirdco/sdk'; * * const myPipe = definePipe('my_pipe', { * params: {}, * nodes: [...], * output: { * name: t.string(), * count: t.uint64(), * }, * }); * * type MyOutput = InferOutput; * // { name: string; count: number }[] * ``` */ export type InferOutput = T extends PipeDefinition ? InferOutputObject[] : never; /** * Extract a single output row type (without array wrapper) */ export type InferOutputRow = T extends PipeDefinition ? InferOutputObject : never; /** * Infer the event type for ingestion (same as row type) * * @example * ```ts * import { defineDatasource, t, InferEvent } from '@tinybirdco/sdk'; * * const events = defineDatasource('events', { * schema: { * id: t.string(), * timestamp: t.dateTime(), * }, * }); * * type Event = InferEvent; * // { id: string; timestamp: string } * * // Use for type-safe event ingestion * const event: Event = { id: '123', timestamp: '2024-01-01 00:00:00' }; * ``` */ export type InferEvent = InferRow; /** * Make all properties of InferRow optional (for partial updates) */ export type PartialRow = T extends DatasourceDefinition ? Partial<{ [K in keyof S]: InferColumn }> : never; /** * Extract the schema definition type from a datasource */ export type InferSchema = T extends DatasourceDefinition ? S : never; /** * Helper type to get the Tinybird type string for a schema * Handles both raw TypeValidators and ColumnDefinition wrappers */ export type InferTinybirdTypes = { [K in keyof T]: T[K] extends ColumnDefinition ? V extends TypeValidator ? TB : never : T[K] extends TypeValidator ? TB : never; }; /** * Extract the target datasource from a materialized view pipe * * @example * ```ts * import { definePipe, defineDatasource, t, engine, InferMaterializedTarget } from '@tinybirdco/sdk'; * * const salesByHour = defineDatasource('sales_by_hour', { * schema: { day: t.date(), total: t.uint64() }, * engine: engine.aggregatingMergeTree({ sortingKey: ['day'] }), * }); * * const salesMv = definePipe('sales_mv', { * nodes: [...], * output: { day: t.date(), total: t.uint64() }, * materialized: { datasource: salesByHour }, * }); * * type Target = InferMaterializedTarget; * // typeof salesByHour * ``` */ export type InferMaterializedTarget = T extends PipeDefinition< ParamsDefinition, OutputDefinition > ? T["options"]["materialized"] extends { datasource: infer D } ? D extends DatasourceDefinition ? D : never : never : never; /** * Extract the target datasource row type from a materialized view pipe * * @example * ```ts * type TargetRow = InferMaterializedTargetRow; * // { day: Date; total: number } * ``` */ export type InferMaterializedTargetRow = InferRow>; /** * Check if a pipe definition is a materialized view (type-level) */ export type IsMaterializedPipe = T extends PipeDefinition< ParamsDefinition, OutputDefinition > ? T["options"]["materialized"] extends { datasource: DatasourceDefinition } ? true : false : false;