@prisma-next/sql-relational-core 0.12.0 → 0.13.0-dev.2
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/dist/{codec-types-Cezo7k-i.d.mts → codec-types-DFLA6Hmj.d.mts} +6 -4
- package/dist/codec-types-DFLA6Hmj.d.mts.map +1 -0
- package/dist/ddl-types-D3vlEjMA.d.mts +126 -0
- package/dist/ddl-types-D3vlEjMA.d.mts.map +1 -0
- package/dist/ddl-types-X9_XHUl0.mjs +130 -0
- package/dist/ddl-types-X9_XHUl0.mjs.map +1 -0
- package/dist/{errors-BF7W5uUd.mjs → errors-BwyJxXME.mjs} +1 -1
- package/dist/{errors-BF7W5uUd.mjs.map → errors-BwyJxXME.mjs.map} +1 -1
- package/dist/{errors-Bavu5wZA.d.mts → errors-CPLfzKkw.d.mts} +2 -2
- package/dist/{errors-Bavu5wZA.d.mts.map → errors-CPLfzKkw.d.mts.map} +1 -1
- package/dist/exports/ast.d.mts +11 -15
- package/dist/exports/ast.d.mts.map +1 -1
- package/dist/exports/ast.mjs +4 -3
- package/dist/exports/ast.mjs.map +1 -1
- package/dist/exports/codec-descriptor-registry.d.mts +8 -4
- package/dist/exports/codec-descriptor-registry.d.mts.map +1 -1
- package/dist/exports/codec-descriptor-registry.mjs +24 -26
- package/dist/exports/codec-descriptor-registry.mjs.map +1 -1
- package/dist/exports/contract-free.d.mts +161 -0
- package/dist/exports/contract-free.d.mts.map +1 -0
- package/dist/exports/contract-free.mjs +268 -0
- package/dist/exports/contract-free.mjs.map +1 -0
- package/dist/exports/errors.d.mts +1 -1
- package/dist/exports/errors.mjs +1 -1
- package/dist/exports/expression.d.mts +2 -2
- package/dist/exports/expression.d.mts.map +1 -1
- package/dist/exports/expression.mjs +1 -1
- package/dist/exports/middleware.d.mts +2 -2
- package/dist/exports/middleware.mjs +1 -1
- package/dist/exports/plan.d.mts +2 -2
- package/dist/exports/query-lane-context.d.mts +1 -1
- package/dist/exports/types.d.mts +3 -3
- package/dist/index.d.mts +12 -11
- package/dist/index.mjs +6 -5
- package/dist/{middleware-EOcO8Ogo.d.mts → middleware-BXSFukKU.d.mts} +2 -2
- package/dist/{middleware-EOcO8Ogo.d.mts.map → middleware-BXSFukKU.d.mts.map} +1 -1
- package/dist/{middleware-B0yz0pff.mjs → middleware-CMr4CHNz.mjs} +2 -2
- package/dist/{middleware-B0yz0pff.mjs.map → middleware-CMr4CHNz.mjs.map} +1 -1
- package/dist/{plan-CG3sy5kw.d.mts → plan-DObuWSWi.d.mts} +3 -3
- package/dist/plan-DObuWSWi.d.mts.map +1 -0
- package/dist/{query-lane-context-Dw1Tz0kv.d.mts → query-lane-context-CY0-e8Qo.d.mts} +8 -6
- package/dist/query-lane-context-CY0-e8Qo.d.mts.map +1 -0
- package/dist/{sql-execution-plan-D4OimCVH.d.mts → sql-execution-plan-JwVeAzXt.d.mts} +2 -2
- package/dist/{sql-execution-plan-D4OimCVH.d.mts.map → sql-execution-plan-JwVeAzXt.d.mts.map} +1 -1
- package/dist/{types-C_1ZqLwZ.d.mts → types-BbGUx5Bi.d.mts} +19 -6
- package/dist/types-BbGUx5Bi.d.mts.map +1 -0
- package/dist/{types-DoolOzqd.d.mts → types-CQVke4QO.d.mts} +8 -20
- package/dist/types-CQVke4QO.d.mts.map +1 -0
- package/dist/{types-C4EdOD-s.mjs → types-D72v8s92.mjs} +24 -5
- package/dist/types-D72v8s92.mjs.map +1 -0
- package/dist/{types-CkTDkFcK.d.mts → types-LGikJRYV.d.mts} +3 -3
- package/dist/{types-CkTDkFcK.d.mts.map → types-LGikJRYV.d.mts.map} +1 -1
- package/dist/{util-DWmhUCEO.mjs → util-DQQgv2j1.mjs} +1 -1
- package/dist/{util-DWmhUCEO.mjs.map → util-DQQgv2j1.mjs.map} +1 -1
- package/package.json +14 -13
- package/src/ast/adapter-types.ts +0 -5
- package/src/ast/codec-types.ts +5 -3
- package/src/ast/ddl-types.ts +198 -0
- package/src/ast/types.ts +31 -6
- package/src/codec-descriptor-registry.ts +2 -2
- package/src/codec-ref-for-column.ts +26 -20
- package/src/contract-free/column.ts +56 -0
- package/src/contract-free/dml.ts +17 -0
- package/src/contract-free/table.ts +390 -0
- package/src/exports/ast.ts +1 -0
- package/src/exports/contract-free.ts +26 -0
- package/src/query-lane-context.ts +5 -3
- package/src/types.ts +3 -23
- package/dist/codec-types-Cezo7k-i.d.mts.map +0 -1
- package/dist/plan-CG3sy5kw.d.mts.map +0 -1
- package/dist/query-lane-context-Dw1Tz0kv.d.mts.map +0 -1
- package/dist/types-C4EdOD-s.mjs.map +0 -1
- package/dist/types-C_1ZqLwZ.d.mts.map +0 -1
- package/dist/types-DoolOzqd.d.mts.map +0 -1
|
@@ -1,50 +1,47 @@
|
|
|
1
1
|
import type { JsonValue } from '@prisma-next/contract/types';
|
|
2
2
|
import type { CodecRef } from '@prisma-next/framework-components/codec';
|
|
3
|
+
import { resolveStorageTable } from '@prisma-next/sql-contract/resolve-storage-table';
|
|
3
4
|
import {
|
|
4
5
|
isPostgresEnumStorageEntry,
|
|
5
6
|
isStorageTypeInstance,
|
|
6
7
|
type SqlStorage,
|
|
7
|
-
type StorageTable,
|
|
8
8
|
} from '@prisma-next/sql-contract/types';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Derive the canonical {@link CodecRef} for a `(table, column)` pair against a {@link SqlStorage}. This is the build-time path every column-bound `ParamRef` / `ProjectionItem` uses to stamp its `codec` slot before the AST is handed to the runtime — the runtime resolver then materialises a memoised {@link import('@prisma-next/sql-relational-core/ast').Codec} for the same `CodecRef` via `forCodecRef`.
|
|
12
12
|
*
|
|
13
|
-
* Resolution rules over `
|
|
13
|
+
* Resolution rules over namespace `entries.table[table].columns[column]`:
|
|
14
14
|
*
|
|
15
15
|
* - `typeRef` column → `{codecId, typeParams}` from `storage.types[typeRef]` (multiple columns sharing the typeRef share one ref → one memoised codec).
|
|
16
16
|
* - inline `typeParams` column → `{codecId, typeParams}` from the column itself.
|
|
17
17
|
* - non-parameterized column → `{codecId}` with `typeParams` undefined.
|
|
18
18
|
*
|
|
19
19
|
* Returns `undefined` when the table or column is unknown, or when a `typeRef` column references a `storage.types` entry that does not exist.
|
|
20
|
+
*
|
|
21
|
+
* `namespaceId` leads the coordinate args and is always supplied: every
|
|
22
|
+
* model/table sits in an explicit namespace, so the table is resolved strictly
|
|
23
|
+
* within that namespace (see {@link resolveStorageTable}).
|
|
20
24
|
*/
|
|
21
25
|
export function codecRefForStorageColumn(
|
|
22
26
|
storage: SqlStorage,
|
|
27
|
+
namespaceId: string,
|
|
23
28
|
tableName: string,
|
|
24
29
|
columnName: string,
|
|
25
30
|
): CodecRef | undefined {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (candidate !== undefined) {
|
|
30
|
-
tableDef = candidate;
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (!tableDef) return undefined;
|
|
31
|
+
const resolved = resolveStorageTable(storage, tableName, namespaceId);
|
|
32
|
+
if (resolved === undefined) return undefined;
|
|
33
|
+
const tableDef = resolved.table;
|
|
35
34
|
const columnDef = tableDef.columns[columnName];
|
|
36
35
|
if (!columnDef) return undefined;
|
|
37
36
|
if (columnDef.typeRef !== undefined) {
|
|
38
37
|
let instance: unknown = storage.types?.[columnDef.typeRef];
|
|
39
38
|
if (!instance) {
|
|
40
39
|
for (const ns of Object.values(storage.namespaces)) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
40
|
+
const typeSlot = (ns.entries as { type?: Record<string, unknown> }).type;
|
|
41
|
+
const nsEntry = typeSlot?.[columnDef.typeRef];
|
|
42
|
+
if (nsEntry !== undefined) {
|
|
43
|
+
instance = nsEntry;
|
|
44
|
+
break;
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
}
|
|
@@ -64,11 +61,20 @@ export function codecRefForStorageColumn(
|
|
|
64
61
|
};
|
|
65
62
|
}
|
|
66
63
|
if (isStorageTypeInstance(instance)) {
|
|
67
|
-
|
|
64
|
+
// Empty-state canonicalization: a `StorageTypeInstance` with absent
|
|
65
|
+
// (or empty) `typeParams` produces a `CodecRef` with no `typeParams`
|
|
66
|
+
// field. Equivalent to the non-parameterized-column branch below.
|
|
67
|
+
// Carrying `{}` here would break content-keyed memoisation and trip
|
|
68
|
+
// the runtime validator against non-parameterized codec descriptors.
|
|
69
|
+
const instanceParams = instance.typeParams;
|
|
70
|
+
const hasParamKeys = instanceParams !== undefined && Object.keys(instanceParams).length > 0;
|
|
71
|
+
return hasParamKeys
|
|
72
|
+
? { codecId: instance.codecId, typeParams: instanceParams as JsonValue }
|
|
73
|
+
: { codecId: instance.codecId };
|
|
68
74
|
}
|
|
69
75
|
return undefined;
|
|
70
76
|
}
|
|
71
|
-
if (columnDef.typeParams !== undefined) {
|
|
77
|
+
if (columnDef.typeParams !== undefined && Object.keys(columnDef.typeParams).length > 0) {
|
|
72
78
|
return { codecId: columnDef.codecId, typeParams: columnDef.typeParams as JsonValue };
|
|
73
79
|
}
|
|
74
80
|
return { codecId: columnDef.codecId };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ColumnDefaultLiteralInputValue } from '@prisma-next/contract/types';
|
|
2
|
+
import type { ReferentialAction } from '@prisma-next/sql-contract/types';
|
|
3
|
+
import type { AnyDdlColumnDefault } from '../ast/ddl-types';
|
|
4
|
+
import {
|
|
5
|
+
DdlColumn,
|
|
6
|
+
ForeignKeyConstraint,
|
|
7
|
+
FunctionColumnDefault,
|
|
8
|
+
LiteralColumnDefault,
|
|
9
|
+
PrimaryKeyConstraint,
|
|
10
|
+
UniqueConstraint,
|
|
11
|
+
} from '../ast/ddl-types';
|
|
12
|
+
|
|
13
|
+
export interface DdlColumnOptions {
|
|
14
|
+
readonly notNull?: boolean;
|
|
15
|
+
readonly primaryKey?: boolean;
|
|
16
|
+
readonly default?: AnyDdlColumnDefault;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function lit(value: ColumnDefaultLiteralInputValue): LiteralColumnDefault {
|
|
20
|
+
return new LiteralColumnDefault(value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function fn(expression: string): FunctionColumnDefault {
|
|
24
|
+
return new FunctionColumnDefault(expression);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function col(name: string, type: string, options?: DdlColumnOptions): DdlColumn {
|
|
28
|
+
return new DdlColumn({ name, type, ...options });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function primaryKey(
|
|
32
|
+
columns: readonly string[],
|
|
33
|
+
options?: { readonly name?: string },
|
|
34
|
+
): PrimaryKeyConstraint {
|
|
35
|
+
return new PrimaryKeyConstraint({ columns, ...options });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function foreignKey(
|
|
39
|
+
columns: readonly string[],
|
|
40
|
+
refTable: string,
|
|
41
|
+
refColumns: readonly string[],
|
|
42
|
+
options?: {
|
|
43
|
+
readonly name?: string;
|
|
44
|
+
readonly onDelete?: ReferentialAction;
|
|
45
|
+
readonly onUpdate?: ReferentialAction;
|
|
46
|
+
},
|
|
47
|
+
): ForeignKeyConstraint {
|
|
48
|
+
return new ForeignKeyConstraint({ columns, refTable, refColumns, ...options });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function unique(
|
|
52
|
+
columns: readonly string[],
|
|
53
|
+
options?: { readonly name?: string },
|
|
54
|
+
): UniqueConstraint {
|
|
55
|
+
return new UniqueConstraint({ columns, ...options });
|
|
56
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export {
|
|
2
|
+
CfConflictClause,
|
|
3
|
+
CfExpr,
|
|
4
|
+
CfInsertQuery,
|
|
5
|
+
CfSelectQuery,
|
|
6
|
+
CfUpdateQuery,
|
|
7
|
+
CfUpsertBuilder,
|
|
8
|
+
CfUpsertQuery,
|
|
9
|
+
type ColumnDescriptor,
|
|
10
|
+
type ColumnProxy,
|
|
11
|
+
type ColumnSchema,
|
|
12
|
+
type ExcludedProxy,
|
|
13
|
+
type TableHandle,
|
|
14
|
+
type TableInsertRow,
|
|
15
|
+
type TableSetValues,
|
|
16
|
+
table,
|
|
17
|
+
} from './table';
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
2
|
+
import {
|
|
3
|
+
AndExpr,
|
|
4
|
+
type AnyExpression,
|
|
5
|
+
BinaryExpr,
|
|
6
|
+
ColumnRef,
|
|
7
|
+
InsertAst,
|
|
8
|
+
InsertOnConflict,
|
|
9
|
+
type InsertValue,
|
|
10
|
+
NullCheckExpr,
|
|
11
|
+
OrderByItem,
|
|
12
|
+
OrExpr,
|
|
13
|
+
ParamRef,
|
|
14
|
+
ProjectionItem,
|
|
15
|
+
SelectAst,
|
|
16
|
+
type TableSource,
|
|
17
|
+
UpdateAst,
|
|
18
|
+
} from '../ast/types';
|
|
19
|
+
|
|
20
|
+
export interface ColumnDescriptor {
|
|
21
|
+
readonly codecId: string;
|
|
22
|
+
readonly nullable: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type ColumnSchema = Record<string, ColumnDescriptor>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A composable WHERE / ON expression. Wraps an `AnyExpression` and exposes
|
|
29
|
+
* fluent boolean combinators, mirroring the spirit of `sql-builder`'s
|
|
30
|
+
* `Expression` interface without the contract-bound type machinery.
|
|
31
|
+
*/
|
|
32
|
+
export class CfExpr {
|
|
33
|
+
constructor(readonly ast: AnyExpression) {}
|
|
34
|
+
|
|
35
|
+
and(other: CfExpr): CfExpr {
|
|
36
|
+
return new CfExpr(AndExpr.of([this.ast, other.ast]));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
or(other: CfExpr): CfExpr {
|
|
40
|
+
return new CfExpr(OrExpr.of([this.ast, other.ast]));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
not(): CfExpr {
|
|
44
|
+
return new CfExpr(this.ast.not());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Per-column authoring handle exposed as a keyed property on a {@link TableHandle}.
|
|
50
|
+
* Carries codec metadata baked at declaration time so no codec ID, table name, or
|
|
51
|
+
* column name needs to be repeated at the call site.
|
|
52
|
+
*/
|
|
53
|
+
export interface ColumnProxy {
|
|
54
|
+
readonly codecId: string;
|
|
55
|
+
readonly nullable: boolean;
|
|
56
|
+
readonly columnName: string;
|
|
57
|
+
readonly tableName: string;
|
|
58
|
+
eq(value: unknown): CfExpr;
|
|
59
|
+
neq(value: unknown): CfExpr;
|
|
60
|
+
isNull(): CfExpr;
|
|
61
|
+
isNotNull(): CfExpr;
|
|
62
|
+
toRef(): ColumnRef;
|
|
63
|
+
toProjectionItem(alias?: string): ProjectionItem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Object passed to the {@link CfConflictClause.doUpdate} callback. Each key
|
|
68
|
+
* resolves to a `ColumnRef` for the corresponding `excluded.<column>`, so the
|
|
69
|
+
* upsert conflict-update branch can copy proposed values without re-binding
|
|
70
|
+
* parameters.
|
|
71
|
+
*/
|
|
72
|
+
export type ExcludedProxy<Schema extends ColumnSchema> = {
|
|
73
|
+
readonly [K in keyof Schema]: ColumnRef;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type TableInsertRow<Schema extends ColumnSchema> = {
|
|
77
|
+
readonly [K in keyof Schema]: unknown;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type TableSetValues<Schema extends ColumnSchema> = {
|
|
81
|
+
readonly [K in keyof Schema]?: unknown;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Fluent authoring handle for a fixed control-plane table. Column proxies are
|
|
86
|
+
* exposed as keyed properties so `handle.columnName.eq(value)` composes without
|
|
87
|
+
* threading codec IDs, table names, or column refs at the call site.
|
|
88
|
+
*/
|
|
89
|
+
export type TableHandle<Schema extends ColumnSchema> = {
|
|
90
|
+
readonly source: TableSource;
|
|
91
|
+
insert(row: TableInsertRow<Schema>): CfInsertQuery<Schema>;
|
|
92
|
+
upsert(row: TableInsertRow<Schema>): CfUpsertBuilder<Schema>;
|
|
93
|
+
update(): CfUpdateQuery<Schema>;
|
|
94
|
+
select(...columns: ReadonlyArray<ColumnProxy>): CfSelectQuery;
|
|
95
|
+
} & {
|
|
96
|
+
readonly [K in keyof Schema]: ColumnProxy;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export class CfInsertQuery<Schema extends ColumnSchema> {
|
|
100
|
+
constructor(
|
|
101
|
+
private readonly src: TableSource,
|
|
102
|
+
private readonly schema: Schema,
|
|
103
|
+
private readonly rowValues: TableInsertRow<Schema>,
|
|
104
|
+
private readonly returningItems: ReadonlyArray<ProjectionItem> | undefined = undefined,
|
|
105
|
+
) {}
|
|
106
|
+
|
|
107
|
+
returning(...columns: ReadonlyArray<ColumnProxy>): CfInsertQuery<Schema> {
|
|
108
|
+
return new CfInsertQuery(
|
|
109
|
+
this.src,
|
|
110
|
+
this.schema,
|
|
111
|
+
this.rowValues,
|
|
112
|
+
columns.map((col) => col.toProjectionItem()),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
build(): InsertAst {
|
|
117
|
+
const row = buildInsertRow(this.schema, this.rowValues);
|
|
118
|
+
const ast = InsertAst.into(this.src).withRows([row]);
|
|
119
|
+
return this.returningItems ? ast.withReturning(this.returningItems) : ast;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export class CfUpsertBuilder<Schema extends ColumnSchema> {
|
|
124
|
+
constructor(
|
|
125
|
+
private readonly src: TableSource,
|
|
126
|
+
private readonly schema: Schema,
|
|
127
|
+
private readonly rowValues: TableInsertRow<Schema>,
|
|
128
|
+
) {}
|
|
129
|
+
|
|
130
|
+
onConflict(...columns: ReadonlyArray<ColumnProxy>): CfConflictClause<Schema> {
|
|
131
|
+
return new CfConflictClause(this.src, this.schema, this.rowValues, [...columns]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export class CfConflictClause<Schema extends ColumnSchema> {
|
|
136
|
+
constructor(
|
|
137
|
+
private readonly src: TableSource,
|
|
138
|
+
private readonly schema: Schema,
|
|
139
|
+
private readonly rowValues: TableInsertRow<Schema>,
|
|
140
|
+
private readonly conflictCols: ReadonlyArray<ColumnProxy>,
|
|
141
|
+
) {}
|
|
142
|
+
|
|
143
|
+
doUpdate(
|
|
144
|
+
setOrCallback:
|
|
145
|
+
| TableSetValues<Schema>
|
|
146
|
+
| ((excluded: ExcludedProxy<Schema>) => TableSetValues<Schema>),
|
|
147
|
+
): CfUpsertQuery<Schema> {
|
|
148
|
+
const set =
|
|
149
|
+
typeof setOrCallback === 'function'
|
|
150
|
+
? setOrCallback(buildExcludedProxy(this.schema))
|
|
151
|
+
: setOrCallback;
|
|
152
|
+
return new CfUpsertQuery(this.src, this.schema, this.rowValues, this.conflictCols, set);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
doNothing(): CfUpsertQuery<Schema> {
|
|
156
|
+
return new CfUpsertQuery(this.src, this.schema, this.rowValues, this.conflictCols, undefined);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export class CfUpsertQuery<Schema extends ColumnSchema> {
|
|
161
|
+
constructor(
|
|
162
|
+
private readonly src: TableSource,
|
|
163
|
+
private readonly schema: Schema,
|
|
164
|
+
private readonly rowValues: TableInsertRow<Schema>,
|
|
165
|
+
private readonly conflictCols: ReadonlyArray<ColumnProxy>,
|
|
166
|
+
private readonly updateSet: TableSetValues<Schema> | undefined,
|
|
167
|
+
) {}
|
|
168
|
+
|
|
169
|
+
build(): InsertAst {
|
|
170
|
+
const row = buildInsertRow(this.schema, this.rowValues);
|
|
171
|
+
const conflictRefs = this.conflictCols.map((col) => col.toRef());
|
|
172
|
+
const onConflict =
|
|
173
|
+
this.updateSet === undefined
|
|
174
|
+
? InsertOnConflict.on(conflictRefs).doNothing()
|
|
175
|
+
: InsertOnConflict.on(conflictRefs).doUpdateSet(buildSetMap(this.schema, this.updateSet));
|
|
176
|
+
return InsertAst.into(this.src).withRows([row]).withOnConflict(onConflict);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export class CfUpdateQuery<Schema extends ColumnSchema> {
|
|
181
|
+
constructor(
|
|
182
|
+
private readonly src: TableSource,
|
|
183
|
+
private readonly schema: Schema,
|
|
184
|
+
private readonly setValues: TableSetValues<Schema> | undefined = undefined,
|
|
185
|
+
private readonly whereExpr: CfExpr | undefined = undefined,
|
|
186
|
+
private readonly returningItems: ReadonlyArray<ProjectionItem> | undefined = undefined,
|
|
187
|
+
) {}
|
|
188
|
+
|
|
189
|
+
set(values: TableSetValues<Schema>): CfUpdateQuery<Schema> {
|
|
190
|
+
return new CfUpdateQuery(this.src, this.schema, values, this.whereExpr, this.returningItems);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
where(expr: CfExpr): CfUpdateQuery<Schema> {
|
|
194
|
+
return new CfUpdateQuery(this.src, this.schema, this.setValues, expr, this.returningItems);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
returning(...columns: ReadonlyArray<ColumnProxy>): CfUpdateQuery<Schema> {
|
|
198
|
+
return new CfUpdateQuery(
|
|
199
|
+
this.src,
|
|
200
|
+
this.schema,
|
|
201
|
+
this.setValues,
|
|
202
|
+
this.whereExpr,
|
|
203
|
+
columns.map((col) => col.toProjectionItem()),
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
build(): UpdateAst {
|
|
208
|
+
const set = buildSetMap(this.schema, this.setValues);
|
|
209
|
+
const base = UpdateAst.table(this.src).withSet(set);
|
|
210
|
+
const withWhere = this.whereExpr ? base.withWhere(this.whereExpr.ast) : base;
|
|
211
|
+
return this.returningItems ? withWhere.withReturning(this.returningItems) : withWhere;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export class CfSelectQuery {
|
|
216
|
+
constructor(
|
|
217
|
+
private readonly src: TableSource,
|
|
218
|
+
private readonly projectionItems: ReadonlyArray<ProjectionItem>,
|
|
219
|
+
private readonly whereExpr: CfExpr | undefined = undefined,
|
|
220
|
+
private readonly orderByItems: ReadonlyArray<OrderByItem> = [],
|
|
221
|
+
) {}
|
|
222
|
+
|
|
223
|
+
where(expr: CfExpr): CfSelectQuery {
|
|
224
|
+
return new CfSelectQuery(this.src, this.projectionItems, expr, this.orderByItems);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
orderBy(column: ColumnProxy, dir: 'asc' | 'desc' = 'asc'): CfSelectQuery {
|
|
228
|
+
const item = dir === 'asc' ? OrderByItem.asc(column.toRef()) : OrderByItem.desc(column.toRef());
|
|
229
|
+
return new CfSelectQuery(this.src, this.projectionItems, this.whereExpr, [
|
|
230
|
+
...this.orderByItems,
|
|
231
|
+
item,
|
|
232
|
+
]);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
build(): SelectAst {
|
|
236
|
+
const base = SelectAst.from(this.src).withProjection(this.projectionItems);
|
|
237
|
+
const withWhere = this.whereExpr ? base.withWhere(this.whereExpr.ast) : base;
|
|
238
|
+
return this.orderByItems.length > 0 ? withWhere.withOrderBy(this.orderByItems) : withWhere;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Declare a control-plane table once, binding column codecs at declaration time.
|
|
244
|
+
* Returns a `TableHandle` whose column properties compose expressions directly
|
|
245
|
+
* without per-call-site codec or column-name threading.
|
|
246
|
+
*
|
|
247
|
+
* ```ts
|
|
248
|
+
* const marker = pgTable({ name: 'marker', schema: 'prisma_contract' }, {
|
|
249
|
+
* space: text(),
|
|
250
|
+
* core_hash: text(),
|
|
251
|
+
* updated_at: timestamptz(),
|
|
252
|
+
* });
|
|
253
|
+
*
|
|
254
|
+
* const query = marker.update()
|
|
255
|
+
* .set({ core_hash: newHash, updated_at: NOW })
|
|
256
|
+
* .where(marker.space.eq(space).and(marker.core_hash.eq(expectedFrom)))
|
|
257
|
+
* .returning(marker.space)
|
|
258
|
+
* .build();
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export function table<Schema extends ColumnSchema>(
|
|
262
|
+
source: TableSource,
|
|
263
|
+
schema: Schema,
|
|
264
|
+
): TableHandle<Schema> {
|
|
265
|
+
const proxies: Record<string, ColumnProxy> = {};
|
|
266
|
+
for (const [col, desc] of Object.entries(schema)) {
|
|
267
|
+
proxies[col] = makeColumnProxy(source.alias ?? source.name, col, desc);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const handle = {
|
|
271
|
+
...proxies,
|
|
272
|
+
source,
|
|
273
|
+
insert: (row: TableInsertRow<Schema>) => new CfInsertQuery(source, schema, row),
|
|
274
|
+
upsert: (row: TableInsertRow<Schema>) => new CfUpsertBuilder(source, schema, row),
|
|
275
|
+
update: () => new CfUpdateQuery(source, schema),
|
|
276
|
+
select: (...cols: ReadonlyArray<ColumnProxy>) =>
|
|
277
|
+
new CfSelectQuery(
|
|
278
|
+
source,
|
|
279
|
+
cols.map((col) => col.toProjectionItem()),
|
|
280
|
+
),
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
return blindCast<
|
|
284
|
+
TableHandle<Schema>,
|
|
285
|
+
'Column proxies are dynamically built from Schema keys — TypeScript cannot verify the per-key ColumnProxy constraint at the spread call site. Construction is correct by construction: every key maps to makeColumnProxy(source.name, key, schema[key]).'
|
|
286
|
+
>(handle);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function makeColumnProxy(
|
|
290
|
+
tableName: string,
|
|
291
|
+
columnName: string,
|
|
292
|
+
desc: ColumnDescriptor,
|
|
293
|
+
): ColumnProxy {
|
|
294
|
+
const ref = ColumnRef.of(tableName, columnName);
|
|
295
|
+
return {
|
|
296
|
+
codecId: desc.codecId,
|
|
297
|
+
nullable: desc.nullable,
|
|
298
|
+
columnName,
|
|
299
|
+
tableName,
|
|
300
|
+
eq: (value) =>
|
|
301
|
+
value === null
|
|
302
|
+
? new CfExpr(NullCheckExpr.isNull(ref))
|
|
303
|
+
: new CfExpr(BinaryExpr.eq(ref, toSetExpression(value, desc))),
|
|
304
|
+
neq: (value) =>
|
|
305
|
+
value === null
|
|
306
|
+
? new CfExpr(NullCheckExpr.isNotNull(ref))
|
|
307
|
+
: new CfExpr(BinaryExpr.neq(ref, toSetExpression(value, desc))),
|
|
308
|
+
isNull: () => new CfExpr(NullCheckExpr.isNull(ref)),
|
|
309
|
+
isNotNull: () => new CfExpr(NullCheckExpr.isNotNull(ref)),
|
|
310
|
+
toRef: () => ref,
|
|
311
|
+
toProjectionItem: (alias = columnName) =>
|
|
312
|
+
ProjectionItem.of(alias, ref, { codecId: desc.codecId }),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function buildExcludedProxy<Schema extends ColumnSchema>(schema: Schema): ExcludedProxy<Schema> {
|
|
317
|
+
return blindCast<
|
|
318
|
+
ExcludedProxy<Schema>,
|
|
319
|
+
'Object.fromEntries cannot preserve per-key ColumnRef types — correct by construction: every key maps to ColumnRef.of("excluded", key).'
|
|
320
|
+
>(Object.fromEntries(Object.keys(schema).map((col) => [col, ColumnRef.of('excluded', col)])));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function isExpressionSource(value: unknown): value is { toExpr(): AnyExpression } {
|
|
324
|
+
return (
|
|
325
|
+
typeof value === 'object' &&
|
|
326
|
+
value !== null &&
|
|
327
|
+
'toExpr' in value &&
|
|
328
|
+
typeof value.toExpr === 'function'
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function toInsertValue(value: unknown, desc: ColumnDescriptor): InsertValue {
|
|
333
|
+
if (isExpressionSource(value)) {
|
|
334
|
+
const expr = value.toExpr();
|
|
335
|
+
if (
|
|
336
|
+
expr.kind === 'column-ref' ||
|
|
337
|
+
expr.kind === 'param-ref' ||
|
|
338
|
+
expr.kind === 'prepared-param-ref' ||
|
|
339
|
+
expr.kind === 'raw-expr'
|
|
340
|
+
) {
|
|
341
|
+
return expr;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return ParamRef.of(value, { codec: { codecId: desc.codecId } });
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function toSetExpression(value: unknown, desc: ColumnDescriptor): AnyExpression {
|
|
348
|
+
if (isExpressionSource(value)) {
|
|
349
|
+
return value.toExpr();
|
|
350
|
+
}
|
|
351
|
+
return ParamRef.of(value, { codec: { codecId: desc.codecId } });
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function buildInsertRow<Schema extends ColumnSchema>(
|
|
355
|
+
schema: Schema,
|
|
356
|
+
values: TableInsertRow<Schema>,
|
|
357
|
+
): Record<string, InsertValue> {
|
|
358
|
+
const row: Record<string, InsertValue> = {};
|
|
359
|
+
const rawValues = blindCast<
|
|
360
|
+
Record<string, unknown>,
|
|
361
|
+
'TableInsertRow<Schema> maps Schema keys to unknown; indexing by the same string keys is correct by construction'
|
|
362
|
+
>(values);
|
|
363
|
+
for (const [col, desc] of Object.entries(schema)) {
|
|
364
|
+
row[col] = toInsertValue(rawValues[col], desc);
|
|
365
|
+
}
|
|
366
|
+
return row;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function buildSetMap<Schema extends ColumnSchema>(
|
|
370
|
+
schema: Schema,
|
|
371
|
+
values: TableSetValues<Schema> | undefined,
|
|
372
|
+
): Record<string, AnyExpression> {
|
|
373
|
+
if (values === undefined) return {};
|
|
374
|
+
const set: Record<string, AnyExpression> = {};
|
|
375
|
+
const rawSchema = blindCast<
|
|
376
|
+
Record<string, ColumnDescriptor>,
|
|
377
|
+
'Schema extends ColumnSchema = Record<string, ColumnDescriptor>; runtime key access is correct by construction'
|
|
378
|
+
>(schema);
|
|
379
|
+
const rawValues = blindCast<
|
|
380
|
+
Record<string, unknown>,
|
|
381
|
+
'TableSetValues<Schema> maps Schema keys to unknown; iterating with Object.entries is correct by construction'
|
|
382
|
+
>(values);
|
|
383
|
+
for (const [col, value] of Object.entries(rawValues)) {
|
|
384
|
+
const desc = rawSchema[col];
|
|
385
|
+
if (desc !== undefined) {
|
|
386
|
+
set[col] = toSetExpression(value, desc);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return set;
|
|
390
|
+
}
|
package/src/exports/ast.ts
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export {
|
|
2
|
+
col,
|
|
3
|
+
type DdlColumnOptions,
|
|
4
|
+
fn,
|
|
5
|
+
foreignKey,
|
|
6
|
+
lit,
|
|
7
|
+
primaryKey,
|
|
8
|
+
unique,
|
|
9
|
+
} from '../contract-free/column';
|
|
10
|
+
export {
|
|
11
|
+
CfConflictClause,
|
|
12
|
+
CfExpr,
|
|
13
|
+
CfInsertQuery,
|
|
14
|
+
CfSelectQuery,
|
|
15
|
+
CfUpdateQuery,
|
|
16
|
+
CfUpsertBuilder,
|
|
17
|
+
CfUpsertQuery,
|
|
18
|
+
type ColumnDescriptor,
|
|
19
|
+
type ColumnProxy,
|
|
20
|
+
type ColumnSchema,
|
|
21
|
+
type ExcludedProxy,
|
|
22
|
+
type TableHandle,
|
|
23
|
+
type TableInsertRow,
|
|
24
|
+
type TableSetValues,
|
|
25
|
+
table,
|
|
26
|
+
} from '../contract-free/dml';
|
|
@@ -15,15 +15,17 @@ export interface CodecDescriptorRegistry {
|
|
|
15
15
|
/**
|
|
16
16
|
* Derive the canonical {@link CodecRef} for a contract `(table, column)`. The builder side calls this at AST construction time to stamp `codec` onto every column-bound `ParamRef` / `ProjectionItem`; the runtime side uses the result as the cache key into the content-keyed codec resolver.
|
|
17
17
|
*
|
|
18
|
-
* Resolution rules over `storage.tables[table].columns[column]`:
|
|
18
|
+
* Resolution rules over `storage.namespaces[namespaceId].tables[table].columns[column]`:
|
|
19
19
|
*
|
|
20
20
|
* - `typeRef` column → emit `{codecId, typeParams}` from `storage.types[typeRef]` (multiple columns sharing the typeRef produce the same ref → same memoised codec).
|
|
21
21
|
* - inline `typeParams` column → emit `{codecId, typeParams}` from the column itself.
|
|
22
22
|
* - non-parameterized column → emit `{codecId}` with `typeParams` undefined (keys as `${codecId}:undefined` → one shared codec).
|
|
23
23
|
*
|
|
24
|
-
*
|
|
24
|
+
* The `namespaceId` coordinate leads and is always supplied — the table is resolved strictly within that namespace, so two same-bare-named tables in different namespaces resolve to their own per-namespace columns/codecs without colliding.
|
|
25
|
+
*
|
|
26
|
+
* Returns `undefined` when the registry was built without contract storage (package-scoped registries used purely as descriptor lookups), when the table or column is unknown in the namespace, or when the column declares a `typeRef` that the storage doesn't define.
|
|
25
27
|
*/
|
|
26
|
-
codecRefForColumn(table: string, column: string): CodecRef | undefined;
|
|
28
|
+
codecRefForColumn(namespaceId: string, table: string, column: string): CodecRef | undefined;
|
|
27
29
|
/**
|
|
28
30
|
* All registered descriptors. Used by `validateCodecRegistryCompleteness` and other startup-time consumers that enumerate descriptors.
|
|
29
31
|
*/
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Contract,
|
|
1
|
+
import type { Contract, ContractModelDefinitions } from '@prisma-next/contract/types';
|
|
2
2
|
import type { ParamSpec } from '@prisma-next/operations';
|
|
3
3
|
import type {
|
|
4
4
|
ExtractFieldOutputTypes,
|
|
@@ -17,7 +17,7 @@ export type Expr = ColumnRef | ParamRef;
|
|
|
17
17
|
* whose `storage.table` matches.
|
|
18
18
|
*/
|
|
19
19
|
type ExtractTableToModel<TContract extends Contract<SqlStorage>, TableName extends string> =
|
|
20
|
-
|
|
20
|
+
ContractModelDefinitions<TContract> extends infer Models extends Record<string, unknown>
|
|
21
21
|
? {
|
|
22
22
|
[M in keyof Models & string]: Models[M] extends {
|
|
23
23
|
readonly storage: { readonly table: TableName };
|
|
@@ -37,7 +37,7 @@ type ExtractColumnToField<
|
|
|
37
37
|
ColumnName extends string,
|
|
38
38
|
> =
|
|
39
39
|
ExtractTableToModel<TContract, TableName> extends infer ModelName extends string
|
|
40
|
-
?
|
|
40
|
+
? ContractModelDefinitions<TContract> extends infer Models extends Record<string, unknown>
|
|
41
41
|
? ModelName & keyof Models extends infer MKey extends string
|
|
42
42
|
? Models[MKey] extends {
|
|
43
43
|
readonly storage: { readonly fields: infer Fields extends Record<string, unknown> };
|
|
@@ -151,26 +151,6 @@ export type ComputeColumnJsType<
|
|
|
151
151
|
: never
|
|
152
152
|
: never;
|
|
153
153
|
|
|
154
|
-
/**
|
|
155
|
-
* Utility type to check if a contract has the required capabilities for includeMany.
|
|
156
|
-
* Requires both `lateral` and `jsonAgg` to be `true` in the contract's capabilities for the target.
|
|
157
|
-
* Capabilities are nested by target: `{ [target]: { lateral: true, jsonAgg: true } }`
|
|
158
|
-
*/
|
|
159
|
-
export type HasIncludeManyCapabilities<TContract extends Contract<SqlStorage>> = TContract extends {
|
|
160
|
-
capabilities: infer C;
|
|
161
|
-
target: infer T;
|
|
162
|
-
}
|
|
163
|
-
? T extends string
|
|
164
|
-
? C extends Record<string, Record<string, boolean>>
|
|
165
|
-
? C extends { [K in T]: infer TargetCaps }
|
|
166
|
-
? TargetCaps extends { lateral: true; jsonAgg: true }
|
|
167
|
-
? true
|
|
168
|
-
: false
|
|
169
|
-
: false
|
|
170
|
-
: false
|
|
171
|
-
: false
|
|
172
|
-
: false;
|
|
173
|
-
|
|
174
154
|
/**
|
|
175
155
|
* Alias for the SQL-domain executable plan, exposed under the legacy
|
|
176
156
|
* `SqlPlan` name for compatibility with SQL builder/utility call sites.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codec-types-Cezo7k-i.d.mts","names":[],"sources":["../src/ast/codec-types.ts"],"mappings":";;;;AAqBA;;;;UAAiB,YAAA;EAAA,SACN,KAAA;EAAA,SACA,IAAI;AAAA;;;;;;UAQE,mBAAA,SAA4B,gBAAgB;EAAA,SAClD,MAAA,GAAS,YAAA;AAAA;;;;;;;;;AAasD;UADzD,uBAAA,SAAgC,oBAAoB;EAAA,SAC1D,MAAA,EAAQ,aAAA;IAAA,SAAyB,KAAA;IAAA,SAAwB,MAAA;EAAA;AAAA;;;;UAMnD,SAAA;EAAA,SACN,EAAA;IAAA,SACE,GAAA;MAAA,SACE,QAAA;QAAA,SACE,UAAA;MAAA;IAAA;EAAA;AAAA;;;;;;;;UAaA,OAAA,sDAEU,UAAA,cAAwB,UAAA,+CAGzC,KAAA,CAAU,EAAA,EAAI,OAAA,EAAS,KAAA,EAAO,MAAA;EACtC,MAAA,CAAO,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,mBAAA,GAAsB,OAAA,CAAQ,KAAA;EACzD,MAAA,CAAO,IAAA,EAAM,KAAA,EAAO,GAAA,EAAK,mBAAA,GAAsB,OAAA,CAAQ,MAAA;AAAA;;;;;;;;UAUxC,qBAAA;EAZG;;;EAgBlB,SAAA,CAAU,KAAA,UAAe,MAAA,WAAiB,OAAA;EAf1C;;;;;EAsBA,WAAA,CAAY,GAAA,EAAK,QAAA,GAAW,OAAA;AAAA;;;;;KAQlB,kBAAA,GAAqB,eAAe;AAAA,KAE3C,uBAAA,MACH,CAAA,SAAU,eAAA,aAA4B,UAAA,CAAW,UAAA,CAAW,CAAA;AAAA,KAElD,iBAAA,MAAuB,CAAA,SAAU,kBAAA,GAAqB,CAAA;AAAA,KAEtD,oBAAA,MACV,uBAAA,CAAwB,CAAA,UAAW,KAAA,kBAA2B,UAAA,yBAC1D,EAAA;AAtCyD;AAU/D;;;;;AAV+D,KA+CnD,qBAAA,MAA2B,CAAA;EAAA,SAC5B,MAAA,iCAAuC,UAAA;AAAA,IAE9C,OAAA,WAAkB,UAAA;;;;;;KAQV,iBAAA,4CAEa,WAAA,GAAc,kBAAA,KACjC,MAAA,yCAEiB,WAAA,IAAe,iBAAA,CAAkB,WAAA,CAAY,CAAA;EAAA,SACvD,KAAA,EAAO,oBAAA,CAAqB,WAAA,CAAY,CAAA;EAAA,SACxC,MAAA,EAAQ,oBAAA,CAAqB,WAAA,CAAY,CAAA;EAAA,SACzC,MAAA,EAAQ,qBAAA,CAAsB,WAAA,CAAY,CAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plan-CG3sy5kw.d.mts","names":[],"sources":["../src/plan.ts"],"mappings":";;;;;;;;AAkBA;;;;;;;;;;;UAAiB,YAAA,wBAAoC,SAAA,CAAU,GAAA;EAAA,SACpD,GAAA,EAAK,WAAA;EAAA,SACL,MAAA;AAAA;AAAM;AAoBjB;;;;;;;;;;;;;;;;AApBiB,iBAoBD,WAAA,eAAA,CACd,GAAA,EAAK,WAAA,EACL,QAAA,EAAU,QAAA,CAAS,UAAA,GACnB,MAAA,YACC,YAAA,CAAa,GAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-lane-context-Dw1Tz0kv.d.mts","names":[],"sources":["../src/query-lane-context.ts"],"mappings":";;;;;;;;;AASA;UAAiB,uBAAA;;;;EAIf,aAAA,CAAc,OAAA,WAAkB,eAAA;EAgBtB;;;;;;;;;;;EAJV,iBAAA,CAAkB,KAAA,UAAe,MAAA,WAAiB,QAAA;EAIxC;;;EAAV,MAAA,IAAU,gBAAA,CAAiB,eAAA;EAIgB;;AAAe;EAA1D,YAAA,CAAa,UAAA,oBAA8B,eAAA;AAAA;;;AAMN;KAA3B,kBAAA,GAAqB,MAAM;AAAA,KAE3B,kBAAA;AAAA,KAEA,sBAAA;EAAA,SACD,MAAA;EAAA,SACA,KAAK;AAAA;AAAA,KAGJ,uBAAA;EAAA,SACD,EAAA,EAAI,kBAAA;EAAA,SACJ,KAAA;EAAA,SACA,MAAA,EAAQ,MAAA;EAHP;;;;EAAA,SAQD,iBAAA,GAAoB,GAAA;AAAA;;;;;;UAQd,gBAAA,mBAAmC,QAAA,CAAS,UAAA,IAAc,QAAA,CAAS,UAAA;EAAA,SACzE,QAAA,EAAU,SAAA;EATV;;;EAAA,SAaA,cAAA,EAAgB,qBAAA;EALV;;;EAAA,SASN,gBAAA,EAAkB,uBAAA;EAAA,SAClB,eAAA,EAAiB,oBAAA;EAVwD;;;EAAA,SAczE,KAAA,EAAO,kBAAA;EALW;;;EAS3B,qBAAA,CAAsB,OAAA,EAAS,uBAAA,GAA0B,aAAA,CAAc,sBAAA;AAAA"}
|