effect-qb 0.17.0 → 0.19.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 (103) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +8065 -0
  3. package/dist/mysql.js +3053 -2505
  4. package/dist/postgres/metadata.js +1366 -1250
  5. package/dist/postgres.js +2020 -2719
  6. package/dist/sqlite.js +3226 -2732
  7. package/dist/standard.js +8019 -0
  8. package/package.json +10 -3
  9. package/src/casing.ts +71 -0
  10. package/src/index.ts +2 -0
  11. package/src/internal/casing.ts +89 -0
  12. package/src/internal/column-state.ts +11 -6
  13. package/src/internal/column.ts +44 -7
  14. package/src/internal/datatypes/define.ts +2 -1
  15. package/src/internal/datatypes/enrich.ts +23 -0
  16. package/src/internal/datatypes/lookup.ts +14 -7
  17. package/src/internal/derived-table.ts +4 -36
  18. package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/mysql.ts} +548 -359
  19. package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +654 -399
  20. package/src/{sqlite/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +501 -345
  21. package/src/internal/dialect.ts +35 -0
  22. package/src/internal/dsl-mutation-runtime.ts +12 -162
  23. package/src/internal/dsl-plan-runtime.ts +10 -138
  24. package/src/internal/dsl-query-runtime.ts +5 -79
  25. package/src/internal/dsl-transaction-ddl-runtime.ts +41 -65
  26. package/src/internal/executor.ts +10 -6
  27. package/src/internal/grouping-key.ts +87 -20
  28. package/src/internal/implication-runtime.ts +1 -1
  29. package/src/internal/predicate/runtime.ts +3 -0
  30. package/src/internal/query.d.ts +38 -11
  31. package/src/internal/query.ts +64 -25
  32. package/src/internal/renderer.ts +26 -14
  33. package/src/internal/runtime/normalize.ts +12 -5
  34. package/src/internal/scalar.ts +6 -1
  35. package/src/internal/schema-derivation.d.ts +12 -61
  36. package/src/internal/schema-derivation.ts +90 -38
  37. package/src/internal/schema-expression.ts +2 -2
  38. package/src/internal/sql-expression-renderer.ts +19 -0
  39. package/src/internal/standard-dsl.ts +6885 -0
  40. package/src/internal/table-options.ts +126 -66
  41. package/src/internal/table.d.ts +33 -32
  42. package/src/internal/table.ts +406 -155
  43. package/src/mysql/column-extension.ts +3 -0
  44. package/src/mysql/column.ts +10 -11
  45. package/src/mysql/datatypes/index.ts +3 -2
  46. package/src/mysql/executor.ts +7 -5
  47. package/src/mysql/internal/dialect.ts +9 -4
  48. package/src/mysql/internal/dsl.ts +219 -155
  49. package/src/mysql/internal/renderer.ts +6 -2
  50. package/src/mysql/json.ts +37 -0
  51. package/src/mysql/query-extension.ts +16 -0
  52. package/src/mysql/renderer.ts +31 -4
  53. package/src/mysql.ts +4 -12
  54. package/src/postgres/column-extension.ts +28 -0
  55. package/src/postgres/column.ts +5 -11
  56. package/src/postgres/datatypes/index.d.ts +2 -1
  57. package/src/postgres/datatypes/index.ts +3 -2
  58. package/src/postgres/executor.ts +7 -5
  59. package/src/postgres/function/core.ts +1 -3
  60. package/src/postgres/function/index.ts +1 -17
  61. package/src/postgres/internal/dialect.ts +9 -4
  62. package/src/postgres/internal/dsl.ts +208 -160
  63. package/src/postgres/internal/renderer.ts +6 -2
  64. package/src/postgres/internal/schema-ddl.ts +22 -10
  65. package/src/postgres/internal/schema-model.ts +238 -7
  66. package/src/postgres/json.ts +43 -7
  67. package/src/postgres/jsonb.ts +38 -0
  68. package/src/postgres/query-extension.ts +2 -0
  69. package/src/postgres/renderer.ts +31 -4
  70. package/src/postgres/schema-management.ts +17 -12
  71. package/src/postgres/schema.ts +98 -15
  72. package/src/postgres/table.ts +193 -524
  73. package/src/postgres/type.ts +8 -7
  74. package/src/postgres.ts +9 -11
  75. package/src/sqlite/column-extension.ts +3 -0
  76. package/src/sqlite/column.ts +10 -11
  77. package/src/sqlite/datatypes/index.ts +3 -2
  78. package/src/sqlite/executor.ts +7 -5
  79. package/src/sqlite/internal/dialect.ts +9 -4
  80. package/src/sqlite/internal/dsl.ts +208 -155
  81. package/src/sqlite/internal/renderer.ts +6 -2
  82. package/src/sqlite/json.ts +37 -0
  83. package/src/sqlite/query-extension.ts +2 -0
  84. package/src/sqlite/renderer.ts +31 -4
  85. package/src/sqlite.ts +4 -12
  86. package/src/standard/column.ts +163 -0
  87. package/src/standard/datatypes/index.ts +83 -0
  88. package/src/standard/datatypes/spec.ts +98 -0
  89. package/src/standard/dialect.ts +40 -0
  90. package/src/standard/function/aggregate.ts +2 -0
  91. package/src/standard/function/core.ts +2 -0
  92. package/src/standard/function/index.ts +18 -0
  93. package/src/standard/function/string.ts +2 -0
  94. package/src/standard/function/temporal.ts +78 -0
  95. package/src/standard/function/window.ts +2 -0
  96. package/src/standard/internal/renderer.ts +45 -0
  97. package/src/standard/query.ts +152 -0
  98. package/src/standard/renderer.ts +21 -0
  99. package/src/standard/table.ts +147 -0
  100. package/src/standard.ts +18 -0
  101. package/src/internal/aggregation-validation.ts +0 -57
  102. package/src/mysql/table.ts +0 -183
  103. package/src/sqlite/table.ts +0 -183
@@ -1,9 +1,10 @@
1
1
  import * as Query from "../../internal/query.js"
2
2
  import type * as Expression from "../../internal/scalar.js"
3
+ import type * as Casing from "../../internal/casing.js"
3
4
  import { type RenderState } from "../../internal/dialect.js"
4
5
  import { postgresDialect } from "./dialect.js"
5
6
  import { type Projection } from "../../internal/projections.js"
6
- import { renderQueryAst } from "./sql-expression-renderer.js"
7
+ import { renderQueryAst } from "../../internal/sql-expression-renderer.js"
7
8
 
8
9
  /**
9
10
  * Minimal rendered-query payload produced by the built-in Postgres renderer.
@@ -20,6 +21,7 @@ export interface PostgresRenderResult {
20
21
 
21
22
  export interface PostgresRenderOptions {
22
23
  readonly valueMappings?: Expression.DriverValueMappings
24
+ readonly casing?: Casing.Options
23
25
  }
24
26
 
25
27
  /**
@@ -32,9 +34,11 @@ export const renderPostgresPlan = <PlanValue extends Query.Plan.Any>(
32
34
  const state: RenderState = {
33
35
  params: [],
34
36
  valueMappings: options.valueMappings,
37
+ casing: options.casing,
35
38
  ctes: [],
36
39
  cteNames: new Set<string>(),
37
- cteSources: new Map<string, unknown>()
40
+ cteSources: new Map<string, unknown>(),
41
+ sourceNames: new Map()
38
42
  }
39
43
  const rendered = renderQueryAst(
40
44
  Query.getAst(plan as Query.Plan.Any) as any,
@@ -1,7 +1,7 @@
1
1
  import type * as Expression from "../../internal/scalar.js"
2
2
  import type { RenderState, SqlDialect } from "../../internal/dialect.js"
3
3
  import * as SchemaExpression from "../../internal/schema-expression.js"
4
- import { renderExpression } from "./sql-expression-renderer.js"
4
+ import { renderExpression } from "../../internal/sql-expression-renderer.js"
5
5
  import type { DdlExpressionLike } from "../../internal/table-options.js"
6
6
  import { parse, toSql } from "pgsql-ast-parser"
7
7
  import { postgresDialect } from "./dialect.js"
@@ -30,21 +30,30 @@ const inlineLiteralDialect: SqlDialect<"postgres"> = {
30
30
  return String(value)
31
31
  }
32
32
  if (value instanceof Date) {
33
+ if (Number.isNaN(value.getTime())) {
34
+ throw new Error("Expected a valid Date value")
35
+ }
33
36
  return escapeString(value.toISOString())
34
37
  }
35
38
  return escapeString(String(value))
36
39
  }
37
40
  }
38
41
 
39
- export const renderDdlExpressionSql = (expression: DdlExpressionLike): string =>
42
+ const makeExpressionState = (state: Partial<RenderState> = {}): RenderState => ({
43
+ ...state,
44
+ params: [],
45
+ ctes: [],
46
+ cteNames: new Set(),
47
+ cteSources: new Map()
48
+ })
49
+
50
+ export const renderDdlExpressionSql = (
51
+ expression: DdlExpressionLike,
52
+ state?: Partial<RenderState>
53
+ ): string =>
40
54
  SchemaExpression.isSchemaExpression(expression)
41
55
  ? SchemaExpression.render(expression)
42
- : renderExpression(expression as Expression.Any, {
43
- params: [],
44
- ctes: [],
45
- cteNames: new Set(),
46
- cteSources: new Map()
47
- }, inlineLiteralDialect)
56
+ : renderExpression(expression as Expression.Any, makeExpressionState(state), inlineLiteralDialect)
48
57
 
49
58
  const stripRedundantOuterParens = (value: string): string => {
50
59
  let current = value.trim()
@@ -99,8 +108,11 @@ const canonicalizeDdlExpressionSql = (value: string): string =>
99
108
  )
100
109
  )
101
110
 
102
- export const normalizeDdlExpressionSql = (expression: DdlExpressionLike): string => {
103
- const rendered = renderDdlExpressionSql(expression)
111
+ export const normalizeDdlExpressionSql = (
112
+ expression: DdlExpressionLike,
113
+ state?: Partial<RenderState>
114
+ ): string => {
115
+ const rendered = renderDdlExpressionSql(expression, state)
104
116
  try {
105
117
  return canonicalizeDdlExpressionSql(toSql.expr(parse(rendered, "expr")))
106
118
  } catch {
@@ -1,7 +1,11 @@
1
1
  import * as Table from "../../internal/table.js"
2
2
  import type { AnyColumnDefinition } from "../../internal/column-state.js"
3
+ import type { RenderState } from "../../internal/dialect.js"
4
+ import * as Casing from "../../internal/casing.js"
5
+ import * as Expression from "../../internal/scalar.js"
6
+ import * as SchemaExpression from "../../internal/schema-expression.js"
3
7
  import { normalizeDdlExpressionSql } from "./schema-ddl.js"
4
- import type { TableOptionSpec } from "../../internal/table-options.js"
8
+ import { validateOptions, type ColumnList, type DdlExpressionLike, type IndexKeySpec, type TableOptionSpec } from "../../internal/table-options.js"
5
9
  import type { EnumDefinition } from "../schema-management.js"
6
10
  import { EnumTypeId } from "../schema-management.js"
7
11
 
@@ -52,15 +56,238 @@ export const isTableDefinition = (value: unknown): value is Table.AnyTable =>
52
56
  export const isEnumDefinition = (value: unknown): value is EnumDefinition =>
53
57
  typeof value === "object" && value !== null && EnumTypeId in value
54
58
 
59
+ const applyCasing = (
60
+ casing: Casing.Options | undefined,
61
+ category: Casing.Category,
62
+ name: string
63
+ ): string =>
64
+ Casing.applyCategory(casing, category, name)
65
+
66
+ const mapColumnList = (
67
+ columns: ColumnList,
68
+ casing: Casing.Options | undefined
69
+ ): ColumnList =>
70
+ !Array.isArray(columns)
71
+ ? columns
72
+ : columns.length === 0
73
+ ? columns
74
+ : [
75
+ mapCasedValue(columns[0], casing, "columns"),
76
+ ...columns.slice(1).map((column) => mapCasedValue(column, casing, "columns"))
77
+ ] as ColumnList
78
+
79
+ const expressionStateForTable = (
80
+ state: Table.AnyTable[typeof Table.TypeId],
81
+ tableName: string,
82
+ columns: ReadonlyMap<string, string>,
83
+ casing: Casing.Options | undefined
84
+ ): Partial<RenderState> => ({
85
+ casing,
86
+ rowLocalColumns: true,
87
+ sourceNames: new Map([
88
+ [state.name, { tableName, columns }],
89
+ [state.baseName, { tableName, columns }]
90
+ ])
91
+ })
92
+
93
+ const mapDdlExpression = (
94
+ expression: DdlExpressionLike,
95
+ state: Partial<RenderState>
96
+ ): SchemaExpression.SchemaExpression =>
97
+ SchemaExpression.fromSql(normalizeDdlExpressionSql(expression, state))
98
+
99
+ function mapOptionName(
100
+ name: string,
101
+ casing: Casing.Options | undefined,
102
+ category: "indexes" | "constraints"
103
+ ): string
104
+ function mapOptionName(
105
+ name: unknown,
106
+ casing: Casing.Options | undefined,
107
+ category: "indexes" | "constraints"
108
+ ): unknown
109
+ function mapOptionName(
110
+ name: unknown,
111
+ casing: Casing.Options | undefined,
112
+ category: "indexes" | "constraints"
113
+ ): unknown {
114
+ return typeof name === "string"
115
+ ? applyCasing(casing, category, name)
116
+ : name
117
+ }
118
+
119
+ function mapCasedValue(
120
+ value: string,
121
+ casing: Casing.Options | undefined,
122
+ category: Casing.Category
123
+ ): string
124
+ function mapCasedValue(
125
+ value: unknown,
126
+ casing: Casing.Options | undefined,
127
+ category: Casing.Category
128
+ ): unknown
129
+ function mapCasedValue(
130
+ value: unknown,
131
+ casing: Casing.Options | undefined,
132
+ category: Casing.Category
133
+ ): unknown {
134
+ return typeof value === "string"
135
+ ? applyCasing(casing, category, value)
136
+ : value
137
+ }
138
+
139
+ const isDdlExpressionLike = (value: unknown): value is DdlExpressionLike =>
140
+ typeof value === "object" &&
141
+ value !== null &&
142
+ (Expression.TypeId in value || SchemaExpression.TypeId in value)
143
+
144
+ function mapIndexKey(
145
+ key: IndexKeySpec,
146
+ casing: Casing.Options | undefined,
147
+ expressionState: Partial<RenderState>
148
+ ): IndexKeySpec
149
+ function mapIndexKey(
150
+ key: unknown,
151
+ casing: Casing.Options | undefined,
152
+ expressionState: Partial<RenderState>
153
+ ): unknown
154
+ function mapIndexKey(
155
+ key: unknown,
156
+ casing: Casing.Options | undefined,
157
+ expressionState: Partial<RenderState>
158
+ ): unknown {
159
+ if (typeof key !== "object" || key === null || !("kind" in key)) {
160
+ return key
161
+ }
162
+ const kind = (key as { readonly kind?: unknown }).kind
163
+ if (kind === "column") {
164
+ const column = (key as { readonly column?: unknown }).column
165
+ return typeof column === "string"
166
+ ? {
167
+ ...key,
168
+ column: applyCasing(casing, "columns", column)
169
+ }
170
+ : key
171
+ }
172
+ if (kind === "expression") {
173
+ const expression = (key as { readonly expression?: unknown }).expression
174
+ return isDdlExpressionLike(expression)
175
+ ? {
176
+ ...key,
177
+ expression: mapDdlExpression(expression, expressionState)
178
+ }
179
+ : key
180
+ }
181
+ return key
182
+ }
183
+
184
+ const mapOption = (
185
+ option: TableOptionSpec,
186
+ casing: Casing.Options | undefined,
187
+ expressionState: Partial<RenderState>
188
+ ): TableOptionSpec => {
189
+ switch (option.kind) {
190
+ case "index":
191
+ return {
192
+ ...option,
193
+ columns: option.columns === undefined ? undefined : mapColumnList(option.columns, casing),
194
+ name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "indexes"),
195
+ include: option.include === undefined
196
+ ? undefined
197
+ : Array.isArray(option.include)
198
+ ? option.include.map((column) => mapCasedValue(column, casing, "columns")) as unknown as readonly string[]
199
+ : option.include,
200
+ predicate: option.predicate === undefined
201
+ ? undefined
202
+ : isDdlExpressionLike(option.predicate)
203
+ ? mapDdlExpression(option.predicate, expressionState)
204
+ : option.predicate,
205
+ keys: option.keys === undefined
206
+ ? undefined
207
+ : Array.isArray(option.keys)
208
+ ? option.keys.length === 0
209
+ ? option.keys
210
+ : [
211
+ mapIndexKey(option.keys[0], casing, expressionState),
212
+ ...option.keys.slice(1).map((key) => mapIndexKey(key, casing, expressionState))
213
+ ] as unknown as readonly [IndexKeySpec, ...IndexKeySpec[]]
214
+ : option.keys
215
+ }
216
+ case "primaryKey":
217
+ return {
218
+ ...option,
219
+ columns: mapColumnList(option.columns, casing),
220
+ name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "constraints")
221
+ }
222
+ case "unique":
223
+ return {
224
+ ...option,
225
+ columns: mapColumnList(option.columns, casing),
226
+ name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "constraints")
227
+ }
228
+ case "foreignKey":
229
+ return {
230
+ ...option,
231
+ columns: mapColumnList(option.columns, casing),
232
+ name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "constraints"),
233
+ references: () => {
234
+ const reference = typeof option.references === "function"
235
+ ? option.references()
236
+ : option.references
237
+ if (typeof reference !== "object" || reference === null) {
238
+ return reference
239
+ }
240
+ const referenceCasing = reference.casing
241
+ return {
242
+ ...reference,
243
+ tableName: mapCasedValue(reference.tableName, referenceCasing, "tables"),
244
+ schemaName: reference.schemaName === undefined
245
+ ? undefined
246
+ : mapCasedValue(reference.schemaName, referenceCasing, "schemas"),
247
+ columns: mapColumnList(reference.columns, referenceCasing),
248
+ knownColumns: reference.knownColumns === undefined
249
+ ? undefined
250
+ : Array.isArray(reference.knownColumns)
251
+ ? reference.knownColumns.map((column) =>
252
+ mapCasedValue(column, referenceCasing, "columns")) as unknown as readonly string[]
253
+ : reference.knownColumns
254
+ }
255
+ }
256
+ }
257
+ case "check":
258
+ return {
259
+ ...option,
260
+ name: mapOptionName(option.name, casing, "constraints"),
261
+ predicate: isDdlExpressionLike(option.predicate)
262
+ ? mapDdlExpression(option.predicate, expressionState)
263
+ : option.predicate
264
+ }
265
+ default:
266
+ return option
267
+ }
268
+ }
269
+
55
270
  export const toTableModel = (table: Table.AnyTable): TableModel => {
56
271
  const state = table[Table.TypeId]
272
+ const casing = state.casing
273
+ const tableName = applyCasing(casing, "tables", state.baseName)
274
+ const schemaName = state.schemaName === undefined
275
+ ? undefined
276
+ : applyCasing(casing, "schemas", state.schemaName)
57
277
  const fields = state.fields as Record<string, AnyColumnDefinition>
278
+ const options = table[Table.OptionsSymbol] as unknown
279
+ const normalizedOptions = (Array.isArray(options) ? options : [options]) as readonly TableOptionSpec[]
280
+ validateOptions(state.name, fields, normalizedOptions)
281
+ const columnNames = new Map(
282
+ Object.keys(fields).map((name) => [name, applyCasing(casing, "columns", name)] as const)
283
+ )
284
+ const expressionState = expressionStateForTable(state, tableName, columnNames, casing)
58
285
  const columns = Object.entries(fields).map(([name, column]) => {
59
286
  const metadata = column.metadata
60
287
  const enumDefinition = metadata.enum
61
288
  const ddlType = metadata.ddlType ?? metadata.dbType.kind
62
289
  return {
63
- name,
290
+ name: columnNames.get(name) ?? name,
64
291
  ddlType,
65
292
  dbTypeKind: enumDefinition?.name ?? column.metadata.dbType.kind,
66
293
  typeKind: enumDefinition === undefined ? undefined : "e",
@@ -70,20 +297,24 @@ export const toTableModel = (table: Table.AnyTable): TableModel => {
70
297
  generated: column.metadata.generated,
71
298
  defaultSql: column.metadata.defaultValue === undefined
72
299
  ? undefined
73
- : normalizeDdlExpressionSql(column.metadata.defaultValue),
300
+ : normalizeDdlExpressionSql(column.metadata.defaultValue, expressionState),
74
301
  generatedSql: column.metadata.generatedValue === undefined
75
302
  ? undefined
76
- : normalizeDdlExpressionSql(column.metadata.generatedValue),
303
+ : normalizeDdlExpressionSql(column.metadata.generatedValue, expressionState),
77
304
  identity: column.metadata.identity,
78
305
  column
79
306
  }
80
307
  }) satisfies ReadonlyArray<ColumnModel>
81
308
  return {
82
309
  kind: "table",
83
- schemaName: state.schemaName,
84
- name: state.baseName,
310
+ schemaName,
311
+ name: tableName,
85
312
  columns,
86
- options: table[Table.OptionsSymbol],
313
+ options: normalizedOptions.map((option) =>
314
+ typeof option === "object" && option !== null && "kind" in option
315
+ ? mapOption(option, casing, expressionState)
316
+ : option as TableOptionSpec
317
+ ),
87
318
  table
88
319
  }
89
320
  }
@@ -9,11 +9,12 @@ import type {
9
9
  JsonTextResult,
10
10
  JsonValueAtPath
11
11
  } from "../internal/json/types.js"
12
+ import type { LiteralStringInput } from "../internal/table-options.js"
12
13
  import { json as postgresJson, jsonb as postgresJsonb } from "./internal/dsl.js"
13
14
 
14
15
  type PostgresJsonExpression<Runtime = unknown> = Expression.Scalar<
15
16
  Runtime,
16
- Expression.DbType.Json<"postgres", "json" | "jsonb">,
17
+ Expression.DbType.Json<"postgres" | "standard", "json" | "jsonb">,
17
18
  Expression.Nullability,
18
19
  string,
19
20
  Expression.ScalarKind,
@@ -31,10 +32,24 @@ type PostgresJsonbExpression<Runtime = unknown> = Expression.Scalar<
31
32
 
32
33
  type ExactJsonPathInput = JsonPath.ExactSegment | JsonPath.Path<any>
33
34
 
35
+ type JsonPathPredicateExpression = Expression.Scalar<
36
+ string | null,
37
+ Expression.DbType.Any,
38
+ Expression.Nullability,
39
+ string,
40
+ Expression.ScalarKind,
41
+ Expression.BindingId
42
+ >
43
+
44
+ type JsonPathPredicateQuery = JsonPath.Path<any> | JsonPathPredicateExpression | string
45
+
46
+ type JsonPathPredicateQueryInput<Query extends JsonPathPredicateQuery> =
47
+ Query extends string ? LiteralStringInput<Query> : Query
48
+
34
49
  type ExactJsonPathUsageError<Target> = {
35
50
  readonly __effect_qb_error__: "effect-qb: postgres json helpers only accept exact key/index paths"
36
51
  readonly __effect_qb_json_path__: Target
37
- readonly __effect_qb_hint__: "Use Postgres.Json.jsonb.path(...) when you need wildcard(), slice(), or descend() segments"
52
+ readonly __effect_qb_hint__: "Use Postgres.Jsonb.path(...) when you need wildcard(), slice(), or descend() segments"
38
53
  }
39
54
 
40
55
  type ExactJsonPathGuard<Target> = Target extends JsonPath.Path<any>
@@ -141,7 +156,7 @@ type JsonbOnlyUsageError<
141
156
  readonly __effect_qb_error__: "effect-qb: postgres jsonb helpers require a jsonb expression"
142
157
  readonly __effect_qb_json_operation__: Operation
143
158
  readonly __effect_qb_received_kind__: Expression.DbTypeOf<Value>["kind"]
144
- readonly __effect_qb_hint__: "Use Column.jsonb(...), Cast.to(..., Type.jsonb()), or Postgres.Json.jsonb.toJsonb(...)"
159
+ readonly __effect_qb_hint__: "Use Column.jsonb(...), Cast.to(..., Type.jsonb()), or Postgres.Jsonb.toJsonb(...)"
145
160
  }
146
161
 
147
162
  type JsonbBaseGuard<
@@ -514,20 +529,41 @@ const jsonb = {
514
529
  base: Base & JsonbBaseGuard<Base, "jsonb.stripNulls">
515
530
  ) => postgresJsonb.stripNulls(base as Base),
516
531
  pathExists: <
517
- Base extends PostgresJsonExpression<any>
532
+ Base extends PostgresJsonExpression<any>,
533
+ Query extends JsonPathPredicateQuery
518
534
  >(
519
535
  base: Base & JsonbBaseGuard<Base, "jsonb.pathExists">,
520
- query: Parameters<typeof postgresJsonb.pathExists>[1]
536
+ query: JsonPathPredicateQueryInput<Query>
521
537
  ) => postgresJsonb.pathExists(base as Base, query),
522
538
  pathMatch: <
523
- Base extends PostgresJsonExpression<any>
539
+ Base extends PostgresJsonExpression<any>,
540
+ Query extends JsonPathPredicateQuery
524
541
  >(
525
542
  base: Base & JsonbBaseGuard<Base, "jsonb.pathMatch">,
526
- query: Parameters<typeof postgresJsonb.pathMatch>[1]
543
+ query: JsonPathPredicateQueryInput<Query>
527
544
  ) => postgresJsonb.pathMatch(base as Base, query)
528
545
  }
529
546
 
530
547
  /** Postgres shared JSON helpers for exact paths and functions that work on both json and jsonb. */
531
548
  export { json }
549
+ export const key = json.key
550
+ export const index = json.index
551
+ export const path = json.path
552
+ export const get = json.get
553
+ export const access = json.access
554
+ export const traverse = json.traverse
555
+ export const text = json.text
556
+ export const accessText = json.accessText
557
+ export const traverseText = json.traverseText
558
+ export const buildObject = json.buildObject
559
+ export const buildArray = json.buildArray
560
+ export const toJson = json.toJson
561
+ export const typeOf = json.typeOf
562
+ export const length = json.length
563
+ export const keys = json.keys
564
+ export const stripNulls = json.stripNulls
565
+ export const delete_ = json.delete
566
+ export { delete_ as delete }
567
+ export const remove = json.remove
532
568
  /** Postgres jsonb-only helpers for containment, mutation, wildcard paths, and SQL/JSON path predicates. */
533
569
  export { jsonb }
@@ -0,0 +1,38 @@
1
+ import { jsonb } from "./json.js"
2
+
3
+ /** Postgres jsonb-only helpers for containment, mutation, wildcard paths, and SQL/JSON path predicates. */
4
+ export { jsonb }
5
+ export const key = jsonb.key
6
+ export const index = jsonb.index
7
+ export const wildcard = jsonb.wildcard
8
+ export const slice = jsonb.slice
9
+ export const descend = jsonb.descend
10
+ export const path = jsonb.path
11
+ export const get = jsonb.get
12
+ export const access = jsonb.access
13
+ export const traverse = jsonb.traverse
14
+ export const text = jsonb.text
15
+ export const accessText = jsonb.accessText
16
+ export const traverseText = jsonb.traverseText
17
+ export const contains = jsonb.contains
18
+ export const containedBy = jsonb.containedBy
19
+ export const hasKey = jsonb.hasKey
20
+ export const keyExists = jsonb.keyExists
21
+ export const hasAnyKeys = jsonb.hasAnyKeys
22
+ export const hasAllKeys = jsonb.hasAllKeys
23
+ export const delete_ = jsonb.delete
24
+ export { delete_ as delete }
25
+ export const remove = jsonb.remove
26
+ export const set = jsonb.set
27
+ export const insert = jsonb.insert
28
+ export const concat = jsonb.concat
29
+ export const merge = jsonb.merge
30
+ export const buildObject = jsonb.buildObject
31
+ export const buildArray = jsonb.buildArray
32
+ export const toJsonb = jsonb.toJsonb
33
+ export const typeOf = jsonb.typeOf
34
+ export const length = jsonb.length
35
+ export const keys = jsonb.keys
36
+ export const stripNulls = jsonb.stripNulls
37
+ export const pathExists = jsonb.pathExists
38
+ export const pathMatch = jsonb.pathMatch
@@ -0,0 +1,2 @@
1
+ /** Postgres-only query helpers. Portable query builders are exported from the root package. */
2
+ export { distinctOn, generateSeries, onConflict } from "./query.js"
@@ -1,5 +1,9 @@
1
+ import { pipeArguments, type Pipeable } from "effect/Pipeable"
2
+
1
3
  import * as CoreRenderer from "../internal/renderer.js"
4
+ import * as Casing from "../internal/casing.js"
2
5
  import type * as Expression from "../internal/scalar.js"
6
+ import type { PostgresDatatypeFamily, PostgresDatatypeKind } from "./datatypes/spec.js"
3
7
  import { renderPostgresPlan } from "./internal/renderer.js"
4
8
 
5
9
  /** Postgres-specialized rendered query shape. */
@@ -7,18 +11,41 @@ export type RenderedQuery<Row> = CoreRenderer.RenderedQuery<Row, "postgres">
7
11
  /** Extracts the row type carried by a Postgres rendered query. */
8
12
  export type RowOf<Value extends RenderedQuery<any>> = CoreRenderer.RowOf<Value>
9
13
  /** Postgres-specialized renderer contract. */
10
- export type Renderer = CoreRenderer.Renderer<"postgres">
14
+ export type Renderer = CoreRenderer.Renderer<"postgres"> & Pipeable & {
15
+ readonly [Casing.TypeId]: Casing.State
16
+ readonly withCasing: (options: Casing.Options) => Renderer
17
+ }
18
+
19
+ export type ValueMappings = Expression.DriverValueMappingsFor<PostgresDatatypeKind, PostgresDatatypeFamily>
11
20
 
12
21
  export interface MakeOptions {
13
- readonly valueMappings?: Expression.DriverValueMappings
22
+ readonly valueMappings?: ValueMappings
23
+ readonly casing?: Casing.Options
14
24
  }
15
25
 
16
26
  export { TypeId } from "../internal/renderer.js"
17
27
  export type { Projection } from "../internal/renderer.js"
18
28
 
29
+ const RendererProto = {
30
+ pipe(this: Pipeable) {
31
+ return pipeArguments(this, arguments)
32
+ }
33
+ }
34
+
19
35
  /** Creates the built-in Postgres renderer. */
20
- export const make = (options: MakeOptions = {}): Renderer =>
21
- CoreRenderer.make("postgres", (plan) => renderPostgresPlan(plan, options))
36
+ export const make = (options: MakeOptions = {}): Renderer => {
37
+ const renderer = CoreRenderer.makeTrusted("postgres", (plan) => renderPostgresPlan(plan, options))
38
+ return Object.assign(Object.create(RendererProto), renderer, {
39
+ [Casing.TypeId]: {
40
+ casing: options.casing
41
+ },
42
+ withCasing: (override: Casing.Options) =>
43
+ make({
44
+ ...options,
45
+ casing: Casing.merge(options.casing, override)
46
+ })
47
+ }) as Renderer
48
+ }
22
49
 
23
50
  /** Shared built-in Postgres renderer instance. */
24
51
  export const postgres = make()
@@ -3,6 +3,7 @@ import { pipeArguments, type Pipeable } from "effect/Pipeable"
3
3
 
4
4
  import type * as Expression from "../internal/scalar.js"
5
5
  import { makeColumnDefinition, type ColumnDefinition } from "../internal/column-state.js"
6
+ import type { NonEmptyStringInput } from "../internal/table-options.js"
6
7
 
7
8
  export const EnumTypeId: unique symbol = Symbol.for("effect-qb/SchemaManagement/Enum")
8
9
  export const SequenceTypeId: unique symbol = Symbol.for("effect-qb/SchemaManagement/Sequence")
@@ -121,7 +122,7 @@ const renderQualifiedTypeName = (
121
122
  : `${renderIdentifier(schemaName)}.${renderIdentifier(name)}`
122
123
 
123
124
  const EnumProto = {
124
- pipe(this: unknown) {
125
+ pipe(this: Pipeable) {
125
126
  return pipeArguments(this, arguments)
126
127
  },
127
128
  qualifiedName(this: EnumDefinition) {
@@ -137,7 +138,11 @@ const EnumProto = {
137
138
  }
138
139
  },
139
140
  column(this: EnumDefinition) {
140
- const values = this.values.map((value) => Schema.Literal(value)) as unknown as readonly [Schema.Schema.Any, ...Schema.Schema.Any[]]
141
+ const [first, ...rest] = this.values
142
+ const values: readonly [Schema.Schema.Any, ...Schema.Schema.Any[]] = [
143
+ Schema.Literal(first),
144
+ ...rest.map((value) => Schema.Literal(value))
145
+ ]
141
146
  return makeColumnDefinition(
142
147
  values.length === 1 ? values[0]! : Schema.Union(...values),
143
148
  {
@@ -161,7 +166,7 @@ const EnumProto = {
161
166
  }
162
167
 
163
168
  const SequenceProto = {
164
- pipe(this: unknown) {
169
+ pipe(this: Pipeable) {
165
170
  return pipeArguments(this, arguments)
166
171
  },
167
172
  qualifiedName(this: SequenceDefinition) {
@@ -212,7 +217,7 @@ export function enumType<
212
217
  Name extends string,
213
218
  const Values extends readonly [string, ...string[]]
214
219
  >(
215
- name: Name,
220
+ name: NonEmptyStringInput<Name>,
216
221
  values: Values
217
222
  ): EnumDefinition<Name, Values, undefined>
218
223
  export function enumType<
@@ -220,9 +225,9 @@ export function enumType<
220
225
  const Values extends readonly [string, ...string[]],
221
226
  SchemaName extends string
222
227
  >(
223
- name: Name,
228
+ name: NonEmptyStringInput<Name>,
224
229
  values: Values,
225
- schemaName: SchemaName
230
+ schemaName: NonEmptyStringInput<SchemaName>
226
231
  ): EnumDefinition<Name, Values, SchemaName>
227
232
  export function enumType(
228
233
  name: string,
@@ -243,11 +248,11 @@ export function enumType(
243
248
  }
244
249
 
245
250
  export function sequence<Name extends string>(
246
- name: Name
251
+ name: NonEmptyStringInput<Name>
247
252
  ): SequenceDefinition<Name, undefined>
248
253
  export function sequence<Name extends string, SchemaName extends string>(
249
- name: Name,
250
- schemaName: SchemaName
254
+ name: NonEmptyStringInput<Name>,
255
+ schemaName: NonEmptyStringInput<SchemaName>
251
256
  ): SequenceDefinition<Name, SchemaName>
252
257
  export function sequence(
253
258
  name: string,
@@ -265,21 +270,21 @@ export function sequence(
265
270
  }
266
271
 
267
272
  export const schema = <SchemaName extends string>(
268
- schemaName: SchemaName
273
+ schemaName: NonEmptyStringInput<SchemaName>
269
274
  ) => ({
270
275
  schemaName,
271
276
  enumType: <
272
277
  Name extends string,
273
278
  const Values extends readonly [string, ...string[]]
274
279
  >(
275
- name: Name,
280
+ name: NonEmptyStringInput<Name>,
276
281
  values: Values
277
282
  ): EnumDefinition<Name, Values, SchemaName> =>
278
283
  enumType(name, values, schemaName) as EnumDefinition<Name, Values, SchemaName>,
279
284
  sequence: <
280
285
  Name extends string
281
286
  >(
282
- name: Name
287
+ name: NonEmptyStringInput<Name>
283
288
  ): SequenceDefinition<Name, SchemaName> =>
284
289
  sequence(name, schemaName) as SequenceDefinition<Name, SchemaName>
285
290
  })