@tablecraft/engine 0.1.4 → 0.1.6

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.
Files changed (47) hide show
  1. package/dist/core/cursorPagination.d.ts +7 -1
  2. package/dist/core/cursorPagination.d.ts.map +1 -1
  3. package/dist/core/cursorPagination.js +77 -12
  4. package/dist/core/cursorPagination.js.map +1 -1
  5. package/dist/core/fieldSelector.d.ts.map +1 -1
  6. package/dist/core/fieldSelector.js +7 -1
  7. package/dist/core/fieldSelector.js.map +1 -1
  8. package/dist/core/filterBuilder.d.ts.map +1 -1
  9. package/dist/core/filterBuilder.js +2 -41
  10. package/dist/core/filterBuilder.js.map +1 -1
  11. package/dist/core/inputValidator.d.ts.map +1 -1
  12. package/dist/core/inputValidator.js +11 -25
  13. package/dist/core/inputValidator.js.map +1 -1
  14. package/dist/core/metadataBuilder.d.ts.map +1 -1
  15. package/dist/core/metadataBuilder.js +9 -4
  16. package/dist/core/metadataBuilder.js.map +1 -1
  17. package/dist/core/queryBuilder.d.ts.map +1 -1
  18. package/dist/core/queryBuilder.js +21 -10
  19. package/dist/core/queryBuilder.js.map +1 -1
  20. package/dist/core/sortBuilder.d.ts +2 -1
  21. package/dist/core/sortBuilder.d.ts.map +1 -1
  22. package/dist/core/sortBuilder.js +29 -12
  23. package/dist/core/sortBuilder.js.map +1 -1
  24. package/dist/core/subqueryBuilder.d.ts +24 -1
  25. package/dist/core/subqueryBuilder.d.ts.map +1 -1
  26. package/dist/core/subqueryBuilder.js +73 -8
  27. package/dist/core/subqueryBuilder.js.map +1 -1
  28. package/dist/define.d.ts +79 -4
  29. package/dist/define.d.ts.map +1 -1
  30. package/dist/define.js +127 -12
  31. package/dist/define.js.map +1 -1
  32. package/dist/engine.d.ts.map +1 -1
  33. package/dist/engine.js +28 -4
  34. package/dist/engine.js.map +1 -1
  35. package/dist/types/table.d.ts +292 -2
  36. package/dist/types/table.d.ts.map +1 -1
  37. package/dist/types/table.js +29 -2
  38. package/dist/types/table.js.map +1 -1
  39. package/dist/utils/joinUtils.d.ts +7 -0
  40. package/dist/utils/joinUtils.d.ts.map +1 -1
  41. package/dist/utils/joinUtils.js +33 -0
  42. package/dist/utils/joinUtils.js.map +1 -1
  43. package/dist/utils/openapi.d.ts.map +1 -1
  44. package/dist/utils/openapi.js +25 -2
  45. package/dist/utils/openapi.js.map +1 -1
  46. package/package.json +9 -9
  47. package/LICENSE +0 -21
