@prisma-next/target-postgres 0.16.0-dev.32 → 0.16.0-dev.34
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 -0
- package/dist/{authoring-DnO1B0N9.mjs → authoring-DL-Y8A7_.mjs} +5 -5
- package/dist/{authoring-DnO1B0N9.mjs.map → authoring-DL-Y8A7_.mjs.map} +1 -1
- package/dist/codec-descriptor-C4SaWX0P.d.mts +36 -0
- package/dist/codec-descriptor-C4SaWX0P.d.mts.map +1 -0
- package/dist/codec-descriptor-cuAuPE0Y.mjs +142 -0
- package/dist/codec-descriptor-cuAuPE0Y.mjs.map +1 -0
- package/dist/codec-descriptor.d.mts +2 -0
- package/dist/codec-descriptor.mjs +2 -0
- package/dist/{codec-types-DdoPc2dy.d.mts → codec-types-Bstec0HR.d.mts} +9 -8
- package/dist/codec-types-Bstec0HR.d.mts.map +1 -0
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs-Deand7sy.mjs → codecs-C-VA-quH.mjs} +228 -40
- package/dist/codecs-C-VA-quH.mjs.map +1 -0
- package/dist/{codecs-CGE5dh94.d.mts → codecs-Cd4TftwI.d.mts} +82 -29
- package/dist/codecs-Cd4TftwI.d.mts.map +1 -0
- package/dist/codecs.d.mts +4 -2
- package/dist/codecs.d.mts.map +1 -1
- package/dist/codecs.mjs +4 -2
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.mjs +2 -2
- package/dist/{control-policy-DEwdS3oK.mjs → control-policy-DMZVl4x7.mjs} +8 -8
- package/dist/{control-policy-DEwdS3oK.mjs.map → control-policy-DMZVl4x7.mjs.map} +1 -1
- package/dist/control.mjs +9 -9
- package/dist/{ddl-BQC6u-L9.mjs → ddl-Db1JOIMn.mjs} +2 -2
- package/dist/{ddl-BQC6u-L9.mjs.map → ddl-Db1JOIMn.mjs.map} +1 -1
- package/dist/{descriptor-meta-DGlJurgA.mjs → descriptor-meta-AnueS0OA.mjs} +4 -4
- package/dist/{descriptor-meta-DGlJurgA.mjs.map → descriptor-meta-AnueS0OA.mjs.map} +1 -1
- package/dist/{diff-database-schema-qRPwuYBH.mjs → diff-database-schema-CluGQkmh.mjs} +8 -8
- package/dist/{diff-database-schema-qRPwuYBH.mjs.map → diff-database-schema-CluGQkmh.mjs.map} +1 -1
- package/dist/diff-database-schema.mjs +1 -1
- package/dist/{errors-DBSNx7EJ.mjs → errors-l1usFTuz.mjs} +2 -2
- package/dist/{errors-DBSNx7EJ.mjs.map → errors-l1usFTuz.mjs.map} +1 -1
- package/dist/errors.d.mts +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.mjs +2 -2
- package/dist/{op-factory-call-CIaPDDUc.mjs → op-factory-call-Cm13qr4w.mjs} +7 -7
- package/dist/{op-factory-call-CIaPDDUc.mjs.map → op-factory-call-Cm13qr4w.mjs.map} +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.d.mts +2 -2
- package/dist/pack.mjs +1 -1
- package/dist/{planner-BhnkIJX-.mjs → planner-CB0e-x6l.mjs} +9 -9
- package/dist/{planner-BhnkIJX-.mjs.map → planner-CB0e-x6l.mjs.map} +1 -1
- package/dist/{planner-ddl-builders-CVo3L7Nd.mjs → planner-ddl-builders-DX8DHY8D.mjs} +4 -4
- package/dist/{planner-ddl-builders-CVo3L7Nd.mjs.map → planner-ddl-builders-DX8DHY8D.mjs.map} +1 -1
- package/dist/planner-ddl-builders.mjs +1 -1
- package/dist/{planner-produced-postgres-migration-BE3EJIRK.mjs → planner-produced-postgres-migration-B0i-PVar.mjs} +3 -3
- package/dist/{planner-produced-postgres-migration-BE3EJIRK.mjs.map → planner-produced-postgres-migration-B0i-PVar.mjs.map} +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/{planner-sql-checks-CmiQ6Nei.mjs → planner-sql-checks-D3Xsln1p.mjs} +3 -3
- package/dist/{planner-sql-checks-CmiQ6Nei.mjs.map → planner-sql-checks-D3Xsln1p.mjs.map} +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/planner.mjs +2 -2
- package/dist/{postgres-contract-view-BeIEyZfD.mjs → postgres-contract-view-v-zxqBtj.mjs} +4 -4
- package/dist/{postgres-contract-view-BeIEyZfD.mjs.map → postgres-contract-view-v-zxqBtj.mjs.map} +1 -1
- package/dist/{postgres-migration--BzvpA92.mjs → postgres-migration-D_6w1hJj.mjs} +5 -5
- package/dist/{postgres-migration--BzvpA92.mjs.map → postgres-migration-D_6w1hJj.mjs.map} +1 -1
- package/dist/{postgres-native-enum-BwVNf0Ku.mjs → postgres-native-enum-DqjHPN11.mjs} +2 -2
- package/dist/{postgres-native-enum-BwVNf0Ku.mjs.map → postgres-native-enum-DqjHPN11.mjs.map} +1 -1
- package/dist/{postgres-role-schema-node-bg32e7I-.mjs → postgres-role-schema-node-DOkim7QI.mjs} +3 -3
- package/dist/{postgres-role-schema-node-bg32e7I-.mjs.map → postgres-role-schema-node-DOkim7QI.mjs.map} +1 -1
- package/dist/{postgres-schema-CTplQZDK.mjs → postgres-schema-DAhXnFac.mjs} +4 -4
- package/dist/{postgres-schema-CTplQZDK.mjs.map → postgres-schema-DAhXnFac.mjs.map} +1 -1
- package/dist/{postgres-table-schema-node-D6LvInCe.mjs → postgres-table-schema-node-DXzwiu16.mjs} +2 -2
- package/dist/{postgres-table-schema-node-D6LvInCe.mjs.map → postgres-table-schema-node-DXzwiu16.mjs.map} +1 -1
- package/dist/{render-ops-TcY9XEkz.mjs → render-ops-DIjVRr1-.mjs} +2 -2
- package/dist/{render-ops-TcY9XEkz.mjs.map → render-ops-DIjVRr1-.mjs.map} +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/{resolve-ddl-schema-BAsJEKW8.mjs → resolve-ddl-schema-nTvL_9Nq.mjs} +2 -2
- package/dist/{resolve-ddl-schema-BAsJEKW8.mjs.map → resolve-ddl-schema-nTvL_9Nq.mjs.map} +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/schema-ir-annotations.mjs +1 -1
- package/dist/{sql-utils-B2lzkKfP.mjs → sql-utils-CuKSscKn.mjs} +2 -2
- package/dist/{sql-utils-B2lzkKfP.mjs.map → sql-utils-CuKSscKn.mjs.map} +1 -1
- package/dist/sql-utils.mjs +1 -1
- package/dist/types.mjs +4 -4
- package/package.json +21 -20
- package/src/core/codec-descriptor.ts +318 -0
- package/src/core/codec-type-map.ts +12 -14
- package/src/core/codecs.ts +232 -39
- package/src/core/registry.ts +4 -0
- package/src/exports/codec-descriptor.ts +11 -0
- package/src/exports/codecs.ts +4 -1
- package/dist/codec-types-DdoPc2dy.d.mts.map +0 -1
- package/dist/codecs-CGE5dh94.d.mts.map +0 -1
- package/dist/codecs-Deand7sy.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as postgresError } from "./errors-
|
|
1
|
+
import { n as postgresError } from "./errors-l1usFTuz.mjs";
|
|
2
2
|
//#region src/core/sql-utils.ts
|
|
3
3
|
/**
|
|
4
4
|
* Shared SQL utility functions for the Postgres target.
|
|
@@ -87,4 +87,4 @@ function validateEnumValueLength(value, enumTypeName) {
|
|
|
87
87
|
//#endregion
|
|
88
88
|
export { validateEnumValueLength as a, quoteQualifiedName as i, qualifyName as n, quoteIdentifier as r, escapeLiteral as t };
|
|
89
89
|
|
|
90
|
-
//# sourceMappingURL=sql-utils-
|
|
90
|
+
//# sourceMappingURL=sql-utils-CuKSscKn.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-utils-
|
|
1
|
+
{"version":3,"file":"sql-utils-CuKSscKn.mjs","names":[],"sources":["../src/core/sql-utils.ts"],"sourcesContent":["/**\n * Shared SQL utility functions for the Postgres target.\n *\n * These functions handle safe SQL identifier and literal escaping\n * with security validations to prevent injection and encoding issues.\n *\n * They live in `target-postgres` because both the control adapter (used at\n * emit time) and the runtime adapter (used at execute time) need the same\n * escaping/validation behavior, and the target package is the natural shared\n * home that both adapters can depend on without crossing planes.\n */\n\nimport { postgresError } from './errors';\n\nconst MAX_IDENTIFIER_LENGTH = 63;\n\n/**\n * Validates and quotes a PostgreSQL identifier (table, column, type, schema names).\n *\n * Security validations:\n * - Rejects null bytes which could cause truncation or unexpected behavior\n * - Rejects empty identifiers\n * - Warns on identifiers exceeding PostgreSQL's 63-character limit\n *\n * @throws `CONTRACT.IDENTIFIER_INVALID` structured error If the identifier contains null bytes or is empty\n */\nexport function quoteIdentifier(identifier: string): string {\n if (identifier.length === 0) {\n throw postgresError('CONTRACT.IDENTIFIER_INVALID', 'Identifier cannot be empty', {\n meta: { value: identifier, context: 'identifier' },\n });\n }\n if (identifier.includes('\\0')) {\n throw postgresError('CONTRACT.IDENTIFIER_INVALID', 'Identifier cannot contain null bytes', {\n meta: { value: identifier.replace(/\\0/g, '\\\\0'), context: 'identifier' },\n });\n }\n if (identifier.length > MAX_IDENTIFIER_LENGTH) {\n console.warn(\n `Identifier \"${identifier.slice(0, 20)}...\" exceeds PostgreSQL's ${MAX_IDENTIFIER_LENGTH}-character limit and will be truncated`,\n );\n }\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Escapes a string literal for safe use in SQL statements.\n *\n * Security validations:\n * - Rejects null bytes which could cause truncation or unexpected behavior\n *\n * Note: This assumes PostgreSQL's `standard_conforming_strings` is ON (default since PG 9.1).\n * Backslashes are treated as literal characters, not escape sequences.\n *\n * @throws `CONTRACT.IDENTIFIER_INVALID` structured error If the value contains null bytes\n */\nexport function escapeLiteral(value: string): string {\n if (value.includes('\\0')) {\n throw postgresError('CONTRACT.IDENTIFIER_INVALID', 'Literal value cannot contain null bytes', {\n meta: { value: value.replace(/\\0/g, '\\\\0'), context: 'literal' },\n });\n }\n return value.replace(/'/g, \"''\");\n}\n\n/**\n * Builds a qualified name (schema.object) with proper quoting.\n */\nexport function qualifyName(schemaName: string, objectName: string): string {\n return `${quoteIdentifier(schemaName)}.${quoteIdentifier(objectName)}`;\n}\n\n/**\n * Quotes a possibly dot-qualified name segment-by-segment:\n * `order_status` -> `\"order_status\"`, `auth.aal_level` -> `\"auth\".\"aal_level\"`.\n * A single-segment name round-trips to exactly {@link quoteIdentifier}; whole-\n * string quoting (`\"auth.aal_level\"`) would be one wrong identifier.\n */\nexport function quoteQualifiedName(name: string): string {\n return name\n .split('.')\n .map((segment) => quoteIdentifier(segment))\n .join('.');\n}\n\n/**\n * Validates that an enum value doesn't exceed PostgreSQL's label length limit.\n *\n * PostgreSQL enum labels have a maximum length of NAMEDATALEN-1 (63 bytes by default).\n * Unlike identifiers, enum labels that exceed this limit cause an error rather than\n * silent truncation.\n *\n * @param value - The enum value to validate\n * @param enumTypeName - Name of the enum type (for error messages)\n * @throws `CONTRACT.IDENTIFIER_INVALID` structured error If the value exceeds the maximum length\n */\nexport function validateEnumValueLength(value: string, enumTypeName: string): void {\n if (new TextEncoder().encode(value).length > MAX_IDENTIFIER_LENGTH) {\n throw postgresError(\n 'CONTRACT.IDENTIFIER_INVALID',\n `Enum value \"${value.slice(0, 20)}...\" for type \"${enumTypeName}\" exceeds PostgreSQL's ` +\n `${MAX_IDENTIFIER_LENGTH}-byte label limit`,\n { meta: { value, context: 'enum-label' } },\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,MAAM,wBAAwB;;;;;;;;;;;AAY9B,SAAgB,gBAAgB,YAA4B;CAC1D,IAAI,WAAW,WAAW,GACxB,MAAM,cAAc,+BAA+B,8BAA8B,EAC/E,MAAM;EAAE,OAAO;EAAY,SAAS;CAAa,EACnD,CAAC;CAEH,IAAI,WAAW,SAAS,IAAI,GAC1B,MAAM,cAAc,+BAA+B,wCAAwC,EACzF,MAAM;EAAE,OAAO,WAAW,QAAQ,OAAO,KAAK;EAAG,SAAS;CAAa,EACzE,CAAC;CAEH,IAAI,WAAW,SAAS,uBACtB,QAAQ,KACN,eAAe,WAAW,MAAM,GAAG,EAAE,EAAE,4BAA4B,sBAAsB,uCAC3F;CAEF,OAAO,IAAI,WAAW,QAAQ,MAAM,MAAI,EAAE;AAC5C;;;;;;;;;;;;AAaA,SAAgB,cAAc,OAAuB;CACnD,IAAI,MAAM,SAAS,IAAI,GACrB,MAAM,cAAc,+BAA+B,2CAA2C,EAC5F,MAAM;EAAE,OAAO,MAAM,QAAQ,OAAO,KAAK;EAAG,SAAS;CAAU,EACjE,CAAC;CAEH,OAAO,MAAM,QAAQ,MAAM,IAAI;AACjC;;;;AAKA,SAAgB,YAAY,YAAoB,YAA4B;CAC1E,OAAO,GAAG,gBAAgB,UAAU,EAAE,GAAG,gBAAgB,UAAU;AACrE;;;;;;;AAQA,SAAgB,mBAAmB,MAAsB;CACvD,OAAO,KACJ,MAAM,GAAG,CAAC,CACV,KAAK,YAAY,gBAAgB,OAAO,CAAC,CAAC,CAC1C,KAAK,GAAG;AACb;;;;;;;;;;;;AAaA,SAAgB,wBAAwB,OAAe,cAA4B;CACjF,IAAI,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,SAAS,uBAC3C,MAAM,cACJ,+BACA,eAAe,MAAM,MAAM,GAAG,EAAE,EAAE,iBAAiB,aAAa,yBAC3D,sBAAsB,oBAC3B,EAAE,MAAM;EAAE;EAAO,SAAS;CAAa,EAAE,CAC3C;AAEJ"}
|
package/dist/sql-utils.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as validateEnumValueLength, i as quoteQualifiedName, n as qualifyName, r as quoteIdentifier, t as escapeLiteral } from "./sql-utils-
|
|
1
|
+
import { a as validateEnumValueLength, i as quoteQualifiedName, n as qualifyName, r as quoteIdentifier, t as escapeLiteral } from "./sql-utils-CuKSscKn.mjs";
|
|
2
2
|
export { escapeLiteral, qualifyName, quoteIdentifier, quoteQualifiedName, validateEnumValueLength };
|
package/dist/types.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as PostgresNativeEnum } from "./postgres-native-enum-
|
|
2
|
-
import { _ as PostgresRlsEnablement, g as PostgresRlsPolicy, i as postgresCreateNamespace, m as PostgresRole, n as PostgresUnboundSchema, r as isPostgresSchema, t as PostgresSchema } from "./postgres-schema-
|
|
3
|
-
import { n as PostgresNativeEnumSchemaNode, r as PostgresSchemaNodeKind, t as PostgresTableSchemaNode } from "./postgres-table-schema-node-
|
|
4
|
-
import { i as PostgresDatabaseSchemaNode, n as PostgresPolicySchemaNode, r as PostgresNamespaceSchemaNode, t as PostgresRoleSchemaNode } from "./postgres-role-schema-node-
|
|
1
|
+
import { t as PostgresNativeEnum } from "./postgres-native-enum-DqjHPN11.mjs";
|
|
2
|
+
import { _ as PostgresRlsEnablement, g as PostgresRlsPolicy, i as postgresCreateNamespace, m as PostgresRole, n as PostgresUnboundSchema, r as isPostgresSchema, t as PostgresSchema } from "./postgres-schema-DAhXnFac.mjs";
|
|
3
|
+
import { n as PostgresNativeEnumSchemaNode, r as PostgresSchemaNodeKind, t as PostgresTableSchemaNode } from "./postgres-table-schema-node-DXzwiu16.mjs";
|
|
4
|
+
import { i as PostgresDatabaseSchemaNode, n as PostgresPolicySchemaNode, r as PostgresNamespaceSchemaNode, t as PostgresRoleSchemaNode } from "./postgres-role-schema-node-DOkim7QI.mjs";
|
|
5
5
|
export { PostgresDatabaseSchemaNode, PostgresNamespaceSchemaNode, PostgresNativeEnum, PostgresNativeEnumSchemaNode, PostgresPolicySchemaNode, PostgresRlsEnablement, PostgresRlsPolicy, PostgresRole, PostgresRoleSchemaNode, PostgresSchema, PostgresSchemaNodeKind, PostgresTableSchemaNode, PostgresUnboundSchema, isPostgresSchema, postgresCreateNamespace };
|
package/package.json
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/target-postgres",
|
|
3
|
-
"version": "0.16.0-dev.
|
|
3
|
+
"version": "0.16.0-dev.34",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "Postgres target pack for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/cli": "0.16.0-dev.
|
|
10
|
-
"@prisma-next/contract": "0.16.0-dev.
|
|
11
|
-
"@prisma-next/errors": "0.16.0-dev.
|
|
12
|
-
"@prisma-next/family-sql": "0.16.0-dev.
|
|
13
|
-
"@prisma-next/framework-components": "0.16.0-dev.
|
|
14
|
-
"@prisma-next/migration-tools": "0.16.0-dev.
|
|
15
|
-
"@prisma-next/psl-parser": "0.16.0-dev.
|
|
16
|
-
"@prisma-next/sql-contract": "0.16.0-dev.
|
|
17
|
-
"@prisma-next/sql-errors": "0.16.0-dev.
|
|
18
|
-
"@prisma-next/sql-operations": "0.16.0-dev.
|
|
19
|
-
"@prisma-next/sql-relational-core": "0.16.0-dev.
|
|
20
|
-
"@prisma-next/sql-schema-ir": "0.16.0-dev.
|
|
21
|
-
"@prisma-next/ts-render": "0.16.0-dev.
|
|
22
|
-
"@prisma-next/utils": "0.16.0-dev.
|
|
9
|
+
"@prisma-next/cli": "0.16.0-dev.34",
|
|
10
|
+
"@prisma-next/contract": "0.16.0-dev.34",
|
|
11
|
+
"@prisma-next/errors": "0.16.0-dev.34",
|
|
12
|
+
"@prisma-next/family-sql": "0.16.0-dev.34",
|
|
13
|
+
"@prisma-next/framework-components": "0.16.0-dev.34",
|
|
14
|
+
"@prisma-next/migration-tools": "0.16.0-dev.34",
|
|
15
|
+
"@prisma-next/psl-parser": "0.16.0-dev.34",
|
|
16
|
+
"@prisma-next/sql-contract": "0.16.0-dev.34",
|
|
17
|
+
"@prisma-next/sql-errors": "0.16.0-dev.34",
|
|
18
|
+
"@prisma-next/sql-operations": "0.16.0-dev.34",
|
|
19
|
+
"@prisma-next/sql-relational-core": "0.16.0-dev.34",
|
|
20
|
+
"@prisma-next/sql-schema-ir": "0.16.0-dev.34",
|
|
21
|
+
"@prisma-next/ts-render": "0.16.0-dev.34",
|
|
22
|
+
"@prisma-next/utils": "0.16.0-dev.34",
|
|
23
23
|
"@standard-schema/spec": "^1.1.0",
|
|
24
24
|
"arktype": "^2.2.2",
|
|
25
25
|
"pathe": "^2.0.3"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@prisma-next/psl-printer": "0.16.0-dev.
|
|
29
|
-
"@prisma-next/sql-contract-psl": "0.16.0-dev.
|
|
30
|
-
"@prisma-next/test-utils": "0.16.0-dev.
|
|
31
|
-
"@prisma-next/tsconfig": "0.16.0-dev.
|
|
32
|
-
"@prisma-next/tsdown": "0.16.0-dev.
|
|
28
|
+
"@prisma-next/psl-printer": "0.16.0-dev.34",
|
|
29
|
+
"@prisma-next/sql-contract-psl": "0.16.0-dev.34",
|
|
30
|
+
"@prisma-next/test-utils": "0.16.0-dev.34",
|
|
31
|
+
"@prisma-next/tsconfig": "0.16.0-dev.34",
|
|
32
|
+
"@prisma-next/tsdown": "0.16.0-dev.34",
|
|
33
33
|
"tsdown": "0.22.8",
|
|
34
34
|
"typescript": "5.9.3",
|
|
35
35
|
"vitest": "4.1.10"
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"packs"
|
|
49
49
|
],
|
|
50
50
|
"exports": {
|
|
51
|
+
"./codec-descriptor": "./dist/codec-descriptor.mjs",
|
|
51
52
|
"./codec-ids": "./dist/codec-ids.mjs",
|
|
52
53
|
"./codec-types": "./dist/codec-types.mjs",
|
|
53
54
|
"./codecs": "./dist/codecs.mjs",
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import type { JsonValue } from '@prisma-next/contract/types';
|
|
2
|
+
import {
|
|
3
|
+
type AnyCodecDescriptor,
|
|
4
|
+
type Codec,
|
|
5
|
+
type CodecDescriptor,
|
|
6
|
+
CodecDescriptorImpl,
|
|
7
|
+
type CodecInstanceContext,
|
|
8
|
+
type CodecMeta,
|
|
9
|
+
type CodecRef,
|
|
10
|
+
type CodecTrait,
|
|
11
|
+
validateCodecTypeParams,
|
|
12
|
+
} from '@prisma-next/framework-components/codec';
|
|
13
|
+
import {
|
|
14
|
+
CaseExpr,
|
|
15
|
+
ColumnRef,
|
|
16
|
+
DerivedTableSource,
|
|
17
|
+
FunctionSource,
|
|
18
|
+
JsonArrayAggExpr,
|
|
19
|
+
LiteralExpr,
|
|
20
|
+
NativeJsonValueProjection,
|
|
21
|
+
NullCheckExpr,
|
|
22
|
+
OrderByItem,
|
|
23
|
+
type ProjectionExpr,
|
|
24
|
+
ProjectionItem,
|
|
25
|
+
SelectAst,
|
|
26
|
+
SubqueryExpr,
|
|
27
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
28
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
29
|
+
import { structuredError } from '@prisma-next/utils/structured-error';
|
|
30
|
+
|
|
31
|
+
const POSTGRES_CODEC_DESCRIPTOR_KIND = 'postgres-codec' as const;
|
|
32
|
+
const ARRAY_INPUT_ALIAS = 'array_input';
|
|
33
|
+
const ARRAY_ELEMENT_ALIAS = 'array_element';
|
|
34
|
+
const ARRAY_VALUE_COLUMN = 'value';
|
|
35
|
+
const ARRAY_ORDINALITY_COLUMN = 'ordinality';
|
|
36
|
+
|
|
37
|
+
export interface AnyPostgresCodecDescriptor extends AnyCodecDescriptor {
|
|
38
|
+
readonly descriptorKind: typeof POSTGRES_CODEC_DESCRIPTOR_KIND;
|
|
39
|
+
nativeTypeFor(ref: CodecRef): string;
|
|
40
|
+
projectJson(expression: ProjectionExpr, ref: CodecRef): ProjectionExpr;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export abstract class PostgresCodecDescriptor<P = void>
|
|
44
|
+
extends CodecDescriptorImpl<P>
|
|
45
|
+
implements AnyPostgresCodecDescriptor
|
|
46
|
+
{
|
|
47
|
+
readonly descriptorKind = POSTGRES_CODEC_DESCRIPTOR_KIND;
|
|
48
|
+
|
|
49
|
+
protected abstract nativeType(params: P): string;
|
|
50
|
+
protected abstract jsonProjection(expression: ProjectionExpr, params: P): ProjectionExpr;
|
|
51
|
+
|
|
52
|
+
protected jsonArrayProjection(expression: ProjectionExpr, params: P): ProjectionExpr {
|
|
53
|
+
const boundArray = ColumnRef.of(ARRAY_INPUT_ALIAS, ARRAY_VALUE_COLUMN);
|
|
54
|
+
const element = ColumnRef.of(ARRAY_ELEMENT_ALIAS, ARRAY_VALUE_COLUMN);
|
|
55
|
+
const ordinality = ColumnRef.of(ARRAY_ELEMENT_ALIAS, ARRAY_ORDINALITY_COLUMN);
|
|
56
|
+
const projectedElement = CaseExpr.of(
|
|
57
|
+
[{ condition: NullCheckExpr.isNull(element), value: LiteralExpr.of(null) }],
|
|
58
|
+
this.jsonProjection(element, params),
|
|
59
|
+
);
|
|
60
|
+
const aggregate = JsonArrayAggExpr.of(
|
|
61
|
+
new NativeJsonValueProjection(projectedElement),
|
|
62
|
+
'emptyArray',
|
|
63
|
+
[OrderByItem.asc(ordinality)],
|
|
64
|
+
);
|
|
65
|
+
const aggregateQuery = SelectAst.from(
|
|
66
|
+
FunctionSource.of('unnest', [boundArray], {
|
|
67
|
+
alias: ARRAY_ELEMENT_ALIAS,
|
|
68
|
+
columnAliases: [ARRAY_VALUE_COLUMN, ARRAY_ORDINALITY_COLUMN],
|
|
69
|
+
}).withOrdinality(),
|
|
70
|
+
).withProjection([ProjectionItem.of(ARRAY_VALUE_COLUMN, aggregate)]);
|
|
71
|
+
const arrayResult = CaseExpr.of(
|
|
72
|
+
[{ condition: NullCheckExpr.isNull(boundArray), value: LiteralExpr.of(null) }],
|
|
73
|
+
SubqueryExpr.of(aggregateQuery),
|
|
74
|
+
);
|
|
75
|
+
const inputBinding = SelectAst.noFrom().withProjection([
|
|
76
|
+
ProjectionItem.of(ARRAY_VALUE_COLUMN, expression),
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
return SubqueryExpr.of(
|
|
80
|
+
SelectAst.from(DerivedTableSource.as(ARRAY_INPUT_ALIAS, inputBinding)).withProjection([
|
|
81
|
+
ProjectionItem.of(ARRAY_VALUE_COLUMN, arrayResult),
|
|
82
|
+
]),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
nativeTypeFor(ref: CodecRef): string {
|
|
87
|
+
return this.nativeType(this.validateParams(ref));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
projectJson(expression: ProjectionExpr, ref: CodecRef): ProjectionExpr {
|
|
91
|
+
const params = this.validateParams(ref);
|
|
92
|
+
return ref.many === true
|
|
93
|
+
? this.jsonArrayProjection(expression, params)
|
|
94
|
+
: this.jsonProjection(expression, params);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private validateParams(ref: CodecRef): P {
|
|
98
|
+
return blindCast<
|
|
99
|
+
P,
|
|
100
|
+
'validateCodecTypeParams synchronously validates this descriptor schema before the typed hook'
|
|
101
|
+
>(validateCodecTypeParams(this, ref));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
type DescriptorParams<D extends AnyCodecDescriptor> =
|
|
106
|
+
D extends CodecDescriptor<infer P> ? P : never;
|
|
107
|
+
|
|
108
|
+
export interface PostgresCodecOptions<P> {
|
|
109
|
+
readonly nativeType: (params: P) => string;
|
|
110
|
+
readonly jsonProjection: (expression: ProjectionExpr, params: P) => ProjectionExpr;
|
|
111
|
+
readonly jsonArrayProjection?: (expression: ProjectionExpr, params: P) => ProjectionExpr;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type AdaptedPostgresCodecDescriptor<D extends AnyCodecDescriptor> = Pick<
|
|
115
|
+
D,
|
|
116
|
+
keyof CodecDescriptor<DescriptorParams<D>>
|
|
117
|
+
> &
|
|
118
|
+
Pick<AnyPostgresCodecDescriptor, 'descriptorKind' | 'nativeTypeFor' | 'projectJson'>;
|
|
119
|
+
|
|
120
|
+
class PostgresCodecDescriptorAdapter<D extends AnyCodecDescriptor> extends PostgresCodecDescriptor<
|
|
121
|
+
DescriptorParams<D>
|
|
122
|
+
> {
|
|
123
|
+
override readonly codecId: string;
|
|
124
|
+
override readonly traits: readonly CodecTrait[];
|
|
125
|
+
override readonly targetTypes: readonly string[];
|
|
126
|
+
override readonly paramsSchema: D['paramsSchema'];
|
|
127
|
+
override readonly metaFor?: (params: DescriptorParams<D>) => CodecMeta | undefined;
|
|
128
|
+
override readonly renderOutputType?: (params: DescriptorParams<D>) => string | undefined;
|
|
129
|
+
override readonly renderInputType?: (params: DescriptorParams<D>) => string | undefined;
|
|
130
|
+
override readonly renderValueLiteral?: (
|
|
131
|
+
value: JsonValue,
|
|
132
|
+
side: 'output' | 'input',
|
|
133
|
+
) => string | undefined;
|
|
134
|
+
override readonly factory: (
|
|
135
|
+
params: DescriptorParams<D>,
|
|
136
|
+
) => (ctx: CodecInstanceContext) => Codec<string, readonly CodecTrait[], unknown, unknown>;
|
|
137
|
+
|
|
138
|
+
constructor(
|
|
139
|
+
private readonly descriptor: D,
|
|
140
|
+
private readonly options: PostgresCodecOptions<DescriptorParams<D>>,
|
|
141
|
+
) {
|
|
142
|
+
super();
|
|
143
|
+
this.codecId = descriptor.codecId;
|
|
144
|
+
this.traits = descriptor.traits;
|
|
145
|
+
this.targetTypes = descriptor.targetTypes;
|
|
146
|
+
this.paramsSchema = descriptor.paramsSchema;
|
|
147
|
+
this.factory = (params) => descriptor.factory(params);
|
|
148
|
+
|
|
149
|
+
if (descriptor.meta !== undefined) {
|
|
150
|
+
Object.defineProperty(this, 'meta', {
|
|
151
|
+
value: descriptor.meta,
|
|
152
|
+
enumerable: true,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const metaFor = descriptor.metaFor;
|
|
157
|
+
if (metaFor !== undefined) {
|
|
158
|
+
this.metaFor = (params) => metaFor.call(descriptor, params);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const renderOutputType = descriptor.renderOutputType;
|
|
162
|
+
if (renderOutputType !== undefined) {
|
|
163
|
+
this.renderOutputType = (params) => renderOutputType.call(descriptor, params);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const renderInputType = descriptor.renderInputType;
|
|
167
|
+
if (renderInputType !== undefined) {
|
|
168
|
+
this.renderInputType = (params) => renderInputType.call(descriptor, params);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const renderValueLiteral = descriptor.renderValueLiteral;
|
|
172
|
+
if (renderValueLiteral !== undefined) {
|
|
173
|
+
this.renderValueLiteral = (value, side) => renderValueLiteral.call(descriptor, value, side);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
override get isParameterized(): boolean {
|
|
178
|
+
return this.descriptor.isParameterized;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
protected override nativeType(params: DescriptorParams<D>): string {
|
|
182
|
+
return this.options.nativeType(params);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
protected override jsonProjection(
|
|
186
|
+
expression: ProjectionExpr,
|
|
187
|
+
params: DescriptorParams<D>,
|
|
188
|
+
): ProjectionExpr {
|
|
189
|
+
return this.options.jsonProjection(expression, params);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
protected override jsonArrayProjection(
|
|
193
|
+
expression: ProjectionExpr,
|
|
194
|
+
params: DescriptorParams<D>,
|
|
195
|
+
): ProjectionExpr {
|
|
196
|
+
return this.options.jsonArrayProjection === undefined
|
|
197
|
+
? super.jsonArrayProjection(expression, params)
|
|
198
|
+
: this.options.jsonArrayProjection(expression, params);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function postgresCodec<D extends AnyCodecDescriptor>(
|
|
203
|
+
descriptor: D,
|
|
204
|
+
options: PostgresCodecOptions<DescriptorParams<D>>,
|
|
205
|
+
): AdaptedPostgresCodecDescriptor<D> {
|
|
206
|
+
return blindCast<
|
|
207
|
+
AdaptedPostgresCodecDescriptor<D>,
|
|
208
|
+
'the adapter delegates every ordinary descriptor member while adding the validated PostgreSQL protocol'
|
|
209
|
+
>(new PostgresCodecDescriptorAdapter(descriptor, options));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function definePostgresCodecs<
|
|
213
|
+
const Descriptors extends readonly AnyPostgresCodecDescriptor[],
|
|
214
|
+
>(descriptors: Descriptors): Descriptors {
|
|
215
|
+
return descriptors;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function isPostgresCodecDescriptor(value: unknown): value is AnyPostgresCodecDescriptor {
|
|
219
|
+
return (
|
|
220
|
+
typeof value === 'object' &&
|
|
221
|
+
value !== null &&
|
|
222
|
+
'descriptorKind' in value &&
|
|
223
|
+
value.descriptorKind === POSTGRES_CODEC_DESCRIPTOR_KIND &&
|
|
224
|
+
'codecId' in value &&
|
|
225
|
+
typeof value.codecId === 'string' &&
|
|
226
|
+
'traits' in value &&
|
|
227
|
+
Array.isArray(value.traits) &&
|
|
228
|
+
'targetTypes' in value &&
|
|
229
|
+
Array.isArray(value.targetTypes) &&
|
|
230
|
+
value.targetTypes.every((targetType) => typeof targetType === 'string') &&
|
|
231
|
+
'paramsSchema' in value &&
|
|
232
|
+
isObjectLike(value.paramsSchema) &&
|
|
233
|
+
'~standard' in value.paramsSchema &&
|
|
234
|
+
isObjectLike(value.paramsSchema['~standard']) &&
|
|
235
|
+
'validate' in value.paramsSchema['~standard'] &&
|
|
236
|
+
typeof value.paramsSchema['~standard'].validate === 'function' &&
|
|
237
|
+
'isParameterized' in value &&
|
|
238
|
+
typeof value.isParameterized === 'boolean' &&
|
|
239
|
+
'factory' in value &&
|
|
240
|
+
typeof value.factory === 'function' &&
|
|
241
|
+
'nativeTypeFor' in value &&
|
|
242
|
+
typeof value.nativeTypeFor === 'function' &&
|
|
243
|
+
'projectJson' in value &&
|
|
244
|
+
typeof value.projectJson === 'function'
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function isObjectLike(value: unknown): value is object {
|
|
249
|
+
return (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface PostgresCodecDescriptorRegistry {
|
|
253
|
+
descriptorFor(codecId: string): AnyPostgresCodecDescriptor | undefined;
|
|
254
|
+
values(): IterableIterator<AnyPostgresCodecDescriptor>;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
class PostgresCodecDescriptorRegistryImpl implements PostgresCodecDescriptorRegistry {
|
|
258
|
+
readonly #descriptors: ReadonlyMap<string, AnyPostgresCodecDescriptor>;
|
|
259
|
+
|
|
260
|
+
constructor(descriptors: ReadonlyMap<string, AnyPostgresCodecDescriptor>) {
|
|
261
|
+
this.#descriptors = descriptors;
|
|
262
|
+
Object.freeze(this);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
descriptorFor(codecId: string): AnyPostgresCodecDescriptor | undefined {
|
|
266
|
+
return this.#descriptors.get(codecId);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
*values(): IterableIterator<AnyPostgresCodecDescriptor> {
|
|
270
|
+
yield* this.#descriptors.values();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export function buildPostgresCodecDescriptorRegistry(
|
|
275
|
+
descriptors: ReadonlyArray<unknown>,
|
|
276
|
+
): PostgresCodecDescriptorRegistry {
|
|
277
|
+
const byId = new Map<string, AnyPostgresCodecDescriptor>();
|
|
278
|
+
|
|
279
|
+
for (const descriptor of descriptors) {
|
|
280
|
+
if (!isPostgresCodecDescriptor(descriptor)) {
|
|
281
|
+
const codecId = candidateCodecId(descriptor);
|
|
282
|
+
throw structuredError(
|
|
283
|
+
'POSTGRES.CODEC_DESCRIPTOR_INVALID',
|
|
284
|
+
`Codec descriptor '${codecId}' is not a valid PostgreSQL codec descriptor.`,
|
|
285
|
+
{
|
|
286
|
+
why: 'PostgreSQL codec registries require the postgres-codec discriminant and complete target descriptor methods.',
|
|
287
|
+
fix: 'Extend PostgresCodecDescriptor or adapt a generic descriptor with postgresCodec().',
|
|
288
|
+
meta: { codecId },
|
|
289
|
+
},
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (byId.has(descriptor.codecId)) {
|
|
294
|
+
throw structuredError(
|
|
295
|
+
'POSTGRES.CODEC_DESCRIPTOR_DUPLICATE',
|
|
296
|
+
`Duplicate PostgreSQL codec descriptor id '${descriptor.codecId}'.`,
|
|
297
|
+
{
|
|
298
|
+
why: 'Each codecId must resolve to exactly one PostgreSQL descriptor during registry composition.',
|
|
299
|
+
fix: 'Remove the duplicate target, adapter, or extension contribution.',
|
|
300
|
+
meta: { codecId: descriptor.codecId },
|
|
301
|
+
},
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
byId.set(descriptor.codecId, descriptor);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return new PostgresCodecDescriptorRegistryImpl(byId);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function candidateCodecId(value: unknown): string {
|
|
312
|
+
return typeof value === 'object' &&
|
|
313
|
+
value !== null &&
|
|
314
|
+
'codecId' in value &&
|
|
315
|
+
typeof value.codecId === 'string'
|
|
316
|
+
? value.codecId
|
|
317
|
+
: '<unknown>';
|
|
318
|
+
}
|
|
@@ -8,14 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { ExtractCodecTypes } from '@prisma-next/sql-relational-core/ast';
|
|
11
|
-
import {
|
|
12
|
-
sqlCharDescriptor,
|
|
13
|
-
sqlFloatDescriptor,
|
|
14
|
-
sqlIntDescriptor,
|
|
15
|
-
sqlTextDescriptor,
|
|
16
|
-
sqlTimestampDescriptor,
|
|
17
|
-
sqlVarcharDescriptor,
|
|
18
|
-
} from '@prisma-next/sql-relational-core/ast';
|
|
19
11
|
import {
|
|
20
12
|
pgBitDescriptor,
|
|
21
13
|
pgBoolDescriptor,
|
|
@@ -43,15 +35,21 @@ import {
|
|
|
43
35
|
pgUuidDescriptor,
|
|
44
36
|
pgVarbitDescriptor,
|
|
45
37
|
pgVarcharDescriptor,
|
|
38
|
+
postgresSqlCharDescriptor,
|
|
39
|
+
postgresSqlFloatDescriptor,
|
|
40
|
+
postgresSqlIntDescriptor,
|
|
41
|
+
postgresSqlTextDescriptor,
|
|
42
|
+
postgresSqlTimestampDescriptor,
|
|
43
|
+
postgresSqlVarcharDescriptor,
|
|
46
44
|
} from './codecs';
|
|
47
45
|
|
|
48
46
|
export const codecDescriptorMap = {
|
|
49
|
-
char:
|
|
50
|
-
varchar:
|
|
51
|
-
int:
|
|
52
|
-
float:
|
|
53
|
-
'sql-text':
|
|
54
|
-
'sql-timestamp':
|
|
47
|
+
char: postgresSqlCharDescriptor,
|
|
48
|
+
varchar: postgresSqlVarcharDescriptor,
|
|
49
|
+
int: postgresSqlIntDescriptor,
|
|
50
|
+
float: postgresSqlFloatDescriptor,
|
|
51
|
+
'sql-text': postgresSqlTextDescriptor,
|
|
52
|
+
'sql-timestamp': postgresSqlTimestampDescriptor,
|
|
55
53
|
text: pgTextDescriptor,
|
|
56
54
|
enum: pgEnumDescriptor,
|
|
57
55
|
character: pgCharDescriptor,
|