@prisma-next/psl-printer 0.5.0-dev.9 → 0.5.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.
@@ -0,0 +1,182 @@
1
+ import type { PrintDocument } from './print-document';
2
+ import type { PrinterEnumValue, PrinterField, PrinterNamedType } from './types';
3
+
4
+ const PSL_IDENTIFIER_PATTERN = /^[A-Za-z_]\w*$/;
5
+ const ENUM_MEMBER_RESERVED_WORDS = new Set([
6
+ 'datasource',
7
+ 'default',
8
+ 'enum',
9
+ 'generator',
10
+ 'model',
11
+ 'type',
12
+ 'types',
13
+ ]);
14
+
15
+ export function escapePslString(value: string): string {
16
+ return value
17
+ .replace(/\\/g, '\\\\')
18
+ .replace(/"/g, '\\"')
19
+ .replace(/\n/g, '\\n')
20
+ .replace(/\r/g, '\\r');
21
+ }
22
+
23
+ export function serializePrintDocument(doc: PrintDocument): string {
24
+ const sections: string[] = [];
25
+
26
+ sections.push(doc.headerComment);
27
+
28
+ const namedTypeEntries = [...doc.namedTypes].sort((a, b) => a.name.localeCompare(b.name));
29
+ if (namedTypeEntries.length > 0) {
30
+ sections.push(serializeTypesBlock(namedTypeEntries));
31
+ }
32
+
33
+ const enumsSorted = [...doc.enums].sort((a, b) => a.name.localeCompare(b.name));
34
+ for (const e of enumsSorted) {
35
+ sections.push(serializeEnum(e));
36
+ }
37
+
38
+ for (const model of doc.models) {
39
+ sections.push(serializeModel(model));
40
+ }
41
+
42
+ return `${sections.join('\n\n')}\n`;
43
+ }
44
+
45
+ function serializeTypesBlock(namedTypes: readonly PrinterNamedType[]): string {
46
+ const lines = ['types {'];
47
+ for (const nt of namedTypes) {
48
+ const attrStr = nt.attributes.length > 0 ? ` ${nt.attributes.join(' ')}` : '';
49
+ lines.push(` ${nt.name} = ${nt.baseType}${attrStr}`);
50
+ }
51
+ lines.push('}');
52
+ return lines.join('\n');
53
+ }
54
+
55
+ function serializeEnum(e: {
56
+ name: string;
57
+ mapName?: string | undefined;
58
+ values: readonly PrinterEnumValue[];
59
+ }): string {
60
+ const lines = [`enum ${e.name} {`];
61
+ const usedNames = new Set<string>();
62
+ for (const value of e.values) {
63
+ const memberName = normalizeEnumMemberName(value.name, usedNames);
64
+ // Emit a per-member `@map("...")` whenever the printed identifier differs
65
+ // from the original storage label (e.g. PostgreSQL enum labels with
66
+ // hyphens that get normalised to camelCase, reserved words that get
67
+ // `_`-prefixed, or names that collide and get a numeric suffix), or when
68
+ // the AST carried an explicit `mapName` from a parsed source. Without
69
+ // this, parsing the emitted PSL would lose the original storage label and
70
+ // a subsequent `contract emit` would talk to the wrong DB enum value.
71
+ const explicitMap = value.mapName;
72
+ const storageLabel =
73
+ explicitMap !== undefined ? explicitMap : memberName !== value.name ? value.name : undefined;
74
+ if (storageLabel !== undefined) {
75
+ lines.push(` ${memberName} @map("${escapePslString(storageLabel)}")`);
76
+ } else {
77
+ lines.push(` ${memberName}`);
78
+ }
79
+ usedNames.add(memberName);
80
+ }
81
+ if (e.mapName) {
82
+ lines.push('');
83
+ lines.push(` @@map("${escapePslString(e.mapName)}")`);
84
+ }
85
+ lines.push('}');
86
+ return lines.join('\n');
87
+ }
88
+
89
+ function serializeModel(model: import('./types').PrinterModel): string {
90
+ const lines: string[] = [];
91
+
92
+ if (model.comment) {
93
+ lines.push(model.comment);
94
+ }
95
+ lines.push(`model ${model.name} {`);
96
+
97
+ const idFields = model.fields.filter((f) => f.isId);
98
+ const scalarFields = model.fields.filter((f) => !f.isId && !f.isRelation);
99
+ const relationFields = model.fields.filter((f) => f.isRelation);
100
+
101
+ const allOrderedFields = [...idFields, ...scalarFields, ...relationFields];
102
+
103
+ if (allOrderedFields.length > 0) {
104
+ const maxNameLen = Math.max(...allOrderedFields.map((f) => f.name.length));
105
+ const maxTypeLen = Math.max(...allOrderedFields.map((f) => formatFieldType(f).length));
106
+
107
+ for (const field of allOrderedFields) {
108
+ const typePart = formatFieldType(field);
109
+ const paddedName = field.name.padEnd(maxNameLen);
110
+ const paddedType = typePart.padEnd(maxTypeLen);
111
+
112
+ if (field.comment) {
113
+ lines.push(` ${field.comment}`);
114
+ }
115
+
116
+ const attrStr = field.attributes.length > 0 ? ` ${field.attributes.join(' ')}` : '';
117
+ lines.push(` ${paddedName} ${paddedType}${attrStr}`.trimEnd());
118
+ }
119
+ }
120
+
121
+ if (model.modelAttributes.length > 0) {
122
+ if (allOrderedFields.length > 0) {
123
+ lines.push('');
124
+ }
125
+ for (const attr of model.modelAttributes) {
126
+ lines.push(` ${attr}`);
127
+ }
128
+ }
129
+
130
+ lines.push('}');
131
+ return lines.join('\n');
132
+ }
133
+
134
+ function formatFieldType(field: PrinterField): string {
135
+ let type = field.typeName;
136
+ if (field.list) {
137
+ type += '[]';
138
+ } else if (field.optional) {
139
+ type += '?';
140
+ }
141
+ return type;
142
+ }
143
+
144
+ function createUniqueFieldName(desiredName: string, usedFieldNames: ReadonlySet<string>): string {
145
+ if (!usedFieldNames.has(desiredName)) {
146
+ return desiredName;
147
+ }
148
+
149
+ let counter = 2;
150
+ while (usedFieldNames.has(`${desiredName}${counter}`)) {
151
+ counter++;
152
+ }
153
+ return `${desiredName}${counter}`;
154
+ }
155
+
156
+ function isNormalizedEnumMemberReservedWord(value: string): boolean {
157
+ return ENUM_MEMBER_RESERVED_WORDS.has(value.toLowerCase());
158
+ }
159
+
160
+ function normalizeEnumMemberName(value: string, usedNames: ReadonlySet<string>): string {
161
+ const desiredName =
162
+ PSL_IDENTIFIER_PATTERN.test(value) && !isNormalizedEnumMemberReservedWord(value)
163
+ ? value
164
+ : createNormalizedEnumMemberBaseName(value);
165
+
166
+ return createUniqueFieldName(desiredName, usedNames);
167
+ }
168
+
169
+ function createNormalizedEnumMemberBaseName(value: string): string {
170
+ const tokens = value.match(/[A-Za-z0-9]+/g)?.map((token) => token.toLowerCase()) ?? [];
171
+ let normalized = tokens[0] ?? 'value';
172
+
173
+ for (const token of tokens.slice(1)) {
174
+ normalized += token.charAt(0).toUpperCase() + token.slice(1);
175
+ }
176
+
177
+ if (isNormalizedEnumMemberReservedWord(normalized) || /^\d/.test(normalized)) {
178
+ normalized = `_${normalized}`;
179
+ }
180
+
181
+ return normalized;
182
+ }
package/src/types.ts CHANGED
@@ -1,64 +1,9 @@
1
- import type { ColumnDefault } from '@prisma-next/contract/types';
2
- import type { DefaultMappingOptions } from './default-mapping';
3
-
4
1
  /**
5
- * Result of resolving a native database type to a PSL type.
2
+ * Internal printer intermediates used by `astDocumentToPrintDocument`
3
+ * `serializePrintDocument`. These types are package-private and never
4
+ * exported through `src/exports/`.
6
5
  */
7
- export type PslNativeTypeAttribute = {
8
- readonly name: string;
9
- readonly args?: readonly string[];
10
- };
11
6
 
12
- export type PslTypeResolution =
13
- | {
14
- readonly pslType: string;
15
- readonly nativeType: string;
16
- readonly typeParams?: Record<string, unknown>;
17
- readonly nativeTypeAttribute?: PslNativeTypeAttribute;
18
- }
19
- | {
20
- readonly unsupported: true;
21
- readonly nativeType: string;
22
- };
23
-
24
- /**
25
- * Interface for mapping native database types to PSL scalar types.
26
- * Implementations are target-specific (e.g., Postgres, MySQL).
27
- */
28
- export interface PslTypeMap {
29
- resolve(nativeType: string, annotations?: Record<string, unknown>): PslTypeResolution;
30
- }
31
-
32
- /**
33
- * Pre-extracted enum information from target-specific annotations.
34
- */
35
- export interface EnumInfo {
36
- readonly typeNames: ReadonlySet<string>;
37
- readonly definitions: ReadonlyMap<string, readonly string[]>;
38
- }
39
-
40
- /**
41
- * Options for the PSL printer.
42
- */
43
- export interface PslPrinterOptions {
44
- readonly typeMap: PslTypeMap;
45
- readonly header?: string;
46
- readonly defaultMapping?: DefaultMappingOptions;
47
- /** Pre-extracted enum info. Required for schemas with enum types. */
48
- readonly enumInfo?: EnumInfo;
49
- /** Target-specific parser for raw default expressions (e.g., Postgres SQL dialect). */
50
- readonly parseRawDefault?: (rawDefault: string, nativeType?: string) => ColumnDefault | undefined;
51
- }
52
-
53
- /**
54
- * Normalized column default, accepted by the printer.
55
- * Re-exported for convenience.
56
- */
57
- export type { ColumnDefault };
58
-
59
- /**
60
- * A processed field ready for serialization.
61
- */
62
7
  export type PrinterField = {
63
8
  readonly name: string;
64
9
  readonly typeName: string;
@@ -72,9 +17,6 @@ export type PrinterField = {
72
17
  readonly comment?: string | undefined;
73
18
  };
74
19
 
75
- /**
76
- * A processed model ready for serialization.
77
- */
78
20
  export type PrinterModel = {
79
21
  readonly name: string;
80
22
  readonly mapName?: string | undefined;
@@ -84,36 +26,25 @@ export type PrinterModel = {
84
26
  };
85
27
 
86
28
  /**
87
- * A processed enum ready for serialization.
29
+ * A printer-internal enum value. `name` is the original storage label as it
30
+ * appeared in the AST or in the producer's input; `serializeEnum` normalises
31
+ * it for emission and emits a per-member `@map(...)` when normalisation
32
+ * changed the printed form (or when the AST already carried an explicit
33
+ * `mapName`), preserving the round-trip through the parser.
88
34
  */
35
+ export type PrinterEnumValue = {
36
+ readonly name: string;
37
+ readonly mapName?: string | undefined;
38
+ };
39
+
89
40
  export type PrinterEnum = {
90
41
  readonly name: string;
91
42
  readonly mapName?: string | undefined;
92
- readonly values: readonly string[];
43
+ readonly values: readonly PrinterEnumValue[];
93
44
  };
94
45
 
95
- /**
96
- * A named type entry for the types block.
97
- */
98
46
  export type PrinterNamedType = {
99
47
  readonly name: string;
100
48
  readonly baseType: string;
101
49
  readonly attributes: readonly string[];
102
50
  };
103
-
104
- /**
105
- * Relation field metadata used during inference.
106
- */
107
- export type RelationField = {
108
- readonly fieldName: string;
109
- readonly typeName: string;
110
- readonly referencedTableName?: string | undefined;
111
- readonly optional: boolean;
112
- readonly list: boolean;
113
- readonly relationName?: string | undefined;
114
- readonly fkName?: string | undefined;
115
- readonly fields?: readonly string[] | undefined;
116
- readonly references?: readonly string[] | undefined;
117
- readonly onDelete?: string | undefined;
118
- readonly onUpdate?: string | undefined;
119
- };
@@ -1,32 +0,0 @@
1
- import { a as DefaultMappingOptions, r as PslTypeMap, t as EnumInfo } from "./types-BmnVaMF1.mjs";
2
- import { ColumnDefault } from "@prisma-next/contract/types";
3
-
4
- //#region src/postgres-default-mapping.d.ts
5
- declare function createPostgresDefaultMapping(): DefaultMappingOptions;
6
- //#endregion
7
- //#region src/postgres-type-map.d.ts
8
- /**
9
- * Creates a Postgres-specific type map for the PSL printer.
10
- *
11
- * @param enumTypeNames - Set of native type names that are enums (from annotations.pg.storageTypes)
12
- */
13
- declare function createPostgresTypeMap(enumTypeNames?: ReadonlySet<string>): PslTypeMap;
14
- /**
15
- * Extracts enum type names and definitions from SqlSchemaIR annotations
16
- * in a single traversal.
17
- */
18
- declare function extractEnumInfo(annotations?: Record<string, unknown>): EnumInfo;
19
- /**
20
- * Extracts enum type names from the SqlSchemaIR annotations.
21
- */
22
- declare function extractEnumTypeNames(annotations?: Record<string, unknown>): ReadonlySet<string>;
23
- /**
24
- * Extracts enum definitions (name → values) from SqlSchemaIR annotations.
25
- */
26
- declare function extractEnumDefinitions(annotations?: Record<string, unknown>): ReadonlyMap<string, readonly string[]>;
27
- //#endregion
28
- //#region src/raw-default-parser.d.ts
29
- declare function parseRawDefault(rawDefault: string, nativeType?: string): ColumnDefault | undefined;
30
- //#endregion
31
- export { createPostgresDefaultMapping, createPostgresTypeMap, extractEnumDefinitions, extractEnumInfo, extractEnumTypeNames, parseRawDefault };
32
- //# sourceMappingURL=postgres.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"postgres.d.mts","names":[],"sources":["../src/postgres-default-mapping.ts","../src/postgres-type-map.ts","../src/raw-default-parser.ts"],"sourcesContent":[],"mappings":";;;;iBAUgB,4BAAA,CAAA,GAAgC;;;;;;AAAhD;;iBCkGgB,qBAAA,iBAAsC,sBAAsB;AAA5E;AAyDA;AA2BA;AAOA;iBAlCgB,eAAA,eAA8B,0BAA0B;;;AC1HxE;iBDqJgB,oBAAA,eAAmC,0BAA0B;;;;iBAO7D,sBAAA,eACA,0BACb;;;iBC9Ja,eAAA,2CAGb"}
package/dist/postgres.mjs DELETED
@@ -1,346 +0,0 @@
1
- //#region src/postgres-default-mapping.ts
2
- const POSTGRES_FUNCTION_ATTRIBUTES = { "gen_random_uuid()": "@default(dbgenerated(\"gen_random_uuid()\"))" };
3
- function formatDbGeneratedAttribute(expression) {
4
- return `@default(dbgenerated(${JSON.stringify(expression)}))`;
5
- }
6
- function createPostgresDefaultMapping() {
7
- return {
8
- functionAttributes: POSTGRES_FUNCTION_ATTRIBUTES,
9
- fallbackFunctionAttribute: formatDbGeneratedAttribute
10
- };
11
- }
12
-
13
- //#endregion
14
- //#region src/postgres-type-map.ts
15
- /**
16
- * Reverse mapping from Postgres native types to PSL scalar types.
17
- * This is the inverse of SCALAR_COLUMN_MAP in the PSL interpreter.
18
- *
19
- * Only types NOT covered by PRESERVED_NATIVE_TYPES belong here — preserved types
20
- * are checked first in createPostgresTypeMap and would shadow any duplicate entries.
21
- */
22
- const POSTGRES_TO_PSL = {
23
- text: "String",
24
- bool: "Boolean",
25
- boolean: "Boolean",
26
- int4: "Int",
27
- integer: "Int",
28
- int8: "BigInt",
29
- bigint: "BigInt",
30
- float8: "Float",
31
- "double precision": "Float",
32
- numeric: "Decimal",
33
- decimal: "Decimal",
34
- timestamptz: "DateTime",
35
- "timestamp with time zone": "DateTime",
36
- jsonb: "Json",
37
- bytea: "Bytes"
38
- };
39
- /**
40
- * Native types that require explicit `@db.*` preservation because the provider's
41
- * default scalar descriptors would otherwise collapse them to a different storage type.
42
- */
43
- const PRESERVED_NATIVE_TYPES = {
44
- "character varying": {
45
- pslType: "String",
46
- attributeName: "db.VarChar"
47
- },
48
- character: {
49
- pslType: "String",
50
- attributeName: "db.Char"
51
- },
52
- char: {
53
- pslType: "String",
54
- attributeName: "db.Char"
55
- },
56
- varchar: {
57
- pslType: "String",
58
- attributeName: "db.VarChar"
59
- },
60
- uuid: {
61
- pslType: "String",
62
- attributeName: "db.Uuid"
63
- },
64
- int2: {
65
- pslType: "Int",
66
- attributeName: "db.SmallInt"
67
- },
68
- smallint: {
69
- pslType: "Int",
70
- attributeName: "db.SmallInt"
71
- },
72
- float4: {
73
- pslType: "Float",
74
- attributeName: "db.Real"
75
- },
76
- real: {
77
- pslType: "Float",
78
- attributeName: "db.Real"
79
- },
80
- timestamp: {
81
- pslType: "DateTime",
82
- attributeName: "db.Timestamp"
83
- },
84
- "timestamp without time zone": {
85
- pslType: "DateTime",
86
- attributeName: "db.Timestamp"
87
- },
88
- date: {
89
- pslType: "DateTime",
90
- attributeName: "db.Date"
91
- },
92
- time: {
93
- pslType: "DateTime",
94
- attributeName: "db.Time"
95
- },
96
- "time without time zone": {
97
- pslType: "DateTime",
98
- attributeName: "db.Time"
99
- },
100
- timetz: {
101
- pslType: "DateTime",
102
- attributeName: "db.Timetz"
103
- },
104
- "time with time zone": {
105
- pslType: "DateTime",
106
- attributeName: "db.Timetz"
107
- },
108
- json: {
109
- pslType: "Json",
110
- attributeName: "db.Json"
111
- }
112
- };
113
- /**
114
- * Parameterized Postgres types that also need explicit `@db.*` preservation.
115
- */
116
- const PARAMETERIZED_NATIVE_TYPES = {
117
- "character varying": {
118
- pslType: "String",
119
- attributeName: "db.VarChar"
120
- },
121
- character: {
122
- pslType: "String",
123
- attributeName: "db.Char"
124
- },
125
- char: {
126
- pslType: "String",
127
- attributeName: "db.Char"
128
- },
129
- varchar: {
130
- pslType: "String",
131
- attributeName: "db.VarChar"
132
- },
133
- numeric: {
134
- pslType: "Decimal",
135
- attributeName: "db.Numeric"
136
- },
137
- timestamp: {
138
- pslType: "DateTime",
139
- attributeName: "db.Timestamp"
140
- },
141
- timestamptz: {
142
- pslType: "DateTime",
143
- attributeName: "db.Timestamptz"
144
- },
145
- time: {
146
- pslType: "DateTime",
147
- attributeName: "db.Time"
148
- },
149
- timetz: {
150
- pslType: "DateTime",
151
- attributeName: "db.Timetz"
152
- }
153
- };
154
- /**
155
- * Regex to extract base type and optional parameters from a native type string.
156
- * Examples: "character varying(255)" → ["character varying", "255"]
157
- * "numeric(10,2)" → ["numeric", "10,2"]
158
- */
159
- const PARAMETERIZED_TYPE_PATTERN = /^(.+?)\((.+)\)$/;
160
- /**
161
- * Set of enum storage type codec IDs used for detection.
162
- */
163
- const ENUM_CODEC_ID = "pg/enum@1";
164
- function getOwnMappingValue(map, key) {
165
- return Object.hasOwn(map, key) ? map[key] : void 0;
166
- }
167
- function getOwnRecordValue(map, key) {
168
- return Object.hasOwn(map, key) ? map[key] : void 0;
169
- }
170
- function createNativeTypeAttribute(name, args) {
171
- return args && args.length > 0 ? {
172
- name,
173
- args
174
- } : { name };
175
- }
176
- function splitTypeParameterList(params) {
177
- return params.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
178
- }
179
- /**
180
- * Creates a Postgres-specific type map for the PSL printer.
181
- *
182
- * @param enumTypeNames - Set of native type names that are enums (from annotations.pg.storageTypes)
183
- */
184
- function createPostgresTypeMap(enumTypeNames) {
185
- return { resolve(nativeType) {
186
- if (enumTypeNames?.has(nativeType)) return {
187
- pslType: nativeType,
188
- nativeType
189
- };
190
- const paramMatch = nativeType.match(PARAMETERIZED_TYPE_PATTERN);
191
- if (paramMatch) {
192
- const [, baseType = nativeType, params = ""] = paramMatch;
193
- const template = getOwnRecordValue(PARAMETERIZED_NATIVE_TYPES, baseType);
194
- if (template) return {
195
- pslType: template.pslType,
196
- nativeType,
197
- typeParams: {
198
- baseType,
199
- params
200
- },
201
- nativeTypeAttribute: createNativeTypeAttribute(template.attributeName, splitTypeParameterList(params))
202
- };
203
- }
204
- const preservedType = getOwnRecordValue(PRESERVED_NATIVE_TYPES, nativeType);
205
- if (preservedType) return {
206
- pslType: preservedType.pslType,
207
- nativeType,
208
- nativeTypeAttribute: createNativeTypeAttribute(preservedType.attributeName)
209
- };
210
- const pslType = getOwnMappingValue(POSTGRES_TO_PSL, nativeType);
211
- if (pslType) return {
212
- pslType,
213
- nativeType
214
- };
215
- return {
216
- unsupported: true,
217
- nativeType
218
- };
219
- } };
220
- }
221
- /**
222
- * Extracts enum type names and definitions from SqlSchemaIR annotations
223
- * in a single traversal.
224
- */
225
- function extractEnumInfo(annotations) {
226
- const storageTypes = (annotations?.["pg"])?.["storageTypes"];
227
- const typeNames = /* @__PURE__ */ new Set();
228
- const definitions = /* @__PURE__ */ new Map();
229
- if (storageTypes) {
230
- for (const [key, typeInstance] of Object.entries(storageTypes)) if (typeInstance.codecId === ENUM_CODEC_ID) {
231
- typeNames.add(key);
232
- const values = typeInstance.typeParams?.["values"];
233
- if (Array.isArray(values)) definitions.set(key, values);
234
- }
235
- }
236
- return {
237
- typeNames,
238
- definitions
239
- };
240
- }
241
- /**
242
- * Extracts enum type names from the SqlSchemaIR annotations.
243
- */
244
- function extractEnumTypeNames(annotations) {
245
- return extractEnumInfo(annotations).typeNames;
246
- }
247
- /**
248
- * Extracts enum definitions (name → values) from SqlSchemaIR annotations.
249
- */
250
- function extractEnumDefinitions(annotations) {
251
- return extractEnumInfo(annotations).definitions;
252
- }
253
-
254
- //#endregion
255
- //#region src/raw-default-parser.ts
256
- /**
257
- * Parses a raw database default expression into a normalized ColumnDefault.
258
- * When nativeType is provided, parsing can preserve Postgres semantics for
259
- * timestamp and JSON defaults that would otherwise be ambiguous.
260
- */
261
- const NEXTVAL_PATTERN = /^nextval\s*\(/i;
262
- const NOW_FUNCTION_PATTERN = /^(now\s*\(\s*\)|CURRENT_TIMESTAMP)$/i;
263
- const CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\s*\(\s*\)$/i;
264
- const TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\s+(?:with|without)\s+time\s+zone)?$/i;
265
- const TEXT_CAST_SUFFIX = /::text$/i;
266
- const NOW_LITERAL_PATTERN = /^'now'$/i;
267
- const UUID_PATTERN = /^gen_random_uuid\s*\(\s*\)$/i;
268
- const UUID_OSSP_PATTERN = /^uuid_generate_v4\s*\(\s*\)$/i;
269
- const NULL_PATTERN = /^NULL(?:::.+)?$/i;
270
- const TRUE_PATTERN = /^true$/i;
271
- const FALSE_PATTERN = /^false$/i;
272
- const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
273
- const JSON_CAST_SUFFIX = /::jsonb?$/i;
274
- const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d+\))?)?$/;
275
- function canonicalizeTimestampDefault(expr) {
276
- if (NOW_FUNCTION_PATTERN.test(expr)) return "now()";
277
- if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return "clock_timestamp()";
278
- if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return void 0;
279
- let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, "").trim();
280
- if (inner.startsWith("(") && inner.endsWith(")")) inner = inner.slice(1, -1).trim();
281
- if (NOW_FUNCTION_PATTERN.test(inner)) return "now()";
282
- if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return "clock_timestamp()";
283
- inner = inner.replace(TEXT_CAST_SUFFIX, "").trim();
284
- if (NOW_LITERAL_PATTERN.test(inner)) return "now()";
285
- }
286
- function parseRawDefault(rawDefault, nativeType) {
287
- const trimmed = rawDefault.trim();
288
- const normalizedType = nativeType?.toLowerCase();
289
- if (NEXTVAL_PATTERN.test(trimmed)) return {
290
- kind: "function",
291
- expression: "autoincrement()"
292
- };
293
- const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);
294
- if (canonicalTimestamp) return {
295
- kind: "function",
296
- expression: canonicalTimestamp
297
- };
298
- if (UUID_PATTERN.test(trimmed) || UUID_OSSP_PATTERN.test(trimmed)) return {
299
- kind: "function",
300
- expression: "gen_random_uuid()"
301
- };
302
- if (NULL_PATTERN.test(trimmed)) return {
303
- kind: "literal",
304
- value: null
305
- };
306
- if (TRUE_PATTERN.test(trimmed)) return {
307
- kind: "literal",
308
- value: true
309
- };
310
- if (FALSE_PATTERN.test(trimmed)) return {
311
- kind: "literal",
312
- value: false
313
- };
314
- if (NUMERIC_PATTERN.test(trimmed)) return {
315
- kind: "literal",
316
- value: Number(trimmed)
317
- };
318
- const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
319
- if (stringMatch?.[1] !== void 0) {
320
- const unescaped = stringMatch[1].replace(/''/g, "'");
321
- if (normalizedType === "json" || normalizedType === "jsonb") {
322
- if (JSON_CAST_SUFFIX.test(trimmed)) return {
323
- kind: "function",
324
- expression: trimmed
325
- };
326
- try {
327
- return {
328
- kind: "literal",
329
- value: JSON.parse(unescaped)
330
- };
331
- } catch {}
332
- }
333
- return {
334
- kind: "literal",
335
- value: unescaped
336
- };
337
- }
338
- return {
339
- kind: "function",
340
- expression: trimmed
341
- };
342
- }
343
-
344
- //#endregion
345
- export { createPostgresDefaultMapping, createPostgresTypeMap, extractEnumDefinitions, extractEnumInfo, extractEnumTypeNames, parseRawDefault };
346
- //# sourceMappingURL=postgres.mjs.map