@prisma-next/adapter-postgres 0.3.0-dev.7 → 0.3.0-dev.71

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.
Files changed (91) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +64 -2
  3. package/dist/adapter-DtehReRR.mjs +271 -0
  4. package/dist/adapter-DtehReRR.mjs.map +1 -0
  5. package/dist/adapter.d.mts +23 -0
  6. package/dist/adapter.d.mts.map +1 -0
  7. package/dist/adapter.mjs +3 -0
  8. package/dist/codec-ids-Bsm9c7ns.mjs +29 -0
  9. package/dist/codec-ids-Bsm9c7ns.mjs.map +1 -0
  10. package/dist/codec-types.d.mts +141 -0
  11. package/dist/codec-types.d.mts.map +1 -0
  12. package/dist/codec-types.mjs +3 -0
  13. package/dist/codecs-BfC_5c-4.mjs +207 -0
  14. package/dist/codecs-BfC_5c-4.mjs.map +1 -0
  15. package/dist/column-types.d.mts +110 -0
  16. package/dist/column-types.d.mts.map +1 -0
  17. package/dist/column-types.mjs +180 -0
  18. package/dist/column-types.mjs.map +1 -0
  19. package/dist/control.d.mts +111 -0
  20. package/dist/control.d.mts.map +1 -0
  21. package/dist/control.mjs +462 -0
  22. package/dist/control.mjs.map +1 -0
  23. package/dist/descriptor-meta-ilnFI7bx.mjs +921 -0
  24. package/dist/descriptor-meta-ilnFI7bx.mjs.map +1 -0
  25. package/dist/runtime.d.mts +19 -0
  26. package/dist/runtime.d.mts.map +1 -0
  27. package/dist/runtime.mjs +85 -0
  28. package/dist/runtime.mjs.map +1 -0
  29. package/dist/sql-utils-CSfAGEwF.mjs +78 -0
  30. package/dist/sql-utils-CSfAGEwF.mjs.map +1 -0
  31. package/dist/types-CXO7EB60.d.mts +19 -0
  32. package/dist/types-CXO7EB60.d.mts.map +1 -0
  33. package/dist/types.d.mts +2 -0
  34. package/dist/types.mjs +1 -0
  35. package/package.json +37 -46
  36. package/src/core/adapter.ts +139 -28
  37. package/src/core/codec-ids.ts +28 -0
  38. package/src/core/codecs.ts +325 -23
  39. package/src/core/control-adapter.ts +400 -178
  40. package/src/core/default-normalizer.ts +90 -0
  41. package/src/core/descriptor-meta.ts +221 -9
  42. package/src/core/enum-control-hooks.ts +735 -0
  43. package/src/core/json-schema-type-expression.ts +131 -0
  44. package/src/core/json-schema-validator.ts +53 -0
  45. package/src/core/parameterized-types.ts +118 -0
  46. package/src/core/sql-utils.ts +111 -0
  47. package/src/core/standard-schema.ts +71 -0
  48. package/src/exports/codec-types.ts +73 -1
  49. package/src/exports/column-types.ts +233 -9
  50. package/src/exports/control.ts +16 -9
  51. package/src/exports/runtime.ts +61 -18
  52. package/dist/chunk-HD5YISNQ.js +0 -47
  53. package/dist/chunk-HD5YISNQ.js.map +0 -1
  54. package/dist/chunk-J3XSOAM2.js +0 -162
  55. package/dist/chunk-J3XSOAM2.js.map +0 -1
  56. package/dist/chunk-T6S3A6VT.js +0 -301
  57. package/dist/chunk-T6S3A6VT.js.map +0 -1
  58. package/dist/core/adapter.d.ts +0 -19
  59. package/dist/core/adapter.d.ts.map +0 -1
  60. package/dist/core/codecs.d.ts +0 -110
  61. package/dist/core/codecs.d.ts.map +0 -1
  62. package/dist/core/control-adapter.d.ts +0 -33
  63. package/dist/core/control-adapter.d.ts.map +0 -1
  64. package/dist/core/descriptor-meta.d.ts +0 -72
  65. package/dist/core/descriptor-meta.d.ts.map +0 -1
  66. package/dist/core/types.d.ts +0 -16
  67. package/dist/core/types.d.ts.map +0 -1
  68. package/dist/exports/adapter.d.ts +0 -2
  69. package/dist/exports/adapter.d.ts.map +0 -1
  70. package/dist/exports/adapter.js +0 -8
  71. package/dist/exports/adapter.js.map +0 -1
  72. package/dist/exports/codec-types.d.ts +0 -11
  73. package/dist/exports/codec-types.d.ts.map +0 -1
  74. package/dist/exports/codec-types.js +0 -7
  75. package/dist/exports/codec-types.js.map +0 -1
  76. package/dist/exports/column-types.d.ts +0 -17
  77. package/dist/exports/column-types.d.ts.map +0 -1
  78. package/dist/exports/column-types.js +0 -49
  79. package/dist/exports/column-types.js.map +0 -1
  80. package/dist/exports/control.d.ts +0 -8
  81. package/dist/exports/control.d.ts.map +0 -1
  82. package/dist/exports/control.js +0 -279
  83. package/dist/exports/control.js.map +0 -1
  84. package/dist/exports/runtime.d.ts +0 -15
  85. package/dist/exports/runtime.d.ts.map +0 -1
  86. package/dist/exports/runtime.js +0 -20
  87. package/dist/exports/runtime.js.map +0 -1
  88. package/dist/exports/types.d.ts +0 -2
  89. package/dist/exports/types.d.ts.map +0 -1
  90. package/dist/exports/types.js +0 -1
  91. package/dist/exports/types.js.map +0 -1
