effect-qb 0.12.3 → 0.13.0

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 (38) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +372 -224
  3. package/dist/mysql.js +5037 -4962
  4. package/dist/postgres.js +4978 -4903
  5. package/package.json +8 -1
  6. package/src/internal/column-state.ts +9 -1
  7. package/src/internal/column.ts +30 -17
  8. package/src/internal/expression-ast.ts +11 -0
  9. package/src/internal/expression.ts +2 -0
  10. package/src/internal/query-factory.ts +50 -63
  11. package/src/internal/query.ts +16 -2
  12. package/src/internal/sql-expression-renderer.ts +33 -9
  13. package/src/internal/table-options.ts +2 -1
  14. package/src/internal/table.ts +4 -3
  15. package/src/mysql/column.ts +2 -1
  16. package/src/mysql/executor.ts +20 -17
  17. package/src/mysql/function/aggregate.ts +6 -0
  18. package/src/mysql/function/core.ts +4 -0
  19. package/src/mysql/function/index.ts +19 -0
  20. package/src/mysql/function/json.ts +4 -0
  21. package/src/mysql/function/string.ts +6 -0
  22. package/src/mysql/function/temporal.ts +103 -0
  23. package/src/mysql/function/window.ts +7 -0
  24. package/src/mysql/private/query.ts +13 -0
  25. package/src/mysql/query.ts +1 -26
  26. package/src/mysql.ts +2 -0
  27. package/src/postgres/column.ts +1 -1
  28. package/src/postgres/executor.ts +19 -17
  29. package/src/postgres/function/aggregate.ts +6 -0
  30. package/src/postgres/function/core.ts +4 -0
  31. package/src/postgres/function/index.ts +19 -0
  32. package/src/postgres/function/json.ts +4 -0
  33. package/src/postgres/function/string.ts +6 -0
  34. package/src/postgres/function/temporal.ts +107 -0
  35. package/src/postgres/function/window.ts +7 -0
  36. package/src/postgres/private/query.ts +13 -0
  37. package/src/postgres/query.ts +1 -26
  38. package/src/postgres.ts +2 -0
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "effect-qb",
3
- "version": "0.12.3",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
7
7
  "src",
8
+ "CHANGELOG.md",
8
9
  "README.md"
9
10
  ],
10
11
  "exports": {
@@ -18,11 +19,17 @@
18
19
  },
19
20
  "./package.json": "./package.json"
20
21
  },
22
+ "imports": {
23
+ "#postgres": "./src/postgres.ts",
24
+ "#mysql": "./src/mysql.ts",
25
+ "#internal/*": "./src/internal/*"
26
+ },
21
27
  "publishConfig": {
22
28
  "access": "public"
23
29
  },
24
30
  "scripts": {
25
31
  "build": "bun scripts/build-package.ts",
32
+ "release": "bun scripts/release.ts",
26
33
  "test": "bun test",
27
34
  "test:types": "bunx tsgo -p tsconfig.type-tests.json",
28
35
  "test:integration": "bun scripts/test-integration.ts",
@@ -42,6 +42,8 @@ export interface ColumnState<
42
42
  readonly primaryKey: PrimaryKey
43
43
  readonly unique: Unique
44
44
  readonly references: Ref
45
+ readonly defaultValue?: Expression.Any
46
+ readonly generatedValue?: Expression.Any
45
47
  readonly source: Source
46
48
  readonly dependencies: Dependencies
47
49
  }
@@ -93,6 +95,8 @@ export interface ColumnDefinition<
93
95
  readonly primaryKey: PrimaryKey
94
96
  readonly unique: Unique
95
97
  readonly references: Ref
98
+ readonly defaultValue?: Expression.Any
99
+ readonly generatedValue?: Expression.Any
96
100
  }
97
101
  }
98
102
 
@@ -249,6 +253,8 @@ export const makeColumnDefinition = <
249
253
  primaryKey: metadata.primaryKey,
250
254
  unique: metadata.unique,
251
255
  references: metadata.references,
256
+ defaultValue: metadata.defaultValue,
257
+ generatedValue: metadata.generatedValue,
252
258
  source: undefined as Source,
253
259
  dependencies: {} as Dependencies
254
260
  }
@@ -338,7 +344,9 @@ export const remapColumnDefinition = <
338
344
  generated: metadata.generated,