@@ -25,7 +25,10 @@ export class SortBuilder {
25
25
  if (!table)
26
26
  return [];
27
27
  const baseColumns = getTableColumns(table);
28
- // Build a whitelist of sortable fields from base columns AND join columns
28
+ // Build a whitelist of sortable fields from base columns AND join columns.
29
+ // sortable: undefined is treated as sortable (same as true) — only an
30
+ // explicit sortable: false disables it. This matches the introspect.ts
31
+ // default of sortable: true for auto-detected columns.
29
32
  const sortableFields = new Set();
30
33
  for (const col of config.columns) {
31
34
  if (col.sortable !== false) {
@@ -89,31 +92,45 @@ export class SortBuilder {
89
92
  *
90
93
  * Note: This implements a "first-match-wins" strategy. If multiple joins
91
94
  * expose a column with the same name, the first one encountered in a
92
- * depth-first traversal of the join tree will be used.
95
+ * depth-first traversal of the join tree will be used, and a console.warn
96
+ * is emitted to help developers detect and resolve the collision.
93
97
  */
94
98
  resolveJoinColumn(config, fieldName) {
95
99
  if (!config.joins)
96
100
  return undefined;
101
+ // Collect all matches (table name + Column) across all joins (depth-first)
102
+ const matches = [];
97
103
  for (const join of config.joins) {
98
104
  const joinColConfig = join.columns?.find((c) => c.name === fieldName);
99
105
  if (joinColConfig) {
100
106
  const joinedTable = this.schema[join.table];
101
- if (!joinedTable)
102
- continue;
103
- const joinedCols = getTableColumns(joinedTable);
104
- const dbCol = joinColConfig.field ?? fieldName;
105
- const column = joinedCols[dbCol];
106
- if (column)
107
- return column;
107
+ if (joinedTable) {
108
+ const joinedCols = getTableColumns(joinedTable);
109
+ const dbCol = joinColConfig.field ?? fieldName;
110
+ const column = joinedCols[dbCol];
111
+ if (column) {
112
+ matches.push({ table: join.table, column });
113
+ }
114
+ }
108
115
  }
109
116
  // Recurse into nested joins
110
117
  if (join.joins) {
111
118
  const nested = this.resolveJoinColumn({ joins: join.joins }, fieldName);
112
- if (nested)
113
- return nested;
119
+ if (nested) {
120
+ // Treat nested match as a candidate (table name not relevant for warning)
121
+ matches.push({ table: join.table + '(nested)', column: nested });
122
+ }
114
123
  }
115
124
  }
116
- return undefined;
125
+ if (matches.length === 0)
126
+ return undefined;
127
+ if (matches.length > 1) {
128
+ console.warn(`[TableCraft] Sort field '${fieldName}' exists in multiple joins ` +
129
+ `(${matches.map((m) => m.table).join(', ')}). ` +
130
+ `Using first match. ` +
131
+ `Use dot-syntax (e.g. '${matches[0].table}.${fieldName}') to be explicit.`);
132
+ }
133
+ return matches[0].column;
117
134
  }
118
135
  getDefaultSort(config) {
119
136
  if (!config.defaultSort || config.defaultSort.length === 0)
@@ -1 +1 @@
1
- {"version":3,"file":"sortBuilder.js","sourceRoot":"","sources":["../../src/core/sortBuilder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sortBuilder.js","sourceRoot":"","sources":["../../src/core/sortBuilder.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,36 @@
1
1
  import { SQL } from 'drizzle-orm';
2
2
  import { TableConfig } from '../types/table';
3
+ import { Dialect } from './dialect';
3
4
  export declare class SubqueryBuilder {
4
5
  private schema;
5
6
  constructor(schema: Record<string, unknown>);
6
7
  /**
7
8
  * Builds correlated subquery select expressions.
8
9
  * Supports count, exists, and first subquery types.
10
+ *
11
+ * @param dialect - Optional dialect for feature gating. When provided,
12
+ * 'first' mode (which uses PostgreSQL-only `row_to_json`) will throw a
13
+ * DialectError on non-PostgreSQL dialects. Pass 'unknown' to skip the
14
+ * guard (e.g. when dialect cannot be detected).
9
15
  */
10
- buildSubqueries(config: TableConfig): Record<string, SQL> | undefined;
16
+ buildSubqueries(config: TableConfig, dialect?: Dialect): Record<string, SQL> | undefined;
11
17
  private buildSingle;
18
+ /**
19
+ * Builds the WHERE clause SQL for a subquery.
20
+ *
21
+ * Priority:
22
+ * 1. `filterSql` — Drizzle SQL expression (full Drizzle DX, passed through as-is)
23
+ * 2. `filterConditions` — structured array of conditions (typed, safe, recommended)
24
+ * 3. `filter` — raw SQL string (@deprecated, developer-authored only)
25
+ * 4. fallback — `true` (uncorrelated, scans whole table)
26
+ */
27
+ private buildFilter;
28
+ /**
29
+ * Converts a `SubqueryCondition[]` into a single AND-combined SQL expression.
30
+ *
31
+ * Column references → emitted via sql.raw() — developer-defined, not user input
32
+ * Literal values → parameterized via sql`${value}` to prevent injection
33
+ */
34
+ private buildStructuredFilter;
12
35
  }
13
36
  //# sourceMappingURL=subqueryBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"subqueryBuilder.d.ts","sourceRoot":"","sources":["../../src/core/subqueryBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,GAAG,EAEJ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAkB,MAAM,gBAAgB,CAAC;AAE7D,qBAAa,eAAe;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEnD;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS;IAuBrE,OAAO,CAAC,WAAW;CAiBpB"}
1
+ {"version":3,"file":"subqueryBuilder.d.ts","sourceRoot":"","sources":["../../src/core/subqueryBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,GAAG,EAEJ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAqC,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,qBAAa,eAAe;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEnD;;;;;;;;OAQG;IACH,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS;IAuBxF,OAAO,CAAC,WAAW;IAoBnB;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;IAanB;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;CAsB9B"}
@@ -1,4 +1,16 @@
1
1
  import { sql, } from 'drizzle-orm';
2
+ import { DialectError } from '../errors';
3
+ // Maps our operator enum to the SQL operator string
4
+ const OP_MAP = {
5
+ eq: '=',
6
+ neq: '!=',
7
+ gt: '>',
8
+ gte: '>=',
9
+ lt: '<',
10
+ lte: '<=',
11
+ like: 'LIKE',
12
+ ilike: 'ILIKE',
13
+ };
2
14
  export class SubqueryBuilder {
3
15
  schema;
4
16
  constructor(schema) {
@@ -7,8 +19,13 @@ export class SubqueryBuilder {
7
19
  /**
8
20
  * Builds correlated subquery select expressions.
9
21
  * Supports count, exists, and first subquery types.
22
+ *
23
+ * @param dialect - Optional dialect for feature gating. When provided,
24
+ * 'first' mode (which uses PostgreSQL-only `row_to_json`) will throw a
25
+ * DialectError on non-PostgreSQL dialects. Pass 'unknown' to skip the
26
+ * guard (e.g. when dialect cannot be detected).
10
27
  */
11
- buildSubqueries(config) {
28
+ buildSubqueries(config, dialect) {
12
29
  if (!config.subqueries || config.subqueries.length === 0) {
13
30
  return undefined;
14
31
  }
@@ -20,28 +37,76 @@ export class SubqueryBuilder {
20
37
  const subTable = this.schema[sub.table];
21
38
  if (!subTable)
22
39
  continue;
23
- const subQuery = this.buildSingle(sub, subTable);
40
+ const subQuery = this.buildSingle(sub, subTable, dialect);
24
41
  if (subQuery) {
25
42
  result[sub.alias] = subQuery;
26
43
  }
27
44
  }
28
45
  return Object.keys(result).length > 0 ? result : undefined;
29
46
  }
30
- buildSingle(sub, subTable) {
31
- // The filter string is a raw SQL correlation condition
32
- // e.g. "orders.user_id = users.id"
33
- // TODO: replace with a structured, parameterised representation
34
- const filterSql = sub.filter ? sql.raw(sub.filter) : sql `true`;
47
+ buildSingle(sub, subTable, dialect) {
48
+ const filterSql = this.buildFilter(sub, dialect);
35
49
  switch (sub.type) {
36
50
  case 'count':
37
51
  return sql `(SELECT count(*) FROM ${subTable} WHERE ${filterSql})`;
38
52
  case 'exists':
39
53
  return sql `EXISTS (SELECT 1 FROM ${subTable} WHERE ${filterSql})`;
40
- case 'first':
54
+ case 'first': {
55
+ // 'first' uses row_to_json() which is PostgreSQL-only.
56
+ if (dialect && dialect !== 'unknown' && dialect !== 'postgresql') {
57
+ throw new DialectError('first', dialect);
58
+ }
41
59
  return sql `(SELECT row_to_json(t) FROM (SELECT * FROM ${subTable} WHERE ${filterSql} LIMIT 1) t)`;
60
+ }
42
61
  default:
43
62
  return undefined;
44
63
  }
45
64
  }
65
+ /**
66
+ * Builds the WHERE clause SQL for a subquery.
67
+ *
68
+ * Priority:
69
+ * 1. `filterSql` — Drizzle SQL expression (full Drizzle DX, passed through as-is)
70
+ * 2. `filterConditions` — structured array of conditions (typed, safe, recommended)
71
+ * 3. `filter` — raw SQL string (@deprecated, developer-authored only)
72
+ * 4. fallback — `true` (uncorrelated, scans whole table)
73
+ */
74
+ buildFilter(sub, dialect) {
75
+ if (sub.filterSql) {
76
+ return sub.filterSql;
77
+ }
78
+ if (sub.filterConditions && sub.filterConditions.length > 0) {
79
+ return this.buildStructuredFilter(sub.filterConditions, dialect);
80
+ }
81
+ if (sub.filter) {
82
+ return sql.raw(sub.filter);
83
+ }
84
+ return sql `true`;
85
+ }
86
+ /**
87
+ * Converts a `SubqueryCondition[]` into a single AND-combined SQL expression.
88
+ *
89
+ * Column references → emitted via sql.raw() — developer-defined, not user input
90
+ * Literal values → parameterized via sql`${value}` to prevent injection
91
+ */
92
+ buildStructuredFilter(conditions, dialect) {
93
+ if (conditions.length === 0)
94
+ return sql `true`;
95
+ const parts = conditions.map((cond) => {
96
+ const leftSql = 'column' in cond.left ? sql.raw(cond.left.column) : sql `${cond.left.value}`;
97
+ const rightSql = 'column' in cond.right ? sql.raw(cond.right.column) : sql `${cond.right.value}`;
98
+ const op = cond.op ?? 'eq';
99
+ if (op === 'ilike') {
100
+ if (dialect && dialect !== 'unknown' && dialect !== 'postgresql') {
101
+ // MySQL/SQLite don't support ILIKE directly. We rewrite to LOWER() LIKE LOWER().
102
+ return sql `LOWER(${leftSql}) LIKE LOWER(${rightSql})`;
103
+ }
104
+ }
105
+ const opStr = OP_MAP[op];
106
+ return sql `${leftSql} ${sql.raw(opStr)} ${rightSql}`;
107
+ });
108
+ // AND-combine all parts
109
+ return parts.reduce((acc, part) => sql `${acc} AND ${part}`);
110
+ }
46
111
  }
47
112
  //# sourceMappingURL=subqueryBuilder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subqueryBuilder.js","sourceRoot":"","sources":["../../src/core/subqueryBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,GAAG,GACJ,MAAM,aAAa,CAAC;AAGrB,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,MAA+B;QAA/B,WAAM,GAAN,MAAM,CAAyB;IAAG,CAAC;IAEvD;;;OAGG;IACH,eAAe,CAAC,MAAmB;QACjC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAU,CAAC;QACpD,IAAI,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC;QAEjC,MAAM,MAAM,GAAwB,EAAE,CAAC;QAEvC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAU,CAAC;YACjD,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAExB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACjD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7D,CAAC;IAEO,WAAW,CAAC,GAAmB,EAAE,QAAe;QACtD,uDAAuD;QACvD,mCAAmC;QACnC,gEAAgE;QAChE,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA,MAAM,CAAC;QAE/D,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,OAAO;gBACV,OAAO,GAAG,CAAA,yBAAyB,QAAQ,UAAU,SAAS,GAAG,CAAC;YACpE,KAAK,QAAQ;gBACX,OAAO,GAAG,CAAA,yBAAyB,QAAQ,UAAU,SAAS,GAAG,CAAC;YACpE,KAAK,OAAO;gBACV,OAAO,GAAG,CAAA,8CAA8C,QAAQ,UAAU,SAAS,cAAc,CAAC;YACpG;gBACE,OAAO,SAAS,CAAC;QACrB,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"subqueryBuilder.js","sourceRoot":"","sources":["../../src/core/subqueryBuilder.ts"],"names":[],"mappings":"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"}
package/dist/define.d.ts CHANGED
@@ -21,8 +21,8 @@ export declare const drizzleOperators: {
21
21
  not: typeof not;
22
22
  sql: typeof sql;
23
23
  };
24
- import { EngineParams, EngineContext } from './types/engine';
25
- import { TableConfig, ColumnConfig, Operator, FilterExpression, ColumnFormat, DatePreset } from './types/table';
24
+ import type { EngineParams, EngineContext, CountMode } from './types/engine';
25
+ import { TableConfig, ColumnConfig, Operator, FilterExpression, ColumnFormat, DatePreset, SubqueryCondition } from './types/table';
26
26
  type InferColumns<T> = T extends {
27
27
  _: {
28
28
  columns: infer C;
@@ -50,6 +50,8 @@ export interface RuntimeExtensions<T extends Table = Table> {
50
50
  rawOrderBys: SQL[];
51
51
  ctes: Map<string, SQL>;
52
52
  sqlJoinConditions: Map<string, SQL>;
53
+ /** How row counting is performed. Defaults to 'exact' when not set. */
54
+ countMode?: CountMode;
53
55
  hooks?: {
54
56
  beforeQuery?: (params: any, context: any) => any;
55
57
  afterQuery?: (data: Record<string, unknown>[], params: any, context: any) => any;
@@ -153,6 +155,7 @@ export declare class TableDefinitionBuilder<T extends Table = Table> {
153
155
  computed(name: string, expression: SQL, options?: {
154
156
  type?: ColumnConfig['type'];
155
157
  label?: string;
158
+ sortable?: boolean;
156
159
  }): this;
157
160
  where(condition: {
158
161
  field: string;
@@ -271,9 +274,81 @@ export declare class TableDefinitionBuilder<T extends Table = Table> {
271
274
  }): this;
272
275
  rawWhere(sqlExpr: SQL): this;
273
276
  rawJoin(sqlExpr: SQL): this;
277
+ /**
278
+ * Add a raw SQL ORDER BY expression.
279
+ *
280
+ * **Warning**: This bypasses the sortable whitelist entirely. The expression
281
+ * is appended unconditionally to ORDER BY without any field validation.
282
+ * Ensure the SQL is safe and not derived from user-supplied input.
283
+ * Prefer `.sort()` or `.sortable()` for user-facing sort controls.
284
+ */
274
285
  rawOrderBy(sqlExpr: SQL): this;
275
286
  cte(name: string, sqlExpr: SQL): this;
276
- subquery(alias: string, table: Table, type: 'count' | 'exists' | 'first', filter?: string): this;
287
+ /**
288
+ * Attach a correlated subquery to every row.
289
+ *
290
+ * The `filter` parameter controls the subquery's WHERE clause and accepts
291
+ * **three forms** — pick whichever fits your style:
292
+ *
293
+ * ---
294
+ *
295
+ * ### 1. Drizzle `sql\`...\`` expression *(best DX — use your schema columns directly)*
296
+ *
297
+ * Import `sql` from `drizzle-orm` and write the WHERE clause exactly as you
298
+ * would in any Drizzle query. TableCraft passes the expression through unchanged,
299
+ * so the full power of Drizzle is available — joins, functions, OR logic, anything.
300
+ * You own the safety of the expression.
301
+ *
302
+ * ```ts
303
+ * import { sql } from 'drizzle-orm';
304
+ * import { orders, orderItems } from '../db/schema';
305
+ *
306
+ * .subquery('itemCount', orderItems, 'count',
307
+ * sql`${orderItems.orderId} = ${orders.id}`)
308
+ *
309
+ * // With an extra condition:
310
+ * .subquery('activeItemCount', orderItems, 'count',
311
+ * sql`${orderItems.orderId} = ${orders.id} AND ${orderItems.status} = ${'active'}`)
312
+ * ```
313
+ *
314
+ * ---
315
+ *
316
+ * ### 2. Structured `SubqueryCondition[]` *(typed, injection-safe)*
317
+ *
318
+ * Pass an array of condition objects. Each has `left`, `op` (default `'eq'`),
319
+ * and `right` operands — either `{ column: 'table.column' }` or `{ value: literal }`.
320
+ * Conditions are AND-combined. Literal values are parameterized automatically.
321
+ *
322
+ * ```ts
323
+ * // Simple column-to-column join:
324
+ * .subquery('itemCount', orderItems, 'count', [
325
+ * { left: { column: 'order_items.order_id' }, op: 'eq', right: { column: 'orders.id' } },
326
+ * ])
327
+ *
328
+ * // With a literal value filter:
329
+ * .subquery('activeItemCount', orderItems, 'count', [
330
+ * { left: { column: 'order_items.order_id' }, op: 'eq', right: { column: 'orders.id' } },
331
+ * { left: { column: 'order_items.status' }, op: 'eq', right: { value: 'active' } },
332
+ * ])
333
+ * ```
334
+ *
335
+ * ---
336
+ *
337
+ * ### 3. Raw SQL string *(@deprecated — developer-authored constants only)*
338
+ *
339
+ * Still accepted for backwards compatibility. Must be a hardcoded string authored
340
+ * by the developer — never derived from user input. Prefer form 1 or 2 instead.
341
+ *
342
+ * ```ts
343
+ * // @deprecated
344
+ * .subquery('itemCount', orderItems, 'count', 'order_items.order_id = orders.id')
345
+ * ```
346
+ *
347
+ * ---
348
+ *
349
+ * Omitting `filter` creates an uncorrelated subquery (full table scan).
350
+ */
351
+ subquery(alias: string, table: Table, type: 'count' | 'exists' | 'first', filter?: string | SubqueryCondition[] | SQL): this;
277
352
  softDelete(field?: string): this;
278
353
  tenant(field?: string): this;
279
354
  exportable(...formats: ('csv' | 'json')[]): this;
@@ -288,7 +363,7 @@ export declare class TableDefinitionBuilder<T extends Table = Table> {
288
363
  * 'estimated' = PostgreSQL's reltuples — fast but approximate
289
364
  * 'none' = skip counting entirely — fastest
290
365
  */
291
- countMode(mode: 'exact' | 'estimated' | 'none'): this;
366
+ countMode(mode: CountMode): this;
292
367
  /** Enable DISTINCT on queries */
293
368
  distinct(): this;
294
369
  /** Add a hook that runs before every query */
@@ -1 +1 @@
1
- {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}
package/dist/define.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getTableName, eq, ne, gt, gte, lt, lte, like, ilike, inArray, notInArray, between, notBetween, isNull, isNotNull, exists, notExists, and, or, not, sql } from 'drizzle-orm';
1
+ import { SQL, getTableName, eq, ne, gt, gte, lt, lte, like, ilike, inArray, notInArray, between, notBetween, isNull, isNotNull, exists, notExists, and, or, not, sql } from 'drizzle-orm';
2
2
  export const drizzleOperators = {
3
3
  eq, ne, gt, gte, lt, lte,
4
4
  like, ilike, inArray, notInArray,
@@ -309,7 +309,7 @@ export class TableDefinitionBuilder {
309
309
  type: options?.type ?? 'string',
310
310
  label: options?.label ?? name,
311
311
  hidden: false,
312
- sortable: true,
312
+ sortable: options?.sortable ?? true,
313
313
  filterable: false,
314
314
  computed: true,
315
315
  });
@@ -540,7 +540,19 @@ export class TableDefinitionBuilder {
540
540
  this._ext.rawJoins.push(sqlExpr);
541
541
  return this;
542
542
  }
543
+ /**
544
+ * Add a raw SQL ORDER BY expression.
545
+ *
546
+ * **Warning**: This bypasses the sortable whitelist entirely. The expression
547
+ * is appended unconditionally to ORDER BY without any field validation.
548
+ * Ensure the SQL is safe and not derived from user-supplied input.
549
+ * Prefer `.sort()` or `.sortable()` for user-facing sort controls.
550
+ */
543
551
  rawOrderBy(sqlExpr) {
552
+ if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
553
+ console.warn(`[TableCraft] rawOrderBy() bypasses the sortable whitelist and should not be used with user input. ` +
554
+ `Expression: ${sqlExpr}`);
555
+ }
544
556
  this._ext.rawOrderBys.push(sqlExpr);
545
557
  return this;
546
558
  }
@@ -549,15 +561,121 @@ export class TableDefinitionBuilder {
549
561
  return this;
550
562
  }
551
563
  // ──── Subqueries ────
564
+ /**
565
+ * Attach a correlated subquery to every row.
566
+ *
567
+ * The `filter` parameter controls the subquery's WHERE clause and accepts
568
+ * **three forms** — pick whichever fits your style:
569
+ *
570
+ * ---
571
+ *
572
+ * ### 1. Drizzle `sql\`...\`` expression *(best DX — use your schema columns directly)*
573
+ *
574
+ * Import `sql` from `drizzle-orm` and write the WHERE clause exactly as you
575
+ * would in any Drizzle query. TableCraft passes the expression through unchanged,
576
+ * so the full power of Drizzle is available — joins, functions, OR logic, anything.
577
+ * You own the safety of the expression.
578
+ *
579
+ * ```ts
580
+ * import { sql } from 'drizzle-orm';
581
+ * import { orders, orderItems } from '../db/schema';
582
+ *
583
+ * .subquery('itemCount', orderItems, 'count',
584
+ * sql`${orderItems.orderId} = ${orders.id}`)
585
+ *
586
+ * // With an extra condition:
587
+ * .subquery('activeItemCount', orderItems, 'count',
588
+ * sql`${orderItems.orderId} = ${orders.id} AND ${orderItems.status} = ${'active'}`)
589
+ * ```
590
+ *
591
+ * ---
592
+ *
593
+ * ### 2. Structured `SubqueryCondition[]` *(typed, injection-safe)*
594
+ *
595
+ * Pass an array of condition objects. Each has `left`, `op` (default `'eq'`),
596
+ * and `right` operands — either `{ column: 'table.column' }` or `{ value: literal }`.
597
+ * Conditions are AND-combined. Literal values are parameterized automatically.
598
+ *
599
+ * ```ts
600
+ * // Simple column-to-column join:
601
+ * .subquery('itemCount', orderItems, 'count', [
602
+ * { left: { column: 'order_items.order_id' }, op: 'eq', right: { column: 'orders.id' } },
603
+ * ])
604
+ *
605
+ * // With a literal value filter:
606
+ * .subquery('activeItemCount', orderItems, 'count', [
607
+ * { left: { column: 'order_items.order_id' }, op: 'eq', right: { column: 'orders.id' } },
608
+ * { left: { column: 'order_items.status' }, op: 'eq', right: { value: 'active' } },
609
+ * ])
610
+ * ```
611
+ *
612
+ * ---
613
+ *
614
+ * ### 3. Raw SQL string *(@deprecated — developer-authored constants only)*
615
+ *
616
+ * Still accepted for backwards compatibility. Must be a hardcoded string authored
617
+ * by the developer — never derived from user input. Prefer form 1 or 2 instead.
618
+ *
619
+ * ```ts
620
+ * // @deprecated
621
+ * .subquery('itemCount', orderItems, 'count', 'order_items.order_id = orders.id')
622
+ * ```
623
+ *
624
+ * ---
625
+ *
626
+ * Omitting `filter` creates an uncorrelated subquery (full table scan).
627
+ */
552
628
  subquery(alias, table, type, filter) {
553
629
  if (!this._config.subqueries)
554
630
  this._config.subqueries = [];
555
- this._config.subqueries.push({
556
- alias,
557
- table: getTableName(table),
558
- type,
559
- filter,
560
- });
631
+ let entry;
632
+ if (filter === undefined || filter === null) {
633
+ entry = { alias, table: getTableName(table), type };
634
+ }
635
+ else if (filter instanceof SQL) {
636
+ // Drizzle SQL expression — stored as runtime-only filterSql (not JSON-serializable)
637
+ entry = { alias, table: getTableName(table), type, filterSql: filter };
638
+ }
639
+ else if (typeof filter === 'string') {
640
+ // @deprecated raw string — kept for backwards compatibility
641
+ entry = { alias, table: getTableName(table), type, filter };
642
+ }
643
+ else {
644
+ entry = { alias, table: getTableName(table), type, filterConditions: filter };
645
+ }
646
+ // Dedupe subquery entries by alias — replace if exists
647
+ const existingIdx = this._config.subqueries.findIndex(e => e.alias === alias);
648
+ if (existingIdx >= 0) {
649
+ this._config.subqueries[existingIdx] = entry;
650
+ }
651
+ else {
652
+ this._config.subqueries.push(entry);
653
+ }
654
+ // Register as a computed column so sorting/filtering validation passes.
655
+ // The actual SQL expression is built at query-time by SubqueryBuilder and
656
+ // merged into the sqlExpressions map by the engine.
657
+ //
658
+ // 'first' mode returns row_to_json() — a non-scalar JSON object — which
659
+ // cannot be used in ORDER BY. Mark it sortable: false to prevent DB errors.
660
+ // 'count' (integer) and 'exists' (boolean) are scalar and safe to sort.
661
+ const existingCol = this._config.columns.find(c => c.name === alias);
662
+ if (existingCol) {
663
+ existingCol.type = type === 'exists' ? 'boolean' : type === 'count' ? 'number' : 'json';
664
+ existingCol.sortable = type !== 'first';
665
+ existingCol.filterable = false;
666
+ existingCol.computed = true;
667
+ }
668
+ else {
669
+ this._config.columns.push({
670
+ name: alias,
671
+ type: type === 'exists' ? 'boolean' : type === 'count' ? 'number' : 'json',
672
+ label: alias,
673
+ hidden: false,
674
+ sortable: type !== 'first',
675
+ filterable: false,
676
+ computed: true,
677
+ });
678
+ }
561
679
  return this;
562
680
  }
563
681
  // ──── Platform Features ────
@@ -599,10 +717,7 @@ export class TableDefinitionBuilder {
599
717
  * 'none' = skip counting entirely — fastest
600
718
  */
601
719
  countMode(mode) {
602
- if (!this._config._countMode) {
603
- this._config._countMode = mode;
604
- }
605
- this._config._countMode = mode;
720
+ this._ext.countMode = mode;
606
721
  return this;
607
722
  }
608
723
  // ──── DISTINCT ────