@bayoudhi/moose-lib-serverless 0.7.11 → 0.7.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,13 +1,17 @@
1
1
  export { JWT, Key } from './browserCompatible';
2
2
  import * as _clickhouse_client from '@clickhouse/client';
3
- import { aE as MooseUtils, aF as MooseClient } from './index-DdE-_e4q';
4
- export { A as Aggregated, h as Api, i as ApiConfig, aP as ApiHelpers, ao as ApiUtil, Y as ClickHouseByteSize, a7 as ClickHouseCodec, X as ClickHouseDecimal, a3 as ClickHouseDefault, C as ClickHouseEngines, Z as ClickHouseFixedStringSize, _ as ClickHouseFloat, $ as ClickHouseInt, a0 as ClickHouseJson, aI as ClickHouseLineString, a5 as ClickHouseMaterialized, aJ as ClickHouseMultiLineString, aL as ClickHouseMultiPolygon, a2 as ClickHouseNamedTuple, aG as ClickHousePoint, aK as ClickHousePolygon, U as ClickHousePrecision, aH as ClickHouseRing, a4 as ClickHouseTTL, j as ConsumptionApi, aQ as ConsumptionHelpers, ap as ConsumptionUtil, a8 as DateTime, a9 as DateTime64, ab as DateTime64String, aa as DateTimeString, e as DeadLetter, D as DeadLetterModel, f as DeadLetterQueue, an as Decimal, m as ETLPipeline, n as ETLPipelineConfig, E as EgressConfig, ac as FixedString, ad as Float32, ae as Float64, F as FrameworkApp, ar as IdentifierBrandedString, I as IngestApi, g as IngestConfig, k as IngestPipeline, ag as Int16, ah as Int32, ai as Int64, af as Int8, L as LifeCycle, a1 as LowCardinality, M as MaterializedView, as as NonIdentifierBrandedString, a as OlapConfig, O as OlapTable, aM as QueryClient, au as RawValue, b as S3QueueTableSettings, S as SimpleAggregated, ax as Sql, l as SqlResource, av as SqlTemplateTag, c as Stream, d as StreamConfig, T as Task, ak as UInt16, al as UInt32, am as UInt64, aj as UInt8, at as Value, V as View, o as WebApp, p as WebAppConfig, q as WebAppHandler, a6 as WithDefault, W as Workflow, aN as WorkflowClient, aC as createClickhouseParameter, y as getApi, x as getApis, w as getIngestApi, v as getIngestApis, Q as getMaterializedView, R as getMaterializedViews, B as getSqlResource, z as getSqlResources, u as getStream, t as getStreams, s as getTable, r as getTables, aO as getTemporalClient, aB as getValueFromParameter, N as getView, P as getViews, K as getWebApp, J as getWebApps, H as getWorkflow, G as getWorkflows, aR as joinQueries, aD as mapToClickHouseType, aq as quoteIdentifier, aw as sql, az as toQuery, aA as toQueryPreview, ay as toStaticQuery } from './index-DdE-_e4q';
3
+ import { V as MooseUtils, X as MooseClient, M as MaterializedView } from './index-Cs6mRtl7';
4
+ export { A as Aggregated, f as Api, g as ApiConfig, a3 as ApiHelpers, R as ApiUtil, C as ConsumptionApi, a4 as ConsumptionHelpers, U as ConsumptionUtil, c as DeadLetter, D as DeadLetterModel, d as DeadLetterQueue, l as ETLPipeline, m as ETLPipelineConfig, E as EgressConfig, F as FrameworkApp, I as IngestApi, e as IngestConfig, h as IngestPipeline, Y as MOOSE_RLS_ROLE, _ as MOOSE_RLS_SETTING_PREFIX, Z as MOOSE_RLS_USER, $ as RowPoliciesConfig, j as SelectRowPolicy, k as SelectRowPolicyConfig, S as SimpleAggregated, i as SqlResource, a as Stream, b as StreamConfig, T as Task, n as WebApp, o as WebAppConfig, p as WebAppHandler, W as Workflow, a1 as WorkflowClient, a0 as buildRowPolicyOptionsFromClaims, x as getApi, w as getApis, v as getIngestApi, u as getIngestApis, N as getMaterializedView, O as getMaterializedViews, P as getSelectRowPolicies, Q as getSelectRowPolicy, z as getSqlResource, y as getSqlResources, t as getStream, s as getStreams, r as getTable, q as getTables, a2 as getTemporalClient, K as getView, L as getViews, J as getWebApp, H as getWebApps, G as getWorkflow, B as getWorkflows, a5 as joinQueries } from './index-Cs6mRtl7';
5
5
  import http from 'http';
6
+ import { M as Sql, O as OlapTable, a0 as Column, _ as QueryClient, a3 as DataType } from './view-CNYx8kUh';
7
+ export { n as ClickHouseAlias, d as ClickHouseByteSize, o as ClickHouseCodec, c as ClickHouseDecimal, k as ClickHouseDefault, C as ClickHouseEngines, e as ClickHouseFixedStringSize, f as ClickHouseFloat, g as ClickHouseInt, h as ClickHouseJson, a6 as ClickHouseLineString, m as ClickHouseMaterialized, a7 as ClickHouseMultiLineString, a9 as ClickHouseMultiPolygon, j as ClickHouseNamedTuple, a4 as ClickHousePoint, a8 as ClickHousePolygon, b as ClickHousePrecision, a5 as ClickHouseRing, l as ClickHouseTTL, D as DateTime, p as DateTime64, r as DateTime64String, q as DateTimeString, A as Decimal, F as FixedString, s as Float32, t as Float64, G as IdentifierBrandedString, B as Insertable, u as Int16, v as Int32, w as Int64, I as Int8, L as LifeCycle, i as LowCardinality, N as NonIdentifierBrandedString, a as OlapConfig, R as RawValue, a1 as RowPolicyOptions, S as S3QueueTableSettings, J as SqlTemplateTag, x as UInt16, y as UInt32, z as UInt64, U as UInt8, H as Value, V as View, W as WithDefault, Y as createClickhouseParameter, X as getValueFromParameter, Z as mapToClickHouseType, E as quoteIdentifier, K as sql, Q as toQuery, T as toQueryPreview, P as toStaticQuery } from './view-CNYx8kUh';
6
8
  import { IsTuple } from 'typia/lib/typings/IsTuple';