339
345
  primaryKey: metadata.primaryKey,
340
346
  unique: metadata.unique,
341
- references: metadata.references
347
+ references: metadata.references,
348
+ defaultValue: metadata.defaultValue,
349
+ generatedValue: metadata.generatedValue
342
350
  }
343
351
  if (ExpressionAst.TypeId in column) {
344
352
  next[ExpressionAst.TypeId] = (column as unknown as {
@@ -105,6 +105,11 @@ type GeneratedColumn<Column extends AnyColumnDefinition> = ColumnDefinition<
105
105
  ReferencesOf<Column>
106
106
  >
107
107
 
108
+ type CompatibleColumnExpression<
109
+ Column extends AnyColumnDefinition,
110
+ Value extends Expression.Any
111
+ > = [Expression.RuntimeOf<Value>] extends [SelectType<Column>] ? Column : never
112
+
108
113
  type ReferencingColumn<
109
114
  Column extends AnyColumnDefinition,
110
115
  Target extends AnyBoundColumn
@@ -378,24 +383,30 @@ export const unique = <Column extends AnyColumnDefinition>(
378
383
  unique: true
379
384
  })
380
385
 
381
- /** Marks a column as having a server-side default and therefore optional on insert. */
382
- export const hasDefault = <Column extends AnyColumnDefinition>(
383
- column: Column[typeof ColumnTypeId]["generated"] extends true ? never : Column
384
- ): HasDefaultColumn<Column> =>
385
- mapColumn(column, {
386
- ...column.metadata,
387
- hasDefault: true
388
- })
386
+ /** Marks a column as having a database default expression and therefore optional on insert. */
387
+ export const default_ = <Value extends Expression.Any>(value: Value) =>
388
+ <Column extends AnyColumnDefinition>(
389
+ column: Column[typeof ColumnTypeId]["generated"] extends true ? never : CompatibleColumnExpression<Column, Value>
390
+ ): HasDefaultColumn<Column> =>
391
+ mapColumn(column, {
392
+ ...column.metadata,
393
+ hasDefault: true,
394
+ defaultValue: value,
395
+ generatedValue: undefined
396
+ })
389
397
 
390
- /** Marks a column as generated by the database and omitted from insert/update. */
391
- export const generated = <Column extends AnyColumnDefinition>(
392
- column: Column[typeof ColumnTypeId]["hasDefault"] extends true ? never : Column
393
- ): GeneratedColumn<Column> =>
394
- mapColumn(column, {
395
- ...column.metadata,
396
- generated: true,
397
- hasDefault: false
398
- })
398
+ /** Marks a column as generated by the database expression and omitted from insert/update. */
399
+ export const generated = <Value extends Expression.Any>(value: Value) =>
400
+ <Column extends AnyColumnDefinition>(
401
+ column: Column[typeof ColumnTypeId]["hasDefault"] extends true ? never : CompatibleColumnExpression<Column, Value>
402
+ ): GeneratedColumn<Column> =>
403
+ mapColumn(column, {
404
+ ...column.metadata,
405
+ generated: true,
406
+ hasDefault: false,
407
+ defaultValue: undefined,
408
+ generatedValue: value
409
+ })
399
410
 
400
411
  /**
401
412
  * Attaches a lazy foreign-key reference to another bound column.
@@ -415,3 +426,5 @@ export const references = <Target extends AnyBoundColumn>(target: () => Target)
415
426
  export type Any = AnyColumnDefinition
416
427
  /** Convenience alias for any bound column. */
417
428
  export type AnyBound = BoundColumn<any, any, any, any, any, any, any, any, any, any, any, any>
429
+
430
+ export { default_ as default }
@@ -34,6 +34,16 @@ export interface CastNode<
34
34
  readonly target: Target
35
35
  }
36
36
 
37
+ /** General SQL function call captured by the internal expression AST. */
38
+ export interface FunctionCallNode<
39
+ Name extends string = string,
40
+ Args extends readonly Expression.Any[] = readonly Expression.Any[]
41
+ > {
42
+ readonly kind: "function"
43
+ readonly name: Name
44
+ readonly args: Args
45
+ }
46
+
37
47
  /** `excluded.column` reference used inside insert conflict handlers. */
38
48
  export interface ExcludedNode<
39
49
  ColumnName extends string = string
@@ -325,6 +335,7 @@ export type Any =
325
335
  | ColumnNode
326
336
  | LiteralNode
327
337
  | CastNode
338
+ | FunctionCallNode
328
339
  | ExcludedNode
329
340
  | UnaryNode
330
341
  | BinaryNode
@@ -168,6 +168,8 @@ export declare namespace DbType {
168
168
  export type PgDate = Base<"postgres", "date">
169
169
  export type PgTime = Base<"postgres", "time">
170
170
  export type PgTimestamp = Base<"postgres", "timestamp">
171
+ export type PgTimetz = Base<"postgres", "timetz">
172
+ export type PgTimestamptz = Base<"postgres", "timestamptz">
171
173
  export type PgInterval = Base<"postgres", "interval">
172
174
  export type PgBytea = Base<"postgres", "bytea">
173
175
  export type PgJsonb = Base<"postgres", "jsonb">
@@ -3802,7 +3802,7 @@ export function makeDialectQuery<
3802
3802
  const firstRow = rows[0]
3803
3803
  const firstColumns = Object.keys(firstRow)
3804
3804
  if (firstColumns.length === 0) {
3805
- throw new Error("values(...) rows must specify at least one column; use defaultValues(...) instead")
3805
+ throw new Error("values(...) rows must specify at least one column; use insert(target) for default-only inserts instead")
3806
3806
  }
3807
3807
  const columns = firstColumns as [string, ...string[]]
3808
3808
  const normalizedRows = rows.map((row) => {
@@ -4072,12 +4072,6 @@ type InsertPlanSelectionShapeError<
4072
4072
  readonly __effect_qb_hint__: "Project a flat object like select({ id: ..., email: ... }) with column-name keys"
4073
4073
  }
4074
4074
 
4075
- type DefaultValuesError<Target extends MutationTargetLike> = Target & {
4076
- readonly __effect_qb_error__: "effect-qb: defaultValues(...) requires every insert column to be optional or generated"
4077
- readonly __effect_qb_required_columns__: RequiredKeys<Table.InsertOf<Target>>
4078
- readonly __effect_qb_hint__: "Use insert(...) for required columns, or mark columns nullable/hasDefault/generated"
4079
- }
4080
-
4081
4075
  type MysqlConflictTargetError<Target> = Target & {
4082
4076
  readonly __effect_qb_error__: "effect-qb: mysql does not support named or predicate-scoped conflict targets"
4083
4077
  readonly __effect_qb_hint__: "Use a column tuple target, or rely on MySQL duplicate-key resolution without target predicates"
@@ -4558,34 +4552,77 @@ type AsCurriedResult<
4558
4552
  return makeDerivedSource(value as CompletePlan<QueryPlan<any, any, any, any, any, any, any, any, any, any>>, resolvedAlias)
4559
4553
  }
4560
4554
 
4555
+ function with_<
4556
+ Alias extends string
4557
+ >(
4558
+ alias: Alias
4559
+ ): <PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
4560
+ value: CompletePlan<PlanValue>
4561
+ ) => import("./query.js").CteSource<PlanValue, Alias>
4561
4562
  function with_<
4562
4563
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
4563
4564
  Alias extends string
4564
4565
  >(
4565
4566
  value: CompletePlan<PlanValue>,
4566
4567
  alias: Alias
4567
- ): import("./query.js").CteSource<PlanValue, Alias> {
4568
- return makeCteSource(value, alias)
4568
+ ): import("./query.js").CteSource<PlanValue, Alias>
4569
+ function with_(valueOrAlias: unknown, alias?: string): unknown {
4570
+ if (alias === undefined) {
4571
+ return (value: unknown) => with_(value as any, valueOrAlias as string)
4572
+ }
4573
+ return makeCteSource(
4574
+ valueOrAlias as CompletePlan<QueryPlan<any, any, any, any, any, any, any, any, any, any>>,
4575
+ alias
4576
+ )
4569
4577
  }
4570
4578
 
4579
+ function withRecursive_<
4580
+ Alias extends string
4581
+ >(
4582
+ alias: Alias
4583
+ ): <PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
4584
+ value: CompletePlan<PlanValue>
4585
+ ) => import("./query.js").CteSource<PlanValue, Alias>
4571
4586
  function withRecursive_<
4572
4587
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
4573
4588
  Alias extends string
4574
4589
  >(
4575
4590
  value: CompletePlan<PlanValue>,
4576
4591
  alias: Alias
4577
- ): import("./query.js").CteSource<PlanValue, Alias> {
4578
- return makeCteSource(value, alias, true)
4592
+ ): import("./query.js").CteSource<PlanValue, Alias>
4593
+ function withRecursive_(valueOrAlias: unknown, alias?: string): unknown {
4594
+ if (alias === undefined) {
4595
+ return (value: unknown) => withRecursive_(value as any, valueOrAlias as string)
4596
+ }
4597
+ return makeCteSource(
4598
+ valueOrAlias as CompletePlan<QueryPlan<any, any, any, any, any, any, any, any, any, any>>,
4599
+ alias,
4600
+ true
4601
+ )
4579
4602
  }
4580
4603
 
4604
+ function lateral<
4605
+ Alias extends string
4606
+ >(
4607
+ alias: Alias
4608
+ ): <PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
4609
+ value: PlanValue
4610
+ ) => import("./query.js").LateralSource<PlanValue, Alias>
4581
4611
  function lateral<
