effect-qb 4.0.0-beta.66 → 4.0.0-beta.98
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/README.md +5 -2
- package/dist/index.js +9376 -0
- package/dist/mysql.js +3921 -2573
- package/dist/postgres/metadata.js +2491 -1373
- package/dist/postgres.js +5453 -5155
- package/dist/sqlite.js +6895 -5529
- package/dist/standard.js +9330 -0
- package/package.json +9 -2
- package/src/casing.ts +71 -0
- package/src/index.ts +2 -0
- package/src/internal/casing.ts +89 -0
- package/src/internal/coercion/rules.ts +13 -1
- package/src/internal/column-state.ts +21 -15
- package/src/internal/column.ts +44 -7
- package/src/internal/datatypes/define.ts +7 -1
- package/src/internal/datatypes/enrich.ts +23 -0
- package/src/internal/datatypes/lookup.ts +81 -25
- package/src/internal/datatypes/matrix.ts +903 -0
- package/src/internal/datatypes/shape.ts +2 -0
- package/src/internal/derived-table.ts +4 -36
- package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/mysql.ts} +552 -361
- package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +657 -400
- package/src/{sqlite/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +505 -347
- package/src/internal/dialect.ts +35 -0
- package/src/internal/dsl-mutation-runtime.ts +12 -162
- package/src/internal/dsl-plan-runtime.ts +10 -138
- package/src/internal/dsl-query-runtime.ts +5 -79
- package/src/internal/dsl-transaction-ddl-runtime.ts +41 -65
- package/src/internal/executor.ts +14 -16
- package/src/internal/grouping-key.ts +87 -20
- package/src/internal/implication-runtime.ts +1 -1
- package/src/internal/json/path-access.ts +351 -0
- package/src/internal/predicate/runtime.ts +3 -0
- package/src/internal/query.d.ts +38 -11
- package/src/internal/query.ts +64 -25
- package/src/internal/renderer.ts +26 -14
- package/src/internal/runtime/normalize.ts +12 -5
- package/src/internal/scalar.ts +7 -1
- package/src/internal/schema-derivation.d.ts +7 -7
- package/src/internal/schema-derivation.ts +9 -9
- package/src/internal/schema-expression.ts +2 -2
- package/src/internal/sql-expression-renderer.ts +19 -0
- package/src/internal/standard-dsl.ts +6978 -0
- package/src/internal/table-options.ts +126 -66
- package/src/internal/table.ts +652 -219
- package/src/mysql/column-extension.ts +3 -0
- package/src/mysql/column.ts +8 -9
- package/src/mysql/datatypes/index.ts +4 -2
- package/src/mysql/datatypes/spec.ts +6 -176
- package/src/mysql/errors/normalize.ts +0 -1
- package/src/mysql/executor.ts +7 -7
- package/src/mysql/internal/dialect.ts +9 -4
- package/src/mysql/internal/dsl.ts +312 -154
- package/src/mysql/internal/renderer.ts +6 -2
- package/src/mysql/json.ts +7 -2
- package/src/mysql/query-extension.ts +16 -0
- package/src/mysql/renderer.ts +37 -3
- package/src/mysql/type.ts +60 -0
- package/src/mysql.ts +7 -13
- package/src/postgres/check.ts +1 -0
- package/src/postgres/column-extension.ts +28 -0
- package/src/postgres/column.ts +2 -8
- package/src/postgres/datatypes/index.d.ts +2 -1
- package/src/postgres/datatypes/index.ts +4 -2
- package/src/postgres/datatypes/spec.ts +6 -260
- package/src/postgres/errors/normalize.ts +0 -1
- package/src/postgres/executor.ts +7 -7
- package/src/postgres/foreign-key.ts +24 -0
- package/src/postgres/function/core.ts +1 -3
- package/src/postgres/function/index.ts +1 -17
- package/src/postgres/index.ts +1 -0
- package/src/postgres/internal/dialect.ts +9 -4
- package/src/postgres/internal/dsl.ts +306 -163
- package/src/postgres/internal/renderer.ts +6 -2
- package/src/postgres/internal/schema-ddl.ts +22 -10
- package/src/postgres/internal/schema-model.ts +238 -7
- package/src/postgres/json-extension.ts +7 -0
- package/src/postgres/json.ts +762 -173
- package/src/postgres/jsonb.ts +37 -0
- package/src/postgres/primary-key.ts +24 -0
- package/src/postgres/query-extension.ts +2 -0
- package/src/postgres/renderer.ts +37 -3
- package/src/postgres/schema-management.ts +12 -11
- package/src/postgres/schema.ts +106 -15
- package/src/postgres/table.ts +205 -530
- package/src/postgres/type.ts +93 -10
- package/src/postgres/unique.ts +32 -0
- package/src/postgres.ts +20 -16
- package/src/sqlite/column-extension.ts +3 -0
- package/src/sqlite/column.ts +8 -9
- package/src/sqlite/datatypes/index.ts +4 -2
- package/src/sqlite/datatypes/spec.ts +6 -94
- package/src/sqlite/errors/normalize.ts +0 -1
- package/src/sqlite/executor.ts +7 -7
- package/src/sqlite/internal/dialect.ts +9 -4
- package/src/sqlite/internal/dsl.ts +301 -154
- package/src/sqlite/internal/renderer.ts +6 -2
- package/src/sqlite/json.ts +8 -2
- package/src/sqlite/query-extension.ts +2 -0
- package/src/sqlite/renderer.ts +37 -3
- package/src/sqlite/type.ts +40 -0
- package/src/sqlite.ts +7 -13
- package/src/standard/cast.ts +113 -0
- package/src/standard/check.ts +17 -0
- package/src/standard/column.ts +163 -0
- package/src/standard/datatypes/index.ts +83 -0
- package/src/standard/datatypes/spec.ts +12 -0
- package/src/standard/dialect.ts +40 -0
- package/src/standard/foreign-key.ts +37 -0
- package/src/standard/function/aggregate.ts +2 -0
- package/src/standard/function/core.ts +2 -0
- package/src/standard/function/index.ts +18 -0
- package/src/standard/function/string.ts +2 -0
- package/src/standard/function/temporal.ts +78 -0
- package/src/standard/function/window.ts +2 -0
- package/src/standard/index.ts +17 -0
- package/src/standard/internal/renderer.ts +45 -0
- package/src/standard/json.ts +883 -0
- package/src/standard/primary-key.ts +17 -0
- package/src/standard/query.ts +152 -0
- package/src/standard/renderer.ts +49 -0
- package/src/standard/table.ts +151 -0
- package/src/standard/unique.ts +17 -0
- package/src/standard.ts +32 -0
- package/src/internal/aggregation-validation.ts +0 -57
- package/src/internal/table.d.ts +0 -180
- package/src/mysql/table.ts +0 -186
- package/src/postgres/cast.ts +0 -45
- package/src/sqlite/table.ts +0 -175
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-qb",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.98",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
"README.md"
|
|
22
22
|
],
|
|
23
23
|
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./src/index.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
},
|
|
24
28
|
"./postgres": {
|
|
25
29
|
"types": "./src/postgres.ts",
|
|
26
30
|
"import": "./dist/postgres.js"
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
"./package.json": "./package.json"
|
|
41
45
|
},
|
|
42
46
|
"imports": {
|
|
47
|
+
"#standard": "./src/standard.ts",
|
|
43
48
|
"#postgres": "./src/postgres.ts",
|
|
44
49
|
"#mysql": "./src/mysql.ts",
|
|
45
50
|
"#sqlite": "./src/sqlite.ts",
|
|
@@ -57,7 +62,9 @@
|
|
|
57
62
|
"@typescript/native-preview": "beta"
|
|
58
63
|
},
|
|
59
64
|
"dependencies": {
|
|
60
|
-
"effect": "4.0.0-beta.66",
|
|
61
65
|
"pgsql-ast-parser": "^12.0.2"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"effect": "4.0.0-beta.98"
|
|
62
69
|
}
|
|
63
70
|
}
|
package/src/casing.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as InternalCasing from "./internal/casing.js"
|
|
2
|
+
import * as BaseTable from "./internal/table.js"
|
|
3
|
+
import * as Table from "./standard/table.js"
|
|
4
|
+
|
|
5
|
+
export type Style = InternalCasing.Style
|
|
6
|
+
export type Options = InternalCasing.Options
|
|
7
|
+
export type Input = Options | Style
|
|
8
|
+
|
|
9
|
+
export interface TableFactory {
|
|
10
|
+
readonly table: typeof Table.make
|
|
11
|
+
readonly [InternalCasing.TypeId]: InternalCasing.State
|
|
12
|
+
readonly withCasing: (options: Input) => TableFactory
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type CasingTarget =
|
|
16
|
+
| BaseTable.TableDefinition<any, any, any, any, any>
|
|
17
|
+
| {
|
|
18
|
+
readonly [InternalCasing.TypeId]: InternalCasing.State
|
|
19
|
+
readonly withCasing: (options: Options) => CasingTarget
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const isTable = (value: unknown): value is BaseTable.TableDefinition<any, any, any, any, any> =>
|
|
23
|
+
typeof value === "object" && value !== null && BaseTable.TypeId in value
|
|
24
|
+
|
|
25
|
+
const allCategories = (style: Style): Options => ({
|
|
26
|
+
tables: style,
|
|
27
|
+
columns: style,
|
|
28
|
+
schemas: style,
|
|
29
|
+
indexes: style,
|
|
30
|
+
constraints: style,
|
|
31
|
+
types: style,
|
|
32
|
+
sequences: style
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const normalize = (input: Input): Options =>
|
|
36
|
+
typeof input === "string" || typeof input === "function" ? allCategories(input) : input
|
|
37
|
+
|
|
38
|
+
export function withCasing(options: Style): <Value extends CasingTarget>(value: Value) => Value
|
|
39
|
+
export function withCasing(options: Options): <Value extends CasingTarget>(value: Value) => Value
|
|
40
|
+
export function withCasing(options: Input) {
|
|
41
|
+
return <Value extends CasingTarget>(value: Value): Value => {
|
|
42
|
+
const normalized = normalize(options)
|
|
43
|
+
if (isTable(value)) {
|
|
44
|
+
return BaseTable.withCasing(value, normalized) as Value
|
|
45
|
+
}
|
|
46
|
+
return (value as Exclude<CasingTarget, BaseTable.TableDefinition<any, any, any, any, any>>).withCasing(normalized) as Value
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function make(options: Style): TableFactory
|
|
51
|
+
export function make(options: Options): TableFactory
|
|
52
|
+
export function make(options: Input): TableFactory {
|
|
53
|
+
const normalized = normalize(options)
|
|
54
|
+
const withFactoryCasing = withCasing(normalized)
|
|
55
|
+
const table = ((name: string, fields: any, schemaName?: string) =>
|
|
56
|
+
schemaName === undefined
|
|
57
|
+
? Table.make(name, fields).pipe(withFactoryCasing)
|
|
58
|
+
: Table.make(name, fields, schemaName).pipe(withFactoryCasing)) as typeof Table.make
|
|
59
|
+
const factory = {
|
|
60
|
+
table,
|
|
61
|
+
[InternalCasing.TypeId]: {
|
|
62
|
+
casing: normalized
|
|
63
|
+
},
|
|
64
|
+
withCasing: (override: Input) => make(InternalCasing.merge(normalized, normalize(override)) ?? {})
|
|
65
|
+
}
|
|
66
|
+
return factory
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const apply = InternalCasing.apply
|
|
70
|
+
export const applyCategory = InternalCasing.applyCategory
|
|
71
|
+
export const merge = InternalCasing.merge
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export const TypeId: unique symbol = Symbol.for("effect-qb/Casing")
|
|
2
|
+
|
|
3
|
+
export type Style =
|
|
4
|
+
| "preserve"
|
|
5
|
+
| "snake_case"
|
|
6
|
+
| "camelCase"
|
|
7
|
+
| "PascalCase"
|
|
8
|
+
| "kebab-case"
|
|
9
|
+
| "SCREAMING_SNAKE_CASE"
|
|
10
|
+
| ((name: string) => string)
|
|
11
|
+
|
|
12
|
+
export interface Options {
|
|
13
|
+
readonly tables?: Style
|
|
14
|
+
readonly columns?: Style
|
|
15
|
+
readonly schemas?: Style
|
|
16
|
+
readonly indexes?: Style
|
|
17
|
+
readonly constraints?: Style
|
|
18
|
+
readonly types?: Style
|
|
19
|
+
readonly sequences?: Style
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type Category = keyof Options
|
|
23
|
+
|
|
24
|
+
export interface State {
|
|
25
|
+
readonly casing?: Options
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const merge = (
|
|
29
|
+
base: Options | undefined,
|
|
30
|
+
override: Options | undefined
|
|
31
|
+
): Options | undefined => {
|
|
32
|
+
if (base === undefined) {
|
|
33
|
+
return override
|
|
34
|
+
}
|
|
35
|
+
if (override === undefined) {
|
|
36
|
+
return base
|
|
37
|
+
}
|
|
38
|
+
return { ...base, ...override }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const words = (name: string): readonly string[] =>
|
|
42
|
+
name
|
|
43
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
44
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
|
|
45
|
+
.split(/[^A-Za-z0-9]+/)
|
|
46
|
+
.filter((part) => part.length > 0)
|
|
47
|
+
|
|
48
|
+
const capitalize = (value: string): string =>
|
|
49
|
+
value.length === 0 ? value : `${value[0]!.toUpperCase()}${value.slice(1)}`
|
|
50
|
+
|
|
51
|
+
const lowerWords = (name: string): readonly string[] =>
|
|
52
|
+
words(name).map((part) => part.toLowerCase())
|
|
53
|
+
|
|
54
|
+
const applyNamedStyle = (style: Exclude<Style, (name: string) => string>, name: string): string => {
|
|
55
|
+
switch (style) {
|
|
56
|
+
case "preserve":
|
|
57
|
+
return name
|
|
58
|
+
case "snake_case":
|
|
59
|
+
return lowerWords(name).join("_")
|
|
60
|
+
case "camelCase": {
|
|
61
|
+
const parts = lowerWords(name)
|
|
62
|
+
const [head, ...tail] = parts
|
|
63
|
+
return head === undefined ? "" : `${head}${tail.map(capitalize).join("")}`
|
|
64
|
+
}
|
|
65
|
+
case "PascalCase":
|
|
66
|
+
return lowerWords(name).map(capitalize).join("")
|
|
67
|
+
case "kebab-case":
|
|
68
|
+
return lowerWords(name).join("-")
|
|
69
|
+
case "SCREAMING_SNAKE_CASE":
|
|
70
|
+
return lowerWords(name).join("_").toUpperCase()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const apply = (
|
|
75
|
+
style: Style | undefined,
|
|
76
|
+
name: string
|
|
77
|
+
): string => {
|
|
78
|
+
if (style === undefined) {
|
|
79
|
+
return name
|
|
80
|
+
}
|
|
81
|
+
return typeof style === "function" ? style(name) : applyNamedStyle(style, name)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const applyCategory = (
|
|
85
|
+
options: Options | undefined,
|
|
86
|
+
category: Category,
|
|
87
|
+
name: string
|
|
88
|
+
): string => apply(options?.[category], name)
|
|
89
|
+
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type * as Expression from "../scalar.js"
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
CanCastDbType as LookupCanCastDbType,
|
|
4
|
+
CanCompareDbTypes as LookupCanCompareDbTypes,
|
|
5
|
+
CanContainDbTypes as LookupCanContainDbTypes,
|
|
6
|
+
CanImplicitlyConvertDbType as LookupCanImplicitlyConvertDbType,
|
|
7
|
+
CanTextuallyCoerceDbType as LookupCanTextuallyCoerceDbType
|
|
8
|
+
} from "../datatypes/lookup.js"
|
|
3
9
|
|
|
4
10
|
export type CanCompareDbTypes<
|
|
5
11
|
Left extends Expression.DbType.Any,
|
|
@@ -18,6 +24,12 @@ export type CanTextuallyCoerceDbType<
|
|
|
18
24
|
Dialect extends string
|
|
19
25
|
> = LookupCanTextuallyCoerceDbType<Db, Dialect>
|
|
20
26
|
|
|
27
|
+
export type CanImplicitlyConvertDbType<
|
|
28
|
+
Source extends Expression.DbType.Any,
|
|
29
|
+
Target extends Expression.DbType.Any,
|
|
30
|
+
Dialect extends string
|
|
31
|
+
> = LookupCanImplicitlyConvertDbType<Source, Target, Dialect>
|
|
32
|
+
|
|
21
33
|
export type CanCastDbType<
|
|
22
34
|
Source extends Expression.DbType.Any,
|
|
23
35
|
Target extends Expression.DbType.Any,
|
|
@@ -4,6 +4,8 @@ import * as Schema from "effect/Schema"
|
|
|
4
4
|
|
|
5
5
|
import * as Expression from "./scalar.js"
|
|
6
6
|
import * as ExpressionAst from "./expression-ast.js"
|
|
7
|
+
import { withJsonPathAccess, type WithJsonPathAccess } from "./json/path-access.js"
|
|
8
|
+
import type * as Casing from "./casing.js"
|
|
7
9
|
import type * as SchemaExpression from "./schema-expression.js"
|
|
8
10
|
|
|
9
11
|
/** Symbol used to attach column-definition metadata. */
|
|
@@ -183,6 +185,7 @@ export interface BoundColumn<
|
|
|
183
185
|
readonly columnName: ColumnName
|
|
184
186
|
readonly baseTableName: BaseTableName
|
|
185
187
|
readonly schemaName?: string
|
|
188
|
+
readonly casing?: Casing.Options
|
|
186
189
|
}
|
|
187
190
|
readonly [Expression.TypeId]: Expression.State<
|
|
188
191
|
Select,
|
|
@@ -227,7 +230,7 @@ export type AnyBoundColumn = BoundColumn<
|
|
|
227
230
|
>
|
|
228
231
|
|
|
229
232
|
const ColumnProto = {
|
|
230
|
-
pipe(this:
|
|
233
|
+
pipe(this: Pipeable) {
|
|
231
234
|
return pipeArguments(this, arguments)
|
|
232
235
|
}
|
|
233
236
|
}
|
|
@@ -236,7 +239,7 @@ const attachPipe = <Value extends object>(value: Value): Value => {
|
|
|
236
239
|
Object.defineProperty(value, "pipe", {
|
|
237
240
|
configurable: true,
|
|
238
241
|
writable: true,
|
|
239
|
-
value: function(this:
|
|
242
|
+
value: function(this: Value) {
|
|
240
243
|
return pipeArguments(value, arguments)
|
|
241
244
|
}
|
|
242
245
|
})
|
|
@@ -271,7 +274,7 @@ export const makeColumnDefinition = <
|
|
|
271
274
|
Ref,
|
|
272
275
|
Dependencies
|
|
273
276
|
>["metadata"]
|
|
274
|
-
): ColumnDefinition<
|
|
277
|
+
): WithJsonPathAccess<ColumnDefinition<
|
|
275
278
|
Select,
|
|
276
279
|
Insert,
|
|
277
280
|
Update,
|
|
@@ -283,7 +286,7 @@ export const makeColumnDefinition = <
|
|
|
283
286
|
Unique,
|
|
284
287
|
Ref,
|
|
285
288
|
Dependencies
|
|
286
|
-
|
|
289
|
+
>> => {
|
|
287
290
|
const column = attachPipe(Object.create(ColumnProto))
|
|
288
291
|
column.schema = schema
|
|
289
292
|
column.metadata = metadata
|
|
@@ -315,7 +318,7 @@ export const makeColumnDefinition = <
|
|
|
315
318
|
identity: metadata.identity,
|
|
316
319
|
enum: metadata.enum
|
|
317
320
|
}
|
|
318
|
-
return column
|
|
321
|
+
return withJsonPathAccess(column)
|
|
319
322
|
}
|
|
320
323
|
|
|
321
324
|
export const remapColumnDefinition = <
|
|
@@ -360,7 +363,7 @@ export const remapColumnDefinition = <
|
|
|
360
363
|
Dependencies
|
|
361
364
|
>["metadata"]
|
|
362
365
|
} = {}
|
|
363
|
-
): ColumnDefinition<
|
|
366
|
+
): WithJsonPathAccess<ColumnDefinition<
|
|
364
367
|
Select,
|
|
365
368
|
Insert,
|
|
366
369
|
Update,
|
|
@@ -372,7 +375,7 @@ export const remapColumnDefinition = <
|
|
|
372
375
|
Unique,
|
|
373
376
|
Ref,
|
|
374
377
|
Dependencies
|
|
375
|
-
|
|
378
|
+
>> => {
|
|
376
379
|
const schema = options.schema ?? column.schema
|
|
377
380
|
const metadata = options.metadata ?? column.metadata
|
|
378
381
|
const next = attachPipe(Object.create(ColumnProto))
|
|
@@ -407,21 +410,22 @@ export const remapColumnDefinition = <
|
|
|
407
410
|
enum: metadata.enum
|
|
408
411
|
}
|
|
409
412
|
if (ExpressionAst.TypeId in column) {
|
|
410
|
-
next[ExpressionAst.TypeId] = (column as
|
|
413
|
+
next[ExpressionAst.TypeId] = (column as {
|
|
411
414
|
readonly [ExpressionAst.TypeId]: ExpressionAst.Any
|
|
412
415
|
})[ExpressionAst.TypeId]
|
|
413
416
|
}
|
|
414
417
|
if (BoundColumnTypeId in column) {
|
|
415
|
-
next[BoundColumnTypeId] = (column as
|
|
418
|
+
next[BoundColumnTypeId] = (column as {
|
|
416
419
|
readonly [BoundColumnTypeId]: {
|
|
417
420
|
readonly tableName: string
|
|
418
421
|
readonly columnName: string
|
|
419
422
|
readonly baseTableName: string
|
|
420
423
|
readonly schemaName?: string
|
|
424
|
+
readonly casing?: Casing.Options
|
|
421
425
|
}
|
|
422
426
|
})[BoundColumnTypeId]
|
|
423
427
|
}
|
|
424
|
-
return next
|
|
428
|
+
return withJsonPathAccess(next)
|
|
425
429
|
}
|
|
426
430
|
|
|
427
431
|
/** Attaches table/column provenance to an existing column definition. */
|
|
@@ -436,7 +440,8 @@ export const bindColumn = <
|
|
|
436
440
|
columnName: ColumnName,
|
|
437
441
|
column: Column,
|
|
438
442
|
baseTableName: BaseTableName,
|
|
439
|
-
schemaName?: SchemaName
|
|
443
|
+
schemaName?: SchemaName,
|
|
444
|
+
casing?: Casing.Options
|
|
440
445
|
): BoundColumnFrom<Column, TableName, ColumnName, BaseTableName> => {
|
|
441
446
|
const brandName = `${tableName}.${columnName}`
|
|
442
447
|
const schema = column.metadata.brand === true
|
|
@@ -467,9 +472,10 @@ export const bindColumn = <
|
|
|
467
472
|
tableName,
|
|
468
473
|
columnName,
|
|
469
474
|
baseTableName,
|
|
470
|
-
schemaName
|
|
475
|
+
schemaName,
|
|
476
|
+
casing
|
|
471
477
|
}
|
|
472
|
-
return bound
|
|
478
|
+
return withJsonPathAccess(bound) as BoundColumnFrom<Column, TableName, ColumnName, BaseTableName>
|
|
473
479
|
}
|
|
474
480
|
|
|
475
481
|
/** Extracts the internal state record for a column. */
|
|
@@ -508,7 +514,7 @@ export type BoundColumnFrom<
|
|
|
508
514
|
TableName extends string,
|
|
509
515
|
ColumnName extends string,
|
|
510
516
|
BaseTableName extends string = TableName
|
|
511
|
-
> = BoundColumn<
|
|
517
|
+
> = WithJsonPathAccess<BoundColumn<
|
|
512
518
|
Column["metadata"]["brand"] extends true
|
|
513
519
|
? BrandedValue<SelectType<Column>, `${TableName}.${ColumnName}`>
|
|
514
520
|
: SelectType<Column>,
|
|
@@ -528,4 +534,4 @@ export type BoundColumnFrom<
|
|
|
528
534
|
TableName,
|
|
529
535
|
ColumnName,
|
|
530
536
|
BaseTableName
|
|
531
|
-
|
|
537
|
+
>>
|
package/src/internal/column.ts
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
type SelectType,
|
|
43
43
|
type UpdateType
|
|
44
44
|
} from "./column-state.js"
|
|
45
|
+
import type { NonEmptyStringInput } from "./table-options.js"
|
|
45
46
|
|
|
46
47
|
type ReferentialAction = "noAction" | "restrict" | "cascade" | "setNull" | "setDefault"
|
|
47
48
|
|
|
@@ -223,6 +224,36 @@ type ForeignKeyOptions<Target extends AnyBoundColumn> = {
|
|
|
223
224
|
readonly initiallyDeferred?: boolean
|
|
224
225
|
}
|
|
225
226
|
|
|
227
|
+
type NonEmptyOptionNameInput<Options> = Options extends { readonly name: infer Name extends string }
|
|
228
|
+
? NonEmptyStringInput<Name> extends never ? never : unknown
|
|
229
|
+
: unknown
|
|
230
|
+
|
|
231
|
+
type NonEmptyStringArrayInput<Values extends readonly string[]> =
|
|
232
|
+
[Extract<Values[number], "">] extends [never] ? unknown : never
|
|
233
|
+
|
|
234
|
+
type NonEmptyIndexMethodInput<Options> = Options extends { readonly method: infer Method extends string }
|
|
235
|
+
? NonEmptyStringInput<Method> extends never ? never : unknown
|
|
236
|
+
: unknown
|
|
237
|
+
|
|
238
|
+
type NonEmptyIndexIncludeInput<Options> = Options extends { readonly include: infer Include extends readonly string[] }
|
|
239
|
+
? NonEmptyStringArrayInput<Include>
|
|
240
|
+
: unknown
|
|
241
|
+
|
|
242
|
+
type NonEmptyIndexOperatorClassInput<Options> = Options extends { readonly operatorClass: infer OperatorClass extends string }
|
|
243
|
+
? NonEmptyStringInput<OperatorClass> extends never ? never : unknown
|
|
244
|
+
: unknown
|
|
245
|
+
|
|
246
|
+
type NonEmptyIndexCollationInput<Options> = Options extends { readonly collation: infer Collation extends string }
|
|
247
|
+
? NonEmptyStringInput<Collation> extends never ? never : unknown
|
|
248
|
+
: unknown
|
|
249
|
+
|
|
250
|
+
type NonEmptyIndexMetadataInput<Options> =
|
|
251
|
+
& NonEmptyOptionNameInput<Options>
|
|
252
|
+
& NonEmptyIndexMethodInput<Options>
|
|
253
|
+
& NonEmptyIndexIncludeInput<Options>
|
|
254
|
+
& NonEmptyIndexOperatorClassInput<Options>
|
|
255
|
+
& NonEmptyIndexCollationInput<Options>
|
|
256
|
+
|
|
226
257
|
type SchemaCompatibleColumn<
|
|
227
258
|
Column extends AnyColumnDefinition,
|
|
228
259
|
SchemaType extends Schema.Top
|
|
@@ -500,7 +531,7 @@ export const primaryKey = <Column extends AnyColumnDefinition>(
|
|
|
500
531
|
type UniqueModifier = {
|
|
501
532
|
<Column extends AnyColumnDefinition>(column: Column): UniqueColumn<Column>
|
|
502
533
|
readonly options: <const Options extends ColumnUniqueOptions>(
|
|
503
|
-
options: Options
|
|
534
|
+
options: Options & NonEmptyOptionNameInput<Options>
|
|
504
535
|
) => <Column extends AnyColumnDefinition>(column: Column) => UniqueColumn<Column>
|
|
505
536
|
}
|
|
506
537
|
|
|
@@ -550,11 +581,11 @@ export const generated = <Value extends DdlExpression>(value: Value) =>
|
|
|
550
581
|
}) as GeneratedColumn<Column>
|
|
551
582
|
|
|
552
583
|
/** Preserves the exact SQL type used for DDL rendering. */
|
|
553
|
-
export const ddlType = <SqlType extends string>(sqlType: SqlType) =>
|
|
584
|
+
export const ddlType = <SqlType extends string>(sqlType: NonEmptyStringInput<SqlType>) =>
|
|
554
585
|
<Column extends AnyColumnDefinition>(column: Column): DdlTypedColumn<Column> =>
|
|
555
586
|
mapColumn(column, {
|
|
556
587
|
...column.metadata,
|
|
557
|
-
ddlType: sqlType
|
|
588
|
+
ddlType: sqlType as SqlType
|
|
558
589
|
}) as DdlTypedColumn<Column>
|
|
559
590
|
|
|
560
591
|
/** Overrides how a column crosses the SQL driver boundary. */
|
|
@@ -590,13 +621,15 @@ export const array = <Options extends ArrayOptions | undefined = undefined>(
|
|
|
590
621
|
}) as ArrayColumn<Column, Options>
|
|
591
622
|
|
|
592
623
|
/** Marks a column as indexed. */
|
|
624
|
+
type IndexPipe = <Column extends AnyColumnDefinition>(column: Column) => IndexedColumn<Column>
|
|
625
|
+
|
|
593
626
|
export function index<Column extends AnyColumnDefinition>(
|
|
594
627
|
column: Column
|
|
595
628
|
): IndexedColumn<Column>
|
|
596
629
|
export function index<const Options extends ColumnIndexOptions>(
|
|
597
|
-
options: Options
|
|
630
|
+
options: Options & NonEmptyIndexMetadataInput<Options>
|
|
598
631
|
): <Column extends AnyColumnDefinition>(column: Column) => IndexedColumn<Column>
|
|
599
|
-
export function index(arg:
|
|
632
|
+
export function index(arg: AnyColumnDefinition | ColumnIndexOptions): IndexedColumn<AnyColumnDefinition> | IndexPipe {
|
|
600
633
|
if (isColumnDefinitionValue(arg)) {
|
|
601
634
|
return mapColumn(arg, {
|
|
602
635
|
...arg.metadata,
|
|
@@ -648,17 +681,21 @@ export const identityAlways = <Column extends AnyColumnDefinition>(
|
|
|
648
681
|
*
|
|
649
682
|
* The base, non-null select types must match.
|
|
650
683
|
*/
|
|
684
|
+
type ForeignKeyPipe<Target extends AnyBoundColumn = AnyBoundColumn> = <Column extends AnyColumnDefinition>(
|
|
685
|
+
column: CompatibleReference<Column, Target>
|
|
686
|
+
) => ReferencingColumn<Column, Target>
|
|
687
|
+
|
|
651
688
|
export function foreignKey<Target extends AnyBoundColumn>(
|
|
652
689
|
target: () => Target
|
|
653
690
|
): <Column extends AnyColumnDefinition>(
|
|
654
691
|
column: CompatibleReference<Column, Target>
|
|
655
692
|
) => ReferencingColumn<Column, Target>
|
|
656
693
|
export function foreignKey<const Options extends ForeignKeyOptions<AnyBoundColumn>>(
|
|
657
|
-
options: Options
|
|
694
|
+
options: Options & NonEmptyOptionNameInput<Options>
|
|
658
695
|
): <Column extends AnyColumnDefinition>(
|
|
659
696
|
column: CompatibleReference<Column, ReturnType<Options["target"]>>
|
|
660
697
|
) => ReferencingColumn<Column, ReturnType<Options["target"]>>
|
|
661
|
-
export function foreignKey(arg:
|
|
698
|
+
export function foreignKey(arg: (() => AnyBoundColumn) | ForeignKeyOptions<AnyBoundColumn>): ForeignKeyPipe {
|
|
662
699
|
if (typeof arg === "function") {
|
|
663
700
|
const target = arg as () => AnyBoundColumn
|
|
664
701
|
return <Column extends AnyColumnDefinition>(
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type * as Expression from "../scalar.js"
|
|
2
|
+
import type { NonEmptyStringInput } from "../table-options.js"
|
|
2
3
|
import type { DatatypeFamilySpec, DatatypeKindSpec } from "./shape.js"
|
|
3
4
|
|
|
5
|
+
type ImplicitTargetsOf<Family> = Family extends { readonly implicitTargets: infer Targets extends readonly string[] }
|
|
6
|
+
? Targets
|
|
7
|
+
: readonly []
|
|
8
|
+
|
|
4
9
|
type DatatypeWitness<
|
|
5
10
|
Dialect extends string,
|
|
6
11
|
Kinds extends Record<string, DatatypeKindSpec>,
|
|
@@ -11,6 +16,7 @@ type DatatypeWitness<
|
|
|
11
16
|
readonly runtime: Kinds[Kind]["runtime"]
|
|
12
17
|
readonly compareGroup: Families[Kinds[Kind]["family"]]["compareGroup"]
|
|
13
18
|
readonly castTargets: Families[Kinds[Kind]["family"]]["castTargets"]
|
|
19
|
+
readonly implicitTargets: ImplicitTargetsOf<Families[Kinds[Kind]["family"]]>
|
|
14
20
|
readonly traits: Families[Kinds[Kind]["family"]]["traits"]
|
|
15
21
|
}
|
|
16
22
|
|
|
@@ -20,7 +26,7 @@ export type DatatypeModule<
|
|
|
20
26
|
Families extends Record<string, DatatypeFamilySpec>,
|
|
21
27
|
Aliases extends Record<string, string> = Record<never, never>
|
|
22
28
|
> = {
|
|
23
|
-
readonly custom: <Kind extends string>(kind: Kind) => Expression.DbType.Base<Dialect, Kind>
|
|
29
|
+
readonly custom: <Kind extends string>(kind: NonEmptyStringInput<Kind>) => Expression.DbType.Base<Dialect, Kind>
|
|
24
30
|
} & {
|
|
25
31
|
readonly [Kind in keyof Kinds]: () => DatatypeWitness<Dialect, Kinds, Families, Kind & string>
|
|
26
32
|
} & {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type * as Expression from "../scalar.js"
|
|
2
|
+
|
|
3
|
+
type DatatypeLookup = Readonly<Record<string, (() => Expression.DbType.Any) | undefined>>
|
|
4
|
+
|
|
5
|
+
export const enrichDbType = <
|
|
6
|
+
Module extends object,
|
|
7
|
+
Db extends Expression.DbType.Any
|
|
8
|
+
>(
|
|
9
|
+
datatypes: Module,
|
|
10
|
+
dbType: Db
|
|
11
|
+
): Db => {
|
|
12
|
+
if (dbType.kind === "custom") {
|
|
13
|
+
return dbType
|
|
14
|
+
}
|
|
15
|
+
const lookup = datatypes as DatatypeLookup
|
|
16
|
+
if (!(dbType.kind in lookup)) {
|
|
17
|
+
return dbType
|
|
18
|
+
}
|
|
19
|
+
const candidate = lookup[dbType.kind]
|
|
20
|
+
return typeof candidate === "function"
|
|
21
|
+
? { ...candidate(), ...dbType } as Db
|
|
22
|
+
: dbType
|
|
23
|
+
}
|