7
9
  import { Readable } from 'node:stream';
8
- import 'typia';
9
- import 'typia/lib/tags';
10
+ declare namespace z { type ZodType = any; }
11
+ type McpServer = any;
12
+ import { IValidation } from 'typia';
10
13
  import 'jose';
14
+ import 'typia/lib/tags';
11
15
 
12
16
  declare const Kafka: any;
13
17
  type Kafka = any;
@@ -371,8 +375,14 @@ interface RuntimeClickHouseConfig {
371
375
  password: string;
372
376
  database: string;
373
377
  useSSL: boolean;
378
+ rlsUser?: string;
379
+ rlsPassword?: string;
374
380
  }
375
381
 
382
+ interface GetMooseUtilsOptions {
383
+ /** Map of JWT claim names to their values for row policy scoping */
384
+ rlsContext?: Record<string, string>;
385
+ }
376
386
  /**
377
387
  * Get Moose utilities for database access and SQL queries.
378
388
  * Works in both Moose runtime and standalone contexts.
@@ -383,21 +393,17 @@ interface RuntimeClickHouseConfig {
383
393
  * const moose = getMooseUtils(); // WRONG - returns Promise, not MooseUtils!
384
394
  * ```
385
395
  *
386
- * **Breaking Change from v1.x**: This function signature changed from sync to async.
387
- * If you were using the old sync API that extracted utils from a request object,
388
- * use `getMooseUtilsFromRequest(req)` for backward compatibility (deprecated).
389
- *
390
- * @param req - DEPRECATED: Request parameter is no longer needed and will be ignored.
391
- * If you need to extract moose from a request, use getMooseUtilsFromRequest().
392
- * @returns Promise resolving to MooseUtils with client and sql utilities.
393
- *
394
- * @example
396
+ * Pass `{ rlsContext }` to get a scoped client that enforces ClickHouse row policies:
395
397
  * ```typescript
396
- * const { client, sql } = await getMooseUtils();
397
- * const result = await client.query.execute(sql`SELECT * FROM table`);
398
+ * const { client, sql } = await getMooseUtils({ rlsContext: { org_id: orgId } });
399
+ * // All queries through this client are filtered by org_id
398
400
  * ```
401
+ *
402
+ * @param options - Optional. Pass `{ rlsContext }` to scope queries via row policies.
403
+ * DEPRECATED: Passing a request object is no longer needed and will be ignored.
404
+ * @returns Promise resolving to MooseUtils with client and sql utilities.
399
405
  */