@@ -0,0 +1,90 @@
1
+ import type { ColumnDefault } from '@prisma-next/contract/types';
2
+
3
+ /**
4
+ * Pre-compiled regex patterns for performance.
5
+ * These are compiled once at module load time rather than on each function call.
6
+ */
7
+ const NEXTVAL_PATTERN = /^nextval\s*\(/i;
8
+ const TIMESTAMP_PATTERN = /^(now\s*\(\s*\)|CURRENT_TIMESTAMP|clock_timestamp\s*\(\s*\))$/i;
9
+ const UUID_PATTERN = /^gen_random_uuid\s*\(\s*\)$/i;
10
+ const UUID_OSSP_PATTERN = /^uuid_generate_v4\s*\(\s*\)$/i;
11
+ const TRUE_PATTERN = /^true$/i;
12
+ const FALSE_PATTERN = /^false$/i;
13
+ const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
14
+ const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d+\))?)?$/;
15
+
16
+ /**
17
+ * Parses a raw Postgres column default expression into a normalized ColumnDefault.
18
+ * This enables semantic comparison between contract defaults and introspected schema defaults.
19
+ *
20
+ * Used by the migration diff layer to normalize raw database defaults during comparison,
21
+ * keeping the introspection layer focused on faithful data capture.
22
+ *
23
+ * @param rawDefault - Raw default expression from information_schema.columns.column_default
24
+ * @param _nativeType - Native column type (currently unused, reserved for future type-aware parsing)
25
+ * @returns Normalized ColumnDefault or undefined if the expression cannot be parsed
26
+ */
27
+ export function parsePostgresDefault(
28
+ rawDefault: string,
29
+ _nativeType?: string,
30
+ ): ColumnDefault | undefined {
31
+ const trimmed = rawDefault.trim();
32
+ const normalizedType = _nativeType?.toLowerCase();
33
+ const isBigInt = normalizedType === 'bigint' || normalizedType === 'int8';
34
+
35
+ // Autoincrement: nextval('tablename_column_seq'::regclass)
36
+ if (NEXTVAL_PATTERN.test(trimmed)) {
37
+ return { kind: 'function', expression: 'autoincrement()' };
38
+ }
39
+
40
+ // now() / CURRENT_TIMESTAMP / clock_timestamp()
41
+ if (TIMESTAMP_PATTERN.test(trimmed)) {
42
+ return { kind: 'function', expression: 'now()' };
43
+ }
44
+
45
+ // gen_random_uuid()
46
+ if (UUID_PATTERN.test(trimmed)) {
47
+ return { kind: 'function', expression: 'gen_random_uuid()' };
48
+ }
49
+
50
+ // uuid_generate_v4() from uuid-ossp extension
51
+ if (UUID_OSSP_PATTERN.test(trimmed)) {
52
+ return { kind: 'function', expression: 'gen_random_uuid()' };
53
+ }
54
+
55
+ // Boolean literals
56
+ if (TRUE_PATTERN.test(trimmed)) {
57
+ return { kind: 'literal', value: true };
58
+ }
59
+ if (FALSE_PATTERN.test(trimmed)) {
60
+ return { kind: 'literal', value: false };
61
+ }
62
+
63
+ // Numeric literals (integer or decimal)
64
+ if (NUMERIC_PATTERN.test(trimmed)) {
65
+ if (isBigInt) {
66
+ return { kind: 'literal', value: { $type: 'bigint', value: trimmed } };
67
+ }
68
+ return { kind: 'literal', value: Number(trimmed) };
69
+ }
70
+
71
+ // String literals: 'value'::type or just 'value'
72
+ // Match: 'some text'::text, 'hello'::character varying, 'value', etc.
73
+ // Strip the ::type cast so the normalized expression matches what contract authors write.
74
+ const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
75
+ if (stringMatch?.[1] !== undefined) {
76
+ const unescaped = stringMatch[1].replace(/''/g, "'");
77
+ if (normalizedType === 'json' || normalizedType === 'jsonb') {
78
+ try {
79
+ return { kind: 'literal', value: JSON.parse(unescaped) };
80
+ } catch {
81
+ // Keep legacy behavior for malformed/non-JSON string content.
82
+ }
83
+ }
84
+ return { kind: 'literal', value: unescaped };
85
+ }
86
+
87
+ // Unrecognized expression - return as a function with the raw expression
88
+ // This preserves the information for debugging while still being comparable
89
+ return { kind: 'function', expression: trimmed };
90
+ }
@@ -1,3 +1,95 @@
1
+ import type { CodecControlHooks } from '@prisma-next/family-sql/control';
2
+ import {
3
+ PG_BIT_CODEC_ID,
4
+ PG_BOOL_CODEC_ID,
5
+ PG_CHAR_CODEC_ID,
6
+ PG_ENUM_CODEC_ID,
7
+ PG_FLOAT_CODEC_ID,
8
+ PG_FLOAT4_CODEC_ID,
9
+ PG_FLOAT8_CODEC_ID,
10
+ PG_INT_CODEC_ID,
11
+ PG_INT2_CODEC_ID,
12
+ PG_INT4_CODEC_ID,
13
+ PG_INT8_CODEC_ID,
14
+ PG_INTERVAL_CODEC_ID,
15
+ PG_JSON_CODEC_ID,
16
+ PG_JSONB_CODEC_ID,
17
+ PG_NUMERIC_CODEC_ID,
18
+ PG_TEXT_CODEC_ID,
19
+ PG_TIME_CODEC_ID,
20
+ PG_TIMESTAMP_CODEC_ID,
21
+ PG_TIMESTAMPTZ_CODEC_ID,
22
+ PG_TIMETZ_CODEC_ID,
23
+ PG_VARBIT_CODEC_ID,
24
+ PG_VARCHAR_CODEC_ID,
25
+ SQL_CHAR_CODEC_ID,
26
+ SQL_FLOAT_CODEC_ID,
27
+ SQL_INT_CODEC_ID,
28
+ SQL_VARCHAR_CODEC_ID,
29
+ } from './codec-ids';
30
+ import { pgEnumControlHooks } from './enum-control-hooks';
31
+ import { renderTypeScriptTypeFromJsonSchema } from './json-schema-type-expression';
32
+ import { expandParameterizedNativeType } from './parameterized-types';
33
+
34
+ // ============================================================================
35
+ // Helper functions for reducing boilerplate
36
+ // ============================================================================
37
+
38
+ /** Creates a type import spec for codec types */
39
+ const codecTypeImport = (named: string) =>
40
+ ({
41
+ package: '@prisma-next/adapter-postgres/codec-types',
42
+ named,
43
+ alias: named,
44
+ }) as const;
45
+
46
+ /** Creates a precision-based TypeScript type renderer for temporal types */
47
+ const precisionRenderer = (typeName: string) =>
48
+ ({
49
+ kind: 'function',
50
+ render: (params: Record<string, unknown>) => {
51
+ const precision = params['precision'];
52
+ return typeof precision === 'number' ? `${typeName}<${precision}>` : typeName;
53
+ },
54
+ }) as const;
55
+
56
+ /** Creates control hooks with just expandNativeType for parameterized types */
57
+ const parameterizedTypeHooks: CodecControlHooks = {
58
+ expandNativeType: expandParameterizedNativeType,
59
+ };
60
+
61
+ /**
62
+ * Validates that a type expression string is safe to embed in generated .d.ts files.
63
+ * Rejects expressions containing patterns that could inject executable code.
64
+ */
65
+ function isSafeTypeExpression(expr: string): boolean {
66
+ return !/import\s*\(|require\s*\(|declare\s|export\s|eval\s*\(/.test(expr);
67
+ }
68
+
69
+ function renderJsonTypeExpression(params: Record<string, unknown>): string {
70
+ const typeName = params['type'];
71
+ if (typeof typeName === 'string' && typeName.trim().length > 0) {
72
+ const trimmed = typeName.trim();
73
+ if (!isSafeTypeExpression(trimmed)) {
74
+ return 'JsonValue';
75
+ }
76
+ return trimmed;
77
+ }
78
+ const schema = params['schemaJson'];
79
+ if (schema && typeof schema === 'object') {
80
+ const rendered = renderTypeScriptTypeFromJsonSchema(schema);
81
+ if (!isSafeTypeExpression(rendered)) {
82
+ return 'JsonValue';
83
+ }
84
+ return rendered;
85
+ }
86
+ return 'JsonValue';
87
+ }
88
+
89
+ // ============================================================================
90
+ // Descriptor metadata
91
+ // ============================================================================
92
+
1
93
  export const postgresAdapterDescriptorMeta = {
2
94
  kind: 'adapter',
3
95
  familyId: 'sql',
@@ -12,6 +104,9 @@ export const postgresAdapterDescriptorMeta = {
12
104
  jsonAgg: true,
13
105
  returning: true,
14
106
  },
107
+ sql: {
108
+ enums: true,
109
+ },
15
110
  },
16
111
  types: {
17
112
  codecTypes: {
@@ -20,22 +115,139 @@ export const postgresAdapterDescriptorMeta = {
20
115
  named: 'CodecTypes',
21
116
  alias: 'PgTypes',
22
117
  },
118
+ parameterized: {
119
+ [SQL_CHAR_CODEC_ID]: 'Char<{{length}}>',
120
+ [SQL_VARCHAR_CODEC_ID]: 'Varchar<{{length}}>',
121
+ [PG_CHAR_CODEC_ID]: 'Char<{{length}}>',
122
+ [PG_VARCHAR_CODEC_ID]: 'Varchar<{{length}}>',
123
+ [PG_NUMERIC_CODEC_ID]: {
124
+ kind: 'function',
125
+ render: (params: Record<string, unknown>) => {
126
+ const precision = params['precision'];
127
+ if (typeof precision !== 'number') {
128
+ throw new Error('pg/numeric@1 renderer expects precision');
129
+ }
130
+ const scale = params['scale'];
131
+ return typeof scale === 'number'
132
+ ? `Numeric<${precision}, ${scale}>`
133
+ : `Numeric<${precision}>`;
134
+ },
135
+ },
136
+ [PG_BIT_CODEC_ID]: 'Bit<{{length}}>',
137
+ [PG_VARBIT_CODEC_ID]: 'VarBit<{{length}}>',
138
+ [PG_TIMESTAMP_CODEC_ID]: precisionRenderer('Timestamp'),
139
+ [PG_TIMESTAMPTZ_CODEC_ID]: precisionRenderer('Timestamptz'),
140
+ [PG_TIME_CODEC_ID]: precisionRenderer('Time'),
141
+ [PG_TIMETZ_CODEC_ID]: precisionRenderer('Timetz'),
142
+ [PG_INTERVAL_CODEC_ID]: precisionRenderer('Interval'),
143
+ [PG_ENUM_CODEC_ID]: {
144
+ kind: 'function',
145
+ render: (params: Record<string, unknown>) => {
146
+ const values = params['values'];
147
+ if (!Array.isArray(values)) {
148
+ throw new Error('pg/enum@1 renderer expects values array');
149
+ }
150
+ return values.map((value) => `'${String(value).replace(/'/g, "\\'")}'`).join(' | ');
151
+ },
152
+ },
153
+ [PG_JSON_CODEC_ID]: {
154
+ kind: 'function',
155
+ render: renderJsonTypeExpression,
156
+ },
157
+ [PG_JSONB_CODEC_ID]: {
158
+ kind: 'function',
159
+ render: renderJsonTypeExpression,
160
+ },
161
+ },
162
+ typeImports: [
163
+ {
164
+ package: '@prisma-next/adapter-postgres/codec-types',
165
+ named: 'JsonValue',
166
+ alias: 'JsonValue',
167
+ },
168
+ codecTypeImport('Char'),
169
+ codecTypeImport('Varchar'),
170
+ codecTypeImport('Numeric'),
171
+ codecTypeImport('Bit'),
172
+ codecTypeImport('VarBit'),
173
+ codecTypeImport('Timestamp'),
174
+ codecTypeImport('Timestamptz'),
175
+ codecTypeImport('Time'),
176
+ codecTypeImport('Timetz'),
177
+ codecTypeImport('Interval'),
178
+ ],
179
+ controlPlaneHooks: {
180
+ [SQL_CHAR_CODEC_ID]: parameterizedTypeHooks,
181
+ [SQL_VARCHAR_CODEC_ID]: parameterizedTypeHooks,
182
+ [PG_CHAR_CODEC_ID]: parameterizedTypeHooks,
183
+ [PG_VARCHAR_CODEC_ID]: parameterizedTypeHooks,
184
+ [PG_NUMERIC_CODEC_ID]: parameterizedTypeHooks,
185
+ [PG_BIT_CODEC_ID]: parameterizedTypeHooks,
186
+ [PG_VARBIT_CODEC_ID]: parameterizedTypeHooks,
187
+ [PG_TIMESTAMP_CODEC_ID]: parameterizedTypeHooks,
188
+ [PG_TIMESTAMPTZ_CODEC_ID]: parameterizedTypeHooks,
189
+ [PG_TIME_CODEC_ID]: parameterizedTypeHooks,
190
+ [PG_TIMETZ_CODEC_ID]: parameterizedTypeHooks,
191
+ [PG_INTERVAL_CODEC_ID]: parameterizedTypeHooks,
192
+ [PG_ENUM_CODEC_ID]: pgEnumControlHooks,
193
+ },
23
194
  },
24
195
  storage: [
25
- { typeId: 'pg/text@1', familyId: 'sql', targetId: 'postgres', nativeType: 'text' },
26
- { typeId: 'pg/int4@1', familyId: 'sql', targetId: 'postgres', nativeType: 'int4' },
27
- { typeId: 'pg/int2@1', familyId: 'sql', targetId: 'postgres', nativeType: 'int2' },
28
- { typeId: 'pg/int8@1', familyId: 'sql', targetId: 'postgres', nativeType: 'int8' },
29
- { typeId: 'pg/float4@1', familyId: 'sql', targetId: 'postgres', nativeType: 'float4' },
30
- { typeId: 'pg/float8@1', familyId: 'sql', targetId: 'postgres', nativeType: 'float8' },
31
- { typeId: 'pg/timestamp@1', familyId: 'sql', targetId: 'postgres', nativeType: 'timestamp' },
196
+ { typeId: PG_TEXT_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'text' },
197
+ { typeId: SQL_CHAR_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'character' },
198
+ {
199
+ typeId: SQL_VARCHAR_CODEC_ID,
200
+ familyId: 'sql',
201
+ targetId: 'postgres',
202
+ nativeType: 'character varying',
203
+ },
204
+ { typeId: SQL_INT_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'int4' },
205
+ { typeId: SQL_FLOAT_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'float8' },
206
+ { typeId: PG_CHAR_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'character' },
207
+ {
208
+ typeId: PG_VARCHAR_CODEC_ID,
209
+ familyId: 'sql',
210
+ targetId: 'postgres',
211
+ nativeType: 'character varying',
212
+ },
213
+ { typeId: PG_INT_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'int4' },
214
+ { typeId: PG_FLOAT_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'float8' },
215
+ { typeId: PG_INT4_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'int4' },
216
+ { typeId: PG_INT2_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'int2' },
217
+ { typeId: PG_INT8_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'int8' },
218
+ { typeId: PG_FLOAT4_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'float4' },
219
+ { typeId: PG_FLOAT8_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'float8' },
220
+ { typeId: PG_NUMERIC_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'numeric' },
32
221
  {
33
- typeId: 'pg/timestamptz@1',
222
+ typeId: PG_TIMESTAMP_CODEC_ID,
223
+ familyId: 'sql',
224
+ targetId: 'postgres',
225
+ nativeType: 'timestamp',
226
+ },
227
+ {
228
+ typeId: PG_TIMESTAMPTZ_CODEC_ID,
34
229
  familyId: 'sql',
35
230
  targetId: 'postgres',
36
231
  nativeType: 'timestamptz',
37
232
  },
38
- { typeId: 'pg/bool@1', familyId: 'sql', targetId: 'postgres', nativeType: 'bool' },
233
+ { typeId: PG_TIME_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'time' },
234
+ { typeId: PG_TIMETZ_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'timetz' },
235
+ { typeId: PG_BOOL_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'bool' },
236
+ { typeId: PG_BIT_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'bit' },
237
+ {
238
+ typeId: PG_VARBIT_CODEC_ID,
239
+ familyId: 'sql',
240
+ targetId: 'postgres',
241
+ nativeType: 'bit varying',
242
+ },
243
+ {
244
+ typeId: PG_INTERVAL_CODEC_ID,
245
+ familyId: 'sql',
246
+ targetId: 'postgres',
247
+ nativeType: 'interval',
248
+ },
249
+ { typeId: PG_JSON_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'json' },
250
+ { typeId: PG_JSONB_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'jsonb' },
39
251
  ],
40
252
  },
41
253
  } as const;