4582
4612
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
4583
4613
  Alias extends string
4584
4614
  >(
4585
4615
  value: PlanValue,
4586
4616
  alias: Alias
4587
- ): import("./query.js").LateralSource<PlanValue, Alias> {
4588
- return makeLateralSource(value, alias)
4617
+ ): import("./query.js").LateralSource<PlanValue, Alias>
4618
+ function lateral(valueOrAlias: unknown, alias?: string): unknown {
4619
+ if (alias === undefined) {
4620
+ return (value: unknown) => lateral(value as any, valueOrAlias as string)
4621
+ }
4622
+ return makeLateralSource(
4623
+ valueOrAlias as QueryPlan<any, any, any, any, any, any, any, any, any, any>,
4624
+ alias
4625
+ )
4589
4626
  }
4590
4627
 
4591
4628
  const values = <
@@ -5714,55 +5751,6 @@ type AsCurriedResult<
5714
5751
  }, undefined as unknown as TrueFormula, "write", "insert", target, insertState)
5715
5752
  }
5716
5753
 
5717
- const defaultValues = <
5718
- Target extends MutationTargetLike
5719
- >(
5720
- target: RequiredKeys<Table.InsertOf<Target>> extends never ? Target : DefaultValuesError<Target>
5721
- ): QueryPlan<
5722
- {},
5723
- never,
5724
- AddAvailable<{}, SourceNameOf<Target>>,
5725
- TableDialectOf<Target>,
5726
- never,
5727
- SourceNameOf<Target>,
5728
- never,
5729
- TrueFormula,
5730
- "write",
5731
- "insert",
5732
- Target,
5733
- "ready"
5734
- > => {
5735
- const { sourceName, sourceBaseName } = targetSourceDetails(target as Target)
5736
- return makePlan({
5737
- selection: {},
5738
- required: [] as never,
5739
- available: {
5740
- [sourceName]: {
5741
- name: sourceName,
5742
- mode: "required",
5743
- baseName: sourceBaseName
5744
- }
5745
- } as AddAvailable<{}, SourceNameOf<Target>>,
5746
- dialect: (target as Target)[Plan.TypeId].dialect as TableDialectOf<Target>
5747
- }, {
5748
- kind: "insert",
5749
- select: {},
5750
- into: {
5751
- kind: "from",
5752
- tableName: sourceName,
5753
- baseTableName: sourceBaseName,
5754
- source: target as Target
5755
- },
5756
- values: [],
5757
- conflict: undefined,
5758
- where: [],
5759
- having: [],
5760
- joins: [],
5761
- groupBy: [],
5762
- orderBy: []
5763
- }, undefined as unknown as TrueFormula, "write", "insert", target as Target, "ready")
5764
- }
5765
-
5766
5754
  const attachInsertSource = (
5767
5755
  plan: QueryPlan<any, any, any, any, any, any, any, any, any, "insert", MutationTargetLike, "missing">,
5768
5756
  source: AnyValuesInput | AnyValuesSource | AnyUnnestSource | CompletePlan<QueryPlan<any, any, any, any, any, any, any, any, any, any>>
@@ -6711,7 +6699,6 @@ type AsCurriedResult<
6711
6699
  unnest,
6712
6700
  generateSeries,
6713
6701
  returning,
6714
- defaultValues,
6715
6702
  onConflict,
6716
6703
  insert,
6717
6704
  update,
@@ -1206,9 +1206,21 @@ type InsertSourceCompletenessError<
1206
1206
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1207
1207
  > = PlanValue & {
1208
1208
  readonly __effect_qb_error__: "effect-qb: insert plan is missing inline values or a source"
1209
- readonly __effect_qb_hint__: "Pass values directly to insert(...), use defaultValues(...), or pipe the insert plan into from(...)"
1209
+ readonly __effect_qb_hint__: "Pass values directly to insert(...), or pipe the insert plan into from(...)"
1210
1210
  }
1211
1211
 
1212
+ type RequiredKeys<Shape> = Extract<{
1213
+ [K in keyof Shape]-?: {} extends Pick<Shape, K> ? never : K
1214
+ }[keyof Shape], string>
1215
+
1216
+ type InsertHasOptionalDefaults<
1217
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1218
+ > = MutationTargetOfPlan<PlanValue> extends infer Target extends MutationTargetLike
1219
+ ? RequiredKeys<Table.InsertOf<Target>> extends never
1220
+ ? true
1221
+ : false
1222
+ : false
1223
+
1212
1224
  /** Narrows a query plan to aggregate-compatible selections. */
1213
1225
  export type AggregationCompatiblePlan<
1214
1226
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
@@ -1221,7 +1233,9 @@ export type CompletePlan<PlanValue extends QueryPlan<any, any, any, any, any, an
1221
1233
  PlanValue extends QueryPlan<infer Selection, infer Required, any, any, infer Grouped, any, any, any, any, infer Statement, any, infer InsertState>
1222
1234
  ? Statement extends "insert"
1223
1235
  ? InsertState extends "missing"
1224
- ? InsertSourceCompletenessError<PlanValue>
1236
+ ? InsertHasOptionalDefaults<PlanValue> extends true
1237
+ ? PlanValue
1238
+ : InsertSourceCompletenessError<PlanValue>
1225
1239
  : HasKnownOutstanding<Required> extends true
1226
1240
  ? SourceCompletenessError<PlanValue, Extract<Required, string>>
1227
1241
  : IsAggregationCompatibleSelection<Selection, Grouped> extends true ? PlanValue : AggregationCompatibilityError<PlanValue>
@@ -46,6 +46,7 @@ const renderCastType = (
46
46
 
47
47
  const renderColumnDefinition = (
48
48
  dialect: SqlDialect,
49
+ state: RenderState,
49
50
  columnName: string,
50
51
  column: Table.AnyTable[typeof Table.TypeId]["fields"][string]
51
52
  ): string => {
@@ -53,6 +54,11 @@ const renderColumnDefinition = (
53
54
  dialect.quoteIdentifier(columnName),
54
55
  renderDbType(dialect, column.metadata.dbType)
55
56
  ]
57
+ if (column.metadata.generatedValue) {
58
+ clauses.push(`generated always as (${renderExpression(column.metadata.generatedValue, state, dialect)}) stored`)
59
+ } else if (column.metadata.defaultValue) {
60
+ clauses.push(`default ${renderExpression(column.metadata.defaultValue, state, dialect)}`)
61
+ }
56
62
  if (!column.metadata.nullable) {
57
63
  clauses.push("not null")
58
64
  }
@@ -60,17 +66,11 @@ const renderColumnDefinition = (
60
66
  }
61
67
 
62
68
  const renderCheckPredicate = (
63
- predicate: unknown,
69
+ predicate: Expression.Any,
64
70
  state: RenderState,
65
71
  dialect: SqlDialect
66
72
  ): string => {
67
- if (typeof predicate === "string") {
68
- return predicate
69
- }
70
- if (predicate !== null && typeof predicate === "object" && Expression.TypeId in predicate) {
71
- return renderExpression(predicate as Expression.Any, state, dialect)
72
- }
73
- throw new Error("Unsupported check constraint predicate for DDL rendering")
73
+ return renderExpression(predicate, state, dialect)
74
74
  }
75
75
 
76
76
  const renderCreateTableSql = (
@@ -82,7 +82,7 @@ const renderCreateTableSql = (
82
82
  const table = targetSource.source as Table.AnyTable
83
83
  const fields = table[Table.TypeId].fields
84
84
  const definitions = Object.entries(fields).map(([columnName, column]) =>
85
- renderColumnDefinition(dialect, columnName, column)
85
+ renderColumnDefinition(dialect, state, columnName, column)
86
86
  )
87
87
  for (const option of table[Table.OptionsSymbol]) {
88
88
  switch (option.kind) {
@@ -305,6 +305,28 @@ const renderJsonOpaquePath = (
305
305
  throw new Error("Unsupported SQL/JSON path input")
306
306
  }
307
307
 
308
+ const renderFunctionCall = (
309
+ name: string,
310
+ args: readonly Expression.Any[],
311
+ state: RenderState,
312
+ dialect: SqlDialect
313
+ ): string => {
314
+ const renderedArgs = args.map((arg) => renderExpression(arg, state, dialect)).join(", ")
315
+ if (args.length === 0) {
316
+ switch (name) {
317
+ case "current_date":
318
+ case "current_time":
319
+ case "current_timestamp":
320
+ case "localtime":
321
+ case "localtimestamp":
322
+ return name
323
+ default:
324
+ return `${name}()`
325
+ }
326
+ }
327
+ return `${name}(${renderedArgs})`
328
+ }
329
+
308
330
  const renderJsonExpression = (
309
331
  ast: Record<string, unknown>,
310
332
  state: RenderState,
@@ -1190,6 +1212,8 @@ export const renderExpression = (
1190
1212
  : `excluded.${dialect.quoteIdentifier(ast.columnName)}`
1191
1213
  case "cast":
1192
1214
  return `cast(${renderExpression(ast.value, state, dialect)} as ${renderCastType(dialect, ast.target)})`
1215
+ case "function":
1216
+ return renderFunctionCall(ast.name, Array.isArray(ast.args) ? ast.args : [], state, dialect)
1193
1217
  case "eq":
1194
1218
  return `(${renderExpression(ast.left, state, dialect)} = ${renderExpression(ast.right, state, dialect)})`
1195
1219
  case "neq":
@@ -4,6 +4,7 @@ import {
4
4
  type AnyColumnDefinition,
5
5
  type IsNullable
6
6
  } from "./column-state.js"
7
+ import type { Any as AnyExpression } from "./expression.js"
7
8
  import type { TableFieldMap } from "./schema-derivation.js"
8
9
 
9
10
  /** Non-empty list of column names. */
@@ -36,7 +37,7 @@ export type TableOptionSpec =
36
37
  | {
37
38
  readonly kind: "check"
38
39
  readonly name: string
39
- readonly predicate: unknown
40
+ readonly predicate: AnyExpression
40
41
  }
41
42
 
42
43
  /** Thin wrapper used by the public `Table.*` option builders. */
@@ -2,6 +2,7 @@ import { pipeArguments, type Pipeable } from "effect/Pipeable"
2
2
  import * as Schema from "effect/Schema"
3
3
 
4
4
  import * as Plan from "./plan.js"
5
+ import type { Any as AnyExpression } from "./expression.js"
5
6
  import type { BoundColumnFrom } from "./column-state.js"
6
7
  import { bindColumn, type AnyColumnDefinition } from "./column-state.js"
7
8
  import {
@@ -646,14 +647,14 @@ export const foreignKey = <
646
647
  })
647
648
  })
648
649
 
649
- /** Declares a metadata-only check constraint placeholder. */
650
+ /** Declares a check constraint expression. */
650
651
  export const check = <Name extends string>(
651
652
  name: Name,
652
- predicate: unknown
653
+ predicate: AnyExpression
653
654
  ): TableOption<{
654
655
  readonly kind: "check"
655
656
  readonly name: Name
656
- readonly predicate: unknown
657
+ readonly predicate: AnyExpression
657
658
  }> => makeOption({
658
659
  kind: "check",
659
660
  name,
@@ -21,10 +21,11 @@ export const custom = BaseColumn.mysql.custom
21
21
  export const nullable = BaseColumn.nullable
22
22
  export const primaryKey = BaseColumn.primaryKey
23
23
  export const unique = BaseColumn.unique
24
- export const hasDefault = BaseColumn.hasDefault
24
+ const default_ = BaseColumn.default_
25
25
  export const generated = BaseColumn.generated
26
26
  export const references = BaseColumn.references
27
27
  export const schema = BaseColumn.schema
28
+ export { default_ as default }
28
29
 
29
30
  export type Any = BaseColumn.Any
30
31
  export type AnyBound = BaseColumn.AnyBound
@@ -2,8 +2,9 @@ import * as Effect from "effect/Effect"
2
2
  import * as SqlClient from "@effect/sql/SqlClient"
3
3
 
4
4
  import * as CoreExecutor from "../internal/executor.js"
5
- import * as Query from "./query.js"
6
- import * as Renderer from "./renderer.js"
5
+ import * as CoreQuery from "../internal/query.js"
6
+ import * as CoreRenderer from "../internal/renderer.js"
7
+ import { renderMysqlPlan } from "../internal/mysql-renderer.js"
7
8
  import {
8
9
  narrowMysqlDriverErrorForReadQuery,
9
10
  normalizeMysqlDriverError,
@@ -19,17 +20,19 @@ export type RowDecodeError = CoreExecutor.RowDecodeError
19
20
  export type Driver<Error = never, Context = never> = CoreExecutor.Driver<"mysql", Error, Context>
20
21
  /** MySQL-specialized executor contract. */
21
22
  export type Executor<Error = never, Context = never> = CoreExecutor.Executor<"mysql", Error, Context>
23
+ /** MySQL-specialized renderer contract. */
24
+ export type Renderer = CoreRenderer.Renderer<"mysql">
22
25
  /** Optional renderer / driver overrides for the standard MySQL executor pipeline. */
23
26
  export interface MakeOptions<Error = never, Context = never> {
24
- readonly renderer?: Renderer.Renderer
27
+ readonly renderer?: Renderer
25
28
  readonly driver?: Driver<Error, Context>
26
29
  readonly driverMode?: CoreExecutor.DriverMode
27
30
  }
28
31
  /** Standard composed error shape for MySQL executors. */
29
32
  export type MysqlExecutorError = MysqlDriverError | RowDecodeError
30
33
  /** Read-query error surface emitted by built-in MySQL executors. */
31
- export type MysqlQueryError<PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>> =
32
- Exclude<Query.CapabilitiesOfPlan<PlanValue>, "read"> extends never ? MysqlReadQueryError : MysqlExecutorError
34
+ export type MysqlQueryError<PlanValue extends CoreQuery.QueryPlan<any, any, any, any, any, any, any, any, any, any>> =
35
+ Exclude<CoreQuery.CapabilitiesOfPlan<PlanValue>, "read"> extends never ? MysqlReadQueryError : MysqlExecutorError
33
36
 
34
37
  /** Runs an effect within the ambient MySQL SQL transaction service. */
35
38
  export const withTransaction = CoreExecutor.withTransaction
@@ -39,9 +42,9 @@ export const withSavepoint = CoreExecutor.withSavepoint
39
42
  /** MySQL executor whose error channel narrows based on the query plan. */
40
43
  export interface QueryExecutor<Context = never> {
41
44
  readonly dialect: "mysql"
42
- execute<PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
43
- plan: Query.DialectCompatiblePlan<PlanValue, "mysql">
44
- ): Effect.Effect<Query.ResultRows<PlanValue>, MysqlQueryError<PlanValue>, Context>
45
+ execute<PlanValue extends CoreQuery.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
46
+ plan: CoreQuery.DialectCompatiblePlan<PlanValue, "mysql">
47
+ ): Effect.Effect<CoreQuery.ResultRows<PlanValue>, MysqlQueryError<PlanValue>, Context>
45
48
  }
46
49
 
47
50
  /** Constructs a MySQL-specialized SQL driver. */
@@ -50,7 +53,7 @@ export const driver = <
50
53
  Context = never
51
54
  >(
52
55
  execute: <Row>(
53
- query: Renderer.RenderedQuery<Row>
56
+ query: CoreRenderer.RenderedQuery<Row, "mysql">
54
57
  ) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
55
58
  ): Driver<Error, Context> =>
56
59
  CoreExecutor.driver("mysql", execute)
@@ -59,7 +62,7 @@ const fromDriver = <
59
62
  Error = never,
60
63
  Context = never
61
64
  >(
62
- renderer: Renderer.Renderer,
65
+ renderer: Renderer,
63
66
  sqlDriver: Driver<Error, Context>,
64
67
  driverMode: CoreExecutor.DriverMode = "raw"
65
68
  ): QueryExecutor<Context> => ({
@@ -102,13 +105,13 @@ const sqlClientDriver = (): Driver<any, SqlClient.SqlClient> =>
102
105
  export function make(): QueryExecutor<SqlClient.SqlClient>
103
106
  export function make(
104
107
  options: {
105
- readonly renderer?: Renderer.Renderer
108
+ readonly renderer?: Renderer
106
109
  readonly driverMode?: CoreExecutor.DriverMode
107
110
  }
108
111
  ): QueryExecutor<SqlClient.SqlClient>
109
112
  export function make<Error = never, Context = never>(
110
113
  options: {
111
- readonly renderer?: Renderer.Renderer
114
+ readonly renderer?: Renderer
112
115
  readonly driver: Driver<Error, Context>
113
116
  readonly driverMode?: CoreExecutor.DriverMode
114
117
  }
@@ -117,9 +120,9 @@ export function make<Error = never, Context = never>(
117
120
  options: MakeOptions<Error, Context> = {}
118
121
  ): QueryExecutor<any> {
119
122
  if (options.driver) {
120
- return fromDriver(options.renderer ?? Renderer.make(), options.driver, options.driverMode)
123
+ return fromDriver(options.renderer ?? CoreRenderer.make("mysql", renderMysqlPlan), options.driver, options.driverMode)
121
124
  }
122
- return fromDriver(options.renderer ?? Renderer.make(), sqlClientDriver(), options.driverMode)
125
+ return fromDriver(options.renderer ?? CoreRenderer.make("mysql", renderMysqlPlan), sqlClientDriver(), options.driverMode)
123
126
  }
124
127
 
125
128
  /** Creates a MySQL-specialized executor from a typed implementation callback. */
@@ -127,8 +130,8 @@ export const custom = <
127
130
  Error = never,
128
131
  Context = never
129
132
  >(
130
- execute: <PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
131
- plan: Query.DialectCompatiblePlan<PlanValue, "mysql">
132
- ) => Effect.Effect<Query.ResultRows<PlanValue>, Error, Context>
133
+ execute: <PlanValue extends CoreQuery.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
134
+ plan: CoreQuery.DialectCompatiblePlan<PlanValue, "mysql">
135
+ ) => Effect.Effect<CoreQuery.ResultRows<PlanValue>, Error, Context>
133
136
  ): Executor<Error, Context> =>
134
137
  CoreExecutor.make("mysql", execute as any) as Executor<Error, Context>
@@ -0,0 +1,6 @@
1
+ import { mysqlQuery } from "../private/query.js"
2
+
3
+ /** MySQL aggregate functions. */
4
+ export const count = mysqlQuery.count
5
+ export const max = mysqlQuery.max
6
+ export const min = mysqlQuery.min
@@ -0,0 +1,4 @@
1
+ import { mysqlQuery } from "../private/query.js"
2
+
3
+ /** MySQL scalar core functions. */
4
+ export const coalesce = mysqlQuery.coalesce
@@ -0,0 +1,19 @@
1
+ export * as core from "./core.js"
2
+ export * as string from "./string.js"
3
+ export * as aggregate from "./aggregate.js"
4
+ export * as window from "./window.js"
5
+ export { json } from "./json.js"
6
+ export * as temporal from "./temporal.js"
7
+
8
+ export { coalesce } from "./core.js"
9
+ export { lower, upper, concat } from "./string.js"
10
+ export { count, max, min } from "./aggregate.js"
11
+ export { over, rowNumber, rank, denseRank } from "./window.js"
12
+ export {
13
+ currentDate,
14
+ currentTime,
15
+ currentTimestamp,
16
+ localTime,
17
+ localTimestamp,
18
+ now
19
+ } from "./temporal.js"
@@ -0,0 +1,4 @@
1
+ import { mysqlQuery } from "../private/query.js"
2
+
3
+ /** MySQL JSON expression helpers. */
4
+ export const json = mysqlQuery.json