400
- declare function getMooseUtils(req?: any): Promise<MooseUtils>;
406
+ declare function getMooseUtils(options?: GetMooseUtilsOptions | any): Promise<MooseUtils>;
401
407
  /**
402
408
  * @deprecated Use getMooseUtils() instead.
403
409
  * Creates a Moose client for database access.
@@ -627,6 +633,754 @@ interface ExtractionResult<T = any> {
627
633
  metadata: Record<string, any>;
628
634
  }
629
635
 
636
+ /**
637
+ * Query Layer Types
638
+ *
639
+ * Consolidated type definitions for the query layer.
640
+ *
641
+ * @module query-layer/types
642
+ */
643
+
644
+ /** Valid SQL values that can be parameterized */
645
+ type SqlValue = string | number | boolean | Date;
646
+ /**
647
+ * Column reference — a Column object from OlapTable.columns.* or a raw Sql expression.
648
+ *
649
+ * @example
650
+ * const col = Events.columns.amount; // Column
651
+ * const expr = sql`CASE WHEN ... END`; // Sql
652
+ */
653
+ type ColRef = Column | Sql;
654
+ /**
655
+ * Supported filter operators for building WHERE conditions.
656
+ *
657
+ * Each operator has specific value type requirements:
658
+ * - Scalar operators (eq, ne, gt, gte, lt, lte, like, ilike): single value
659
+ * - List operators (in, notIn): array of values
660
+ * - Range operators (between): tuple [low, high]
661
+ * - Null operators (isNull, isNotNull): boolean flag
662
+ */
663
+ type FilterOperator = "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "like" | "ilike" | "in" | "notIn" | "between" | "isNull" | "isNotNull";
664
+ /** Sort direction for ORDER BY clauses */
665
+ type SortDir = "ASC" | "DESC";
666
+ /**
667
+ * Dimension definition — a column or expression used for grouping.
668
+ *
669
+ * @template TModel - The table's model type
670
+ * @template TKey - The column key (must be a key of TModel)
671
+ *
672
+ * @example
673
+ * dimensions: {
674
+ * status: { column: "status" },
675
+ * day: { expression: sql`toDate(timestamp)`, as: "day" },
676
+ * }
677
+ */
678
+ interface DimensionDef<TModel = any, TKey extends keyof TModel = keyof TModel> {
679
+ column?: TKey;
680
+ expression?: Sql;
681
+ as?: string;
682
+ description?: string;
683
+ }
684
+ /**
685
+ * Metric definition — an aggregate or computed value.
686
+ *
687
+ * @example
688
+ * metrics: {
689
+ * totalAmount: { agg: sql`sum(amount)` },
690
+ * totalEvents: { agg: sql`count(*)` },
691
+ * revenue: { agg: sql`sum(amount)`, as: "total_revenue" },
692
+ * }
693
+ */
694
+ interface MetricDef {
695
+ agg: Sql;
696
+ as?: string;
697
+ description?: string;
698
+ }
699
+ /**
700
+ * Column definition for detail (non-aggregated) queries.
701
+ *
702
+ * @template TModel - The table's model type
703
+ * @template TKey - The column key (must be a key of TModel)
704
+ *
705
+ * @example
706
+ * columns: {
707
+ * visitId: { column: "id" },
708
+ * firstName: { join: "user", column: "first_name" },
709
+ * }
710
+ */
711
+ interface ColumnDef<TModel = any, TKey extends keyof TModel = keyof TModel> {
712
+ column: TKey | string;
713
+ join?: string;
714
+ as?: string;
715
+ }
716
+ /**
717
+ * Join definition for lookup JOINs.
718
+ *
719
+ * @example
720
+ * joins: {
721
+ * user: {
722
+ * table: UsersTable,
723
+ * leftKey: "user_id",
724
+ * rightKey: "id",
725
+ * type: "LEFT",
726
+ * },
727
+ * }
728
+ */
729
+ interface JoinDef {
730
+ table: OlapTable<any> | MaterializedView<any>;
731
+ on?: Sql;
732
+ leftKey?: string;
733
+ rightKey?: string;
734
+ type?: "LEFT" | "INNER";
735
+ }
736
+ /** Input type hint for filter UI rendering */
737
+ type FilterInputTypeHint = "text" | "number" | "date" | "select" | "multiselect";
738
+ /**
739
+ * Filter definition for use in defineQueryModel configuration.
740
+ *
741
+ * @template TModel - The table's model type
742
+ * @template TKey - The column key (must be a key of TModel)
743
+ *
744
+ * @example
745
+ * filters: {
746
+ * status: { column: "status", operators: ["eq", "in"] as const },
747
+ * amount: { column: "amount", operators: ["gte", "lte"] as const },
748
+ * }
749
+ */
750
+ interface ModelFilterDef<TModel, TKey extends keyof TModel = keyof TModel> {
751
+ column?: TKey;
752
+ /** Metric name — filters referencing a metric are auto-routed to HAVING */
753
+ metric?: string;
754
+ operators: readonly FilterOperator[];
755
+ transform?: (value: TModel[TKey]) => SqlValue;
756
+ inputType?: FilterInputTypeHint;
757
+ /** When true, this filter's `eq` param is required in MCP tool schemas */
758
+ required?: true;
759
+ description?: string;
760
+ }
761
+ /** Extract string keys from a record type */
762
+ type Names<T> = Extract<keyof T, string>;
763
+ /**
764
+ * Infer the value type for a given operator and base value type.
765
+ *
766
+ * Maps filter operators to their required value types:
767
+ * - Scalar operators: single value
768
+ * - List operators (in, notIn): array of values
769
+ * - Range operators (between): tuple [low, high]
770
+ * - Null operators (isNull, isNotNull): boolean flag
771
+ */
772
+ type OperatorValueType<Op extends FilterOperator, TValue = SqlValue> = Op extends "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "like" | "ilike" ? TValue : Op extends "in" | "notIn" ? TValue[] : Op extends "between" ? [TValue, TValue] : Op extends "isNull" | "isNotNull" ? boolean : never;
773
+ /** Base constraint for filter definitions */
774
+ type FilterDefBase = {
775
+ operators: readonly FilterOperator[];
776
+ };
777
+ /** Filter parameters structure derived from filter definitions */
778
+ type FilterParams<TFilters extends Record<string, FilterDefBase>, TTable = any> = {
779
+ [K in keyof TFilters]?: {
780
+ [Op in TFilters[K]["operators"][number]]?: OperatorValueType<Op, TFilters[K] extends {
781
+ column: infer TKey extends keyof TTable;
782
+ } ? TTable[TKey] : SqlValue>;
783
+ };
784
+ };
785
+ /**
786
+ * User-facing query request specification.
787
+ *
788
+ * Users specify dimensions and metrics — semantic concepts, not SQL concepts.
789
+ * The query model handles the translation to actual SQL.
790
+ *
791
+ * @example
792
+ * const request: QueryRequest = {
793
+ * dimensions: ["status", "day"],
794
+ * metrics: ["totalEvents", "totalAmount"],
795
+ * filters: { status: { eq: "active" } },
796
+ * orderBy: [["totalAmount", "DESC"]],
797
+ * limit: 10,
798
+ * };
799
+ */
800
+ type QueryRequest<TMetrics extends string = string, TDimensions extends string = string, TFilters extends Record<string, FilterDefBase> = Record<string, FilterDefBase>, TSortable extends string = string, TColumns extends string = string, TTable = any> = {
801
+ filters?: FilterParams<TFilters, TTable>;
802
+ dimensions?: TDimensions[];
803
+ metrics?: TMetrics[];
804
+ /** Columns for detail mode (no aggregation). Mutually exclusive with dimensions/metrics. */
805
+ columns?: TColumns[];
806
+ orderBy?: Array<[TSortable, SortDir]>;
807
+ limit?: number;
808
+ /** Page number (0-indexed). Mutually exclusive with offset. */
809
+ page?: number;
810
+ /** Row offset. Mutually exclusive with page. */
811
+ offset?: number;
812
+ };
813
+ /** Individual SQL clauses for custom query assembly */
814
+ interface QueryParts {
815
+ select: Sql;
816
+ dimensions: Sql;
817
+ metrics: Sql;
818
+ columns: Sql;
819
+ from: Sql;
820
+ conditions: Sql[];
821
+ where: Sql;
822
+ groupBy: Sql;
823
+ having: Sql;
824
+ orderBy: Sql;
825
+ /** Composed LIMIT + OFFSET clause */
826
+ pagination: Sql;
827
+ }
828
+
829
+ /**
830
+ * Query Model — Core query building interface and implementation.
831
+ *
832
+ * @module query-layer/query-model
833
+ */
834
+
835
+ /**
836
+ * Configuration for defining a query model.
837
+ *
838
+ * @template TTable - The table's model type (row type)
839
+ * @template TMetrics - Record of metric definitions
840
+ * @template TDimensions - Record of dimension definitions
841
+ * @template TFilters - Record of filter definitions
842
+ * @template TSortable - Union type of sortable field names
843
+ */
844
+ interface QueryModelConfig<TTable, TMetrics extends Record<string, MetricDef>, TDimensions extends Record<string, DimensionDef<TTable, keyof TTable>>, TFilters extends Record<string, ModelFilterDef<TTable, keyof TTable>>, TSortable extends string, TColumns extends Record<string, ColumnDef<TTable>> = Record<string, never>, TJoins extends Record<string, JoinDef> = Record<string, never>> {
845
+ /** Tool name used by registerModelTools (e.g. "query_visits") */
846
+ name?: string;
847
+ /** Tool description used by registerModelTools */
848
+ description?: string;
849
+ /** The OlapTable or MaterializedView to query. If a MaterializedView is passed, its targetTable is used. */
850
+ table: OlapTable<TTable> | MaterializedView<TTable>;
851
+ /**
852
+ * Dimension fields — columns used for grouping, filtering, and display.
853
+ *
854
+ * @example
855
+ * dimensions: {
856
+ * status: { column: "status" },
857
+ * day: { expression: sql`toDate(timestamp)`, as: "day" },
858
+ * }
859
+ */
860
+ dimensions?: TDimensions;
861
+ /**
862
+ * Metric fields — aggregate values computed over dimensions.
863
+ *
864
+ * @example
865
+ * metrics: {
866
+ * totalAmount: { agg: sum(Events.columns.amount), as: "total_amount" },
867
+ * totalEvents: { agg: count(), as: "total_events" },
868
+ * }
869
+ */
870
+ metrics?: TMetrics;
871
+ /**
872
+ * Column fields for detail (non-aggregated) queries.
873
+ *
874
+ * @example
875
+ * columns: {
876
+ * visitId: { column: "id" },
877
+ * firstName: { join: "user", column: "first_name" },
878
+ * }
879
+ */
880
+ columns?: TColumns;
881
+ /**
882
+ * Lookup JOIN definitions.
883
+ *
884
+ * @example
885
+ * joins: {
886
+ * user: {
887
+ * table: UsersTable,
888
+ * leftKey: "user_id",
889
+ * rightKey: "id",
890
+ * type: "LEFT",
891
+ * },
892
+ * }
893
+ */
894
+ joins?: TJoins;
895
+ /**
896
+ * Filterable fields with allowed operators.
897
+ *
898
+ * @example
899
+ * filters: {
900
+ * status: { column: "status", operators: ["eq", "in"] as const },
901
+ * amount: { column: "amount", operators: ["gte", "lte"] as const },
902
+ * }
903
+ */
904
+ filters: TFilters;
905
+ /**
906
+ * Which fields can be sorted.
907
+ *
908
+ * @example
909
+ * sortable: ["timestamp", "amount", "status"] as const
910
+ */
911
+ sortable: readonly TSortable[];
912
+ /** Default query behavior */
913
+ defaults?: {
914
+ orderBy?: Array<[TSortable, SortDir]>;
915
+ groupBy?: string[];
916
+ limit?: number;
917
+ maxLimit?: number;
918
+ dimensions?: string[];
919
+ metrics?: string[];
920
+ columns?: string[];
921
+ };
922
+ }
923
+ /**
924
+ * Query model interface providing type-safe query building and execution.
925
+ */
926
+ interface QueryModel<TTable, TMetrics extends Record<string, MetricDef>, TDimensions extends Record<string, DimensionDef>, TFilters extends Record<string, FilterDefBase>, TSortable extends string, TResult, TColumns extends Record<string, ColumnDef> = Record<string, never>> {
927
+ readonly name?: string;
928
+ readonly description?: string;
929
+ readonly defaults: {
930
+ orderBy?: Array<[TSortable, SortDir]>;
931
+ groupBy?: string[];
932
+ limit?: number;
933
+ maxLimit?: number;
934
+ dimensions?: string[];
935
+ metrics?: string[];
936
+ columns?: string[];
937
+ };
938
+ readonly filters: TFilters;
939
+ readonly sortable: readonly TSortable[];
940
+ readonly dimensions?: TDimensions;
941
+ readonly metrics?: TMetrics;
942
+ readonly columns?: TColumns;
943
+ readonly columnNames: readonly string[];
944
+ /** Type inference helpers (similar to Drizzle's $inferSelect pattern). */
945
+ readonly $inferDimensions: Names<TDimensions>;
946
+ readonly $inferMetrics: Names<TMetrics>;
947
+ readonly $inferColumns: Names<TColumns>;
948
+ readonly $inferFilters: FilterParams<TFilters, TTable>;
949
+ readonly $inferRequest: QueryRequest<Names<TMetrics>, Names<TDimensions>, TFilters, TSortable, Names<TColumns>, TTable>;
950
+ readonly $inferResult: TResult;
951
+ /** Execute query with Moose QueryClient. */
952
+ query(request: QueryRequest<Names<TMetrics>, Names<TDimensions>, TFilters, TSortable, Names<TColumns>, TTable>, client: QueryClient): Promise<TResult[]>;
953
+ /** Build complete SQL query from request. */
954
+ toSql(request: QueryRequest<Names<TMetrics>, Names<TDimensions>, TFilters, TSortable, Names<TColumns>, TTable>): Sql;
955
+ /** Get individual SQL parts for custom assembly. */
956
+ toParts(request: QueryRequest<Names<TMetrics>, Names<TDimensions>, TFilters, TSortable, Names<TColumns>, TTable>): QueryParts;
957
+ }
958
+ /**
959
+ * Define a query model with controlled field selection, filtering, and sorting.
960
+ *
961
+ * @example
962
+ * const model = defineQueryModel({
963
+ * table: Events,
964
+ * dimensions: {
965
+ * status: { column: "status" },
966
+ * day: { expression: sql`toDate(timestamp)`, as: "day" },
967
+ * },
968
+ * metrics: {
969
+ * totalEvents: { agg: count(), as: "total_events" },
970
+ * totalAmount: { agg: sum(Events.columns.amount), as: "total_amount" },
971
+ * },
972
+ * filters: {
973
+ * status: { column: "status", operators: ["eq", "in"] as const },
974
+ * },
975
+ * sortable: ["amount", "timestamp"] as const,
976
+ * });
977
+ */
978
+ declare function defineQueryModel<TTable, TMetrics extends Record<string, MetricDef>, TDimensions extends Record<string, DimensionDef<TTable, keyof TTable>>, TFilters extends Record<string, ModelFilterDef<TTable, keyof TTable>>, TSortable extends string, TColumns extends Record<string, ColumnDef<TTable>> = Record<string, never>, TJoins extends Record<string, JoinDef> = Record<string, never>, TResult = TTable>(config: QueryModelConfig<TTable, TMetrics, TDimensions, TFilters, TSortable, TColumns, TJoins>): QueryModel<TTable, TMetrics, TDimensions, TFilters, TSortable, TResult, TColumns>;
979
+
980
+ /**
981
+ * Composable helpers that leverage moose-lib table metadata to reduce
982
+ * boilerplate in QueryModel definitions.
983
+ *
984
+ * @module query-layer/helpers
985
+ */
986
+
987
+ /**
988
+ * Derive FilterInputTypeHint from a ClickHouse column data_type.
989
+ */
990
+ declare function deriveInputTypeFromDataType(dataType: DataType): FilterInputTypeHint;
991
+ type DefaultTimePeriods = {
992
+ day: DimensionDef;
993
+ month: DimensionDef;
994
+ week: DimensionDef;
995
+ };
996
+ /**
997
+ * Generate day/month/week dimension definitions from a date column reference.
998
+ *
999
+ * @param dateColumn - A Column reference from `Table.columns.some_date`
1000
+ * @returns `{ day, month, week }` dimension definitions
1001
+ *
1002
+ * @example
1003
+ * dimensions: {
1004
+ * status: { column: "status" },
1005
+ * ...timeDimensions(VisitsTable.columns.start_date),
1006
+ * }
1007
+ */
1008
+ declare function timeDimensions(dateColumn: Column): DefaultTimePeriods;
1009
+ declare function timeDimensions(dateColumn: Column, options: {
1010
+ periods: string[];
1011
+ }): Record<string, DimensionDef>;
1012
+ interface TableFieldOptions {
1013
+ /** Only include these column names (snake_case as in the table) */
1014
+ include?: string[];
1015
+ /** Exclude these column names */
1016
+ exclude?: string[];
1017
+ /** Convert snake_case keys to camelCase (default: true) */
1018
+ camelCase?: boolean;
1019
+ }
1020
+ /**
1021
+ * Generate ColumnDef records from a table's columnArray metadata.
1022
+ *
1023
+ * @example
1024
+ * columns: {
1025
+ * ...columnsFromTable(VisitsTable, { include: ["id", "name", "status"] }),
1026
+ * firstName: { join: "user", column: "first_name" },
1027
+ * }
1028
+ */
1029
+ declare function columnsFromTable<T>(table: OlapTable<T>, options?: TableFieldOptions): Record<string, ColumnDef<T>>;
1030
+ /**
1031
+ * Generate ModelFilterDef records from a table's columnArray metadata.
1032
+ *
1033
+ * **Conservative defaults**: all filters get `["eq"]` operators only.
1034
+ * Consumers widen operators explicitly via spread overrides.
1035
+ *
1036
+ * @example
1037
+ * filters: {
1038
+ * ...filtersFromTable(VisitsTable, { include: ["studio_id", "start_date", "status"] }),
1039
+ * status: { column: "status", operators: ["eq", "ne", "in"] as const },
1040
+ * }
1041
+ */
1042
+ declare function filtersFromTable<T>(table: OlapTable<T>, options?: TableFieldOptions): Record<string, ModelFilterDef<T, keyof T>>;
1043
+
1044
+ /**
1045
+ * Fluent Query Builder API
1046
+ *
1047
+ * Provides a chainable API for building QueryRequest objects.
1048
+ *
1049
+ * @module query-layer/query-builder
1050
+ */
1051
+
1052
+ /**
1053
+ * Fluent builder for constructing query requests.
1054
+ *
1055
+ * @example
1056
+ * const results = await buildQuery(model)
1057
+ * .dimensions(["status"])
1058
+ * .metrics(["totalEvents", "totalAmount"])
1059
+ * .filter("status", "eq", "active")
1060
+ * .orderBy(["totalAmount", "DESC"])
1061
+ * .limit(10)
1062
+ * .execute(client.query);
1063
+ */
1064
+ interface QueryBuilder<TMetrics extends string, TDimensions extends string, TFilters extends Record<string, FilterDefBase>, TSortable extends string, TResult, TTable = any, TColumns extends string = string> {
1065
+ /** Add a filter condition. Automatically skips if value is undefined or null. */
1066
+ filter<K extends keyof TFilters, Op extends TFilters[K]["operators"][number]>(filterName: K, op: Op, value: OperatorValueType<Op, SqlValue> | undefined): this;
1067
+ /** Set dimensions to include in query (aggregate mode) */
1068
+ dimensions(fields: TDimensions[]): this;
1069
+ /** Set metrics to include in query (aggregate mode) */
1070
+ metrics(fields: TMetrics[]): this;
1071
+ /** Set columns for detail mode (no aggregation, no GROUP BY) */
1072
+ columns(fields: TColumns[]): this;
1073
+ /** Set multi-column sort */
1074
+ orderBy(...orders: Array<[TSortable, SortDir]>): this;
1075
+ /** Set maximum number of rows to return */
1076
+ limit(n: number): this;
1077
+ /** Set page number (0-indexed) for pagination */
1078
+ page(n: number): this;
1079
+ /** Set row offset for pagination */
1080
+ offset(n: number): this;
1081
+ /** Build the QueryRequest object */
1082
+ build(): QueryRequest<TMetrics, TDimensions, TFilters, TSortable, TColumns, TTable>;
1083
+ /** Build the SQL query */
1084
+ toSql(): Sql;
1085
+ /** Get query parts for custom assembly */
1086
+ toParts(): QueryParts;
1087
+ /** Build SQL with custom assembly function */
1088
+ assemble(fn: (parts: QueryParts) => Sql): Sql;
1089
+ /** Execute the query with Moose QueryClient. */
1090
+ execute(client: QueryClient): Promise<TResult[]>;
1091
+ }
1092
+ /**
1093
+ * Create a fluent query builder for a model.
1094
+ *
1095
+ * @param model - QueryModel instance to build queries for
1096
+ * @returns QueryBuilder instance with chainable methods
1097
+ *
1098
+ * @example
1099
+ * const results = await buildQuery(model)
1100
+ * .dimensions(["status"])
1101
+ * .metrics(["totalEvents", "totalAmount"])
1102
+ * .filter("status", "eq", "active")
1103
+ * .orderBy(["totalAmount", "DESC"])
1104
+ * .limit(10)
1105
+ * .execute(client.query);
1106
+ */
1107
+ declare function buildQuery<TTable, TMetrics extends Record<string, MetricDef>, TDimensions extends Record<string, DimensionDef>, TFilters extends Record<string, FilterDefBase>, TSortable extends string, TResult, TColumns extends Record<string, ColumnDef> = Record<string, never>>(model: QueryModel<TTable, TMetrics, TDimensions, TFilters, TSortable, TResult, TColumns>): QueryBuilder<Names<TMetrics>, Names<TDimensions>, TFilters, TSortable, TResult, TTable, Names<TColumns>>;
1108
+
1109
+ /**
1110
+ * MCP Schema Generation from QueryModel
1111
+ *
1112
+ * Auto-generates Zod schemas and request builders for MCP tools
1113
+ * directly from QueryModel metadata (filters, dimensions, metrics, columns).
1114
+ *
1115
+ * @module query-layer/model-tools
1116
+ */
1117
+
1118
+ /** Filter definition shape expected by MCP utilities. */
1119
+ interface QueryModelFilter {
1120
+ operators: readonly string[];
1121
+ inputType?: FilterInputTypeHint;
1122
+ required?: true;
1123
+ description?: string;
1124
+ }
1125
+ /**
1126
+ * Minimal model interface consumed by createModelTool / registerModelTools.
1127
+ *
1128
+ * Any QueryModel from defineQueryModel() satisfies this structurally —
1129
+ * no explicit `implements` needed. This avoids propagating generic
1130
+ * type parameters into the MCP layer.
1131
+ */
1132
+ interface QueryModelBase {
1133
+ readonly name?: string;
1134
+ readonly description?: string;
1135
+ readonly defaults: {
1136
+ orderBy?: Array<[string, SortDir]>;
1137
+ groupBy?: string[];
1138
+ limit?: number;
1139
+ maxLimit?: number;
1140
+ dimensions?: string[];
1141
+ metrics?: string[];
1142
+ columns?: string[];
1143
+ };
1144
+ readonly filters: Record<string, QueryModelFilter>;
1145
+ readonly sortable: readonly string[];
1146
+ readonly dimensions?: Record<string, {
1147
+ description?: string;
1148
+ }>;
1149
+ readonly metrics?: Record<string, {
1150
+ description?: string;
1151
+ }>;
1152
+ readonly columnNames: readonly string[];
1153
+ toSql(request: Record<string, unknown>): Sql;
1154
+ }
1155
+ interface ModelToolOptions {
1156
+ /** Filter names whose `eq` param is required (not optional). Merged with model-level `required` flags. */
1157
+ requiredFilters?: string[];
1158
+ /** Maximum limit for the tool. Falls back to model.defaults.maxLimit, then 1000. */
1159
+ maxLimit?: number;
1160
+ /** Default limit for the tool. Falls back to model.defaults.limit, then 100. */
1161
+ defaultLimit?: number;
1162
+ /** Default values applied when params are absent. Merged with model.defaults. */
1163
+ defaults?: {
1164
+ dimensions?: string[];
1165
+ metrics?: string[];
1166
+ columns?: string[];
1167
+ limit?: number;
1168
+ };
1169
+ }
1170
+ interface ModelToolResult {
1171
+ /** Zod shape object to pass to server.tool() */
1172
+ schema: Record<string, z.ZodType>;
1173
+ /** Convert flat MCP params into a nested QueryRequest */
1174
+ buildRequest: (params: Record<string, unknown>) => Record<string, unknown>;
1175
+ }
1176
+ /**
1177
+ * Generate a Zod schema and request builder from a QueryModel.
1178
+ *
1179
+ * Required filters, maxLimit, and default selections are first read from the
1180
+ * model itself (via `required: true` on filter defs and `model.defaults`).
1181
+ * The optional `options` param can override or extend any of these.
1182
+ *
1183
+ * @param model - A QueryModel instance (from defineQueryModel)
1184
+ * @param options - Optional overrides for required filters, limits, defaults
1185
+ * @returns `{ schema, buildRequest }` ready for `server.tool()`
1186
+ */
1187
+ declare function createModelTool(model: QueryModelBase, options?: ModelToolOptions): ModelToolResult;
1188
+ /**
1189
+ * Register MCP tools for all models that have a `name` defined.
1190
+ *
1191
+ * Each model with a `name` property becomes an MCP tool. The library handles
1192
+ * everything: schema generation from model metadata, request building from
1193
+ * flat MCP params, SQL generation via `model.toSql()`, parameterized
1194
+ * execution with readonly enforcement, and MCP response formatting.
1195
+ *
1196
+ * Models without a `name` are silently skipped.
1197
+ *
1198
+ * @param server - McpServer instance
1199
+ * @param models - Array of QueryModel instances (from `defineQueryModel`)
1200
+ * @param queryClient - The QueryClient from `mooseUtils.client.query`.
1201
+ * Queries are executed in readonly mode with parameterized SQL.
1202
+ *
1203
+ * @example
1204
+ * import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1205
+ * import { getMooseUtils, MooseUtils } from "@514labs/moose-lib";
1206
+ * import { registerModelTools } from "@514labs/moose-lib";
1207
+ * import { visitsModel, usersModel } from "./models";
1208
+ *
1209
+ * const serverFactory = (mooseUtils: MooseUtils) => {
1210
+ * const server = new McpServer({ name: "my-tools", version: "1.0.0" });
1211
+ *
1212
+ * // One line registers all named models as MCP tools
1213
+ * registerModelTools(server, [visitsModel, usersModel], mooseUtils.client.query);
1214
+ *
1215
+ * return server;
1216
+ * };
1217
+ */
1218
+ declare function registerModelTools(server: McpServer, models: QueryModelBase[], queryClient: QueryClient): void;
1219
+
1220
+ /**
1221
+ * SQL Utilities
1222
+ *
1223
+ * Low-level SQL building utilities for constructing type-safe queries.
1224
+ * These are the building blocks used by QueryModel and can also be used
1225
+ * directly for custom query construction.
1226
+ *
1227
+ * @module query-layer/sql-utils
1228
+ */
1229
+
1230
+ /**
1231
+ * Create raw SQL (literal string, no parameterization).
1232
+ * Delegates to sql.raw from sqlHelpers.
1233
+ *
1234
+ * Only for developer-defined constants (column names, expressions, sort
1235
+ * directions) that originate from model config — never for HTTP/user input.
1236
+ */
1237
+ declare const raw: (text: string) => Sql;
1238
+ /** Empty SQL fragment — useful as a no-op. */
1239
+ declare const empty: Sql;
1240
+ /**
1241
+ * Join SQL fragments with a separator.
1242
+ * Delegates to sql.join from sqlHelpers.
1243
+ */
1244
+ declare const join: (fragments: Sql[], separator?: string) => Sql;
1245
+ /** Check if a Sql fragment is empty */
1246
+ declare function isEmpty(fragment: Sql): boolean;
1247
+ /**
1248
+ * Create a filter condition. Automatically skips if value is undefined/null.
1249
+ * This is the recommended way to build conditional WHERE clauses.
1250
+ *
1251
+ * @example
1252
+ * where(
1253
+ * filter(Events.columns.amount, "gte", params.minAmount),
1254
+ * filter(Events.columns.amount, "lte", params.maxAmount),
1255
+ * filter(Events.columns.status, "eq", params.status),
1256
+ * )
1257
+ */
1258
+ declare function filter(col: ColRef, op: "between", value: [SqlValue, SqlValue] | undefined): Sql;
1259
+ declare function filter(col: ColRef, op: "in" | "notIn", value: SqlValue[] | undefined): Sql;
1260
+ declare function filter(col: ColRef, op: "isNull" | "isNotNull", value: boolean | undefined): Sql;
1261
+ declare function filter(col: ColRef, op: "like" | "ilike", value: string | undefined): Sql;
1262
+ declare function filter(col: ColRef, op: Exclude<FilterOperator, "between" | "in" | "notIn" | "isNull" | "isNotNull" | "like" | "ilike">, value: SqlValue | undefined): Sql;
1263
+ /** Equal: column = value */
1264
+ declare function eq(col: ColRef, value: SqlValue): Sql;
1265
+ /** Not equal: column != value */
1266
+ declare function ne(col: ColRef, value: SqlValue): Sql;
1267
+ /** Greater than: column > value */
1268
+ declare function gt(col: ColRef, value: SqlValue): Sql;
1269
+ /** Greater than or equal: column >= value */
1270
+ declare function gte(col: ColRef, value: SqlValue): Sql;
1271
+ /** Less than: column < value */
1272
+ declare function lt(col: ColRef, value: SqlValue): Sql;
1273
+ /** Less than or equal: column <= value */
1274
+ declare function lte(col: ColRef, value: SqlValue): Sql;
1275
+ /** LIKE pattern match (case-sensitive) */
1276
+ declare function like(col: ColRef, pattern: string): Sql;
1277
+ /** ILIKE pattern match (case-insensitive, ClickHouse) */
1278
+ declare function ilike(col: ColRef, pattern: string): Sql;
1279
+ /** IN list: column IN (a, b, c) */
1280
+ declare function inList(col: ColRef, values: SqlValue[]): Sql;
1281
+ /** NOT IN list */
1282
+ declare function notIn(col: ColRef, values: SqlValue[]): Sql;
1283
+ /** BETWEEN: column BETWEEN low AND high */
1284
+ declare function between(col: ColRef, low: SqlValue, high: SqlValue): Sql;
1285
+ /** IS NULL */
1286
+ declare function isNull(col: ColRef): Sql;
1287
+ /** IS NOT NULL */
1288
+ declare function isNotNull(col: ColRef): Sql;
1289
+ /** Combine conditions with AND, filtering out empty fragments */
1290
+ declare function and(...conditions: Sql[]): Sql;
1291
+ /** Combine conditions with OR, filtering out empty fragments */
1292
+ declare function or(...conditions: Sql[]): Sql;
1293
+ /** Negate a condition: NOT (condition) */
1294
+ declare function not(condition: Sql): Sql;
1295
+ /** Build WHERE clause — returns empty if no conditions */
1296
+ declare function where(...conditions: Sql[]): Sql;
1297
+ /** Build ORDER BY clause */
1298
+ declare function orderBy(...cols: Array<ColRef | [ColRef, "ASC" | "DESC"]>): Sql;
1299
+ /** Build LIMIT clause */
1300
+ declare function limit(n: number): Sql;
1301
+ /** Build OFFSET clause */
1302
+ declare function offset(n: number): Sql;
1303
+ /** Build LIMIT + OFFSET for pagination */
1304
+ declare function paginate(pageSize: number, page?: number): Sql;
1305
+ /** Build GROUP BY clause */
1306
+ declare function groupBy(...cols: ColRef[]): Sql;
1307
+ /** Build HAVING clause */
1308
+ declare function having(...conditions: Sql[]): Sql;
1309
+ /** SQL expression with fluent `.as()` method */
1310
+ interface Expr extends Sql {
1311
+ as(alias: string): Sql;
1312
+ }
1313
+ /** COUNT(*) or COUNT(column) */
1314
+ declare function count(col?: ColRef): Expr;
1315
+ /** COUNT(DISTINCT column) */
1316
+ declare function countDistinct(col: ColRef): Expr;
1317
+ /** SUM(column) */
1318
+ declare function sum(col: ColRef): Expr;
1319
+ /** AVG(column) */
1320
+ declare function avg(col: ColRef): Expr;
1321
+ /** MIN(column) */
1322
+ declare function min(col: ColRef): Expr;
1323
+ /** MAX(column) */
1324
+ declare function max(col: ColRef): Expr;
1325
+ /** Build SELECT clause with columns */
1326
+ declare function select(...cols: Array<ColRef | [ColRef, string]>): Sql;
1327
+ /** Alias a column or expression */
1328
+ declare function as(expression: Sql, alias: string): Sql;
1329
+
1330
+ /**
1331
+ * Validation Utilities
1332
+ *
1333
+ * Request validation and error handling for API endpoints.
1334
+ *
1335
+ * @module query-layer/validation
1336
+ */
1337
+
1338
+ /** Frontend-friendly validation error structure */
1339
+ interface ValidationError {
1340
+ path: string;
1341
+ message: string;
1342
+ expected: string;
1343
+ received: string;
1344
+ }
1345
+ /** Error thrown when validation fails */
1346
+ declare class BadRequestError extends Error {
1347
+ readonly errors: ValidationError[];
1348
+ constructor(typiaErrors: IValidation.IError[]);
1349
+ toJSON(): {
1350
+ error: string;
1351
+ details: ValidationError[];
1352
+ };
1353
+ }
1354
+ /** Assert validation result, throw BadRequestError if invalid */
1355
+ declare function assertValid<T>(result: IValidation<T>): T;
1356
+ /**
1357
+ * Query handler with three entry points for queries.
1358
+ * Use this when writing raw SQL without a query model.
1359
+ */
1360
+ interface QueryHandler<P, R> {
1361
+ run: (params: P) => Promise<R>;
1362
+ fromObject: (input: unknown) => Promise<R>;
1363
+ fromUrl: (url: string | URL) => Promise<R>;
1364
+ }
1365
+ /**
1366
+ * Create a simple query handler with validation.
1367
+ *
1368
+ * @example
1369
+ * const handler = createQueryHandler({
1370
+ * fromUrl: typia.http.createValidateQuery<MyParams>(),
1371
+ * fromObject: typia.createValidate<MyParams>(),
1372
+ * queryFn: async (params) => {
1373
+ * const query = sql`SELECT * FROM ${Table} ${where(...)}`;
1374
+ * return executeQuery(query);
1375
+ * },
1376
+ * });
1377
+ */
1378
+ declare function createQueryHandler<P, R>(config: {
1379
+ fromUrl: (input: string | URLSearchParams) => IValidation<P>;
1380
+ fromObject: (input: unknown) => IValidation<P>;
1381
+ queryFn: (params: P) => Promise<R>;
1382
+ }): QueryHandler<P, R>;
1383
+
630
1384
  type DataModelConfig<T> = Partial<{
631
1385
  ingestion: true;
632
1386
  storage: {
@@ -638,7 +1392,7 @@ type DataModelConfig<T> = Partial<{
638
1392
  parallelism?: number;
639
1393
  }>;
640
1394
 
641
- export { ACKs, type CSVParsingConfig, CSV_DELIMITERS, type CliLogData, DEFAULT_CSV_CONFIG, DEFAULT_JSON_CONFIG, type DataModelConfig, DataSource, type DataSourceConfig, type ExpressRequestWithMoose, type ExtractionResult, type JSONParsingConfig, type KafkaClientConfig, type Logger, MAX_RETRIES, MAX_RETRIES_PRODUCER, MAX_RETRY_TIME_MS, MOOSE_RUNTIME_ENV_PREFIX, MooseCache, MooseClient, MooseUtils, type Producer, RETRY_FACTOR_PRODUCER, RETRY_INITIAL_TIME_MS, type StripDateIntersection, type TaskConfig, type TaskDefinition, type TaskFunction, antiCachePath, cliLog, compilerLog, createProducerConfig, expressMiddleware, getClickhouseClient, getFileName, getKafkaClient, getKafkaProducer, getLegacyMooseUtils, getMooseClients, getMooseUtils, getMooseUtilsFromRequest, isValidCSVDelimiter, logError, mapTstoJs, mooseEnvSecrets, mooseRuntimeEnv, parseCSV, parseJSON, parseJSONWithDates, rewriteImportExtensions };
1395
+ export { ACKs, BadRequestError, type CSVParsingConfig, CSV_DELIMITERS, type CliLogData, type ColRef, Column, type ColumnDef, DEFAULT_CSV_CONFIG, DEFAULT_JSON_CONFIG, type DataModelConfig, DataSource, type DataSourceConfig, type DimensionDef, type Expr, type ExpressRequestWithMoose, type ExtractionResult, type FilterDefBase, type FilterInputTypeHint, type FilterOperator, type FilterParams, type GetMooseUtilsOptions, type JSONParsingConfig, type JoinDef, type KafkaClientConfig, type Logger, MAX_RETRIES, MAX_RETRIES_PRODUCER, MAX_RETRY_TIME_MS, MOOSE_RUNTIME_ENV_PREFIX, MaterializedView, type MetricDef, type ModelFilterDef, type ModelToolOptions, type ModelToolResult, MooseCache, MooseClient, MooseUtils, type Names, OlapTable, type OperatorValueType, type Producer, type QueryBuilder, QueryClient, type QueryHandler, type QueryModel, type QueryModelBase, type QueryModelConfig, type QueryModelFilter, type QueryParts, type QueryRequest, RETRY_FACTOR_PRODUCER, RETRY_INITIAL_TIME_MS, type SortDir, Sql, type SqlValue, type StripDateIntersection, type TaskConfig, type TaskDefinition, type TaskFunction, type ValidationError, and, antiCachePath, as, assertValid, avg, between, buildQuery, cliLog, columnsFromTable, compilerLog, count, countDistinct, createModelTool, createProducerConfig, createQueryHandler, defineQueryModel, deriveInputTypeFromDataType, empty, eq, expressMiddleware, filter, filtersFromTable, getClickhouseClient, getFileName, getKafkaClient, getKafkaProducer, getLegacyMooseUtils, getMooseClients, getMooseUtils, getMooseUtilsFromRequest, groupBy, gt, gte, having, ilike, inList, isEmpty, isNotNull, isNull, isValidCSVDelimiter, join, like, limit, logError, lt, lte, mapTstoJs, max, min, mooseEnvSecrets, mooseRuntimeEnv, ne, not, notIn, offset, or, orderBy, paginate, parseCSV, parseJSON, parseJSONWithDates, raw, registerModelTools, rewriteImportExtensions, select, sum, timeDimensions, where };
642
1396
 
643
1397
  // ── @bayoudhi/moose-lib-serverless additions ──────────────────────────────
644
1398