@prisma-next/contract-authoring 0.3.0-dev.5 → 0.3.0-dev.50
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 +4 -1
- package/dist/index.d.mts +295 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +229 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +22 -14
- package/src/builder-state.ts +95 -8
- package/src/contract-builder.ts +26 -16
- package/src/index.ts +6 -1
- package/src/table-builder.ts +245 -36
- package/src/types.ts +16 -10
- package/dist/builder-state.d.ts +0 -60
- package/dist/builder-state.d.ts.map +0 -1
- package/dist/contract-builder.d.ts +0 -15
- package/dist/contract-builder.d.ts.map +0 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -179
- package/dist/index.js.map +0 -1
- package/dist/model-builder.d.ts +0 -38
- package/dist/model-builder.d.ts.map +0 -1
- package/dist/table-builder.d.ts +0 -20
- package/dist/table-builder.d.ts.map +0 -1
- package/dist/types.d.ts +0 -46
- package/dist/types.d.ts.map +0 -1
package/package.json
CHANGED
|
@@ -1,37 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/contract-authoring",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.50",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Target-agnostic contract authoring builder core for Prisma Next",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"ts-toolbelt": "^9.6.0",
|
|
9
|
-
"@prisma-next/contract": "0.3.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.3.0-dev.50",
|
|
10
|
+
"@prisma-next/utils": "0.3.0-dev.50"
|
|
10
11
|
},
|
|
11
12
|
"devDependencies": {
|
|
12
|
-
"
|
|
13
|
-
"tsup": "8.5.1",
|
|
13
|
+
"tsdown": "0.18.4",
|
|
14
14
|
"typescript": "5.9.3",
|
|
15
|
-
"vitest": "4.0.
|
|
15
|
+
"vitest": "4.0.17",
|
|
16
|
+
"@prisma-next/tsconfig": "0.0.0",
|
|
17
|
+
"@prisma-next/tsdown": "0.0.0"
|
|
16
18
|
},
|
|
17
19
|
"files": [
|
|
18
20
|
"dist",
|
|
19
21
|
"src"
|
|
20
22
|
],
|
|
21
23
|
"exports": {
|
|
22
|
-
".":
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
".": "./dist/index.mjs",
|
|
25
|
+
"./package.json": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/index.mjs",
|
|
28
|
+
"module": "./dist/index.mjs",
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/prisma/prisma-next.git",
|
|
33
|
+
"directory": "packages/1-framework/2-authoring/contract"
|
|
26
34
|
},
|
|
27
35
|
"scripts": {
|
|
28
|
-
"build": "
|
|
36
|
+
"build": "tsdown",
|
|
29
37
|
"test": "vitest run",
|
|
30
38
|
"test:coverage": "vitest run --coverage",
|
|
31
39
|
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
32
|
-
"lint": "biome check . --
|
|
33
|
-
"lint:fix": "biome check --write .
|
|
34
|
-
"lint:fix:unsafe": "biome check --write --unsafe .
|
|
35
|
-
"clean": "
|
|
40
|
+
"lint": "biome check . --error-on-warnings",
|
|
41
|
+
"lint:fix": "biome check --write .",
|
|
42
|
+
"lint:fix:unsafe": "biome check --write --unsafe .",
|
|
43
|
+
"clean": "rm -rf dist dist-tsc dist-tsc-prod coverage .tmp-output"
|
|
36
44
|
}
|
|
37
45
|
}
|
package/src/builder-state.ts
CHANGED
|
@@ -1,21 +1,97 @@
|
|
|
1
|
+
import type { ColumnDefault, ExecutionMutationDefaultValue } from '@prisma-next/contract/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Duplicated from sql-contract to avoid cross-layer dependency
|
|
5
|
+
* (framework authoring cannot depend on the SQL domain's contract package).
|
|
6
|
+
*/
|
|
7
|
+
export type ReferentialAction = 'noAction' | 'restrict' | 'cascade' | 'setNull' | 'setDefault';
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Column type descriptor containing both codec ID and native type.
|
|
3
11
|
* Used when defining columns with descriptor objects instead of string IDs.
|
|
12
|
+
*
|
|
13
|
+
* For parameterized types (e.g., `vector(1536)`), the `typeParams` field
|
|
14
|
+
* carries codec-owned parameters that affect both TypeScript type generation
|
|
15
|
+
* and native DDL output.
|
|
4
16
|
*/
|
|
5
17
|
export type ColumnTypeDescriptor = {
|
|
6
18
|
readonly codecId: string;
|
|
7
19
|
readonly nativeType: string;
|
|
20
|
+
readonly typeParams?: Record<string, unknown>;
|
|
21
|
+
readonly typeRef?: string;
|
|
8
22
|
};
|
|
9
23
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
> {
|
|
24
|
+
/**
|
|
25
|
+
* Base column properties shared by all column states.
|
|
26
|
+
*/
|
|
27
|
+
type ColumnBuilderStateBase<Name extends string, Type extends string> = {
|
|
15
28
|
readonly name: Name;
|
|
16
|
-
readonly nullable: Nullable;
|
|
17
29
|
readonly type: Type;
|
|
18
30
|
readonly nativeType: string;
|
|
31
|
+
readonly typeParams?: Record<string, unknown>;
|
|
32
|
+
readonly typeRef?: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type StorageTypeInstanceState = {
|
|
36
|
+
readonly codecId: string;
|
|
37
|
+
readonly nativeType: string;
|
|
38
|
+
readonly typeParams: Record<string, unknown>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Column builder state.
|
|
43
|
+
*
|
|
44
|
+
* Both nullable and non-nullable columns can define defaults to match database behavior.
|
|
45
|
+
*/
|
|
46
|
+
export type ColumnBuilderState<
|
|
47
|
+
Name extends string,
|
|
48
|
+
Nullable extends boolean,
|
|
49
|
+
Type extends string,
|
|
50
|
+
> = ColumnBuilderStateBase<Name, Type> &
|
|
51
|
+
(Nullable extends true
|
|
52
|
+
? { readonly nullable: true; readonly default?: ColumnDefault }
|
|
53
|
+
: {
|
|
54
|
+
readonly nullable: false;
|
|
55
|
+
readonly default?: ColumnDefault;
|
|
56
|
+
readonly executionDefault?: ExecutionMutationDefaultValue;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Unique constraint definition for table builder.
|
|
61
|
+
*/
|
|
62
|
+
export interface UniqueConstraintDef {
|
|
63
|
+
readonly columns: readonly string[];
|
|
64
|
+
readonly name?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Index definition for table builder.
|
|
69
|
+
*/
|
|
70
|
+
export interface IndexDef {
|
|
71
|
+
readonly columns: readonly string[];
|
|
72
|
+
readonly name?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Options for configuring a foreign key's name and referential actions.
|
|
77
|
+
*/
|
|
78
|
+
export type ForeignKeyOptions = {
|
|
79
|
+
readonly name?: string;
|
|
80
|
+
readonly onDelete?: ReferentialAction;
|
|
81
|
+
readonly onUpdate?: ReferentialAction;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Foreign key definition for table builder.
|
|
86
|
+
*/
|
|
87
|
+
export interface ForeignKeyDef extends ForeignKeyOptions {
|
|
88
|
+
readonly columns: readonly string[];
|
|
89
|
+
readonly references: {
|
|
90
|
+
readonly table: string;
|
|
91
|
+
readonly columns: readonly string[];
|
|
92
|
+
};
|
|
93
|
+
readonly constraint?: boolean;
|
|
94
|
+
readonly index?: boolean;
|
|
19
95
|
}
|
|
20
96
|
|
|
21
97
|
export interface TableBuilderState<
|
|
@@ -26,6 +102,10 @@ export interface TableBuilderState<
|
|
|
26
102
|
readonly name: Name;
|
|
27
103
|
readonly columns: Columns;
|
|
28
104
|
readonly primaryKey?: PrimaryKey;
|
|
105
|
+
readonly primaryKeyName?: string;
|
|
106
|
+
readonly uniques: readonly UniqueConstraintDef[];
|
|
107
|
+
readonly indexes: readonly IndexDef[];
|
|
108
|
+
readonly foreignKeys: readonly ForeignKeyDef[];
|
|
29
109
|
}
|
|
30
110
|
|
|
31
111
|
export type RelationDefinition = {
|
|
@@ -54,6 +134,11 @@ export interface ModelBuilderState<
|
|
|
54
134
|
readonly relations: Relations;
|
|
55
135
|
}
|
|
56
136
|
|
|
137
|
+
export interface ForeignKeyDefaultsState {
|
|
138
|
+
readonly constraint: boolean;
|
|
139
|
+
readonly index: boolean;
|
|
140
|
+
}
|
|
141
|
+
|
|
57
142
|
export interface ContractBuilderState<
|
|
58
143
|
Target extends string | undefined = string | undefined,
|
|
59
144
|
Tables extends Record<
|
|
@@ -78,16 +163,18 @@ export interface ContractBuilderState<
|
|
|
78
163
|
never,
|
|
79
164
|
ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>
|
|
80
165
|
>,
|
|
81
|
-
|
|
166
|
+
StorageHash extends string | undefined = string | undefined,
|
|
82
167
|
ExtensionPacks extends Record<string, unknown> | undefined = undefined,
|
|
83
168
|
Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
84
169
|
> {
|
|
85
170
|
readonly target?: Target;
|
|
86
171
|
readonly tables: Tables;
|
|
87
172
|
readonly models: Models;
|
|
88
|
-
readonly
|
|
173
|
+
readonly storageHash?: StorageHash;
|
|
89
174
|
readonly extensionPacks?: ExtensionPacks;
|
|
90
175
|
readonly capabilities?: Capabilities;
|
|
176
|
+
readonly storageTypes?: Record<string, StorageTypeInstanceState>;
|
|
177
|
+
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
|
91
178
|
/**
|
|
92
179
|
* Array of extension pack namespace identifiers (e.g., ['pgvector', 'postgis']).
|
|
93
180
|
* Populated when extension packs are registered during contract building.
|
package/src/contract-builder.ts
CHANGED
|
@@ -2,12 +2,13 @@ import type { TargetPackRef } from '@prisma-next/contract/framework-components';
|
|
|
2
2
|
import type {
|
|
3
3
|
ColumnBuilderState,
|
|
4
4
|
ContractBuilderState,
|
|
5
|
+
ForeignKeyDefaultsState,
|
|
5
6
|
ModelBuilderState,
|
|
6
7
|
RelationDefinition,
|
|
7
8
|
TableBuilderState,
|
|
8
9
|
} from './builder-state';
|
|
9
10
|
import { ModelBuilder } from './model-builder';
|
|
10
|
-
import { TableBuilder } from './table-builder';
|
|
11
|
+
import { createTable, TableBuilder } from './table-builder';
|
|
11
12
|
|
|
12
13
|
export class ContractBuilder<
|
|
13
14
|
Target extends string | undefined = undefined,
|
|
@@ -23,7 +24,7 @@ export class ContractBuilder<
|
|
|
23
24
|
string,
|
|
24
25
|
ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>
|
|
25
26
|
> = Record<never, never>,
|
|
26
|
-
|
|
27
|
+
StorageHash extends string | undefined = undefined,
|
|
27
28
|
ExtensionPacks extends Record<string, unknown> | undefined = undefined,
|
|
28
29
|
Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
29
30
|
> {
|
|
@@ -31,26 +32,26 @@ export class ContractBuilder<
|
|
|
31
32
|
Target,
|
|
32
33
|
Tables,
|
|
33
34
|
Models,
|
|
34
|
-
|
|
35
|
+
StorageHash,
|
|
35
36
|
ExtensionPacks,
|
|
36
37
|
Capabilities
|
|
37
38
|
>;
|
|
38
39
|
|
|
39
40
|
constructor(
|
|
40
|
-
state?: ContractBuilderState<Target, Tables, Models,
|
|
41
|
+
state?: ContractBuilderState<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities>,
|
|
41
42
|
) {
|
|
42
43
|
this.state =
|
|
43
44
|
state ??
|
|
44
45
|
({
|
|
45
46
|
tables: {},
|
|
46
47
|
models: {},
|
|
47
|
-
} as ContractBuilderState<Target, Tables, Models,
|
|
48
|
+
} as ContractBuilderState<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities>);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
target<T extends string>(
|
|
51
52
|
packRef: TargetPackRef<string, T>,
|
|
52
|
-
): ContractBuilder<T, Tables, Models,
|
|
53
|
-
return new ContractBuilder<T, Tables, Models,
|
|
53
|
+
): ContractBuilder<T, Tables, Models, StorageHash, ExtensionPacks, Capabilities> {
|
|
54
|
+
return new ContractBuilder<T, Tables, Models, StorageHash, ExtensionPacks, Capabilities>({
|
|
54
55
|
...this.state,
|
|
55
56
|
target: packRef.targetId,
|
|
56
57
|
});
|
|
@@ -58,8 +59,8 @@ export class ContractBuilder<
|
|
|
58
59
|
|
|
59
60
|
capabilities<C extends Record<string, Record<string, boolean>>>(
|
|
60
61
|
capabilities: C,
|
|
61
|
-
): ContractBuilder<Target, Tables, Models,
|
|
62
|
-
return new ContractBuilder<Target, Tables, Models,
|
|
62
|
+
): ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, C> {
|
|
63
|
+
return new ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, C>({
|
|
63
64
|
...this.state,
|
|
64
65
|
capabilities,
|
|
65
66
|
});
|
|
@@ -79,11 +80,11 @@ export class ContractBuilder<
|
|
|
79
80
|
Target,
|
|
80
81
|
Tables & Record<TableName, ReturnType<T['build']>>,
|
|
81
82
|
Models,
|
|
82
|
-
|
|
83
|
+
StorageHash,
|
|
83
84
|
ExtensionPacks,
|
|
84
85
|
Capabilities
|
|
85
86
|
> {
|
|
86
|
-
const tableBuilder =
|
|
87
|
+
const tableBuilder = createTable(name);
|
|
87
88
|
const result = callback(tableBuilder);
|
|
88
89
|
const finalBuilder = result instanceof TableBuilder ? result : tableBuilder;
|
|
89
90
|
const tableState = finalBuilder.build();
|
|
@@ -92,7 +93,7 @@ export class ContractBuilder<
|
|
|
92
93
|
Target,
|
|
93
94
|
Tables & Record<TableName, ReturnType<T['build']>>,
|
|
94
95
|
Models,
|
|
95
|
-
|
|
96
|
+
StorageHash,
|
|
96
97
|
ExtensionPacks,
|
|
97
98
|
Capabilities
|
|
98
99
|
>({
|
|
@@ -121,7 +122,7 @@ export class ContractBuilder<
|
|
|
121
122
|
Target,
|
|
122
123
|
Tables,
|
|
123
124
|
Models & Record<ModelName, ReturnType<M['build']>>,
|
|
124
|
-
|
|
125
|
+
StorageHash,
|
|
125
126
|
ExtensionPacks,
|
|
126
127
|
Capabilities
|
|
127
128
|
> {
|
|
@@ -134,7 +135,7 @@ export class ContractBuilder<
|
|
|
134
135
|
Target,
|
|
135
136
|
Tables,
|
|
136
137
|
Models & Record<ModelName, ReturnType<M['build']>>,
|
|
137
|
-
|
|
138
|
+
StorageHash,
|
|
138
139
|
ExtensionPacks,
|
|
139
140
|
Capabilities
|
|
140
141
|
>({
|
|
@@ -144,12 +145,21 @@ export class ContractBuilder<
|
|
|
144
145
|
});
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
storageHash<H extends string>(
|
|
148
149
|
hash: H,
|
|
149
150
|
): ContractBuilder<Target, Tables, Models, H, ExtensionPacks, Capabilities> {
|
|
150
151
|
return new ContractBuilder<Target, Tables, Models, H, ExtensionPacks, Capabilities>({
|
|
151
152
|
...this.state,
|
|
152
|
-
|
|
153
|
+
storageHash: hash,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
foreignKeyDefaults(
|
|
158
|
+
config: ForeignKeyDefaultsState,
|
|
159
|
+
): ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities> {
|
|
160
|
+
return new ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities>({
|
|
161
|
+
...this.state,
|
|
162
|
+
foreignKeyDefaults: config,
|
|
153
163
|
});
|
|
154
164
|
}
|
|
155
165
|
}
|
package/src/index.ts
CHANGED
|
@@ -3,14 +3,19 @@ export type {
|
|
|
3
3
|
ColumnBuilderState,
|
|
4
4
|
ColumnTypeDescriptor,
|
|
5
5
|
ContractBuilderState,
|
|
6
|
+
ForeignKeyDef,
|
|
7
|
+
ForeignKeyDefaultsState,
|
|
8
|
+
ForeignKeyOptions,
|
|
9
|
+
IndexDef,
|
|
6
10
|
ModelBuilderState,
|
|
7
11
|
RelationDefinition,
|
|
8
12
|
TableBuilderState,
|
|
13
|
+
UniqueConstraintDef,
|
|
9
14
|
} from './builder-state';
|
|
10
15
|
|
|
11
16
|
export { ContractBuilder, defineContract } from './contract-builder';
|
|
12
17
|
export { ModelBuilder } from './model-builder';
|
|
13
|
-
export { TableBuilder } from './table-builder';
|
|
18
|
+
export { createTable, TableBuilder } from './table-builder';
|
|
14
19
|
|
|
15
20
|
export type {
|
|
16
21
|
BuildModelFields,
|
package/src/table-builder.ts
CHANGED
|
@@ -1,5 +1,82 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ColumnDefault, ExecutionMutationDefaultValue } from '@prisma-next/contract/types';
|
|
2
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
3
|
+
import type {
|
|
4
|
+
ColumnBuilderState,
|
|
5
|
+
ColumnTypeDescriptor,
|
|
6
|
+
ForeignKeyDef,
|
|
7
|
+
ForeignKeyOptions,
|
|
8
|
+
IndexDef,
|
|
9
|
+
TableBuilderState,
|
|
10
|
+
UniqueConstraintDef,
|
|
11
|
+
} from './builder-state';
|
|
2
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Column options for nullable columns.
|
|
15
|
+
*/
|
|
16
|
+
interface NullableColumnOptions<Descriptor extends ColumnTypeDescriptor> {
|
|
17
|
+
type: Descriptor;
|
|
18
|
+
nullable: true;
|
|
19
|
+
typeParams?: Record<string, unknown>;
|
|
20
|
+
default?: ColumnDefault;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Column options for non-nullable columns.
|
|
25
|
+
* Non-nullable columns can optionally have a default value.
|
|
26
|
+
*/
|
|
27
|
+
interface NonNullableColumnOptions<Descriptor extends ColumnTypeDescriptor> {
|
|
28
|
+
type: Descriptor;
|
|
29
|
+
nullable?: false;
|
|
30
|
+
typeParams?: Record<string, unknown>;
|
|
31
|
+
default?: ColumnDefault;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type GeneratedColumnOptions<Descriptor extends ColumnTypeDescriptor> = Omit<
|
|
35
|
+
NonNullableColumnOptions<Descriptor>,
|
|
36
|
+
'default' | 'nullable'
|
|
37
|
+
> & {
|
|
38
|
+
/**
|
|
39
|
+
* Generated columns are always non-nullable and use mutation-time defaults
|
|
40
|
+
* that the runtime injects when the column is omitted from insert input.
|
|
41
|
+
*/
|
|
42
|
+
nullable?: false;
|
|
43
|
+
generated: ExecutionMutationDefaultValue;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Column options for any column nullability. */
|
|
47
|
+
type ColumnOptions<Descriptor extends ColumnTypeDescriptor> =
|
|
48
|
+
| NullableColumnOptions<Descriptor>
|
|
49
|
+
| NonNullableColumnOptions<Descriptor>;
|
|
50
|
+
|
|
51
|
+
type NullableFromOptions<TOptions> = TOptions extends { nullable: true } ? true : false;
|
|
52
|
+
|
|
53
|
+
interface TableBuilderInternalState<
|
|
54
|
+
Name extends string,
|
|
55
|
+
Columns extends Record<string, ColumnBuilderState<string, boolean, string>>,
|
|
56
|
+
PrimaryKey extends readonly string[] | undefined,
|
|
57
|
+
> {
|
|
58
|
+
readonly name: Name;
|
|
59
|
+
readonly columns: Columns;
|
|
60
|
+
readonly primaryKey: PrimaryKey;
|
|
61
|
+
readonly primaryKeyName: string | undefined;
|
|
62
|
+
readonly uniques: readonly UniqueConstraintDef[];
|
|
63
|
+
readonly indexes: readonly IndexDef[];
|
|
64
|
+
readonly foreignKeys: readonly ForeignKeyDef[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Creates a new table builder with the given name.
|
|
69
|
+
* This is the preferred way to create a TableBuilder - it ensures
|
|
70
|
+
* type parameters are inferred correctly without unsafe casts.
|
|
71
|
+
*/
|
|
72
|
+
export function createTable<Name extends string>(name: Name): TableBuilder<Name> {
|
|
73
|
+
return new TableBuilder(name, {}, undefined, undefined, [], [], []);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Builder for defining table structure with type-safe chaining.
|
|
78
|
+
* Use `createTable(name)` to create instances.
|
|
79
|
+
*/
|
|
3
80
|
export class TableBuilder<
|
|
4
81
|
Name extends string,
|
|
5
82
|
Columns extends Record<string, ColumnBuilderState<string, boolean, string>> = Record<
|
|
@@ -8,76 +85,202 @@ export class TableBuilder<
|
|
|
8
85
|
>,
|
|
9
86
|
PrimaryKey extends readonly string[] | undefined = undefined,
|
|
10
87
|
> {
|
|
11
|
-
private readonly
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
88
|
+
private readonly _state: TableBuilderInternalState<Name, Columns, PrimaryKey>;
|
|
89
|
+
|
|
90
|
+
/** @internal Use createTable() instead */
|
|
91
|
+
constructor(
|
|
92
|
+
name: Name,
|
|
93
|
+
columns: Columns,
|
|
94
|
+
primaryKey: PrimaryKey,
|
|
95
|
+
primaryKeyName: string | undefined,
|
|
96
|
+
uniques: readonly UniqueConstraintDef[],
|
|
97
|
+
indexes: readonly IndexDef[],
|
|
98
|
+
foreignKeys: readonly ForeignKeyDef[],
|
|
99
|
+
) {
|
|
100
|
+
this._state = {
|
|
101
|
+
name,
|
|
102
|
+
columns,
|
|
103
|
+
primaryKey,
|
|
104
|
+
primaryKeyName,
|
|
105
|
+
uniques,
|
|
106
|
+
indexes,
|
|
107
|
+
foreignKeys,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private get _name(): Name {
|
|
112
|
+
return this._state.name;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private get _columns(): Columns {
|
|
116
|
+
return this._state.columns;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private get _primaryKey(): PrimaryKey {
|
|
120
|
+
return this._state.primaryKey;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Add a nullable column to the table. */
|
|
124
|
+
column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
125
|
+
name: ColName,
|
|
126
|
+
options: NullableColumnOptions<Descriptor>,
|
|
127
|
+
): TableBuilder<
|
|
128
|
+
Name,
|
|
129
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, true, Descriptor['codecId']>>,
|
|
130
|
+
PrimaryKey
|
|
131
|
+
>;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Add a non-nullable column to the table.
|
|
135
|
+
* Non-nullable columns can optionally have a default value.
|
|
136
|
+
*/
|
|
137
|
+
column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
138
|
+
name: ColName,
|
|
139
|
+
options: NonNullableColumnOptions<Descriptor>,
|
|
140
|
+
): TableBuilder<
|
|
141
|
+
Name,
|
|
142
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
|
|
143
|
+
PrimaryKey
|
|
144
|
+
>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Implementation of the column method.
|
|
148
|
+
*/
|
|
149
|
+
column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
150
|
+
name: ColName,
|
|
151
|
+
options: ColumnOptions<Descriptor>,
|
|
152
|
+
): TableBuilder<
|
|
153
|
+
Name,
|
|
154
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, boolean, Descriptor['codecId']>>,
|
|
155
|
+
PrimaryKey
|
|
156
|
+
> {
|
|
157
|
+
return this.columnInternal(name, options);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
generated<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
|
|
161
|
+
name: ColName,
|
|
162
|
+
options: GeneratedColumnOptions<Descriptor>,
|
|
163
|
+
): TableBuilder<
|
|
164
|
+
Name,
|
|
165
|
+
Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
|
|
166
|
+
PrimaryKey
|
|
167
|
+
> {
|
|
168
|
+
const { generated, ...columnOptions } = options;
|
|
169
|
+
return this.columnInternal(name, columnOptions, generated);
|
|
19
170
|
}
|
|
20
171
|
|
|
21
|
-
|
|
172
|
+
private columnInternal<
|
|
22
173
|
ColName extends string,
|
|
23
174
|
Descriptor extends ColumnTypeDescriptor,
|
|
24
|
-
|
|
175
|
+
Options extends ColumnOptions<Descriptor>,
|
|
25
176
|
>(
|
|
26
177
|
name: ColName,
|
|
27
|
-
options:
|
|
28
|
-
|
|
29
|
-
nullable?: Nullable;
|
|
30
|
-
},
|
|
178
|
+
options: Options,
|
|
179
|
+
executionDefault?: ExecutionMutationDefaultValue,
|
|
31
180
|
): TableBuilder<
|
|
32
181
|
Name,
|
|
33
182
|
Columns &
|
|
34
183
|
Record<
|
|
35
184
|
ColName,
|
|
36
|
-
ColumnBuilderState<ColName,
|
|
185
|
+
ColumnBuilderState<ColName, NullableFromOptions<Options>, Descriptor['codecId']>
|
|
37
186
|
>,
|
|
38
187
|
PrimaryKey
|
|
39
188
|
> {
|
|
40
|
-
const nullable =
|
|
41
|
-
const { codecId, nativeType } = options.type;
|
|
189
|
+
const nullable = options.nullable ?? false;
|
|
190
|
+
const { codecId, nativeType, typeParams: descriptorTypeParams, typeRef } = options.type;
|
|
191
|
+
const typeParams = options.typeParams ?? descriptorTypeParams;
|
|
42
192
|
|
|
43
193
|
const columnState = {
|
|
44
194
|
name,
|
|
45
195
|
nullable,
|
|
46
196
|
type: codecId,
|
|
47
197
|
nativeType,
|
|
48
|
-
|
|
198
|
+
...ifDefined('typeParams', typeParams),
|
|
199
|
+
...ifDefined('typeRef', typeRef),
|
|
200
|
+
...ifDefined('default', 'default' in options ? options.default : undefined),
|
|
201
|
+
...ifDefined('executionDefault', executionDefault),
|
|
202
|
+
} as ColumnBuilderState<ColName, NullableFromOptions<Options>, Descriptor['codecId']>;
|
|
203
|
+
const newColumns = { ...this._columns, [name]: columnState } as Columns &
|
|
204
|
+
Record<
|
|
205
|
+
ColName,
|
|
206
|
+
ColumnBuilderState<ColName, NullableFromOptions<Options>, Descriptor['codecId']>
|
|
207
|
+
>;
|
|
49
208
|
return new TableBuilder(
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.
|
|
209
|
+
this._state.name,
|
|
210
|
+
newColumns,
|
|
211
|
+
this._state.primaryKey,
|
|
212
|
+
this._state.primaryKeyName,
|
|
213
|
+
this._state.uniques,
|
|
214
|
+
this._state.indexes,
|
|
215
|
+
this._state.foreignKeys,
|
|
57
216
|
);
|
|
58
217
|
}
|
|
59
218
|
|
|
60
219
|
primaryKey<PK extends readonly string[]>(
|
|
61
220
|
columns: PK,
|
|
62
|
-
|
|
221
|
+
name?: string,
|
|
63
222
|
): TableBuilder<Name, Columns, PK> {
|
|
64
|
-
return new TableBuilder(
|
|
223
|
+
return new TableBuilder(
|
|
224
|
+
this._state.name,
|
|
225
|
+
this._state.columns,
|
|
226
|
+
columns,
|
|
227
|
+
name,
|
|
228
|
+
this._state.uniques,
|
|
229
|
+
this._state.indexes,
|
|
230
|
+
this._state.foreignKeys,
|
|
231
|
+
);
|
|
65
232
|
}
|
|
66
233
|
|
|
67
|
-
unique(
|
|
68
|
-
|
|
234
|
+
unique(columns: readonly string[], name?: string): TableBuilder<Name, Columns, PrimaryKey> {
|
|
235
|
+
const constraint: UniqueConstraintDef = name ? { columns, name } : { columns };
|
|
236
|
+
return new TableBuilder(
|
|
237
|
+
this._state.name,
|
|
238
|
+
this._state.columns,
|
|
239
|
+
this._state.primaryKey,
|
|
240
|
+
this._state.primaryKeyName,
|
|
241
|
+
[...this._state.uniques, constraint],
|
|
242
|
+
this._state.indexes,
|
|
243
|
+
this._state.foreignKeys,
|
|
244
|
+
);
|
|
69
245
|
}
|
|
70
246
|
|
|
71
|
-
index(
|
|
72
|
-
|
|
247
|
+
index(columns: readonly string[], name?: string): TableBuilder<Name, Columns, PrimaryKey> {
|
|
248
|
+
const indexDef: IndexDef = name ? { columns, name } : { columns };
|
|
249
|
+
return new TableBuilder(
|
|
250
|
+
this._state.name,
|
|
251
|
+
this._state.columns,
|
|
252
|
+
this._state.primaryKey,
|
|
253
|
+
this._state.primaryKeyName,
|
|
254
|
+
this._state.uniques,
|
|
255
|
+
[...this._state.indexes, indexDef],
|
|
256
|
+
this._state.foreignKeys,
|
|
257
|
+
);
|
|
73
258
|
}
|
|
74
259
|
|
|
75
260
|
foreignKey(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
261
|
+
columns: readonly string[],
|
|
262
|
+
references: { table: string; columns: readonly string[] },
|
|
263
|
+
opts?: string | (ForeignKeyOptions & { constraint?: boolean; index?: boolean }),
|
|
79
264
|
): TableBuilder<Name, Columns, PrimaryKey> {
|
|
80
|
-
|
|
265
|
+
const resolved = typeof opts === 'string' ? { name: opts } : opts;
|
|
266
|
+
const fkDef: ForeignKeyDef = {
|
|
267
|
+
columns,
|
|
268
|
+
references,
|
|
269
|
+
...ifDefined('name', resolved?.name),
|
|
270
|
+
...ifDefined('onDelete', resolved?.onDelete),
|
|
271
|
+
...ifDefined('onUpdate', resolved?.onUpdate),
|
|
272
|
+
...ifDefined('constraint', resolved?.constraint),
|
|
273
|
+
...ifDefined('index', resolved?.index),
|
|
274
|
+
};
|
|
275
|
+
return new TableBuilder(
|
|
276
|
+
this._state.name,
|
|
277
|
+
this._state.columns,
|
|
278
|
+
this._state.primaryKey,
|
|
279
|
+
this._state.primaryKeyName,
|
|
280
|
+
this._state.uniques,
|
|
281
|
+
this._state.indexes,
|
|
282
|
+
[...this._state.foreignKeys, fkDef],
|
|
283
|
+
);
|
|
81
284
|
}
|
|
82
285
|
|
|
83
286
|
build(): TableBuilderState<Name, Columns, PrimaryKey> {
|
|
@@ -85,6 +288,12 @@ export class TableBuilder<
|
|
|
85
288
|
name: this._name,
|
|
86
289
|
columns: this._columns,
|
|
87
290
|
...(this._primaryKey !== undefined ? { primaryKey: this._primaryKey } : {}),
|
|
291
|
+
...(this._state.primaryKeyName !== undefined
|
|
292
|
+
? { primaryKeyName: this._state.primaryKeyName }
|
|
293
|
+
: {}),
|
|
294
|
+
uniques: this._state.uniques,
|
|
295
|
+
indexes: this._state.indexes,
|
|
296
|
+
foreignKeys: this._state.foreignKeys,
|
|
88
297
|
} as TableBuilderState<Name, Columns, PrimaryKey>;
|
|
89
298
|
}
|
|
90
299
|
}
|