@prisma-next/sql-builder 0.0.1
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 +68 -0
- package/package.json +66 -0
- package/src/exports/types.ts +8 -0
- package/src/expression.ts +158 -0
- package/src/index.ts +8 -0
- package/src/resolve.ts +14 -0
- package/src/runtime/builder-base.ts +369 -0
- package/src/runtime/expression-impl.ts +23 -0
- package/src/runtime/field-proxy.ts +37 -0
- package/src/runtime/functions.ts +190 -0
- package/src/runtime/index.ts +4 -0
- package/src/runtime/joined-tables-impl.ts +238 -0
- package/src/runtime/mutation-impl.ts +317 -0
- package/src/runtime/query-impl.ts +254 -0
- package/src/runtime/sql.ts +31 -0
- package/src/runtime/table-proxy-impl.ts +173 -0
- package/src/scope.ts +83 -0
- package/src/types/db.ts +13 -0
- package/src/types/grouped-query.ts +68 -0
- package/src/types/joined-tables.ts +6 -0
- package/src/types/mutation-query.ts +73 -0
- package/src/types/select-query.ts +64 -0
- package/src/types/shared.ts +121 -0
- package/src/types/table-proxy.ts +52 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { StorageTable } from '@prisma-next/sql-contract/types';
|
|
2
|
+
import { type AnyFromSource, TableSource } from '@prisma-next/sql-relational-core/ast';
|
|
3
|
+
import type {
|
|
4
|
+
AggregateFunctions,
|
|
5
|
+
Expression,
|
|
6
|
+
ExpressionBuilder,
|
|
7
|
+
ExtractScopeFields,
|
|
8
|
+
FieldProxy,
|
|
9
|
+
WithField,
|
|
10
|
+
WithFields,
|
|
11
|
+
} from '../expression';
|
|
12
|
+
import type {
|
|
13
|
+
EmptyRow,
|
|
14
|
+
Expand,
|
|
15
|
+
JoinOuterScope,
|
|
16
|
+
JoinSource,
|
|
17
|
+
MergeScopes,
|
|
18
|
+
NullableScope,
|
|
19
|
+
QueryContext,
|
|
20
|
+
RebindScope,
|
|
21
|
+
Scope,
|
|
22
|
+
ScopeField,
|
|
23
|
+
ScopeTable,
|
|
24
|
+
StorageTableToScopeTable,
|
|
25
|
+
Subquery,
|
|
26
|
+
} from '../scope';
|
|
27
|
+
import type { TableProxyContract } from '../types/db';
|
|
28
|
+
import type { JoinedTables } from '../types/joined-tables';
|
|
29
|
+
import type { DeleteQuery, InsertQuery, UpdateQuery } from '../types/mutation-query';
|
|
30
|
+
import type { SelectQuery } from '../types/select-query';
|
|
31
|
+
import type { LateralBuilder } from '../types/shared';
|
|
32
|
+
import type { TableProxy } from '../types/table-proxy';
|
|
33
|
+
import { BuilderBase, type BuilderContext, emptyState, tableToScope } from './builder-base';
|
|
34
|
+
import { JoinedTablesImpl } from './joined-tables-impl';
|
|
35
|
+
import { DeleteQueryImpl, InsertQueryImpl, UpdateQueryImpl } from './mutation-impl';
|
|
36
|
+
import { SelectQueryImpl } from './query-impl';
|
|
37
|
+
|
|
38
|
+
export class TableProxyImpl<
|
|
39
|
+
C extends TableProxyContract,
|
|
40
|
+
Name extends string & keyof C['storage']['tables'],
|
|
41
|
+
Alias extends string,
|
|
42
|
+
AvailableScope extends Scope,
|
|
43
|
+
QC extends QueryContext,
|
|
44
|
+
>
|
|
45
|
+
extends BuilderBase<C['capabilities']>
|
|
46
|
+
implements TableProxy<C, Name, Alias, AvailableScope, QC>
|
|
47
|
+
{
|
|
48
|
+
declare readonly [JoinOuterScope]: JoinSource<
|
|
49
|
+
StorageTableToScopeTable<C['storage']['tables'][Name]>,
|
|
50
|
+
Alias
|
|
51
|
+
>[typeof JoinOuterScope];
|
|
52
|
+
|
|
53
|
+
readonly #tableName: string;
|
|
54
|
+
readonly #table: StorageTable;
|
|
55
|
+
readonly #fromSource: TableSource;
|
|
56
|
+
readonly #scope: Scope;
|
|
57
|
+
|
|
58
|
+
constructor(tableName: string, table: StorageTable, alias: string, ctx: BuilderContext) {
|
|
59
|
+
super(ctx);
|
|
60
|
+
this.#tableName = tableName;
|
|
61
|
+
this.#table = table;
|
|
62
|
+
this.#scope = tableToScope(alias, table);
|
|
63
|
+
this.#fromSource = TableSource.named(tableName, alias !== tableName ? alias : undefined);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
lateralJoin = this._gate(
|
|
67
|
+
{ sql: { lateral: true } },
|
|
68
|
+
'lateralJoin',
|
|
69
|
+
<LAlias extends string, LateralRow extends Record<string, ScopeField>>(
|
|
70
|
+
alias: LAlias,
|
|
71
|
+
builder: (lateral: LateralBuilder<QC, AvailableScope>) => Subquery<LateralRow>,
|
|
72
|
+
): JoinedTables<
|
|
73
|
+
QC,
|
|
74
|
+
MergeScopes<AvailableScope, { topLevel: LateralRow; namespaces: Record<LAlias, LateralRow> }>
|
|
75
|
+
> => {
|
|
76
|
+
return this.#toJoined().lateralJoin(alias, builder);
|
|
77
|
+
},
|
|
78
|
+
) as TableProxy<C, Name, Alias, AvailableScope, QC>['lateralJoin'];
|
|
79
|
+
|
|
80
|
+
outerLateralJoin = this._gate(
|
|
81
|
+
{ sql: { lateral: true } },
|
|
82
|
+
'outerLateralJoin',
|
|
83
|
+
<LAlias extends string, LateralRow extends Record<string, ScopeField>>(
|
|
84
|
+
alias: LAlias,
|
|
85
|
+
builder: (lateral: LateralBuilder<QC, AvailableScope>) => Subquery<LateralRow>,
|
|
86
|
+
): JoinedTables<
|
|
87
|
+
QC,
|
|
88
|
+
MergeScopes<
|
|
89
|
+
AvailableScope,
|
|
90
|
+
NullableScope<{ topLevel: LateralRow; namespaces: Record<LAlias, LateralRow> }>
|
|
91
|
+
>
|
|
92
|
+
> => {
|
|
93
|
+
return this.#toJoined().outerLateralJoin(alias, builder);
|
|
94
|
+
},
|
|
95
|
+
) as TableProxy<C, Name, Alias, AvailableScope, QC>['outerLateralJoin'];
|
|
96
|
+
|
|
97
|
+
getJoinOuterScope(): Scope {
|
|
98
|
+
return this.#scope;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
buildAst(): AnyFromSource {
|
|
102
|
+
return this.#fromSource;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
as<NewAlias extends string>(
|
|
106
|
+
newAlias: NewAlias,
|
|
107
|
+
): TableProxy<C, Name, NewAlias, RebindScope<AvailableScope, Alias, NewAlias>> {
|
|
108
|
+
return new TableProxyImpl(this.#tableName, this.#table, newAlias, this.ctx);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
select<Columns extends (keyof AvailableScope['topLevel'] & string)[]>(
|
|
112
|
+
...columns: Columns
|
|
113
|
+
): SelectQuery<QC, AvailableScope, WithFields<EmptyRow, AvailableScope['topLevel'], Columns>>;
|
|
114
|
+
select<LAlias extends string, Field extends ScopeField>(
|
|
115
|
+
alias: LAlias,
|
|
116
|
+
expr: (fields: FieldProxy<AvailableScope>, fns: AggregateFunctions<QC>) => Expression<Field>,
|
|
117
|
+
): SelectQuery<QC, AvailableScope, WithField<EmptyRow, Field, LAlias>>;
|
|
118
|
+
select<Result extends Record<string, Expression<ScopeField>>>(
|
|
119
|
+
callback: (fields: FieldProxy<AvailableScope>, fns: AggregateFunctions<QC>) => Result,
|
|
120
|
+
): SelectQuery<QC, AvailableScope, Expand<ExtractScopeFields<Result>>>;
|
|
121
|
+
select(...args: unknown[]): unknown {
|
|
122
|
+
return new SelectQueryImpl(emptyState(this.#fromSource, this.#scope), this.ctx).select(
|
|
123
|
+
...(args as string[]),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
innerJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
128
|
+
other: Other,
|
|
129
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
130
|
+
): JoinedTables<QC, MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>> {
|
|
131
|
+
return this.#toJoined().innerJoin(other, on);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
outerLeftJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
135
|
+
other: Other,
|
|
136
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
137
|
+
): JoinedTables<QC, MergeScopes<AvailableScope, NullableScope<Other[typeof JoinOuterScope]>>> {
|
|
138
|
+
return this.#toJoined().outerLeftJoin(other, on);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
outerRightJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
142
|
+
other: Other,
|
|
143
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
144
|
+
): JoinedTables<QC, MergeScopes<NullableScope<AvailableScope>, Other[typeof JoinOuterScope]>> {
|
|
145
|
+
return this.#toJoined().outerRightJoin(other, on);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
outerFullJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
149
|
+
other: Other,
|
|
150
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
151
|
+
): JoinedTables<
|
|
152
|
+
QC,
|
|
153
|
+
MergeScopes<NullableScope<AvailableScope>, NullableScope<Other[typeof JoinOuterScope]>>
|
|
154
|
+
> {
|
|
155
|
+
return this.#toJoined().outerFullJoin(other, on);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
insert(values: Record<string, unknown>): InsertQuery<QC, AvailableScope, EmptyRow> {
|
|
159
|
+
return new InsertQueryImpl(this.#tableName, this.#table, this.#scope, values, this.ctx);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
update(set: Record<string, unknown>): UpdateQuery<QC, AvailableScope, EmptyRow> {
|
|
163
|
+
return new UpdateQueryImpl(this.#tableName, this.#table, this.#scope, set, this.ctx);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
delete(): DeleteQuery<QC, AvailableScope, EmptyRow> {
|
|
167
|
+
return new DeleteQueryImpl(this.#tableName, this.#scope, this.ctx);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#toJoined(): JoinedTables<QC, AvailableScope> {
|
|
171
|
+
return new JoinedTablesImpl(emptyState(this.#fromSource, this.#scope), this.ctx);
|
|
172
|
+
}
|
|
173
|
+
}
|
package/src/scope.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { QueryOperationTypesBase, StorageTable } from '@prisma-next/sql-contract/types';
|
|
2
|
+
import type { AnyFromSource, SelectAst } from '@prisma-next/sql-relational-core/ast';
|
|
3
|
+
|
|
4
|
+
export type GatedMethod<Capabilities, Required, Method> = Capabilities extends Required
|
|
5
|
+
? Method
|
|
6
|
+
: never;
|
|
7
|
+
|
|
8
|
+
type CodecTypesBase = Record<string, { readonly input: unknown; readonly output: unknown }>;
|
|
9
|
+
export declare const ExpressionType: unique symbol;
|
|
10
|
+
export declare const JoinOuterScope: unique symbol;
|
|
11
|
+
export declare const SubqueryMarker: unique symbol;
|
|
12
|
+
|
|
13
|
+
export type Expand<T> = { [K in keyof T]: T[K] } & unknown;
|
|
14
|
+
export type EmptyRow = Record<never, ScopeField>;
|
|
15
|
+
|
|
16
|
+
export type ScopeField = { codecId: string; nullable: boolean };
|
|
17
|
+
export type ScopeTable = Record<string, ScopeField>;
|
|
18
|
+
|
|
19
|
+
export type Scope = {
|
|
20
|
+
topLevel: ScopeTable;
|
|
21
|
+
namespaces: Record<string, ScopeTable>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type JoinSource<Row extends ScopeTable, Alias extends string> = {
|
|
25
|
+
readonly [JoinOuterScope]: {
|
|
26
|
+
topLevel: Row;
|
|
27
|
+
namespaces: Record<Alias, Row>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
getJoinOuterScope(): Scope;
|
|
31
|
+
buildAst(): AnyFromSource;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type DefaultScope<Name extends string, Table extends StorageTable> = {
|
|
35
|
+
topLevel: StorageTableToScopeTable<Table>;
|
|
36
|
+
namespaces: {
|
|
37
|
+
[K in Name]: StorageTableToScopeTable<Table>;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type StorageTableToScopeTable<T extends StorageTable> = {
|
|
42
|
+
[K in keyof T['columns']]: {
|
|
43
|
+
codecId: T['columns'][K]['codecId'];
|
|
44
|
+
nullable: T['columns'][K]['nullable'];
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type MergeScopes<A extends Scope, B extends Scope> = {
|
|
49
|
+
topLevel: Expand<
|
|
50
|
+
Omit<A['topLevel'], keyof B['topLevel']> & Omit<B['topLevel'], keyof A['topLevel']>
|
|
51
|
+
>;
|
|
52
|
+
namespaces: Expand<A['namespaces'] & B['namespaces']>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type RebindScope<S extends Scope, OldKey extends string, NewKey extends string> = {
|
|
56
|
+
topLevel: S['topLevel'];
|
|
57
|
+
namespaces: Expand<Omit<S['namespaces'], OldKey> & Record<NewKey, S['namespaces'][OldKey]>>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type NullableScopeTable<S extends ScopeTable> = {
|
|
61
|
+
[K in keyof S]: { codecId: S[K]['codecId']; nullable: true };
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type NullableScope<S extends Scope> = {
|
|
65
|
+
topLevel: NullableScopeTable<S['topLevel']>;
|
|
66
|
+
namespaces: {
|
|
67
|
+
[TableName in keyof S['namespaces']]: NullableScopeTable<S['namespaces'][TableName]>;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type Subquery<RowType extends Record<string, ScopeField>> = {
|
|
72
|
+
[SubqueryMarker]: RowType;
|
|
73
|
+
buildAst(): SelectAst;
|
|
74
|
+
getRowFields(): Record<string, ScopeField>;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export type QueryContext = {
|
|
78
|
+
readonly codecTypes: CodecTypesBase;
|
|
79
|
+
readonly capabilities: Record<string, Record<string, boolean>>;
|
|
80
|
+
readonly queryOperationTypes: QueryOperationTypesBase;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type { CodecTypesBase, StorageTable };
|
package/src/types/db.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StorageTable } from '@prisma-next/sql-contract/types';
|
|
2
|
+
import type { TableProxy } from './table-proxy';
|
|
3
|
+
|
|
4
|
+
export type CapabilitiesBase = Record<string, Record<string, boolean>>;
|
|
5
|
+
|
|
6
|
+
export type TableProxyContract = {
|
|
7
|
+
readonly storage: { readonly tables: Record<string, StorageTable> };
|
|
8
|
+
readonly capabilities: CapabilitiesBase;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type Db<C extends TableProxyContract> = {
|
|
12
|
+
[Name in string & keyof C['storage']['tables']]: TableProxy<C, Name>;
|
|
13
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AggregateFunctions,
|
|
3
|
+
BooleanCodecType,
|
|
4
|
+
Expression,
|
|
5
|
+
FieldProxy,
|
|
6
|
+
Functions,
|
|
7
|
+
OrderByOptions,
|
|
8
|
+
OrderByScope,
|
|
9
|
+
} from '../expression';
|
|
10
|
+
import type { GatedMethod, QueryContext, Scope, ScopeField, Subquery } from '../scope';
|
|
11
|
+
import type { WithAlias, WithBuild, WithDistinct, WithPagination } from './shared';
|
|
12
|
+
|
|
13
|
+
export interface GroupedQuery<
|
|
14
|
+
QC extends QueryContext,
|
|
15
|
+
AvailableScope extends Scope,
|
|
16
|
+
RowType extends Record<string, ScopeField>,
|
|
17
|
+
> extends Subquery<RowType>,
|
|
18
|
+
WithPagination,
|
|
19
|
+
WithDistinct,
|
|
20
|
+
WithAlias<RowType>,
|
|
21
|
+
WithBuild<QC, RowType> {
|
|
22
|
+
groupBy(
|
|
23
|
+
...fields: ((keyof RowType | keyof AvailableScope['topLevel']) & string)[]
|
|
24
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
25
|
+
|
|
26
|
+
groupBy(
|
|
27
|
+
expr: (
|
|
28
|
+
fields: FieldProxy<OrderByScope<AvailableScope, RowType>>,
|
|
29
|
+
fns: Functions<QC>,
|
|
30
|
+
) => Expression<ScopeField>,
|
|
31
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
32
|
+
|
|
33
|
+
having(
|
|
34
|
+
expr: (
|
|
35
|
+
fields: FieldProxy<OrderByScope<AvailableScope, RowType>>,
|
|
36
|
+
fns: AggregateFunctions<QC>,
|
|
37
|
+
) => Expression<BooleanCodecType>,
|
|
38
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
39
|
+
|
|
40
|
+
orderBy(
|
|
41
|
+
field: (keyof RowType | keyof AvailableScope['topLevel']) & string,
|
|
42
|
+
options?: OrderByOptions,
|
|
43
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
44
|
+
|
|
45
|
+
orderBy(
|
|
46
|
+
expr: (
|
|
47
|
+
fields: FieldProxy<OrderByScope<AvailableScope, RowType>>,
|
|
48
|
+
fns: AggregateFunctions<QC>,
|
|
49
|
+
) => Expression<ScopeField>,
|
|
50
|
+
options?: OrderByOptions,
|
|
51
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
52
|
+
|
|
53
|
+
distinctOn: GatedMethod<
|
|
54
|
+
QC['capabilities'],
|
|
55
|
+
{ postgres: { distinctOn: true } },
|
|
56
|
+
{
|
|
57
|
+
(
|
|
58
|
+
...fields: ((keyof RowType | keyof AvailableScope['topLevel']) & string)[]
|
|
59
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
60
|
+
(
|
|
61
|
+
expr: (
|
|
62
|
+
fields: FieldProxy<OrderByScope<AvailableScope, RowType>>,
|
|
63
|
+
fns: Functions<QC>,
|
|
64
|
+
) => Expression<ScopeField>,
|
|
65
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
66
|
+
}
|
|
67
|
+
>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EmptyRow, QueryContext, Scope } from '../scope';
|
|
2
|
+
import type { WithJoin, WithSelect } from './shared';
|
|
3
|
+
|
|
4
|
+
export interface JoinedTables<QC extends QueryContext, AvailableScope extends Scope>
|
|
5
|
+
extends WithSelect<QC, AvailableScope, EmptyRow>,
|
|
6
|
+
WithJoin<QC, AvailableScope, QC['capabilities']> {}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { StorageTable } from '@prisma-next/sql-contract/types';
|
|
2
|
+
import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
|
|
3
|
+
import type { ExpressionBuilder, WithFields } from '../expression';
|
|
4
|
+
import type { ResolveRow } from '../resolve';
|
|
5
|
+
import type { EmptyRow, GatedMethod, QueryContext, Scope, ScopeField } from '../scope';
|
|
6
|
+
|
|
7
|
+
export type ReturningCapability = { sql: { returning: true } };
|
|
8
|
+
|
|
9
|
+
// Map table columns to their codec input types
|
|
10
|
+
export type InsertValues<
|
|
11
|
+
Table extends StorageTable,
|
|
12
|
+
CT extends Record<string, { readonly input: unknown }>,
|
|
13
|
+
> = {
|
|
14
|
+
[K in keyof Table['columns']]?: Table['columns'][K]['codecId'] extends keyof CT
|
|
15
|
+
? CT[Table['columns'][K]['codecId']]['input']
|
|
16
|
+
: unknown;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type UpdateValues<
|
|
20
|
+
Table extends StorageTable,
|
|
21
|
+
CT extends Record<string, { readonly input: unknown }>,
|
|
22
|
+
> = {
|
|
23
|
+
[K in keyof Table['columns']]?: Table['columns'][K]['codecId'] extends keyof CT
|
|
24
|
+
? CT[Table['columns'][K]['codecId']]['input']
|
|
25
|
+
: unknown;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export interface InsertQuery<
|
|
29
|
+
QC extends QueryContext,
|
|
30
|
+
AvailableScope extends Scope,
|
|
31
|
+
RowType extends Record<string, ScopeField>,
|
|
32
|
+
> {
|
|
33
|
+
returning: GatedMethod<
|
|
34
|
+
QC['capabilities'],
|
|
35
|
+
ReturningCapability,
|
|
36
|
+
<Columns extends (keyof AvailableScope['topLevel'] & string)[]>(
|
|
37
|
+
...columns: Columns
|
|
38
|
+
) => InsertQuery<QC, AvailableScope, WithFields<EmptyRow, AvailableScope['topLevel'], Columns>>
|
|
39
|
+
>;
|
|
40
|
+
build(): SqlQueryPlan<ResolveRow<RowType, QC['codecTypes']>>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface UpdateQuery<
|
|
44
|
+
QC extends QueryContext,
|
|
45
|
+
AvailableScope extends Scope,
|
|
46
|
+
RowType extends Record<string, ScopeField>,
|
|
47
|
+
> {
|
|
48
|
+
where(expr: ExpressionBuilder<AvailableScope, QC>): UpdateQuery<QC, AvailableScope, RowType>;
|
|
49
|
+
returning: GatedMethod<
|
|
50
|
+
QC['capabilities'],
|
|
51
|
+
ReturningCapability,
|
|
52
|
+
<Columns extends (keyof AvailableScope['topLevel'] & string)[]>(
|
|
53
|
+
...columns: Columns
|
|
54
|
+
) => UpdateQuery<QC, AvailableScope, WithFields<EmptyRow, AvailableScope['topLevel'], Columns>>
|
|
55
|
+
>;
|
|
56
|
+
build(): SqlQueryPlan<ResolveRow<RowType, QC['codecTypes']>>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface DeleteQuery<
|
|
60
|
+
QC extends QueryContext,
|
|
61
|
+
AvailableScope extends Scope,
|
|
62
|
+
RowType extends Record<string, ScopeField>,
|
|
63
|
+
> {
|
|
64
|
+
where(expr: ExpressionBuilder<AvailableScope, QC>): DeleteQuery<QC, AvailableScope, RowType>;
|
|
65
|
+
returning: GatedMethod<
|
|
66
|
+
QC['capabilities'],
|
|
67
|
+
ReturningCapability,
|
|
68
|
+
<Columns extends (keyof AvailableScope['topLevel'] & string)[]>(
|
|
69
|
+
...columns: Columns
|
|
70
|
+
) => DeleteQuery<QC, AvailableScope, WithFields<EmptyRow, AvailableScope['topLevel'], Columns>>
|
|
71
|
+
>;
|
|
72
|
+
build(): SqlQueryPlan<ResolveRow<RowType, QC['codecTypes']>>;
|
|
73
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Expression,
|
|
3
|
+
ExpressionBuilder,
|
|
4
|
+
FieldProxy,
|
|
5
|
+
Functions,
|
|
6
|
+
OrderByOptions,
|
|
7
|
+
OrderByScope,
|
|
8
|
+
} from '../expression';
|
|
9
|
+
import type { GatedMethod, QueryContext, Scope, ScopeField, Subquery } from '../scope';
|
|
10
|
+
import type { GroupedQuery } from './grouped-query';
|
|
11
|
+
import type { WithAlias, WithBuild, WithDistinct, WithPagination, WithSelect } from './shared';
|
|
12
|
+
|
|
13
|
+
export interface SelectQuery<
|
|
14
|
+
QC extends QueryContext,
|
|
15
|
+
AvailableScope extends Scope,
|
|
16
|
+
RowType extends Record<string, ScopeField>,
|
|
17
|
+
> extends Subquery<RowType>,
|
|
18
|
+
WithSelect<QC, AvailableScope, RowType>,
|
|
19
|
+
WithPagination,
|
|
20
|
+
WithDistinct,
|
|
21
|
+
WithAlias<RowType>,
|
|
22
|
+
WithBuild<QC, RowType> {
|
|
23
|
+
where(expr: ExpressionBuilder<AvailableScope, QC>): SelectQuery<QC, AvailableScope, RowType>;
|
|
24
|
+
|
|
25
|
+
orderBy(
|
|
26
|
+
field: (keyof RowType | keyof AvailableScope['topLevel']) & string,
|
|
27
|
+
options?: OrderByOptions,
|
|
28
|
+
): SelectQuery<QC, AvailableScope, RowType>;
|
|
29
|
+
|
|
30
|
+
orderBy(
|
|
31
|
+
expr: (
|
|
32
|
+
fields: FieldProxy<OrderByScope<AvailableScope, RowType>>,
|
|
33
|
+
fns: Functions<QC>,
|
|
34
|
+
) => Expression<ScopeField>,
|
|
35
|
+
options?: OrderByOptions,
|
|
36
|
+
): SelectQuery<QC, AvailableScope, RowType>;
|
|
37
|
+
|
|
38
|
+
groupBy(
|
|
39
|
+
...fields: ((keyof RowType | keyof AvailableScope['topLevel']) & string)[]
|
|
40
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
41
|
+
|
|
42
|
+
groupBy(
|
|
43
|
+
expr: (
|
|
44
|
+
fields: FieldProxy<OrderByScope<AvailableScope, RowType>>,
|
|
45
|
+
fns: Functions<QC>,
|
|
46
|
+
) => Expression<ScopeField>,
|
|
47
|
+
): GroupedQuery<QC, AvailableScope, RowType>;
|
|
48
|
+
|
|
49
|
+
distinctOn: GatedMethod<
|
|
50
|
+
QC['capabilities'],
|
|
51
|
+
{ postgres: { distinctOn: true } },
|
|
52
|
+
{
|
|
53
|
+
(
|
|
54
|
+
...fields: ((keyof RowType | keyof AvailableScope['topLevel']) & string)[]
|
|
55
|
+
): SelectQuery<QC, AvailableScope, RowType>;
|
|
56
|
+
(
|
|
57
|
+
expr: (
|
|
58
|
+
fields: FieldProxy<OrderByScope<AvailableScope, RowType>>,
|
|
59
|
+
fns: Functions<QC>,
|
|
60
|
+
) => Expression<ScopeField>,
|
|
61
|
+
): SelectQuery<QC, AvailableScope, RowType>;
|
|
62
|
+
}
|
|
63
|
+
>;
|
|
64
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
|
|
2
|
+
import type {
|
|
3
|
+
AggregateFunctions,
|
|
4
|
+
Expression,
|
|
5
|
+
ExpressionBuilder,
|
|
6
|
+
ExtractScopeFields,
|
|
7
|
+
FieldProxy,
|
|
8
|
+
WithField,
|
|
9
|
+
WithFields,
|
|
10
|
+
} from '../expression';
|
|
11
|
+
import type { ResolveRow } from '../resolve';
|
|
12
|
+
import type {
|
|
13
|
+
EmptyRow,
|
|
14
|
+
Expand,
|
|
15
|
+
GatedMethod,
|
|
16
|
+
JoinOuterScope,
|
|
17
|
+
JoinSource,
|
|
18
|
+
MergeScopes,
|
|
19
|
+
NullableScope,
|
|
20
|
+
QueryContext,
|
|
21
|
+
Scope,
|
|
22
|
+
ScopeField,
|
|
23
|
+
ScopeTable,
|
|
24
|
+
Subquery,
|
|
25
|
+
} from '../scope';
|
|
26
|
+
import type { JoinedTables } from './joined-tables';
|
|
27
|
+
import type { SelectQuery } from './select-query';
|
|
28
|
+
|
|
29
|
+
export interface LateralBuilder<QC extends QueryContext, ParentScope extends Scope> {
|
|
30
|
+
from<Other extends JoinSource<ScopeTable, string | never>>(
|
|
31
|
+
other: Other,
|
|
32
|
+
): SelectQuery<QC, MergeScopes<ParentScope, Other[typeof JoinOuterScope]>, EmptyRow>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface WithSelect<
|
|
36
|
+
QC extends QueryContext,
|
|
37
|
+
AvailableScope extends Scope,
|
|
38
|
+
RowType extends Record<string, ScopeField> = EmptyRow,
|
|
39
|
+
> {
|
|
40
|
+
select<Columns extends (keyof AvailableScope['topLevel'] & string)[]>(
|
|
41
|
+
...columns: Columns
|
|
42
|
+
): SelectQuery<QC, AvailableScope, WithFields<RowType, AvailableScope['topLevel'], Columns>>;
|
|
43
|
+
|
|
44
|
+
select<Alias extends string, Field extends ScopeField>(
|
|
45
|
+
alias: Alias,
|
|
46
|
+
expr: (fields: FieldProxy<AvailableScope>, fns: AggregateFunctions<QC>) => Expression<Field>,
|
|
47
|
+
): SelectQuery<QC, AvailableScope, WithField<RowType, Field, Alias>>;
|
|
48
|
+
|
|
49
|
+
select<Result extends Record<string, Expression<ScopeField>>>(
|
|
50
|
+
callback: (fields: FieldProxy<AvailableScope>, fns: AggregateFunctions<QC>) => Result,
|
|
51
|
+
): SelectQuery<QC, AvailableScope, Expand<RowType & ExtractScopeFields<Result>>>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface WithJoin<QC extends QueryContext, AvailableScope extends Scope, Capabilities> {
|
|
55
|
+
innerJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
56
|
+
other: Other,
|
|
57
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
58
|
+
): JoinedTables<QC, MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>>;
|
|
59
|
+
|
|
60
|
+
outerLeftJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
61
|
+
other: Other,
|
|
62
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
63
|
+
): JoinedTables<QC, MergeScopes<AvailableScope, NullableScope<Other[typeof JoinOuterScope]>>>;
|
|
64
|
+
|
|
65
|
+
outerRightJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
66
|
+
other: Other,
|
|
67
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
68
|
+
): JoinedTables<QC, MergeScopes<NullableScope<AvailableScope>, Other[typeof JoinOuterScope]>>;
|
|
69
|
+
|
|
70
|
+
outerFullJoin<Other extends JoinSource<ScopeTable, string | never>>(
|
|
71
|
+
other: Other,
|
|
72
|
+
on: ExpressionBuilder<MergeScopes<AvailableScope, Other[typeof JoinOuterScope]>, QC>,
|
|
73
|
+
): JoinedTables<
|
|
74
|
+
QC,
|
|
75
|
+
MergeScopes<NullableScope<AvailableScope>, NullableScope<Other[typeof JoinOuterScope]>>
|
|
76
|
+
>;
|
|
77
|
+
|
|
78
|
+
lateralJoin: GatedMethod<
|
|
79
|
+
Capabilities,
|
|
80
|
+
{ sql: { lateral: true } },
|
|
81
|
+
<Alias extends string, LateralRow extends Record<string, ScopeField>>(
|
|
82
|
+
alias: Alias,
|
|
83
|
+
builder: (lateral: LateralBuilder<QC, AvailableScope>) => Subquery<LateralRow>,
|
|
84
|
+
) => JoinedTables<
|
|
85
|
+
QC,
|
|
86
|
+
MergeScopes<AvailableScope, { topLevel: LateralRow; namespaces: Record<Alias, LateralRow> }>
|
|
87
|
+
>
|
|
88
|
+
>;
|
|
89
|
+
|
|
90
|
+
outerLateralJoin: GatedMethod<
|
|
91
|
+
Capabilities,
|
|
92
|
+
{ sql: { lateral: true } },
|
|
93
|
+
<Alias extends string, LateralRow extends Record<string, ScopeField>>(
|
|
94
|
+
alias: Alias,
|
|
95
|
+
builder: (lateral: LateralBuilder<QC, AvailableScope>) => Subquery<LateralRow>,
|
|
96
|
+
) => JoinedTables<
|
|
97
|
+
QC,
|
|
98
|
+
MergeScopes<
|
|
99
|
+
AvailableScope,
|
|
100
|
+
NullableScope<{ topLevel: LateralRow; namespaces: Record<Alias, LateralRow> }>
|
|
101
|
+
>
|
|
102
|
+
>
|
|
103
|
+
>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface WithPagination {
|
|
107
|
+
limit(count: number): this;
|
|
108
|
+
offset(count: number): this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface WithDistinct {
|
|
112
|
+
distinct(): this;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface WithAlias<RowType extends Record<string, ScopeField>> {
|
|
116
|
+
as<Alias extends string>(newAlias: Alias): JoinSource<RowType, Alias>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface WithBuild<QC extends QueryContext, RowType extends Record<string, ScopeField>> {
|
|
120
|
+
build(): SqlQueryPlan<ResolveRow<RowType, QC['codecTypes']>>;
|
|
121
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtractCodecTypes,
|
|
3
|
+
ExtractQueryOperationTypes,
|
|
4
|
+
} from '@prisma-next/sql-contract/types';
|
|
5
|
+
import type {
|
|
6
|
+
DefaultScope,
|
|
7
|
+
EmptyRow,
|
|
8
|
+
JoinSource,
|
|
9
|
+
QueryContext,
|
|
10
|
+
RebindScope,
|
|
11
|
+
Scope,
|
|
12
|
+
StorageTableToScopeTable,
|
|
13
|
+
} from '../scope';
|
|
14
|
+
import type { TableProxyContract } from './db';
|
|
15
|
+
import type {
|
|
16
|
+
DeleteQuery,
|
|
17
|
+
InsertQuery,
|
|
18
|
+
InsertValues,
|
|
19
|
+
UpdateQuery,
|
|
20
|
+
UpdateValues,
|
|
21
|
+
} from './mutation-query';
|
|
22
|
+
import type { WithJoin, WithSelect } from './shared';
|
|
23
|
+
|
|
24
|
+
type ContractToQC<C extends TableProxyContract> = {
|
|
25
|
+
readonly codecTypes: ExtractCodecTypes<C>;
|
|
26
|
+
readonly capabilities: C['capabilities'];
|
|
27
|
+
readonly queryOperationTypes: ExtractQueryOperationTypes<C>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export interface TableProxy<
|
|
31
|
+
C extends TableProxyContract,
|
|
32
|
+
Name extends string & keyof C['storage']['tables'],
|
|
33
|
+
Alias extends string = Name,
|
|
34
|
+
AvailableScope extends Scope = DefaultScope<Name, C['storage']['tables'][Name]>,
|
|
35
|
+
QC extends QueryContext = ContractToQC<C>,
|
|
36
|
+
> extends JoinSource<StorageTableToScopeTable<C['storage']['tables'][Name]>, Alias>,
|
|
37
|
+
WithSelect<QC, AvailableScope, EmptyRow>,
|
|
38
|
+
WithJoin<QC, AvailableScope, C['capabilities']> {
|
|
39
|
+
as<NewAlias extends string>(
|
|
40
|
+
newAlias: NewAlias,
|
|
41
|
+
): TableProxy<C, Name, NewAlias, RebindScope<AvailableScope, Alias, NewAlias>>;
|
|
42
|
+
|
|
43
|
+
insert(
|
|
44
|
+
values: InsertValues<C['storage']['tables'][Name], QC['codecTypes']>,
|
|
45
|
+
): InsertQuery<QC, AvailableScope, EmptyRow>;
|
|
46
|
+
|
|
47
|
+
update(
|
|
48
|
+
set: UpdateValues<C['storage']['tables'][Name], QC['codecTypes']>,
|
|
49
|
+
): UpdateQuery<QC, AvailableScope, EmptyRow>;
|
|
50
|
+
|
|
51
|
+
delete(): DeleteQuery<QC, AvailableScope, EmptyRow>;
|
|
52
|
+
}
|