@prisma-next/sql-contract 0.3.0-dev.131 → 0.3.0-dev.132
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 -9
- package/dist/factories.d.mts +11 -15
- package/dist/factories.d.mts.map +1 -1
- package/dist/factories.mjs +10 -13
- package/dist/factories.mjs.map +1 -1
- package/dist/{types-CB821Pqa.d.mts → types-D6K16_9R.d.mts} +4 -23
- package/dist/types-D6K16_9R.d.mts.map +1 -0
- package/dist/types-DRR5stkj.mjs.map +1 -1
- package/dist/types.d.mts +2 -2
- package/dist/validate.d.mts +1 -1
- package/dist/validate.d.mts.map +1 -1
- package/dist/validate.mjs +39 -270
- package/dist/validate.mjs.map +1 -1
- package/dist/{validators-CNxeypbZ.mjs → validators-_1sYf-29.mjs} +4 -23
- package/dist/validators-_1sYf-29.mjs.map +1 -0
- package/dist/validators.d.mts +2 -9
- package/dist/validators.d.mts.map +1 -1
- package/dist/validators.mjs +1 -1
- package/package.json +4 -4
- package/src/construct.ts +2 -167
- package/src/exports/types.ts +0 -4
- package/src/factories.ts +24 -40
- package/src/types.ts +3 -28
- package/src/validate.ts +57 -286
- package/src/validators.ts +5 -26
- package/dist/types-CB821Pqa.d.mts.map +0 -1
- package/dist/validators-CNxeypbZ.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.132",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "SQL contract types, validators, and IR factories for Prisma Next",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"arktype": "^2.1.25",
|
|
9
|
-
"@prisma-next/contract": "0.3.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.3.0-dev.132"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"tsdown": "0.18.4",
|
|
13
13
|
"typescript": "5.9.3",
|
|
14
14
|
"vitest": "4.0.17",
|
|
15
|
+
"@prisma-next/test-utils": "0.0.1",
|
|
15
16
|
"@prisma-next/tsconfig": "0.0.0",
|
|
16
|
-
"@prisma-next/tsdown": "0.0.0"
|
|
17
|
-
"@prisma-next/test-utils": "0.0.1"
|
|
17
|
+
"@prisma-next/tsdown": "0.0.0"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
package/src/construct.ts
CHANGED
|
@@ -1,158 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
type ResolvedMappings = {
|
|
4
|
-
modelToTable: Record<string, string>;
|
|
5
|
-
tableToModel: Record<string, string>;
|
|
6
|
-
fieldToColumn: Record<string, Record<string, string>>;
|
|
7
|
-
columnToField: Record<string, Record<string, string>>;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
function computeDefaultMappings(models: Record<string, ModelDefinition>): ResolvedMappings {
|
|
11
|
-
const modelToTable: Record<string, string> = {};
|
|
12
|
-
const tableToModel: Record<string, string> = {};
|
|
13
|
-
const fieldToColumn: Record<string, Record<string, string>> = {};
|
|
14
|
-
const columnToField: Record<string, Record<string, string>> = {};
|
|
15
|
-
|
|
16
|
-
for (const [modelName, model] of Object.entries(models)) {
|
|
17
|
-
const tableName = model.storage.table;
|
|
18
|
-
modelToTable[modelName] = tableName;
|
|
19
|
-
tableToModel[tableName] = modelName;
|
|
20
|
-
|
|
21
|
-
const modelFieldToColumn: Record<string, string> = {};
|
|
22
|
-
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
23
|
-
const columnName = field.column;
|
|
24
|
-
modelFieldToColumn[fieldName] = columnName;
|
|
25
|
-
if (!columnToField[tableName]) {
|
|
26
|
-
columnToField[tableName] = {};
|
|
27
|
-
}
|
|
28
|
-
columnToField[tableName][columnName] = fieldName;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
fieldToColumn[modelName] = modelFieldToColumn;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
modelToTable,
|
|
36
|
-
tableToModel,
|
|
37
|
-
fieldToColumn,
|
|
38
|
-
columnToField,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function assertInverseModelMappings(
|
|
43
|
-
modelToTable: Record<string, string>,
|
|
44
|
-
tableToModel: Record<string, string>,
|
|
45
|
-
): void {
|
|
46
|
-
for (const [model, table] of Object.entries(modelToTable)) {
|
|
47
|
-
if (tableToModel[table] !== model) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
`Mappings override mismatch: modelToTable.${model}="${table}" is not mirrored in tableToModel`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
for (const [table, model] of Object.entries(tableToModel)) {
|
|
54
|
-
if (modelToTable[model] !== table) {
|
|
55
|
-
throw new Error(
|
|
56
|
-
`Mappings override mismatch: tableToModel.${table}="${model}" is not mirrored in modelToTable`,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function assertInverseFieldMappings(
|
|
63
|
-
fieldToColumn: Record<string, Record<string, string>>,
|
|
64
|
-
columnToField: Record<string, Record<string, string>>,
|
|
65
|
-
modelToTable: Record<string, string>,
|
|
66
|
-
tableToModel: Record<string, string>,
|
|
67
|
-
): void {
|
|
68
|
-
for (const [model, fields] of Object.entries(fieldToColumn)) {
|
|
69
|
-
const table = modelToTable[model];
|
|
70
|
-
if (!table) {
|
|
71
|
-
throw new Error(
|
|
72
|
-
`Mappings override mismatch: fieldToColumn references unknown model "${model}"`,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
const reverseFields = columnToField[table];
|
|
76
|
-
if (!reverseFields) {
|
|
77
|
-
throw new Error(
|
|
78
|
-
`Mappings override mismatch: columnToField is missing table "${table}" for model "${model}"`,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
for (const [field, column] of Object.entries(fields)) {
|
|
82
|
-
if (reverseFields[column] !== field) {
|
|
83
|
-
throw new Error(
|
|
84
|
-
`Mappings override mismatch: fieldToColumn.${model}.${field}="${column}" is not mirrored in columnToField.${table}`,
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
for (const [table, columns] of Object.entries(columnToField)) {
|
|
91
|
-
const model = tableToModel[table];
|
|
92
|
-
if (!model) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
`Mappings override mismatch: columnToField references unknown table "${table}"`,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
const forwardFields = fieldToColumn[model];
|
|
98
|
-
if (!forwardFields) {
|
|
99
|
-
throw new Error(
|
|
100
|
-
`Mappings override mismatch: fieldToColumn is missing model "${model}" for table "${table}"`,
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
for (const [column, field] of Object.entries(columns)) {
|
|
104
|
-
if (forwardFields[field] !== column) {
|
|
105
|
-
throw new Error(
|
|
106
|
-
`Mappings override mismatch: columnToField.${table}.${column}="${field}" is not mirrored in fieldToColumn.${model}`,
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function mergeMappings(
|
|
114
|
-
defaults: ResolvedMappings,
|
|
115
|
-
existingMappings?: Partial<SqlMappings>,
|
|
116
|
-
): ResolvedMappings {
|
|
117
|
-
const hasModelToTable = existingMappings?.modelToTable !== undefined;
|
|
118
|
-
const hasTableToModel = existingMappings?.tableToModel !== undefined;
|
|
119
|
-
if (hasModelToTable !== hasTableToModel) {
|
|
120
|
-
throw new Error(
|
|
121
|
-
'Mappings override mismatch: modelToTable and tableToModel must be provided together',
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const hasFieldToColumn = existingMappings?.fieldToColumn !== undefined;
|
|
126
|
-
const hasColumnToField = existingMappings?.columnToField !== undefined;
|
|
127
|
-
if (hasFieldToColumn !== hasColumnToField) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
'Mappings override mismatch: fieldToColumn and columnToField must be provided together',
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const modelToTable: Record<string, string> = hasModelToTable
|
|
134
|
-
? (existingMappings?.modelToTable ?? {})
|
|
135
|
-
: defaults.modelToTable;
|
|
136
|
-
const tableToModel: Record<string, string> = hasTableToModel
|
|
137
|
-
? (existingMappings?.tableToModel ?? {})
|
|
138
|
-
: defaults.tableToModel;
|
|
139
|
-
assertInverseModelMappings(modelToTable, tableToModel);
|
|
140
|
-
|
|
141
|
-
const fieldToColumn: Record<string, Record<string, string>> = hasFieldToColumn
|
|
142
|
-
? (existingMappings?.fieldToColumn ?? {})
|
|
143
|
-
: defaults.fieldToColumn;
|
|
144
|
-
const columnToField: Record<string, Record<string, string>> = hasColumnToField
|
|
145
|
-
? (existingMappings?.columnToField ?? {})
|
|
146
|
-
: defaults.columnToField;
|
|
147
|
-
assertInverseFieldMappings(fieldToColumn, columnToField, modelToTable, tableToModel);
|
|
148
|
-
|
|
149
|
-
return {
|
|
150
|
-
modelToTable,
|
|
151
|
-
tableToModel,
|
|
152
|
-
fieldToColumn,
|
|
153
|
-
columnToField,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
1
|
+
import type { SqlContract, SqlStorage } from './types';
|
|
156
2
|
|
|
157
3
|
type ValidatedContractInput = SqlContract<SqlStorage> & { _generated?: unknown };
|
|
158
4
|
|
|
@@ -165,17 +11,6 @@ function stripGenerated(obj: ValidatedContractInput): Omit<ValidatedContractInpu
|
|
|
165
11
|
export function constructContract<TContract extends SqlContract<SqlStorage>>(
|
|
166
12
|
input: ValidatedContractInput,
|
|
167
13
|
): TContract {
|
|
168
|
-
const existingMappings = (input as { mappings?: Partial<SqlMappings> }).mappings;
|
|
169
|
-
const defaultMappings = computeDefaultMappings(input.models as Record<string, ModelDefinition>);
|
|
170
|
-
const mappings = mergeMappings(defaultMappings, existingMappings);
|
|
171
|
-
|
|
172
14
|
const stripped = stripGenerated(input);
|
|
173
|
-
|
|
174
|
-
const contractWithMappings = {
|
|
175
|
-
...stripped,
|
|
176
|
-
mappings,
|
|
177
|
-
roots: stripped.roots,
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
return contractWithMappings as TContract;
|
|
15
|
+
return stripped as TContract;
|
|
181
16
|
}
|
package/src/exports/types.ts
CHANGED
|
@@ -9,9 +9,6 @@ export type {
|
|
|
9
9
|
ForeignKeyOptions,
|
|
10
10
|
ForeignKeyReferences,
|
|
11
11
|
Index,
|
|
12
|
-
ModelDefinition,
|
|
13
|
-
ModelField,
|
|
14
|
-
ModelStorage,
|
|
15
12
|
OperationTypesOf,
|
|
16
13
|
PrimaryKey,
|
|
17
14
|
QueryOperationTypeEntry,
|
|
@@ -21,7 +18,6 @@ export type {
|
|
|
21
18
|
ResolveCodecTypes,
|
|
22
19
|
ResolveOperationTypes,
|
|
23
20
|
SqlContract,
|
|
24
|
-
SqlMappings,
|
|
25
21
|
SqlModelFieldStorage,
|
|
26
22
|
SqlModelStorage,
|
|
27
23
|
SqlQueryOperationTypes,
|
package/src/factories.ts
CHANGED
|
@@ -8,12 +8,10 @@ import type {
|
|
|
8
8
|
ForeignKeyOptions,
|
|
9
9
|
ForeignKeyReferences,
|
|
10
10
|
Index,
|
|
11
|
-
ModelDefinition,
|
|
12
|
-
ModelField,
|
|
13
|
-
ModelStorage,
|
|
14
11
|
PrimaryKey,
|
|
15
12
|
SqlContract,
|
|
16
|
-
|
|
13
|
+
SqlModelFieldStorage,
|
|
14
|
+
SqlModelStorage,
|
|
17
15
|
SqlStorage,
|
|
18
16
|
StorageColumn,
|
|
19
17
|
StorageTable,
|
|
@@ -21,14 +19,6 @@ import type {
|
|
|
21
19
|
} from './types';
|
|
22
20
|
import { applyFkDefaults } from './types';
|
|
23
21
|
|
|
24
|
-
/**
|
|
25
|
-
* Creates a StorageColumn with nativeType and codecId.
|
|
26
|
-
*
|
|
27
|
-
* @param nativeType - Native database type identifier (e.g., 'int4', 'text', 'vector')
|
|
28
|
-
* @param codecId - Codec identifier (e.g., 'pg/int4@1', 'pg/text@1')
|
|
29
|
-
* @param nullable - Whether the column is nullable (default: false)
|
|
30
|
-
* @returns StorageColumn with nativeType and codecId
|
|
31
|
-
*/
|
|
32
22
|
export function col(nativeType: string, codecId: string, nullable = false): StorageColumn {
|
|
33
23
|
return {
|
|
34
24
|
nativeType,
|
|
@@ -95,14 +85,27 @@ export function table(
|
|
|
95
85
|
}
|
|
96
86
|
|
|
97
87
|
export function model(
|
|
98
|
-
|
|
99
|
-
fields: Record<string,
|
|
88
|
+
tableName: string,
|
|
89
|
+
fields: Record<string, SqlModelFieldStorage>,
|
|
100
90
|
relations: Record<string, unknown> = {},
|
|
101
|
-
):
|
|
102
|
-
|
|
91
|
+
): {
|
|
92
|
+
storage: SqlModelStorage;
|
|
93
|
+
fields: Record<string, { nullable: boolean; codecId?: string }>;
|
|
94
|
+
relations: Record<string, unknown>;
|
|
95
|
+
} {
|
|
96
|
+
const storage: SqlModelStorage = { table: tableName, fields };
|
|
97
|
+
const domainFields = Object.fromEntries(
|
|
98
|
+
Object.entries(fields).map(([name, field]) => [
|
|
99
|
+
name,
|
|
100
|
+
{
|
|
101
|
+
nullable: field.nullable ?? false,
|
|
102
|
+
...(field.codecId !== undefined ? { codecId: field.codecId } : {}),
|
|
103
|
+
},
|
|
104
|
+
]),
|
|
105
|
+
) as Record<string, { nullable: boolean; codecId?: string }>;
|
|
103
106
|
return {
|
|
104
107
|
storage,
|
|
105
|
-
fields,
|
|
108
|
+
fields: domainFields,
|
|
106
109
|
relations,
|
|
107
110
|
};
|
|
108
111
|
}
|
|
@@ -120,9 +123,7 @@ export function contract<
|
|
|
120
123
|
storageHash: TStorageHash;
|
|
121
124
|
executionHash?: TExecutionHash;
|
|
122
125
|
storage: SqlStorage;
|
|
123
|
-
models?: Record<string,
|
|
124
|
-
relations?: Record<string, unknown>;
|
|
125
|
-
mappings?: Partial<SqlMappings>;
|
|
126
|
+
models?: Record<string, unknown>;
|
|
126
127
|
schemaVersion?: '1';
|
|
127
128
|
targetFamily?: 'sql';
|
|
128
129
|
profileHash?: TProfileHash;
|
|
@@ -130,15 +131,7 @@ export function contract<
|
|
|
130
131
|
extensionPacks?: Record<string, unknown>;
|
|
131
132
|
meta?: Record<string, unknown>;
|
|
132
133
|
sources?: Record<string, unknown>;
|
|
133
|
-
}): SqlContract<
|
|
134
|
-
SqlStorage,
|
|
135
|
-
Record<string, unknown>,
|
|
136
|
-
Record<string, unknown>,
|
|
137
|
-
SqlMappings,
|
|
138
|
-
TStorageHash,
|
|
139
|
-
TExecutionHash,
|
|
140
|
-
TProfileHash
|
|
141
|
-
> {
|
|
134
|
+
}): SqlContract<SqlStorage, Record<string, unknown>, TStorageHash, TExecutionHash, TProfileHash> {
|
|
142
135
|
return {
|
|
143
136
|
schemaVersion: opts.schemaVersion ?? '1',
|
|
144
137
|
target: opts.target,
|
|
@@ -147,20 +140,11 @@ export function contract<
|
|
|
147
140
|
...(opts.executionHash !== undefined && { executionHash: opts.executionHash }),
|
|
148
141
|
storage: opts.storage,
|
|
149
142
|
models: opts.models ?? {},
|
|
150
|
-
|
|
151
|
-
mappings: (opts.mappings ?? {}) as SqlMappings,
|
|
143
|
+
roots: {},
|
|
152
144
|
...(opts.profileHash !== undefined && { profileHash: opts.profileHash }),
|
|
153
145
|
...(opts.capabilities !== undefined && { capabilities: opts.capabilities }),
|
|
154
146
|
...(opts.extensionPacks !== undefined && { extensionPacks: opts.extensionPacks }),
|
|
155
147
|
...(opts.meta !== undefined && { meta: opts.meta }),
|
|
156
148
|
...(opts.sources !== undefined && { sources: opts.sources as Record<string, unknown> }),
|
|
157
|
-
} as SqlContract<
|
|
158
|
-
SqlStorage,
|
|
159
|
-
Record<string, unknown>,
|
|
160
|
-
Record<string, unknown>,
|
|
161
|
-
SqlMappings,
|
|
162
|
-
TStorageHash,
|
|
163
|
-
TExecutionHash,
|
|
164
|
-
TProfileHash
|
|
165
|
-
>;
|
|
149
|
+
} as SqlContract<SqlStorage, Record<string, unknown>, TStorageHash, TExecutionHash, TProfileHash>;
|
|
166
150
|
}
|
package/src/types.ts
CHANGED
|
@@ -120,21 +120,6 @@ export type SqlStorage = {
|
|
|
120
120
|
readonly types?: Record<string, StorageTypeInstance>;
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
-
export type ModelField = {
|
|
124
|
-
readonly column: string;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
export type ModelStorage = {
|
|
128
|
-
readonly table: string;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
export type ModelDefinition = {
|
|
132
|
-
readonly storage: ModelStorage;
|
|
133
|
-
readonly fields: Record<string, ModelField>;
|
|
134
|
-
readonly relations: Record<string, unknown>;
|
|
135
|
-
readonly owner?: string;
|
|
136
|
-
};
|
|
137
|
-
|
|
138
123
|
export type SqlModelFieldStorage = {
|
|
139
124
|
readonly column: string;
|
|
140
125
|
readonly codecId?: string;
|
|
@@ -152,13 +137,6 @@ export type SqlRelation = {
|
|
|
152
137
|
readonly on: DomainRelationOn;
|
|
153
138
|
};
|
|
154
139
|
|
|
155
|
-
export type SqlMappings = {
|
|
156
|
-
readonly modelToTable?: Record<string, string>;
|
|
157
|
-
readonly tableToModel?: Record<string, string>;
|
|
158
|
-
readonly fieldToColumn?: Record<string, Record<string, string>>;
|
|
159
|
-
readonly columnToField?: Record<string, Record<string, string>>;
|
|
160
|
-
};
|
|
161
|
-
|
|
162
140
|
export const DEFAULT_FK_CONSTRAINT = true;
|
|
163
141
|
export const DEFAULT_FK_INDEX = true;
|
|
164
142
|
|
|
@@ -223,17 +201,14 @@ export type ContractWithTypeMaps<TContract, TTypeMaps> = TContract & {
|
|
|
223
201
|
|
|
224
202
|
export type SqlContract<
|
|
225
203
|
S extends SqlStorage = SqlStorage,
|
|
226
|
-
|
|
227
|
-
R extends Record<string, unknown> = Record<string, unknown>,
|
|
228
|
-
Map extends SqlMappings = SqlMappings,
|
|
204
|
+
TModels extends Record<string, unknown> = Record<string, unknown>,
|
|
229
205
|
TStorageHash extends StorageHashBase<string> = StorageHashBase<string>,
|
|
230
206
|
TExecutionHash extends ExecutionHashBase<string> = ExecutionHashBase<string>,
|
|
231
207
|
TProfileHash extends ProfileHashBase<string> = ProfileHashBase<string>,
|
|
232
|
-
> = ContractBase<TStorageHash, TExecutionHash, TProfileHash
|
|
208
|
+
> = Omit<ContractBase<TStorageHash, TExecutionHash, TProfileHash>, 'models'> & {
|
|
233
209
|
readonly targetFamily: string;
|
|
234
210
|
readonly storage: S;
|
|
235
|
-
readonly
|
|
236
|
-
readonly mappings: Map;
|
|
211
|
+
readonly models: TModels;
|
|
237
212
|
readonly execution?: ExecutionSection;
|
|
238
213
|
};
|
|
239
214
|
|