@prisma-next/sql-orm-lane 0.3.0-dev.3 → 0.3.0-dev.30
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 +2 -2
- package/dist/{chunk-3DNKIXXB.js → chunk-C4EECZ4E.js} +106 -119
- package/dist/chunk-C4EECZ4E.js.map +1 -0
- package/dist/exports/orm.d.ts +3 -5
- package/dist/exports/orm.d.ts.map +1 -0
- package/dist/exports/orm.js +1 -1
- package/dist/index.d.ts +4 -42
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/mutations/delete-builder.d.ts +9 -0
- package/dist/mutations/delete-builder.d.ts.map +1 -0
- package/dist/mutations/insert-builder.d.ts +7 -0
- package/dist/mutations/insert-builder.d.ts.map +1 -0
- package/dist/mutations/update-builder.d.ts +9 -0
- package/dist/mutations/update-builder.d.ts.map +1 -0
- package/dist/orm/builder.d.ts +38 -0
- package/dist/orm/builder.d.ts.map +1 -0
- package/dist/orm/capabilities.d.ts +3 -0
- package/dist/orm/capabilities.d.ts.map +1 -0
- package/dist/orm/context.d.ts +5 -0
- package/dist/orm/context.d.ts.map +1 -0
- package/dist/orm/state.d.ts +45 -0
- package/dist/orm/state.d.ts.map +1 -0
- package/dist/orm-include-child.d.ts +35 -0
- package/dist/orm-include-child.d.ts.map +1 -0
- package/dist/orm-relation-filter.d.ts +19 -0
- package/dist/orm-relation-filter.d.ts.map +1 -0
- package/dist/{orm-DAnGd7z2.d.ts → orm-types.d.ts} +16 -27
- package/dist/orm-types.d.ts.map +1 -0
- package/dist/orm.d.ts +5 -0
- package/dist/orm.d.ts.map +1 -0
- package/dist/plan/lowering.d.ts +2 -0
- package/dist/plan/lowering.d.ts.map +1 -0
- package/dist/plan/plan-assembly.d.ts +24 -0
- package/dist/plan/plan-assembly.d.ts.map +1 -0
- package/dist/plan/result-typing.d.ts +2 -0
- package/dist/plan/result-typing.d.ts.map +1 -0
- package/dist/relations/include-plan.d.ts +38 -0
- package/dist/relations/include-plan.d.ts.map +1 -0
- package/dist/selection/join.d.ts +3 -0
- package/dist/selection/join.d.ts.map +1 -0
- package/dist/selection/ordering.d.ts +11 -0
- package/dist/selection/ordering.d.ts.map +1 -0
- package/dist/selection/pagination.d.ts +6 -0
- package/dist/selection/pagination.d.ts.map +1 -0
- package/dist/selection/predicates.d.ts +10 -0
- package/dist/selection/predicates.d.ts.map +1 -0
- package/dist/selection/projection.d.ts +28 -0
- package/dist/selection/projection.d.ts.map +1 -0
- package/dist/selection/select-builder.d.ts +22 -0
- package/dist/selection/select-builder.d.ts.map +1 -0
- package/dist/types/internal.d.ts +4 -0
- package/dist/types/internal.d.ts.map +1 -0
- package/dist/utils/ast.d.ts +2 -0
- package/dist/utils/ast.d.ts.map +1 -0
- package/dist/utils/errors.d.ts +29 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/param-descriptor.d.ts +10 -0
- package/dist/utils/param-descriptor.d.ts.map +1 -0
- package/package.json +21 -21
- package/src/exports/orm.ts +12 -0
- package/src/index.ts +11 -0
- package/src/mutations/delete-builder.ts +87 -0
- package/src/mutations/insert-builder.ts +148 -0
- package/src/mutations/update-builder.ts +141 -0
- package/src/orm/builder.ts +744 -0
- package/src/orm/capabilities.ts +14 -0
- package/src/orm/context.ts +10 -0
- package/src/orm/state.ts +52 -0
- package/src/orm-include-child.ts +169 -0
- package/src/orm-relation-filter.ts +93 -0
- package/src/orm-types.ts +271 -0
- package/src/orm.ts +51 -0
- package/src/plan/lowering.ts +1 -0
- package/src/plan/plan-assembly.ts +312 -0
- package/src/plan/result-typing.ts +1 -0
- package/src/relations/include-plan.ts +324 -0
- package/src/selection/join.ts +13 -0
- package/src/selection/ordering.ts +52 -0
- package/src/selection/pagination.ts +11 -0
- package/src/selection/predicates.ts +104 -0
- package/src/selection/projection.ts +142 -0
- package/src/selection/select-builder.ts +80 -0
- package/src/types/internal.ts +3 -0
- package/src/utils/ast.ts +12 -0
- package/src/utils/errors.ts +130 -0
- package/src/utils/param-descriptor.ts +19 -0
- package/dist/chunk-3DNKIXXB.js.map +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface PaginationState {
|
|
2
|
+
limit?: number;
|
|
3
|
+
offset?: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function createPaginationState(limit?: number, offset?: number): PaginationState {
|
|
7
|
+
return {
|
|
8
|
+
...(limit !== undefined ? { limit } : {}),
|
|
9
|
+
...(offset !== undefined ? { offset } : {}),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { ParamDescriptor } from '@prisma-next/contract/types';
|
|
2
|
+
import type { SqlContract, SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
|
|
3
|
+
import type { BinaryExpr, Expression, ParamRef } from '@prisma-next/sql-relational-core/ast';
|
|
4
|
+
import { augmentDescriptorWithColumnMeta } from '@prisma-next/sql-relational-core/plan';
|
|
5
|
+
import type { BinaryBuilder, ParamPlaceholder } from '@prisma-next/sql-relational-core/types';
|
|
6
|
+
import {
|
|
7
|
+
isColumnBuilder,
|
|
8
|
+
isExpressionBuilder,
|
|
9
|
+
isParamPlaceholder,
|
|
10
|
+
} from '@prisma-next/sql-relational-core/utils/guards';
|
|
11
|
+
import { createBinaryExpr, createParamRef } from '../utils/ast';
|
|
12
|
+
import {
|
|
13
|
+
errorFailedToBuildWhereClause,
|
|
14
|
+
errorMissingParameter,
|
|
15
|
+
errorUnknownTable,
|
|
16
|
+
} from '../utils/errors';
|
|
17
|
+
|
|
18
|
+
export function buildWhereExpr(
|
|
19
|
+
where: BinaryBuilder,
|
|
20
|
+
contract: SqlContract<SqlStorage>,
|
|
21
|
+
paramsMap: Record<string, unknown>,
|
|
22
|
+
descriptors: ParamDescriptor[],
|
|
23
|
+
values: unknown[],
|
|
24
|
+
): {
|
|
25
|
+
expr: BinaryExpr;
|
|
26
|
+
codecId?: string;
|
|
27
|
+
paramName: string;
|
|
28
|
+
} {
|
|
29
|
+
let leftExpr: Expression;
|
|
30
|
+
let codecId: string | undefined;
|
|
31
|
+
let rightExpr: Expression | ParamRef;
|
|
32
|
+
let paramName: string;
|
|
33
|
+
|
|
34
|
+
// where.left is now an Expression (ColumnRef or OperationExpr)
|
|
35
|
+
leftExpr = where.left;
|
|
36
|
+
|
|
37
|
+
// If leftExpr is a ColumnRef, extract codecId from contract
|
|
38
|
+
if (leftExpr.kind === 'col') {
|
|
39
|
+
const { table, column } = leftExpr;
|
|
40
|
+
|
|
41
|
+
const contractTable = contract.storage.tables[table];
|
|
42
|
+
if (!contractTable) {
|
|
43
|
+
errorUnknownTable(table);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const columnMeta: StorageColumn | undefined = contractTable.columns[column];
|
|
47
|
+
// If column not found in contract, still build expression but without codecId
|
|
48
|
+
// This allows flexibility when columnMeta is available on the column builder
|
|
49
|
+
if (columnMeta) {
|
|
50
|
+
codecId = columnMeta.codecId;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Handle where.right - can be ParamPlaceholder or AnyExpressionSource
|
|
55
|
+
if (isParamPlaceholder(where.right)) {
|
|
56
|
+
// Handle param placeholder (existing logic)
|
|
57
|
+
const placeholder: ParamPlaceholder = where.right;
|
|
58
|
+
paramName = placeholder.name;
|
|
59
|
+
|
|
60
|
+
if (!Object.hasOwn(paramsMap, paramName)) {
|
|
61
|
+
errorMissingParameter(paramName);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const value = paramsMap[paramName];
|
|
65
|
+
const index = values.push(value);
|
|
66
|
+
|
|
67
|
+
// Construct descriptor from where.left Expression
|
|
68
|
+
// For ColumnRef, we can extract table/column directly
|
|
69
|
+
// For OperationExpr, we extract the base column reference
|
|
70
|
+
if (leftExpr.kind === 'col') {
|
|
71
|
+
const { table, column } = leftExpr;
|
|
72
|
+
const contractTable = contract.storage.tables[table];
|
|
73
|
+
const columnMeta = contractTable?.columns[column];
|
|
74
|
+
|
|
75
|
+
descriptors.push({
|
|
76
|
+
name: paramName,
|
|
77
|
+
source: 'dsl',
|
|
78
|
+
refs: { table, column },
|
|
79
|
+
...(columnMeta && typeof columnMeta.nullable === 'boolean'
|
|
80
|
+
? { nullable: columnMeta.nullable }
|
|
81
|
+
: {}),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
augmentDescriptorWithColumnMeta(descriptors, columnMeta);
|
|
85
|
+
}
|
|
86
|
+
// For OperationExpr, we don't create descriptors since we can't reliably extract column info
|
|
87
|
+
|
|
88
|
+
rightExpr = createParamRef(index, paramName);
|
|
89
|
+
} else if (isColumnBuilder(where.right) || isExpressionBuilder(where.right)) {
|
|
90
|
+
// Handle ExpressionSource on the right - use toExpr() to get the Expression
|
|
91
|
+
rightExpr = where.right.toExpr();
|
|
92
|
+
// Use a placeholder paramName for expression references (not used for params)
|
|
93
|
+
paramName = '';
|
|
94
|
+
} else {
|
|
95
|
+
// where.right is neither ParamPlaceholder nor ExpressionSource - invalid state
|
|
96
|
+
errorFailedToBuildWhereClause();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
expr: createBinaryExpr(where.op, leftExpr, rightExpr),
|
|
101
|
+
...(codecId ? { codecId } : {}),
|
|
102
|
+
paramName,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { TableRef } from '@prisma-next/sql-relational-core/ast';
|
|
2
|
+
import type {
|
|
3
|
+
AnyBinaryBuilder,
|
|
4
|
+
AnyExpressionSource,
|
|
5
|
+
AnyOrderBuilder,
|
|
6
|
+
JoinOnPredicate,
|
|
7
|
+
NestedProjection,
|
|
8
|
+
} from '@prisma-next/sql-relational-core/types';
|
|
9
|
+
import {
|
|
10
|
+
isColumnBuilder,
|
|
11
|
+
isExpressionBuilder,
|
|
12
|
+
} from '@prisma-next/sql-relational-core/utils/guards';
|
|
13
|
+
import {
|
|
14
|
+
errorAliasCollision,
|
|
15
|
+
errorAliasPathEmpty,
|
|
16
|
+
errorIncludeAliasNotFound,
|
|
17
|
+
errorInvalidProjectionKey,
|
|
18
|
+
errorInvalidProjectionValue,
|
|
19
|
+
errorProjectionEmpty,
|
|
20
|
+
} from '../utils/errors';
|
|
21
|
+
|
|
22
|
+
export interface ProjectionState {
|
|
23
|
+
readonly aliases: string[];
|
|
24
|
+
readonly columns: AnyExpressionSource[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type ProjectionInput = Record<string, AnyExpressionSource | boolean | NestedProjection>;
|
|
28
|
+
|
|
29
|
+
function generateAlias(path: string[]): string {
|
|
30
|
+
if (path.length === 0) {
|
|
31
|
+
errorAliasPathEmpty();
|
|
32
|
+
}
|
|
33
|
+
return path.join('_');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class AliasTracker {
|
|
37
|
+
private readonly aliases = new Set<string>();
|
|
38
|
+
private readonly aliasToPath = new Map<string, string[]>();
|
|
39
|
+
|
|
40
|
+
register(path: string[]): string {
|
|
41
|
+
const alias = generateAlias(path);
|
|
42
|
+
if (this.aliases.has(alias)) {
|
|
43
|
+
const existingPath = this.aliasToPath.get(alias);
|
|
44
|
+
errorAliasCollision(path, alias, existingPath);
|
|
45
|
+
}
|
|
46
|
+
this.aliases.add(alias);
|
|
47
|
+
this.aliasToPath.set(alias, path);
|
|
48
|
+
return alias;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getPath(alias: string): string[] | undefined {
|
|
52
|
+
return this.aliasToPath.get(alias);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
has(alias: string): boolean {
|
|
56
|
+
return this.aliases.has(alias);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function flattenProjection(
|
|
61
|
+
projection: NestedProjection,
|
|
62
|
+
tracker: AliasTracker,
|
|
63
|
+
currentPath: string[] = [],
|
|
64
|
+
): { aliases: string[]; columns: AnyExpressionSource[] } {
|
|
65
|
+
const aliases: string[] = [];
|
|
66
|
+
const columns: AnyExpressionSource[] = [];
|
|
67
|
+
|
|
68
|
+
for (const [key, value] of Object.entries(projection)) {
|
|
69
|
+
const path = [...currentPath, key];
|
|
70
|
+
|
|
71
|
+
if (isColumnBuilder(value) || isExpressionBuilder(value)) {
|
|
72
|
+
const alias = tracker.register(path);
|
|
73
|
+
aliases.push(alias);
|
|
74
|
+
columns.push(value);
|
|
75
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
76
|
+
const nested = flattenProjection(value, tracker, path);
|
|
77
|
+
aliases.push(...nested.aliases);
|
|
78
|
+
columns.push(...nested.columns);
|
|
79
|
+
} else {
|
|
80
|
+
errorInvalidProjectionValue(path);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { aliases, columns };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function buildProjectionState(
|
|
88
|
+
_table: TableRef,
|
|
89
|
+
projection: ProjectionInput,
|
|
90
|
+
includes?: ReadonlyArray<{
|
|
91
|
+
readonly alias: string;
|
|
92
|
+
readonly table: TableRef;
|
|
93
|
+
readonly on: JoinOnPredicate;
|
|
94
|
+
readonly childProjection: ProjectionState;
|
|
95
|
+
readonly childWhere?: AnyBinaryBuilder;
|
|
96
|
+
readonly childOrderBy?: AnyOrderBuilder;
|
|
97
|
+
readonly childLimit?: number;
|
|
98
|
+
}>,
|
|
99
|
+
): ProjectionState {
|
|
100
|
+
const tracker = new AliasTracker();
|
|
101
|
+
const aliases: string[] = [];
|
|
102
|
+
const columns: AnyExpressionSource[] = [];
|
|
103
|
+
|
|
104
|
+
for (const [key, value] of Object.entries(projection)) {
|
|
105
|
+
if (value === true) {
|
|
106
|
+
const matchingInclude = includes?.find((inc) => inc.alias === key);
|
|
107
|
+
if (!matchingInclude) {
|
|
108
|
+
errorIncludeAliasNotFound(key);
|
|
109
|
+
}
|
|
110
|
+
aliases.push(key);
|
|
111
|
+
columns.push({
|
|
112
|
+
kind: 'column',
|
|
113
|
+
table: matchingInclude.table.name,
|
|
114
|
+
column: '',
|
|
115
|
+
columnMeta: {
|
|
116
|
+
nativeType: 'jsonb',
|
|
117
|
+
codecId: 'core/json@1',
|
|
118
|
+
nullable: true,
|
|
119
|
+
},
|
|
120
|
+
toExpr() {
|
|
121
|
+
return { kind: 'col', table: matchingInclude.table.name, column: '' };
|
|
122
|
+
},
|
|
123
|
+
} as AnyExpressionSource);
|
|
124
|
+
} else if (isColumnBuilder(value) || isExpressionBuilder(value)) {
|
|
125
|
+
const alias = tracker.register([key]);
|
|
126
|
+
aliases.push(alias);
|
|
127
|
+
columns.push(value);
|
|
128
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
129
|
+
const nested = flattenProjection(value as NestedProjection, tracker, [key]);
|
|
130
|
+
aliases.push(...nested.aliases);
|
|
131
|
+
columns.push(...nested.columns);
|
|
132
|
+
} else {
|
|
133
|
+
errorInvalidProjectionKey(key);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (aliases.length === 0) {
|
|
138
|
+
errorProjectionEmpty();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return { aliases, columns };
|
|
142
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BinaryExpr,
|
|
3
|
+
Direction,
|
|
4
|
+
ExistsExpr,
|
|
5
|
+
Expression,
|
|
6
|
+
IncludeAst,
|
|
7
|
+
IncludeRef,
|
|
8
|
+
SelectAst,
|
|
9
|
+
TableRef,
|
|
10
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
11
|
+
import { isExpressionBuilder } from '@prisma-next/sql-relational-core/utils/guards';
|
|
12
|
+
import type { IncludeState } from '../relations/include-plan';
|
|
13
|
+
import { createSelectAst, createTableRef } from '../utils/ast';
|
|
14
|
+
import { errorInvalidColumn, errorMissingAlias, errorMissingColumn } from '../utils/errors';
|
|
15
|
+
import type { ProjectionState } from './projection';
|
|
16
|
+
|
|
17
|
+
export function buildProjectionItems(
|
|
18
|
+
projectionState: ProjectionState,
|
|
19
|
+
includesForMeta: ReadonlyArray<IncludeState>,
|
|
20
|
+
): Array<{ alias: string; expr: Expression | IncludeRef }> {
|
|
21
|
+
const projectEntries: Array<{ alias: string; expr: Expression | IncludeRef }> = [];
|
|
22
|
+
for (let i = 0; i < projectionState.aliases.length; i++) {
|
|
23
|
+
const alias = projectionState.aliases[i];
|
|
24
|
+
if (!alias) {
|
|
25
|
+
errorMissingAlias(i);
|
|
26
|
+
}
|
|
27
|
+
const column = projectionState.columns[i];
|
|
28
|
+
if (!column) {
|
|
29
|
+
errorMissingColumn(alias, i);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const matchingInclude = includesForMeta.find((inc) => inc.alias === alias);
|
|
33
|
+
if (matchingInclude) {
|
|
34
|
+
projectEntries.push({
|
|
35
|
+
alias,
|
|
36
|
+
expr: { kind: 'includeRef', alias },
|
|
37
|
+
});
|
|
38
|
+
} else if (isExpressionBuilder(column)) {
|
|
39
|
+
// ExpressionBuilder (operation result) - use its expr
|
|
40
|
+
projectEntries.push({
|
|
41
|
+
alias,
|
|
42
|
+
expr: column.expr,
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
// ColumnBuilder - use toExpr() to get ColumnRef
|
|
46
|
+
const expr = column.toExpr();
|
|
47
|
+
// Validate the expression has valid table and column values
|
|
48
|
+
if (expr.kind === 'col' && (!expr.table || !expr.column)) {
|
|
49
|
+
errorInvalidColumn(alias, i);
|
|
50
|
+
}
|
|
51
|
+
projectEntries.push({
|
|
52
|
+
alias,
|
|
53
|
+
expr,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return projectEntries;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function buildSelectAst(params: {
|
|
61
|
+
table: TableRef;
|
|
62
|
+
projectEntries: Array<{ alias: string; expr: Expression | IncludeRef }>;
|
|
63
|
+
includesAst?: ReadonlyArray<IncludeAst>;
|
|
64
|
+
whereExpr?: BinaryExpr | ExistsExpr;
|
|
65
|
+
orderByClause?: ReadonlyArray<{
|
|
66
|
+
expr: Expression;
|
|
67
|
+
dir: Direction;
|
|
68
|
+
}>;
|
|
69
|
+
limit?: number;
|
|
70
|
+
}): SelectAst {
|
|
71
|
+
const { table, projectEntries, includesAst, whereExpr, orderByClause, limit } = params;
|
|
72
|
+
return createSelectAst({
|
|
73
|
+
from: createTableRef(table.name),
|
|
74
|
+
project: projectEntries,
|
|
75
|
+
...(includesAst ? { includes: includesAst } : {}),
|
|
76
|
+
...(whereExpr ? { where: whereExpr } : {}),
|
|
77
|
+
...(orderByClause ? { orderBy: orderByClause } : {}),
|
|
78
|
+
...(limit !== undefined ? { limit } : {}),
|
|
79
|
+
});
|
|
80
|
+
}
|
package/src/utils/ast.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { planInvalid } from '@prisma-next/plan';
|
|
2
|
+
import type { StorageColumn } from '@prisma-next/sql-contract/types';
|
|
3
|
+
|
|
4
|
+
export function errorModelNotFound(modelName: string): never {
|
|
5
|
+
throw planInvalid(`Model ${modelName} not found in mappings`);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function errorTableNotFound(tableName: string): never {
|
|
9
|
+
throw planInvalid(`Table ${tableName} not found in schema`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function errorUnknownTable(tableName: string): never {
|
|
13
|
+
throw planInvalid(`Unknown table ${tableName}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function errorUnknownColumn(columnName: string, tableName: string): never {
|
|
17
|
+
throw planInvalid(`Unknown column ${columnName} in table ${tableName}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function errorMissingParameter(paramName: string): never {
|
|
21
|
+
throw planInvalid(`Missing value for parameter ${paramName}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function errorAliasPathEmpty(): never {
|
|
25
|
+
throw planInvalid('Alias path cannot be empty');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function errorAliasCollision(path: string[], alias: string, existingPath?: string[]): never {
|
|
29
|
+
throw planInvalid(
|
|
30
|
+
`Alias collision: path ${path.join('.')} would generate alias "${alias}" which conflicts with path ${existingPath?.join('.') ?? 'unknown'}`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function errorInvalidProjectionValue(path: string[]): never {
|
|
35
|
+
throw planInvalid(
|
|
36
|
+
`Invalid projection value at path ${path.join('.')}: expected ColumnBuilder or nested object`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function errorIncludeAliasNotFound(alias: string): never {
|
|
41
|
+
throw planInvalid(
|
|
42
|
+
`Include alias "${alias}" not found. Did you call includeMany() with alias "${alias}"?`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function errorInvalidProjectionKey(key: string): never {
|
|
47
|
+
throw planInvalid(
|
|
48
|
+
`Invalid projection value at key "${key}": expected ColumnBuilder, boolean true (for includes), or nested object`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function errorProjectionEmpty(): never {
|
|
53
|
+
throw planInvalid('select() requires at least one column or include');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function errorCreateRequiresFields(): never {
|
|
57
|
+
throw planInvalid('create() requires at least one field');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function errorUpdateRequiresFields(): never {
|
|
61
|
+
throw planInvalid('update() requires at least one field');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function errorIncludeRequiresCapabilities(): never {
|
|
65
|
+
throw planInvalid('includeMany requires lateral and jsonAgg capabilities');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function errorIncludeCapabilitiesNotTrue(): never {
|
|
69
|
+
throw planInvalid('includeMany requires lateral and jsonAgg capabilities to be true');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function errorMultiColumnJoinsNotSupported(): never {
|
|
73
|
+
throw planInvalid('Multi-column joins in includes are not yet supported');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function errorJoinColumnsMustBeDefined(): never {
|
|
77
|
+
throw planInvalid('Join columns must be defined');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function errorColumnNotFound(columnName: string, tableName: string): never {
|
|
81
|
+
throw planInvalid(`Column ${columnName} not found in table ${tableName}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function errorChildProjectionMustBeSpecified(): never {
|
|
85
|
+
throw planInvalid('Child projection must be specified');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function errorChildProjectionEmpty(): never {
|
|
89
|
+
throw planInvalid('Child projection must not be empty after filtering boolean values');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function errorMissingAlias(index: number): never {
|
|
93
|
+
throw planInvalid(`Missing alias at index ${index}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function errorMissingColumn(alias: string, index: number): never {
|
|
97
|
+
throw planInvalid(`Missing column for alias "${alias}" at index ${index}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function errorInvalidColumn(alias: string, index: number): never {
|
|
101
|
+
throw planInvalid(`Invalid column for alias "${alias}" at index ${index}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function errorRelationNotFound(relationName: string, modelName: string): never {
|
|
105
|
+
throw planInvalid(`Relation ${relationName} not found on model ${modelName}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function errorFailedToBuildWhereClause(): never {
|
|
109
|
+
throw planInvalid('Failed to build WHERE clause');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function assertColumnExists(
|
|
113
|
+
columnMeta: StorageColumn | undefined,
|
|
114
|
+
columnName: string,
|
|
115
|
+
tableName: string,
|
|
116
|
+
): asserts columnMeta is StorageColumn {
|
|
117
|
+
if (!columnMeta) {
|
|
118
|
+
errorUnknownColumn(columnName, tableName);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function assertParameterExists(
|
|
123
|
+
paramsMap: Record<string, unknown>,
|
|
124
|
+
paramName: string,
|
|
125
|
+
): unknown {
|
|
126
|
+
if (!Object.hasOwn(paramsMap, paramName)) {
|
|
127
|
+
errorMissingParameter(paramName);
|
|
128
|
+
}
|
|
129
|
+
return paramsMap[paramName];
|
|
130
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ParamDescriptor } from '@prisma-next/contract/types';
|
|
2
|
+
|
|
3
|
+
export function createParamDescriptor(args: {
|
|
4
|
+
name: string;
|
|
5
|
+
table: string;
|
|
6
|
+
column: string;
|
|
7
|
+
codecId?: string;
|
|
8
|
+
nativeType?: string;
|
|
9
|
+
nullable: boolean;
|
|
10
|
+
}): ParamDescriptor {
|
|
11
|
+
return {
|
|
12
|
+
name: args.name,
|
|
13
|
+
source: 'dsl',
|
|
14
|
+
refs: { table: args.table, column: args.column },
|
|
15
|
+
...(args.codecId ? { codecId: args.codecId } : {}),
|
|
16
|
+
...(args.nativeType ? { nativeType: args.nativeType } : {}),
|
|
17
|
+
nullable: args.nullable,
|
|
18
|
+
};
|
|
19
|
+
}
|