@prisma-next/psl-printer 0.5.0-dev.9 → 0.6.0-dev.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.
@@ -1 +0,0 @@
1
- {"version":3,"file":"postgres.mjs","names":["POSTGRES_FUNCTION_ATTRIBUTES: Readonly<Record<string, string>>","POSTGRES_TO_PSL: Record<string, string>","PRESERVED_NATIVE_TYPES: Record<\n string,\n { readonly pslType: string; readonly attributeName: string }\n>","PARAMETERIZED_NATIVE_TYPES: Record<\n string,\n { readonly pslType: string; readonly attributeName: string }\n>"],"sources":["../src/postgres-default-mapping.ts","../src/postgres-type-map.ts","../src/raw-default-parser.ts"],"sourcesContent":["import type { DefaultMappingOptions } from './default-mapping';\n\nconst POSTGRES_FUNCTION_ATTRIBUTES: Readonly<Record<string, string>> = {\n 'gen_random_uuid()': '@default(dbgenerated(\"gen_random_uuid()\"))',\n};\n\nfunction formatDbGeneratedAttribute(expression: string): string {\n return `@default(dbgenerated(${JSON.stringify(expression)}))`;\n}\n\nexport function createPostgresDefaultMapping(): DefaultMappingOptions {\n return {\n functionAttributes: POSTGRES_FUNCTION_ATTRIBUTES,\n fallbackFunctionAttribute: formatDbGeneratedAttribute,\n };\n}\n","import type { EnumInfo, PslNativeTypeAttribute, PslTypeMap, PslTypeResolution } from './types';\n\n/**\n * Reverse mapping from Postgres native types to PSL scalar types.\n * This is the inverse of SCALAR_COLUMN_MAP in the PSL interpreter.\n *\n * Only types NOT covered by PRESERVED_NATIVE_TYPES belong here — preserved types\n * are checked first in createPostgresTypeMap and would shadow any duplicate entries.\n */\nconst POSTGRES_TO_PSL: Record<string, string> = {\n text: 'String',\n bool: 'Boolean',\n boolean: 'Boolean',\n int4: 'Int',\n integer: 'Int',\n int8: 'BigInt',\n bigint: 'BigInt',\n float8: 'Float',\n 'double precision': 'Float',\n numeric: 'Decimal',\n decimal: 'Decimal',\n timestamptz: 'DateTime',\n 'timestamp with time zone': 'DateTime',\n jsonb: 'Json',\n bytea: 'Bytes',\n};\n\n/**\n * Native types that require explicit `@db.*` preservation because the provider's\n * default scalar descriptors would otherwise collapse them to a different storage type.\n */\nconst PRESERVED_NATIVE_TYPES: Record<\n string,\n { readonly pslType: string; readonly attributeName: string }\n> = {\n 'character varying': { pslType: 'String', attributeName: 'db.VarChar' },\n character: { pslType: 'String', attributeName: 'db.Char' },\n char: { pslType: 'String', attributeName: 'db.Char' },\n varchar: { pslType: 'String', attributeName: 'db.VarChar' },\n uuid: { pslType: 'String', attributeName: 'db.Uuid' },\n int2: { pslType: 'Int', attributeName: 'db.SmallInt' },\n smallint: { pslType: 'Int', attributeName: 'db.SmallInt' },\n float4: { pslType: 'Float', attributeName: 'db.Real' },\n real: { pslType: 'Float', attributeName: 'db.Real' },\n timestamp: { pslType: 'DateTime', attributeName: 'db.Timestamp' },\n 'timestamp without time zone': { pslType: 'DateTime', attributeName: 'db.Timestamp' },\n date: { pslType: 'DateTime', attributeName: 'db.Date' },\n time: { pslType: 'DateTime', attributeName: 'db.Time' },\n 'time without time zone': { pslType: 'DateTime', attributeName: 'db.Time' },\n timetz: { pslType: 'DateTime', attributeName: 'db.Timetz' },\n 'time with time zone': { pslType: 'DateTime', attributeName: 'db.Timetz' },\n json: { pslType: 'Json', attributeName: 'db.Json' },\n};\n\n/**\n * Parameterized Postgres types that also need explicit `@db.*` preservation.\n */\nconst PARAMETERIZED_NATIVE_TYPES: Record<\n string,\n { readonly pslType: string; readonly attributeName: string }\n> = {\n 'character varying': { pslType: 'String', attributeName: 'db.VarChar' },\n character: { pslType: 'String', attributeName: 'db.Char' },\n char: { pslType: 'String', attributeName: 'db.Char' },\n varchar: { pslType: 'String', attributeName: 'db.VarChar' },\n numeric: { pslType: 'Decimal', attributeName: 'db.Numeric' },\n timestamp: { pslType: 'DateTime', attributeName: 'db.Timestamp' },\n timestamptz: { pslType: 'DateTime', attributeName: 'db.Timestamptz' },\n time: { pslType: 'DateTime', attributeName: 'db.Time' },\n timetz: { pslType: 'DateTime', attributeName: 'db.Timetz' },\n};\n\n/**\n * Regex to extract base type and optional parameters from a native type string.\n * Examples: \"character varying(255)\" → [\"character varying\", \"255\"]\n * \"numeric(10,2)\" → [\"numeric\", \"10,2\"]\n */\nconst PARAMETERIZED_TYPE_PATTERN = /^(.+?)\\((.+)\\)$/;\n\n/**\n * Set of enum storage type codec IDs used for detection.\n */\nconst ENUM_CODEC_ID = 'pg/enum@1';\n\nfunction getOwnMappingValue(map: Record<string, string>, key: string): string | undefined {\n return Object.hasOwn(map, key) ? map[key] : undefined;\n}\n\nfunction getOwnRecordValue<T>(map: Record<string, T>, key: string): T | undefined {\n return Object.hasOwn(map, key) ? map[key] : undefined;\n}\n\nfunction createNativeTypeAttribute(name: string, args?: readonly string[]): PslNativeTypeAttribute {\n return args && args.length > 0 ? { name, args } : { name };\n}\n\nfunction splitTypeParameterList(params: string): readonly string[] {\n return params\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part.length > 0);\n}\n\n/**\n * Creates a Postgres-specific type map for the PSL printer.\n *\n * @param enumTypeNames - Set of native type names that are enums (from annotations.pg.storageTypes)\n */\nexport function createPostgresTypeMap(enumTypeNames?: ReadonlySet<string>): PslTypeMap {\n return {\n resolve(nativeType: string): PslTypeResolution {\n // Check for enum types first\n if (enumTypeNames?.has(nativeType)) {\n return { pslType: nativeType, nativeType };\n }\n\n // Check for parameterized types first so we keep precision/scale/length.\n const paramMatch = nativeType.match(PARAMETERIZED_TYPE_PATTERN);\n if (paramMatch) {\n const [, baseType = nativeType, params = ''] = paramMatch;\n const template = getOwnRecordValue(PARAMETERIZED_NATIVE_TYPES, baseType);\n if (template) {\n return {\n pslType: template.pslType,\n nativeType,\n typeParams: { baseType, params },\n nativeTypeAttribute: createNativeTypeAttribute(\n template.attributeName,\n splitTypeParameterList(params),\n ),\n };\n }\n }\n\n // Non-parameterized native types that still need explicit preservation.\n const preservedType = getOwnRecordValue(PRESERVED_NATIVE_TYPES, nativeType);\n if (preservedType) {\n return {\n pslType: preservedType.pslType,\n nativeType,\n nativeTypeAttribute: createNativeTypeAttribute(preservedType.attributeName),\n };\n }\n\n // Direct scalar mapping\n const pslType = getOwnMappingValue(POSTGRES_TO_PSL, nativeType);\n if (pslType) {\n return {\n pslType,\n nativeType,\n };\n }\n\n // Unsupported type\n return { unsupported: true, nativeType };\n },\n };\n}\n\nexport type { EnumInfo };\n\n/**\n * Extracts enum type names and definitions from SqlSchemaIR annotations\n * in a single traversal.\n */\nexport function extractEnumInfo(annotations?: Record<string, unknown>): EnumInfo {\n const pgAnnotations = annotations?.['pg'] as Record<string, unknown> | undefined;\n const storageTypes = pgAnnotations?.['storageTypes'] as\n | Record<string, { codecId: string; nativeType: string; typeParams?: Record<string, unknown> }>\n | undefined;\n\n const typeNames = new Set<string>();\n const definitions = new Map<string, readonly string[]>();\n\n if (storageTypes) {\n for (const [key, typeInstance] of Object.entries(storageTypes)) {\n if (typeInstance.codecId === ENUM_CODEC_ID) {\n typeNames.add(key);\n const values = typeInstance.typeParams?.['values'];\n if (Array.isArray(values)) {\n definitions.set(key, values as string[]);\n }\n }\n }\n }\n\n return { typeNames, definitions };\n}\n\n/**\n * Extracts enum type names from the SqlSchemaIR annotations.\n */\nexport function extractEnumTypeNames(annotations?: Record<string, unknown>): ReadonlySet<string> {\n return extractEnumInfo(annotations).typeNames;\n}\n\n/**\n * Extracts enum definitions (name → values) from SqlSchemaIR annotations.\n */\nexport function extractEnumDefinitions(\n annotations?: Record<string, unknown>,\n): ReadonlyMap<string, readonly string[]> {\n return extractEnumInfo(annotations).definitions;\n}\n","import type { ColumnDefault } from '@prisma-next/contract/types';\n\n/**\n * Parses a raw database default expression into a normalized ColumnDefault.\n * When nativeType is provided, parsing can preserve Postgres semantics for\n * timestamp and JSON defaults that would otherwise be ambiguous.\n */\n\nconst NEXTVAL_PATTERN = /^nextval\\s*\\(/i;\nconst NOW_FUNCTION_PATTERN = /^(now\\s*\\(\\s*\\)|CURRENT_TIMESTAMP)$/i;\nconst CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\\s*\\(\\s*\\)$/i;\nconst TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\\s+(?:with|without)\\s+time\\s+zone)?$/i;\nconst TEXT_CAST_SUFFIX = /::text$/i;\nconst NOW_LITERAL_PATTERN = /^'now'$/i;\nconst UUID_PATTERN = /^gen_random_uuid\\s*\\(\\s*\\)$/i;\nconst UUID_OSSP_PATTERN = /^uuid_generate_v4\\s*\\(\\s*\\)$/i;\nconst NULL_PATTERN = /^NULL(?:::.+)?$/i;\nconst TRUE_PATTERN = /^true$/i;\nconst FALSE_PATTERN = /^false$/i;\nconst NUMERIC_PATTERN = /^-?\\d+(\\.\\d+)?$/;\nconst JSON_CAST_SUFFIX = /::jsonb?$/i;\nconst STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:\"[^\"]+\"|[\\w\\s]+)(?:\\(\\d+\\))?)?$/;\n\nfunction canonicalizeTimestampDefault(expr: string): string | undefined {\n if (NOW_FUNCTION_PATTERN.test(expr)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return 'clock_timestamp()';\n\n if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return undefined;\n\n let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, '').trim();\n if (inner.startsWith('(') && inner.endsWith(')')) {\n inner = inner.slice(1, -1).trim();\n }\n\n if (NOW_FUNCTION_PATTERN.test(inner)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return 'clock_timestamp()';\n\n inner = inner.replace(TEXT_CAST_SUFFIX, '').trim();\n if (NOW_LITERAL_PATTERN.test(inner)) return 'now()';\n\n return undefined;\n}\n\nexport function parseRawDefault(\n rawDefault: string,\n nativeType?: string,\n): ColumnDefault | undefined {\n const trimmed = rawDefault.trim();\n const normalizedType = nativeType?.toLowerCase();\n\n if (NEXTVAL_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'autoincrement()' };\n }\n\n const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);\n if (canonicalTimestamp) {\n return { kind: 'function', expression: canonicalTimestamp };\n }\n\n if (UUID_PATTERN.test(trimmed) || UUID_OSSP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n if (NULL_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: null };\n }\n\n if (TRUE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: true };\n }\n\n if (FALSE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: false };\n }\n\n if (NUMERIC_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: Number(trimmed) };\n }\n\n const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);\n if (stringMatch?.[1] !== undefined) {\n const unescaped = stringMatch[1].replace(/''/g, \"'\");\n if (normalizedType === 'json' || normalizedType === 'jsonb') {\n if (JSON_CAST_SUFFIX.test(trimmed)) {\n return { kind: 'function', expression: trimmed };\n }\n try {\n return { kind: 'literal', value: JSON.parse(unescaped) };\n } catch {\n // Fall through to the string form for malformed/non-JSON values.\n }\n }\n return { kind: 'literal', value: unescaped };\n }\n\n // Unrecognized — return as function with raw expression\n return { kind: 'function', expression: trimmed };\n}\n"],"mappings":"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"}
@@ -1,54 +0,0 @@
1
- import { ColumnDefault, ColumnDefault as ColumnDefault$1 } from "@prisma-next/contract/types";
2
-
3
- //#region src/default-mapping.d.ts
4
- interface DefaultMappingOptions {
5
- readonly functionAttributes?: Readonly<Record<string, string>>;
6
- readonly fallbackFunctionAttribute?: ((expression: string) => string | undefined) | undefined;
7
- }
8
- //#endregion
9
- //#region src/types.d.ts
10
- /**
11
- * Result of resolving a native database type to a PSL type.
12
- */
13
- type PslNativeTypeAttribute = {
14
- readonly name: string;
15
- readonly args?: readonly string[];
16
- };
17
- type PslTypeResolution = {
18
- readonly pslType: string;
19
- readonly nativeType: string;
20
- readonly typeParams?: Record<string, unknown>;
21
- readonly nativeTypeAttribute?: PslNativeTypeAttribute;
22
- } | {
23
- readonly unsupported: true;
24
- readonly nativeType: string;
25
- };
26
- /**
27
- * Interface for mapping native database types to PSL scalar types.
28
- * Implementations are target-specific (e.g., Postgres, MySQL).
29
- */
30
- interface PslTypeMap {
31
- resolve(nativeType: string, annotations?: Record<string, unknown>): PslTypeResolution;
32
- }
33
- /**
34
- * Pre-extracted enum information from target-specific annotations.
35
- */
36
- interface EnumInfo {
37
- readonly typeNames: ReadonlySet<string>;
38
- readonly definitions: ReadonlyMap<string, readonly string[]>;
39
- }
40
- /**
41
- * Options for the PSL printer.
42
- */
43
- 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$1 | undefined;
51
- }
52
- //#endregion
53
- export { DefaultMappingOptions as a, PslTypeResolution as i, PslPrinterOptions as n, PslTypeMap as r, EnumInfo as t };
54
- //# sourceMappingURL=types-BmnVaMF1.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-BmnVaMF1.d.mts","names":[],"sources":["../src/default-mapping.ts","../src/types.ts"],"sourcesContent":[],"mappings":";;;UAOiB,qBAAA;gCACe,SAAS;EADxB,SAAA,yBAAqB,CAAA,EACG,CAAA,CAAA,UAAT,EAAA,MAAQ,EAAA,GAAA,MAAA,GAAA,SAAA,CAAA,GAAA,SAAA;;;;;AADxC;;KCDY,sBAAA;;EAAA,SAAA,IAAA,CAAA,EAAA,SAAsB,MAAA,EAAA;AAKlC,CAAA;AAgBiB,KAhBL,iBAAA,GAiBgC;EAM3B,SAAA,OAAQ,EAAA,MACH;EAOL,SAAA,UAAA,EAAiB,MAAA;EACd,SAAA,UAAA,CAAA,EA5BQ,MA4BR,CAAA,MAAA,EAAA,OAAA,CAAA;EAEQ,SAAA,mBAAA,CAAA,EA7BS,sBA6BT;CAEN,GAAA;EAEoD,SAAA,WAAA,EAAA,IAAA;EAAa,SAAA,UAAA,EAAA,MAAA;;;;;;UAtBtE,UAAA;4CAC2B,0BAA0B;;;;;UAMrD,QAAA;sBACK;wBACE;;;;;UAMP,iBAAA;oBACG;;4BAEQ;;sBAEN;;0EAEoD"}
@@ -1,66 +0,0 @@
1
- import type { ColumnDefault } from '@prisma-next/contract/types';
2
-
3
- const DEFAULT_FUNCTION_ATTRIBUTES: Readonly<Record<string, string>> = {
4
- 'autoincrement()': '@default(autoincrement())',
5
- 'now()': '@default(now())',
6
- };
7
-
8
- export interface DefaultMappingOptions {
9
- readonly functionAttributes?: Readonly<Record<string, string>>;
10
- readonly fallbackFunctionAttribute?: ((expression: string) => string | undefined) | undefined;
11
- }
12
-
13
- /**
14
- * Result of mapping a ColumnDefault to a PSL @default expression.
15
- */
16
- export type DefaultMappingResult = { readonly attribute: string } | { readonly comment: string };
17
-
18
- /**
19
- * Maps a normalized ColumnDefault to a PSL @default(...) attribute string,
20
- * or a comment for unrecognized expressions.
21
- */
22
- export function mapDefault(
23
- columnDefault: ColumnDefault,
24
- options?: DefaultMappingOptions,
25
- ): DefaultMappingResult {
26
- switch (columnDefault.kind) {
27
- case 'literal':
28
- return { attribute: `@default(${formatLiteralValue(columnDefault.value)})` };
29
- case 'function': {
30
- const attribute =
31
- options?.functionAttributes?.[columnDefault.expression] ??
32
- DEFAULT_FUNCTION_ATTRIBUTES[columnDefault.expression] ??
33
- options?.fallbackFunctionAttribute?.(columnDefault.expression);
34
- return attribute
35
- ? { attribute }
36
- : { comment: `// Raw default: ${columnDefault.expression.replace(/[\r\n]+/g, ' ')}` };
37
- }
38
- }
39
- }
40
-
41
- /**
42
- * Formats a literal value for use in @default(...).
43
- */
44
- function formatLiteralValue(value: unknown): string {
45
- if (value === null) {
46
- return 'null';
47
- }
48
-
49
- switch (typeof value) {
50
- case 'boolean':
51
- case 'number':
52
- return String(value);
53
- case 'string':
54
- return quoteString(value);
55
- default:
56
- return quoteString(JSON.stringify(value));
57
- }
58
- }
59
-
60
- function quoteString(str: string): string {
61
- return `"${escapeString(str)}"`;
62
- }
63
-
64
- function escapeString(str: string): string {
65
- return JSON.stringify(str).slice(1, -1);
66
- }
@@ -1,8 +0,0 @@
1
- export { createPostgresDefaultMapping } from '../postgres-default-mapping';
2
- export {
3
- createPostgresTypeMap,
4
- extractEnumDefinitions,
5
- extractEnumInfo,
6
- extractEnumTypeNames,
7
- } from '../postgres-type-map';
8
- export { parseRawDefault } from '../raw-default-parser';
@@ -1,234 +0,0 @@
1
- /**
2
- * PSL reserved words that cannot be used as identifiers without escaping.
3
- */
4
- const PSL_RESERVED_WORDS = new Set(['model', 'enum', 'types', 'type', 'generator', 'datasource']);
5
-
6
- const IDENTIFIER_PART_PATTERN = /[A-Za-z0-9]+/g;
7
-
8
- type NameResult = {
9
- readonly name: string;
10
- readonly map?: string;
11
- };
12
-
13
- /**
14
- * Checks whether normalization needs to split or sanitize the identifier.
15
- */
16
- function hasSeparators(input: string): boolean {
17
- return /[^A-Za-z0-9]/.test(input);
18
- }
19
-
20
- function extractIdentifierParts(input: string): string[] {
21
- return input.match(IDENTIFIER_PART_PATTERN) ?? [];
22
- }
23
-
24
- function createSyntheticIdentifier(input: string): string {
25
- let hash = 2166136261;
26
-
27
- for (const char of input) {
28
- hash ^= char.codePointAt(0) ?? 0;
29
- hash = Math.imul(hash, 16777619);
30
- }
31
-
32
- return `x${(hash >>> 0).toString(16)}`;
33
- }
34
-
35
- function sanitizeIdentifierCharacters(input: string): string {
36
- const sanitized = input.replace(/[^\w]/g, '');
37
- return sanitized.length > 0 ? sanitized : createSyntheticIdentifier(input);
38
- }
39
-
40
- function capitalize(word: string): string {
41
- return word.charAt(0).toUpperCase() + word.slice(1);
42
- }
43
-
44
- /**
45
- * Converts a normalized identifier to PascalCase.
46
- */
47
- function snakeToPascalCase(input: string): string {
48
- const parts = extractIdentifierParts(input);
49
- if (parts.length === 0) {
50
- return capitalize(sanitizeIdentifierCharacters(input));
51
- }
52
- return parts.map(capitalize).join('');
53
- }
54
-
55
- /**
56
- * Converts a normalized identifier to camelCase.
57
- */
58
- function snakeToCamelCase(input: string): string {
59
- const parts = extractIdentifierParts(input);
60
- if (parts.length === 0) {
61
- return sanitizeIdentifierCharacters(input);
62
- }
63
- const [firstPart = input, ...rest] = parts;
64
- return firstPart.charAt(0).toLowerCase() + firstPart.slice(1) + rest.map(capitalize).join('');
65
- }
66
-
67
- /**
68
- * Checks if a name needs escaping (reserved word or starts with digit).
69
- */
70
- function needsEscaping(name: string): boolean {
71
- return PSL_RESERVED_WORDS.has(name.toLowerCase()) || /^\d/.test(name);
72
- }
73
-
74
- /**
75
- * Escapes a name by prefixing with underscore.
76
- */
77
- function escapeName(name: string): string {
78
- return `_${name}`;
79
- }
80
-
81
- function escapeIfNeeded(name: string): string {
82
- return needsEscaping(name) ? escapeName(name) : name;
83
- }
84
-
85
- /**
86
- * Converts a database table name to a PSL model name.
87
- * snake_case → PascalCase, with @@map("db_name") when the name was transformed.
88
- * Names that are already PascalCase (no separators, start with uppercase) are kept as-is.
89
- */
90
- export function toModelName(tableName: string): NameResult {
91
- let name: string;
92
-
93
- if (hasSeparators(tableName)) {
94
- name = snakeToPascalCase(tableName);
95
- } else {
96
- // Ensure first character is uppercase
97
- name = tableName.charAt(0).toUpperCase() + tableName.slice(1);
98
- }
99
-
100
- if (needsEscaping(name)) {
101
- const escaped = escapeName(name);
102
- return { name: escaped, map: tableName };
103
- }
104
-
105
- if (name !== tableName) {
106
- return { name, map: tableName };
107
- }
108
-
109
- return { name };
110
- }
111
-
112
- /**
113
- * Converts a database column name to a PSL field name.
114
- * snake_case → camelCase, with @map("db_col") when the name was transformed.
115
- * Names that are already camelCase (no separators, start with lowercase) are kept as-is.
116
- */
117
- export function toFieldName(columnName: string): NameResult {
118
- let name: string;
119
-
120
- if (hasSeparators(columnName)) {
121
- name = snakeToCamelCase(columnName);
122
- } else {
123
- // Ensure first character is lowercase
124
- name = columnName.charAt(0).toLowerCase() + columnName.slice(1);
125
- }
126
-
127
- if (needsEscaping(name)) {
128
- const escaped = escapeName(name);
129
- return { name: escaped, map: columnName };
130
- }
131
-
132
- if (name !== columnName) {
133
- return { name, map: columnName };
134
- }
135
-
136
- return { name };
137
- }
138
-
139
- /**
140
- * Converts a Postgres enum type name to a PSL enum name.
141
- * snake_case → PascalCase, with @@map when transformed.
142
- */
143
- export function toEnumName(pgTypeName: string): NameResult {
144
- let name: string;
145
-
146
- if (hasSeparators(pgTypeName)) {
147
- name = snakeToPascalCase(pgTypeName);
148
- } else {
149
- name = pgTypeName.charAt(0).toUpperCase() + pgTypeName.slice(1);
150
- }
151
-
152
- if (needsEscaping(name)) {
153
- const escaped = escapeName(name);
154
- return { name: escaped, map: pgTypeName };
155
- }
156
-
157
- if (name !== pgTypeName) {
158
- return { name, map: pgTypeName };
159
- }
160
-
161
- return { name };
162
- }
163
-
164
- /**
165
- * Simple English pluralization for back-relation field names.
166
- * Handles: s→ses, y→ies, default→s
167
- */
168
- export function pluralize(word: string): string {
169
- if (
170
- word.endsWith('s') ||
171
- word.endsWith('x') ||
172
- word.endsWith('z') ||
173
- word.endsWith('ch') ||
174
- word.endsWith('sh')
175
- ) {
176
- return `${word}es`;
177
- }
178
- if (word.endsWith('y') && !/[aeiou]y$/i.test(word)) {
179
- return `${word.slice(0, -1)}ies`;
180
- }
181
- return `${word}s`;
182
- }
183
-
184
- /**
185
- * Derives a relation field name from FK column names.
186
- *
187
- * For single-column FKs: strip _id/Id suffix, camelCase the result.
188
- * For composite FKs: use the referenced table name (lowercased, camelCased).
189
- */
190
- export function deriveRelationFieldName(
191
- fkColumns: readonly string[],
192
- referencedTableName: string,
193
- ): string {
194
- if (fkColumns.length === 1) {
195
- const [col = referencedTableName] = fkColumns;
196
- // Strip common FK suffixes
197
- const stripped = col.replace(/_id$/i, '').replace(/Id$/, '');
198
-
199
- if (stripped.length > 0 && stripped !== col) {
200
- return escapeIfNeeded(snakeToCamelCase(stripped));
201
- }
202
- // If stripping didn't change anything, use the referenced table name
203
- return escapeIfNeeded(snakeToCamelCase(referencedTableName));
204
- }
205
-
206
- // Composite FK: use referenced table name
207
- return escapeIfNeeded(snakeToCamelCase(referencedTableName));
208
- }
209
-
210
- /**
211
- * Derives a back-relation field name.
212
- * For 1:N: pluralize the child model name (lowercased first char).
213
- * For 1:1: lowercase first char of child model name.
214
- */
215
- export function deriveBackRelationFieldName(childModelName: string, isOneToOne: boolean): string {
216
- const base = childModelName.charAt(0).toLowerCase() + childModelName.slice(1);
217
- return isOneToOne ? base : pluralize(base);
218
- }
219
-
220
- /**
221
- * Converts a column name to a named type name for the types block.
222
- * E.g., column "email" with type "character varying(255)" → "Email"
223
- */
224
- export function toNamedTypeName(columnName: string): string {
225
- let name: string;
226
-
227
- if (hasSeparators(columnName)) {
228
- name = snakeToPascalCase(columnName);
229
- } else {
230
- name = columnName.charAt(0).toUpperCase() + columnName.slice(1);
231
- }
232
-
233
- return escapeIfNeeded(name);
234
- }
@@ -1,16 +0,0 @@
1
- import type { DefaultMappingOptions } from './default-mapping';
2
-
3
- const POSTGRES_FUNCTION_ATTRIBUTES: Readonly<Record<string, string>> = {
4
- 'gen_random_uuid()': '@default(dbgenerated("gen_random_uuid()"))',
5
- };
6
-
7
- function formatDbGeneratedAttribute(expression: string): string {
8
- return `@default(dbgenerated(${JSON.stringify(expression)}))`;
9
- }
10
-
11
- export function createPostgresDefaultMapping(): DefaultMappingOptions {
12
- return {
13
- functionAttributes: POSTGRES_FUNCTION_ATTRIBUTES,
14
- fallbackFunctionAttribute: formatDbGeneratedAttribute,
15
- };
16
- }
@@ -1,204 +0,0 @@
1
- import type { EnumInfo, PslNativeTypeAttribute, PslTypeMap, PslTypeResolution } from './types';
2
-
3
- /**
4
- * Reverse mapping from Postgres native types to PSL scalar types.
5
- * This is the inverse of SCALAR_COLUMN_MAP in the PSL interpreter.
6
- *
7
- * Only types NOT covered by PRESERVED_NATIVE_TYPES belong here — preserved types
8
- * are checked first in createPostgresTypeMap and would shadow any duplicate entries.
9
- */
10
- const POSTGRES_TO_PSL: Record<string, string> = {
11
- text: 'String',
12
- bool: 'Boolean',
13
- boolean: 'Boolean',
14
- int4: 'Int',
15
- integer: 'Int',
16
- int8: 'BigInt',
17
- bigint: 'BigInt',
18
- float8: 'Float',
19
- 'double precision': 'Float',
20
- numeric: 'Decimal',
21
- decimal: 'Decimal',
22
- timestamptz: 'DateTime',
23
- 'timestamp with time zone': 'DateTime',
24
- jsonb: 'Json',
25
- bytea: 'Bytes',
26
- };
27
-
28
- /**
29
- * Native types that require explicit `@db.*` preservation because the provider's
30
- * default scalar descriptors would otherwise collapse them to a different storage type.
31
- */
32
- const PRESERVED_NATIVE_TYPES: Record<
33
- string,
34
- { readonly pslType: string; readonly attributeName: string }
35
- > = {
36
- 'character varying': { pslType: 'String', attributeName: 'db.VarChar' },
37
- character: { pslType: 'String', attributeName: 'db.Char' },
38
- char: { pslType: 'String', attributeName: 'db.Char' },
39
- varchar: { pslType: 'String', attributeName: 'db.VarChar' },
40
- uuid: { pslType: 'String', attributeName: 'db.Uuid' },
41
- int2: { pslType: 'Int', attributeName: 'db.SmallInt' },
42
- smallint: { pslType: 'Int', attributeName: 'db.SmallInt' },
43
- float4: { pslType: 'Float', attributeName: 'db.Real' },
44
- real: { pslType: 'Float', attributeName: 'db.Real' },
45
- timestamp: { pslType: 'DateTime', attributeName: 'db.Timestamp' },
46
- 'timestamp without time zone': { pslType: 'DateTime', attributeName: 'db.Timestamp' },
47
- date: { pslType: 'DateTime', attributeName: 'db.Date' },
48
- time: { pslType: 'DateTime', attributeName: 'db.Time' },
49
- 'time without time zone': { pslType: 'DateTime', attributeName: 'db.Time' },
50
- timetz: { pslType: 'DateTime', attributeName: 'db.Timetz' },
51
- 'time with time zone': { pslType: 'DateTime', attributeName: 'db.Timetz' },
52
- json: { pslType: 'Json', attributeName: 'db.Json' },
53
- };
54
-
55
- /**
56
- * Parameterized Postgres types that also need explicit `@db.*` preservation.
57
- */
58
- const PARAMETERIZED_NATIVE_TYPES: Record<
59
- string,
60
- { readonly pslType: string; readonly attributeName: string }
61
- > = {
62
- 'character varying': { pslType: 'String', attributeName: 'db.VarChar' },
63
- character: { pslType: 'String', attributeName: 'db.Char' },
64
- char: { pslType: 'String', attributeName: 'db.Char' },
65
- varchar: { pslType: 'String', attributeName: 'db.VarChar' },
66
- numeric: { pslType: 'Decimal', attributeName: 'db.Numeric' },
67
- timestamp: { pslType: 'DateTime', attributeName: 'db.Timestamp' },
68
- timestamptz: { pslType: 'DateTime', attributeName: 'db.Timestamptz' },
69
- time: { pslType: 'DateTime', attributeName: 'db.Time' },
70
- timetz: { pslType: 'DateTime', attributeName: 'db.Timetz' },
71
- };
72
-
73
- /**
74
- * Regex to extract base type and optional parameters from a native type string.
75
- * Examples: "character varying(255)" → ["character varying", "255"]
76
- * "numeric(10,2)" → ["numeric", "10,2"]
77
- */
78
- const PARAMETERIZED_TYPE_PATTERN = /^(.+?)\((.+)\)$/;
79
-
80
- /**
81
- * Set of enum storage type codec IDs used for detection.
82
- */
83
- const ENUM_CODEC_ID = 'pg/enum@1';
84
-
85
- function getOwnMappingValue(map: Record<string, string>, key: string): string | undefined {
86
- return Object.hasOwn(map, key) ? map[key] : undefined;
87
- }
88
-
89
- function getOwnRecordValue<T>(map: Record<string, T>, key: string): T | undefined {
90
- return Object.hasOwn(map, key) ? map[key] : undefined;
91
- }
92
-
93
- function createNativeTypeAttribute(name: string, args?: readonly string[]): PslNativeTypeAttribute {
94
- return args && args.length > 0 ? { name, args } : { name };
95
- }
96
-
97
- function splitTypeParameterList(params: string): readonly string[] {
98
- return params
99
- .split(',')
100
- .map((part) => part.trim())
101
- .filter((part) => part.length > 0);
102
- }
103
-
104
- /**
105
- * Creates a Postgres-specific type map for the PSL printer.
106
- *
107
- * @param enumTypeNames - Set of native type names that are enums (from annotations.pg.storageTypes)
108
- */
109
- export function createPostgresTypeMap(enumTypeNames?: ReadonlySet<string>): PslTypeMap {
110
- return {
111
- resolve(nativeType: string): PslTypeResolution {
112
- // Check for enum types first
113
- if (enumTypeNames?.has(nativeType)) {
114
- return { pslType: nativeType, nativeType };
115
- }
116
-
117
- // Check for parameterized types first so we keep precision/scale/length.
118
- const paramMatch = nativeType.match(PARAMETERIZED_TYPE_PATTERN);
119
- if (paramMatch) {
120
- const [, baseType = nativeType, params = ''] = paramMatch;
121
- const template = getOwnRecordValue(PARAMETERIZED_NATIVE_TYPES, baseType);
122
- if (template) {
123
- return {
124
- pslType: template.pslType,
125
- nativeType,
126
- typeParams: { baseType, params },
127
- nativeTypeAttribute: createNativeTypeAttribute(
128
- template.attributeName,
129
- splitTypeParameterList(params),
130
- ),
131
- };
132
- }
133
- }
134
-
135
- // Non-parameterized native types that still need explicit preservation.
136
- const preservedType = getOwnRecordValue(PRESERVED_NATIVE_TYPES, nativeType);
137
- if (preservedType) {
138
- return {
139
- pslType: preservedType.pslType,
140
- nativeType,
141
- nativeTypeAttribute: createNativeTypeAttribute(preservedType.attributeName),
142
- };
143
- }
144
-
145
- // Direct scalar mapping
146
- const pslType = getOwnMappingValue(POSTGRES_TO_PSL, nativeType);
147
- if (pslType) {
148
- return {
149
- pslType,
150
- nativeType,
151
- };
152
- }
153
-
154
- // Unsupported type
155
- return { unsupported: true, nativeType };
156
- },
157
- };
158
- }
159
-
160
- export type { EnumInfo };
161
-
162
- /**
163
- * Extracts enum type names and definitions from SqlSchemaIR annotations
164
- * in a single traversal.
165
- */
166
- export function extractEnumInfo(annotations?: Record<string, unknown>): EnumInfo {
167
- const pgAnnotations = annotations?.['pg'] as Record<string, unknown> | undefined;
168
- const storageTypes = pgAnnotations?.['storageTypes'] as
169
- | Record<string, { codecId: string; nativeType: string; typeParams?: Record<string, unknown> }>
170
- | undefined;
171
-
172
- const typeNames = new Set<string>();
173
- const definitions = new Map<string, readonly string[]>();
174
-
175
- if (storageTypes) {
176
- for (const [key, typeInstance] of Object.entries(storageTypes)) {
177
- if (typeInstance.codecId === ENUM_CODEC_ID) {
178
- typeNames.add(key);
179
- const values = typeInstance.typeParams?.['values'];
180
- if (Array.isArray(values)) {
181
- definitions.set(key, values as string[]);
182
- }
183
- }
184
- }
185
- }
186
-
187
- return { typeNames, definitions };
188
- }
189
-
190
- /**
191
- * Extracts enum type names from the SqlSchemaIR annotations.
192
- */
193
- export function extractEnumTypeNames(annotations?: Record<string, unknown>): ReadonlySet<string> {
194
- return extractEnumInfo(annotations).typeNames;
195
- }
196
-
197
- /**
198
- * Extracts enum definitions (name → values) from SqlSchemaIR annotations.
199
- */
200
- export function extractEnumDefinitions(
201
- annotations?: Record<string, unknown>,
202
- ): ReadonlyMap<string, readonly string[]> {
203
- return extractEnumInfo(annotations).definitions;
204
- }