ormbridge 0.9.0 → 0.11.0

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 (146) hide show
  1. package/README.md +19 -18
  2. package/dist/cliRunner.js +4 -4
  3. package/dist/cliRunner.js.map +1 -1
  4. package/dist/config.d.ts +2 -2
  5. package/dist/convert.js +30 -1
  6. package/dist/convert.js.map +1 -1
  7. package/dist/emitters/cockroach.d.ts +33 -0
  8. package/dist/emitters/cockroach.js +81 -0
  9. package/dist/emitters/cockroach.js.map +1 -0
  10. package/dist/emitters/doctrine.js +11 -0
  11. package/dist/emitters/doctrine.js.map +1 -1
  12. package/dist/emitters/drizzle.js +39 -4
  13. package/dist/emitters/drizzle.js.map +1 -1
  14. package/dist/emitters/efcore.js +18 -1
  15. package/dist/emitters/efcore.js.map +1 -1
  16. package/dist/emitters/efcoreColumns.js +23 -2
  17. package/dist/emitters/efcoreColumns.js.map +1 -1
  18. package/dist/emitters/gorm.js +20 -1
  19. package/dist/emitters/gorm.js.map +1 -1
  20. package/dist/emitters/jpa.d.ts +36 -0
  21. package/dist/emitters/jpa.js +262 -0
  22. package/dist/emitters/jpa.js.map +1 -0
  23. package/dist/emitters/jpaColumns.d.ts +27 -0
  24. package/dist/emitters/jpaColumns.js +342 -0
  25. package/dist/emitters/jpaColumns.js.map +1 -0
  26. package/dist/emitters/jpaDefaults.d.ts +24 -0
  27. package/dist/emitters/jpaDefaults.js +223 -0
  28. package/dist/emitters/jpaDefaults.js.map +1 -0
  29. package/dist/emitters/jpaEnums.d.ts +11 -0
  30. package/dist/emitters/jpaEnums.js +134 -0
  31. package/dist/emitters/jpaEnums.js.map +1 -0
  32. package/dist/emitters/jpaFormat.d.ts +16 -0
  33. package/dist/emitters/jpaFormat.js +73 -0
  34. package/dist/emitters/jpaFormat.js.map +1 -0
  35. package/dist/emitters/jpaKeys.d.ts +25 -0
  36. package/dist/emitters/jpaKeys.js +110 -0
  37. package/dist/emitters/jpaKeys.js.map +1 -0
  38. package/dist/emitters/jpaNames.d.ts +26 -0
  39. package/dist/emitters/jpaNames.js +234 -0
  40. package/dist/emitters/jpaNames.js.map +1 -0
  41. package/dist/emitters/jpaRelations.d.ts +41 -0
  42. package/dist/emitters/jpaRelations.js +304 -0
  43. package/dist/emitters/jpaRelations.js.map +1 -0
  44. package/dist/emitters/jpaRender.d.ts +10 -0
  45. package/dist/emitters/jpaRender.js +81 -0
  46. package/dist/emitters/jpaRender.js.map +1 -0
  47. package/dist/emitters/jpaScalars.d.ts +32 -0
  48. package/dist/emitters/jpaScalars.js +201 -0
  49. package/dist/emitters/jpaScalars.js.map +1 -0
  50. package/dist/emitters/jpaTable.d.ts +10 -0
  51. package/dist/emitters/jpaTable.js +109 -0
  52. package/dist/emitters/jpaTable.js.map +1 -0
  53. package/dist/emitters/jpaTypes.d.ts +85 -0
  54. package/dist/emitters/jpaTypes.js +36 -0
  55. package/dist/emitters/jpaTypes.js.map +1 -0
  56. package/dist/emitters/laravel.js +11 -0
  57. package/dist/emitters/laravel.js.map +1 -1
  58. package/dist/emitters/prisma.d.ts +1 -1
  59. package/dist/emitters/prisma.js +47 -5
  60. package/dist/emitters/prisma.js.map +1 -1
  61. package/dist/emitters/sequelize.js +82 -6
  62. package/dist/emitters/sequelize.js.map +1 -1
  63. package/dist/emitters/sqlClickhouse.d.ts +43 -0
  64. package/dist/emitters/sqlClickhouse.js +265 -0
  65. package/dist/emitters/sqlClickhouse.js.map +1 -0
  66. package/dist/emitters/sqlClickhouseIndexes.d.ts +3 -0
  67. package/dist/emitters/sqlClickhouseIndexes.js +98 -0
  68. package/dist/emitters/sqlClickhouseIndexes.js.map +1 -0
  69. package/dist/emitters/sqlClickhouseTypes.d.ts +39 -0
  70. package/dist/emitters/sqlClickhouseTypes.js +360 -0
  71. package/dist/emitters/sqlClickhouseTypes.js.map +1 -0
  72. package/dist/emitters/sqlDdl.d.ts +29 -1
  73. package/dist/emitters/sqlDdl.js +141 -21
  74. package/dist/emitters/sqlDdl.js.map +1 -1
  75. package/dist/emitters/sqlalchemy.d.ts +7 -1
  76. package/dist/emitters/sqlalchemy.js +39 -0
  77. package/dist/emitters/sqlalchemy.js.map +1 -1
  78. package/dist/emitters/typeorm.js +44 -9
  79. package/dist/emitters/typeorm.js.map +1 -1
  80. package/dist/formats.d.ts +5 -2
  81. package/dist/formats.js +36 -1
  82. package/dist/formats.js.map +1 -1
  83. package/dist/index.d.ts +4 -0
  84. package/dist/index.js +2 -0
  85. package/dist/index.js.map +1 -1
  86. package/dist/io.js +27 -1
  87. package/dist/io.js.map +1 -1
  88. package/dist/parsers/javaSyntax.d.ts +120 -0
  89. package/dist/parsers/javaSyntax.js +304 -0
  90. package/dist/parsers/javaSyntax.js.map +1 -0
  91. package/dist/parsers/javaValues.d.ts +5 -0
  92. package/dist/parsers/javaValues.js +187 -0
  93. package/dist/parsers/javaValues.js.map +1 -0
  94. package/dist/parsers/jpa.d.ts +17 -0
  95. package/dist/parsers/jpa.js +131 -0
  96. package/dist/parsers/jpa.js.map +1 -0
  97. package/dist/parsers/jpaAnnotations.d.ts +46 -0
  98. package/dist/parsers/jpaAnnotations.js +156 -0
  99. package/dist/parsers/jpaAnnotations.js.map +1 -0
  100. package/dist/parsers/jpaBuild.d.ts +4 -0
  101. package/dist/parsers/jpaBuild.js +297 -0
  102. package/dist/parsers/jpaBuild.js.map +1 -0
  103. package/dist/parsers/jpaClasses.d.ts +27 -0
  104. package/dist/parsers/jpaClasses.js +257 -0
  105. package/dist/parsers/jpaClasses.js.map +1 -0
  106. package/dist/parsers/jpaCollections.d.ts +12 -0
  107. package/dist/parsers/jpaCollections.js +106 -0
  108. package/dist/parsers/jpaCollections.js.map +1 -0
  109. package/dist/parsers/jpaColumns.d.ts +26 -0
  110. package/dist/parsers/jpaColumns.js +361 -0
  111. package/dist/parsers/jpaColumns.js.map +1 -0
  112. package/dist/parsers/jpaEntities.d.ts +9 -0
  113. package/dist/parsers/jpaEntities.js +181 -0
  114. package/dist/parsers/jpaEntities.js.map +1 -0
  115. package/dist/parsers/jpaIndexes.d.ts +12 -0
  116. package/dist/parsers/jpaIndexes.js +87 -0
  117. package/dist/parsers/jpaIndexes.js.map +1 -0
  118. package/dist/parsers/jpaJoins.d.ts +68 -0
  119. package/dist/parsers/jpaJoins.js +131 -0
  120. package/dist/parsers/jpaJoins.js.map +1 -0
  121. package/dist/parsers/jpaModel.d.ts +73 -0
  122. package/dist/parsers/jpaModel.js +2 -0
  123. package/dist/parsers/jpaModel.js.map +1 -0
  124. package/dist/parsers/jpaNotes.d.ts +20 -0
  125. package/dist/parsers/jpaNotes.js +138 -0
  126. package/dist/parsers/jpaNotes.js.map +1 -0
  127. package/dist/parsers/jpaRelations.d.ts +4 -0
  128. package/dist/parsers/jpaRelations.js +242 -0
  129. package/dist/parsers/jpaRelations.js.map +1 -0
  130. package/dist/parsers/jpaTypes.d.ts +23 -0
  131. package/dist/parsers/jpaTypes.js +232 -0
  132. package/dist/parsers/jpaTypes.js.map +1 -0
  133. package/dist/parsers/prisma.js +9 -1
  134. package/dist/parsers/prisma.js.map +1 -1
  135. package/dist/parsers/sqlDdl.js +40 -2
  136. package/dist/parsers/sqlDdl.js.map +1 -1
  137. package/dist/parsers/sqlSyntax.js +15 -1
  138. package/dist/parsers/sqlSyntax.js.map +1 -1
  139. package/dist/parsers/sqlTypes.js +37 -2
  140. package/dist/parsers/sqlTypes.js.map +1 -1
  141. package/dist/parsers/typeorm.js +2 -0
  142. package/dist/parsers/typeorm.js.map +1 -1
  143. package/dist/styles.d.ts +3 -2
  144. package/dist/styles.js +4 -1
  145. package/dist/styles.js.map +1 -1
  146. package/package.json +8 -1
@@ -0,0 +1,262 @@
1
+ import { prismaOnlyWarnings } from '../prismaOnlyConstructs.js';
2
+ import { normalizeSchema } from '../transforms.js';
3
+ import { buildColumn, } from './jpaColumns.js';
4
+ import { planEnums, renderConverterBody, renderEnumBody } from './jpaEnums.js';
5
+ import { annotation } from './jpaFormat.js';
6
+ import { renderIdClass, keyOf } from './jpaKeys.js';
7
+ import { classNameOf, RESERVED_TYPE_NAMES, attributeNameOf, uniqueName, DEFAULT_JPA_PACKAGE, } from './jpaNames.js';
8
+ import { addInverseRelations, addOwningRelations, } from './jpaRelations.js';
9
+ import { renderEntity, renderFile } from './jpaRender.js';
10
+ import { tableAnnotation } from './jpaTable.js';
11
+ import { Imports, } from './jpaTypes.js';
12
+ import { COCKROACH_PREFIX, cockroachSequentialWarning, isCockroach, } from './cockroach.js';
13
+ /**
14
+ * Writes Hibernate / JPA entities (Java): one `@Entity` class per model, a Java `enum` per enum (with an
15
+ * `AttributeConverter` when the stored values differ from the constant names) and an `@IdClass` class for every
16
+ * composite primary key. Two styles choose the persistence API: `jakarta` (the default; `jakarta.persistence`,
17
+ * Hibernate 6, Spring Boot 3) and `javax` (`javax.persistence`, Hibernate 5, Spring Boot 2).
18
+ *
19
+ * Every table, column, key, index and foreign key is written explicitly (`@Table`, `@Column`, `@JoinColumn`), so
20
+ * the output creates the schema of the IR whatever naming strategy the application uses, and the JPA reader reads
21
+ * it back.
22
+ */
23
+ export { DEFAULT_JPA_PACKAGE, isValidJavaPackage } from './jpaNames.js';
24
+ export const JPA_STYLES = ['jakarta', 'javax'];
25
+ /** True when a value is one of the JPA `--style` values. */
26
+ export function isJpaStyle(value) {
27
+ return JPA_STYLES.includes(value);
28
+ }
29
+ // ---------------------------------------------------------------------------
30
+ // Entry point
31
+ // ---------------------------------------------------------------------------
32
+ export function emitJpa(schema, options) {
33
+ const prepared = options.naming === 'normalize' ? normalizeSchema(schema) : schema;
34
+ const warnings = prismaOnlyWarnings(prepared, true).filter(isUnhandledWarning);
35
+ if (options.provider === 'mongodb') {
36
+ warnings.push('Provider "mongodb": JPA is relational (Hibernate OGM and Spring Data MongoDB are separate projects); PostgreSQL column types were written.');
37
+ }
38
+ if (prepared.models.length === 0) {
39
+ return { files: {}, warnings };
40
+ }
41
+ const style = options.style ?? 'jakarta';
42
+ if (isCockroach(options.provider)) {
43
+ warnings.push(`${COCKROACH_PREFIX} the entities use the PostgreSQL column types; set hibernate.dialect to ${style === 'jakarta' ? 'org.hibernate.dialect.CockroachDialect (Hibernate 6)' : 'org.hibernate.dialect.CockroachDB201Dialect (Hibernate 5)'} and keep the PostgreSQL JDBC driver. hstore and range types (which CockroachDB lacks) are written as JSON or large text.`);
44
+ }
45
+ const layout = {
46
+ packageName: options.packageName ?? DEFAULT_JPA_PACKAGE,
47
+ header: options.header !== false,
48
+ };
49
+ const files = {};
50
+ planAndRender(prepared, options, style, layout, files, warnings);
51
+ return { files, warnings: [...new Set(warnings)] };
52
+ }
53
+ /** Drops the Prisma-only notes for things this emitter writes (schemas, views, defaults, composite keys, indexes). */
54
+ function isUnhandledWarning(warning) {
55
+ if (warning.includes('the database default expression')) {
56
+ return false;
57
+ }
58
+ if (warning.includes('(Prisma Unsupported)')) {
59
+ return false;
60
+ }
61
+ if (warning.includes('is generated by Prisma Client and was dropped')) {
62
+ return false;
63
+ }
64
+ if (warning.includes('has no equivalent here; the relation was dropped')) {
65
+ return false;
66
+ }
67
+ if (warning.includes('the index type, clustering, sort order')) {
68
+ return false;
69
+ }
70
+ if (warning.includes('full-text indexes are not supported here')) {
71
+ return false;
72
+ }
73
+ if (warning.includes('is not supported by this format and was ignored')) {
74
+ return false;
75
+ }
76
+ return !(warning.includes('(@@schema) was ignored') && !warning.startsWith('enum '));
77
+ }
78
+ // ---------------------------------------------------------------------------
79
+ // Planning
80
+ // ---------------------------------------------------------------------------
81
+ function pathOf(packageName, className) {
82
+ return `${packageName.replace(/\./g, '/')}/${className}.java`;
83
+ }
84
+ function planAndRender(schema, options, style, layout, files, warnings) {
85
+ const warn = (message) => {
86
+ warnings.push(message);
87
+ };
88
+ const sequentialKeys = [];
89
+ const typeNames = new Set(RESERVED_TYPE_NAMES);
90
+ const enums = planEnums(schema, typeNames, warn);
91
+ const plans = new Map();
92
+ for (const model of schema.models) {
93
+ const raw = classNameOf(model.name);
94
+ const className = uniqueName(RESERVED_TYPE_NAMES.has(raw) ? `${raw}Entity` : raw, typeNames);
95
+ if (className !== raw) {
96
+ warn(`${model.name}: "${raw}" is a name the generated code uses or another type has, so the class was named "${className}".`);
97
+ }
98
+ plans.set(model.name, {
99
+ model,
100
+ className,
101
+ fieldNames: new Map(),
102
+ relationNames: new Map(),
103
+ used: new Set(),
104
+ attributes: [],
105
+ classAnnotations: [],
106
+ imports: new Imports(style),
107
+ dynamicInsert: false,
108
+ });
109
+ }
110
+ const keys = new Map();
111
+ for (const model of schema.models) {
112
+ keys.set(model.name, keyOf(model, warn));
113
+ }
114
+ // Columns ------------------------------------------------------------------------------------
115
+ const context = {
116
+ style,
117
+ provider: options.provider,
118
+ enums,
119
+ warn,
120
+ ...(isCockroach(options.provider) ? { sequentialKeys } : {}),
121
+ };
122
+ const built = new Map();
123
+ for (const model of schema.models) {
124
+ const plan = planFor(plans, model);
125
+ const info = keys.get(model.name) ?? {
126
+ parts: [],
127
+ synthesized: false,
128
+ };
129
+ for (const field of model.fields) {
130
+ const wanted = attributeNameOf(field.name);
131
+ const name = uniqueName(wanted, plan.used);
132
+ if (name !== wanted) {
133
+ warn(`${model.name}.${field.name}: "${wanted}" is taken in ${plan.className}, so the attribute was named "${name}".`);
134
+ }
135
+ plan.fieldNames.set(field.name, name);
136
+ const isKey = info.parts.some((part) => part.kind === 'field' && part.field === field);
137
+ const column = buildColumn(context, `${model.name}.${field.name}`, field, name, { isKey, singleKey: info.parts.length === 1 });
138
+ built.set(field, column);
139
+ plan.attributes.push(column.attribute);
140
+ plan.dynamicInsert ||= column.dynamicInsert;
141
+ }
142
+ }
143
+ if (sequentialKeys.length > 0) {
144
+ warn(cockroachSequentialWarning(sequentialKeys, 'GenerationType.IDENTITY relies on a SERIAL-style column, which is unique_rowid() on CockroachDB (64-bit and not consecutive), so the key is a Long'));
145
+ }
146
+ // Relations ----------------------------------------------------------------------------------
147
+ const keyTypes = new Map();
148
+ const typeOfKey = (model, depth) => {
149
+ const info = keys.get(model.name);
150
+ const part = info?.parts.length === 1 ? info.parts[0] : undefined;
151
+ if (part === undefined || depth > 6) {
152
+ return undefined;
153
+ }
154
+ if (part.kind === 'field') {
155
+ const column = built.get(part.field);
156
+ return column === undefined
157
+ ? undefined
158
+ : { type: column.boxedType, imports: column.attribute.imports };
159
+ }
160
+ const target = schema.models.find((candidate) => candidate.name === part.relation.targetModel);
161
+ return target === undefined ? undefined : typeOfKey(target, depth + 1);
162
+ };
163
+ for (const model of schema.models) {
164
+ const found = typeOfKey(model, 0);
165
+ if (found !== undefined) {
166
+ keyTypes.set(model.name, found);
167
+ }
168
+ }
169
+ const relationContext = {
170
+ style,
171
+ schema,
172
+ plans,
173
+ keys,
174
+ keyTypes,
175
+ inverses: [],
176
+ warn,
177
+ };
178
+ const keyRelations = new Map();
179
+ for (const model of schema.models) {
180
+ keyRelations.set(model.name, addOwningRelations(relationContext, planFor(plans, model)));
181
+ }
182
+ addInverseRelations(relationContext);
183
+ // Classes -----------------------------------------------------------------------------------
184
+ for (const model of schema.models) {
185
+ const plan = planFor(plans, model);
186
+ const info = keys.get(model.name) ?? {
187
+ parts: [],
188
+ synthesized: false,
189
+ };
190
+ const imports = plan.imports;
191
+ plan.classAnnotations.push(annotation(imports.persistence('Entity')), tableAnnotation({ model, imports, warn }));
192
+ if (info.parts.length > 1) {
193
+ const parts = [];
194
+ for (const part of info.parts) {
195
+ if (part.kind === 'field') {
196
+ const column = built.get(part.field);
197
+ const name = plan.fieldNames.get(part.field.name);
198
+ if (column !== undefined && name !== undefined) {
199
+ parts.push({
200
+ name,
201
+ type: column.boxedType,
202
+ imports: column.attribute.imports,
203
+ });
204
+ }
205
+ }
206
+ else {
207
+ const found = keyRelations
208
+ .get(model.name)
209
+ ?.get(part.relation);
210
+ if (found === undefined) {
211
+ warn(`${model.name}.${part.relation.name}: the relation is part of the composite primary key but could not be written, so it is missing from the key.`);
212
+ }
213
+ else {
214
+ parts.push({
215
+ name: found.attribute,
216
+ type: found.type,
217
+ imports: found.imports,
218
+ });
219
+ }
220
+ }
221
+ }
222
+ const idName = uniqueName(`${plan.className}Id`, typeNames);
223
+ plan.idClass = { name: idName, parts };
224
+ const idImports = plan.imports;
225
+ plan.classAnnotations.push(annotation(idImports.persistence('IdClass'), [
226
+ [undefined, `${idName}.class`],
227
+ ]));
228
+ const rendered = renderIdClass(idName, parts, style);
229
+ files[pathOf(layout.packageName, idName)] = renderFile(layout, rendered.imports, rendered.lines);
230
+ }
231
+ if (info.parts.length === 1 && info.parts[0]?.kind === 'relation') {
232
+ plan.serializable = true;
233
+ // The entity is Serializable only because Hibernate 5 asks for it; its relationship attributes are not.
234
+ plan.classAnnotations.push(annotation('SuppressWarnings', [[undefined, '"serial"']]));
235
+ }
236
+ if (plan.dynamicInsert) {
237
+ plan.classAnnotations.push(annotation(imports.hibernate('DynamicInsert')));
238
+ }
239
+ if (model.isView === true) {
240
+ plan.classAnnotations.push(annotation(imports.hibernate('Immutable')));
241
+ warn(`${model.name}: the table "${model.tableName}" is a database view; the class is @Immutable, but Hibernate would create a table of that name if it manages the schema (turn schema generation off for it).`);
242
+ }
243
+ files[pathOf(layout.packageName, plan.className)] = renderEntity(plan, layout);
244
+ }
245
+ // Enums and converters --------------------------------------------------------------------------
246
+ for (const plan of enums.values()) {
247
+ const body = renderEnumBody(plan);
248
+ files[pathOf(layout.packageName, plan.typeName)] = renderFile(layout, new Imports(style), body);
249
+ if (plan.storage === 'converter') {
250
+ const converter = renderConverterBody(plan, style);
251
+ files[pathOf(layout.packageName, plan.converterName)] = renderFile(layout, converter.imports, converter.lines);
252
+ }
253
+ }
254
+ }
255
+ function planFor(plans, model) {
256
+ const plan = plans.get(model.name);
257
+ if (plan === undefined) {
258
+ throw new Error(`No plan exists for the model "${model.name}".`);
259
+ }
260
+ return plan;
261
+ }
262
+ //# sourceMappingURL=jpa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jpa.js","sourceRoot":"","sources":["../../src/emitters/jpa.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { IrField } from '../ir.js';
2
+ import { type Attribute, type EnumPlan, type JpaStyle } from './jpaTypes.js';
3
+ import type { PrismaProvider } from './prisma.js';
4
+ /** Works out how one IR field is written as a Java attribute with its JPA and Hibernate annotations. */
5
+ export interface ColumnContext {
6
+ style: JpaStyle;
7
+ provider: PrismaProvider;
8
+ enums: ReadonlyMap<string, EnumPlan>;
9
+ warn: (message: string) => void;
10
+ /** CockroachDB: auto-increment keys, collected so the emitter can report them in one warning. */
11
+ sequentialKeys?: string[];
12
+ }
13
+ export interface KeyRole {
14
+ /** True when the column is part of the primary key. */
15
+ isKey: boolean;
16
+ /** True when it is the only column of the primary key. */
17
+ singleKey: boolean;
18
+ }
19
+ export interface BuiltColumn {
20
+ attribute: Attribute;
21
+ /** The boxed Java type, which an `@IdClass` repeats. */
22
+ boxedType: string;
23
+ /** True when the column has a database default that Hibernate must not overwrite with null. */
24
+ dynamicInsert: boolean;
25
+ }
26
+ /** Builds the Java attribute of an IR field. `name` is the attribute name chosen for it. */
27
+ export declare function buildColumn(context: ColumnContext, label: string, source: IrField, name: string, role: KeyRole): BuiltColumn;
@@ -0,0 +1,342 @@
1
+ import { defaultOf, isPostgres } from './jpaDefaults.js';
2
+ import { annotation, } from './jpaFormat.js';
3
+ import { javaString } from './jpaNames.js';
4
+ import { scalarOf, withNativeFacets, } from './jpaScalars.js';
5
+ import { Imports, } from './jpaTypes.js';
6
+ /** Python expressions of Django generated columns: not SQL, so they cannot be written to the database. */
7
+ const PYTHON_EXPRESSION = /\b(F|Value|ExpressionWrapper|Func|Cast)\(/;
8
+ /** Columns that record when the row was created: Hibernate fills them in, whatever the application set. */
9
+ function isCreationColumn(field) {
10
+ return /^(created(at)?|datecreated|creationdate|creationtime)$/.test(field.columnName.replace(/_/g, '').toLowerCase());
11
+ }
12
+ function isInteger(field) {
13
+ return ((field.type === 'int' || field.type === 'bigInt') &&
14
+ field.arrayDepth === undefined &&
15
+ field.enumName === undefined);
16
+ }
17
+ /** How an array column is written: a Java array on PostgreSQL, JSON elsewhere, large text for Hibernate 5. */
18
+ function arrayOf(context, label, field, element) {
19
+ const { imports } = context;
20
+ const depth = field.arrayDepth ?? 1;
21
+ if (depth > 1) {
22
+ context.warn(`${label}: Hibernate maps one-dimensional arrays only; the ${depth}-dimensional array was written as a one-dimensional one.`);
23
+ }
24
+ if (context.style === 'javax') {
25
+ context.warn(`${label}: Hibernate 5 cannot map arrays; the column was written as a String with the column definition ${element.columnDefinition ?? 'text'}[].`);
26
+ return {
27
+ boxed: imports.use('java.lang.String'),
28
+ columnDefinition: `${element.columnDefinition ?? sqlNameOf(field)}[]`,
29
+ extra: [],
30
+ };
31
+ }
32
+ if (isPostgres(context.provider)) {
33
+ return {
34
+ boxed: `${element.boxed}[]`,
35
+ extra: element.extra.filter((item) => item.name !== 'Lob'),
36
+ ...(element.length === undefined ? {} : { length: element.length }),
37
+ ...(element.precision === undefined
38
+ ? {}
39
+ : { precision: element.precision }),
40
+ };
41
+ }
42
+ context.warn(`${label}: ${context.provider} has no array type; the column was written as a JSON array.`);
43
+ imports.use('java.util.List');
44
+ return {
45
+ boxed: `List<${element.boxed}>`,
46
+ extra: [
47
+ annotation(imports.hibernate('JdbcTypeCode'), [
48
+ [undefined, `${imports.use('org.hibernate.type.SqlTypes')}.JSON`],
49
+ ]),
50
+ ],
51
+ };
52
+ }
53
+ /** The SQL type name of an array element, for a Hibernate 5 column definition. */
54
+ function sqlNameOf(field) {
55
+ switch (field.type) {
56
+ case 'int':
57
+ return 'integer';
58
+ case 'bigInt':
59
+ return 'bigint';
60
+ case 'float':
61
+ return 'double precision';
62
+ case 'boolean':
63
+ return 'boolean';
64
+ case 'decimal':
65
+ return 'numeric';
66
+ case 'dateTime':
67
+ return 'timestamp';
68
+ case 'date':
69
+ return 'date';
70
+ case 'time':
71
+ return 'time';
72
+ case 'uuid':
73
+ return 'uuid';
74
+ case 'string':
75
+ return field.maxLength === undefined
76
+ ? 'text'
77
+ : `varchar(${field.maxLength})`;
78
+ default:
79
+ return 'text';
80
+ }
81
+ }
82
+ /** The annotations that store an enum, and the Java type. */
83
+ function enumScalar(context, field, plan) {
84
+ const { imports } = context;
85
+ const extra = [];
86
+ if (plan.storage === 'converter') {
87
+ extra.push(annotation(imports.persistence('Convert'), [
88
+ ['converter', `${plan.converterName}.class`],
89
+ ]));
90
+ }
91
+ else {
92
+ const enumType = imports.persistence('EnumType');
93
+ extra.push(annotation(imports.persistence('Enumerated'), [
94
+ [
95
+ undefined,
96
+ `${enumType}.${plan.storage === 'ordinal' ? 'ORDINAL' : 'STRING'}`,
97
+ ],
98
+ ]));
99
+ }
100
+ const stringStored = plan.storage !== 'ordinal' && !plan.numeric;
101
+ return {
102
+ boxed: plan.typeName,
103
+ extra,
104
+ ...(stringStored && field.maxLength !== undefined
105
+ ? { length: field.maxLength }
106
+ : {}),
107
+ };
108
+ }
109
+ function columnArguments(field, scalar, nullable, role, readOnly) {
110
+ const args = [
111
+ ['name', javaString(field.columnName)],
112
+ ];
113
+ if (!nullable && !role.isKey) {
114
+ args.push(['nullable', 'false']);
115
+ }
116
+ if (field.isUnique && !role.isKey && field.uniqueName === undefined) {
117
+ args.push(['unique', 'true']);
118
+ }
119
+ if (scalar.length !== undefined) {
120
+ args.push(['length', String(scalar.length)]);
121
+ }
122
+ if (scalar.precision !== undefined) {
123
+ args.push(['precision', String(scalar.precision.precision)]);
124
+ args.push(['scale', String(scalar.precision.scale)]);
125
+ }
126
+ if (scalar.columnDefinition !== undefined) {
127
+ args.push(['columnDefinition', javaString(scalar.columnDefinition)]);
128
+ }
129
+ if (readOnly) {
130
+ args.push(['insertable', 'false'], ['updatable', 'false']);
131
+ }
132
+ return args;
133
+ }
134
+ /** The generator annotations of a key column; `undefined` when the key is assigned by the application. */
135
+ function keyGenerator(context, label, field, imports, defaults) {
136
+ const generated = imports.persistence('GeneratedValue');
137
+ const nodes = [];
138
+ if (field.default?.kind === 'autoIncrement') {
139
+ if (!isInteger(field)) {
140
+ context.warn(`${label}: an auto-increment default on a ${field.type} column cannot be written; the key is assigned by the application.`);
141
+ return nodes;
142
+ }
143
+ const strategy = imports.persistence('GenerationType');
144
+ nodes.push(annotation(generated, [['strategy', `${strategy}.IDENTITY`]]));
145
+ context.sequentialKeys?.push(label);
146
+ return nodes;
147
+ }
148
+ if (field.type === 'uuid' && (defaults.uuid === true || defaults.sql)) {
149
+ if (context.style === 'jakarta') {
150
+ const strategy = imports.persistence('GenerationType');
151
+ nodes.push(annotation(generated, [['strategy', `${strategy}.UUID`]]));
152
+ }
153
+ else {
154
+ nodes.push(annotation(generated, [['generator', javaString('uuid2')]]), annotation(imports.hibernate('GenericGenerator'), [
155
+ ['name', javaString('uuid2')],
156
+ ['strategy', javaString('uuid2')],
157
+ ]));
158
+ }
159
+ }
160
+ return nodes;
161
+ }
162
+ const NOW_TYPES = new Set([
163
+ 'LocalDateTime',
164
+ 'OffsetDateTime',
165
+ 'LocalDate',
166
+ 'LocalTime',
167
+ ]);
168
+ /**
169
+ * The initializer of a column that has a default: the literal itself, `now()` for a "now" default, and an empty
170
+ * map for the JSON default `{}`. Without one, a property that is NOT NULL would be rejected by Hibernate's
171
+ * nullability check before the database could fill in its default.
172
+ */
173
+ function initializerOf(context, imports, field, scalar, defaults) {
174
+ if (defaults.initializer !== undefined) {
175
+ for (const name of defaults.initializerImports ?? []) {
176
+ imports.use(name);
177
+ }
178
+ return defaults.initializer;
179
+ }
180
+ if (field.default?.kind === 'now' && NOW_TYPES.has(scalar.boxed)) {
181
+ return `${scalar.boxed}.now()`;
182
+ }
183
+ if (field.type === 'json' && field.default?.kind === 'literal') {
184
+ if (context.style === 'javax') {
185
+ return javaString(String(field.default.value));
186
+ }
187
+ if (String(field.default.value).replace(/\s+/g, '') === '{}') {
188
+ imports.use('java.util.HashMap');
189
+ return 'new HashMap<>()';
190
+ }
191
+ }
192
+ return undefined;
193
+ }
194
+ /** Builds the Java attribute of an IR field. `name` is the attribute name chosen for it. */
195
+ export function buildColumn(context, label, source, name, role) {
196
+ const field = withNativeFacets(source);
197
+ const imports = new Imports(context.style);
198
+ const scalarContext = {
199
+ style: context.style,
200
+ provider: context.provider,
201
+ imports,
202
+ warn: context.warn,
203
+ };
204
+ const plan = field.enumName === undefined
205
+ ? undefined
206
+ : context.enums.get(field.enumName);
207
+ if (field.enumName !== undefined && plan === undefined) {
208
+ context.warn(`${label}: the enum "${field.enumName}" does not exist; the column was written as its stored type.`);
209
+ }
210
+ const depth = field.arrayDepth ?? 0;
211
+ let scalar;
212
+ if (plan !== undefined && depth === 0) {
213
+ scalar = enumScalar(scalarContext, field, plan);
214
+ }
215
+ else {
216
+ if (plan !== undefined) {
217
+ context.warn(`${label}: an array of the enum ${plan.typeName} is stored as an array of its stored values, not as an enum.`);
218
+ }
219
+ const elementField = { ...field };
220
+ delete elementField.arrayDepth;
221
+ const element = scalarOf(scalarContext, label, elementField);
222
+ scalar =
223
+ depth > 0 ? arrayOf(scalarContext, label, field, element) : element;
224
+ }
225
+ // Generated (computed) column ----------------------------------------------------------------
226
+ let generatedSql;
227
+ if (field.generated !== undefined) {
228
+ if (PYTHON_EXPRESSION.test(field.generated.expression)) {
229
+ context.warn(`${label}: the generated column expression ${field.generated.expression} is Python, not SQL; the column was written as a regular column.`);
230
+ }
231
+ else if (context.style === 'javax') {
232
+ context.warn(`${label}: Hibernate 5 has no generated column mapping; the column was written as a regular column.`);
233
+ }
234
+ else {
235
+ generatedSql = field.generated.expression;
236
+ }
237
+ }
238
+ // Defaults ---------------------------------------------------------------------------------
239
+ const defaults = generatedSql !== undefined
240
+ ? {}
241
+ : defaultOf({ provider: context.provider, warn: context.warn }, label, field, plan);
242
+ const singleKey = role.isKey && role.singleKey;
243
+ let sqlDefault = defaults.sql;
244
+ let uuidGenerator = false;
245
+ const generators = singleKey
246
+ ? keyGenerator(context, label, field, imports, defaults)
247
+ : [];
248
+ if (role.isKey && !role.singleKey && field.default !== undefined) {
249
+ if (field.default.kind === 'autoIncrement' || defaults.uuid === true) {
250
+ context.warn(`${label}: JPA cannot generate one column of a composite key; the value is assigned by the application.`);
251
+ }
252
+ }
253
+ if (!role.isKey && field.default?.kind === 'autoIncrement') {
254
+ context.warn(`${label}: JPA generates identifiers only, so an auto-increment column that is not the key is a plain column; the database fills it only if it is created with an identity by hand.`);
255
+ }
256
+ if (defaults.uuid === true && !role.isKey) {
257
+ if (context.style === 'jakarta') {
258
+ generators.push(annotation(imports.hibernate('UuidGenerator')));
259
+ uuidGenerator = true;
260
+ }
261
+ else if (isPostgres(context.provider)) {
262
+ sqlDefault = 'gen_random_uuid()';
263
+ context.warn(`${label}: Hibernate 5 generates identifiers only; the UUID is generated by the database (gen_random_uuid()).`);
264
+ }
265
+ else {
266
+ context.warn(`${label}: Hibernate 5 generates identifiers only, so the UUID default was dropped and the application must set the value.`);
267
+ }
268
+ }
269
+ const keyGenerated = generators.length > 0 && singleKey;
270
+ // Timestamps ---------------------------------------------------------------------------------
271
+ const timestamps = [];
272
+ if (defaults.creationTimestamp === true &&
273
+ isCreationColumn(field) &&
274
+ !role.isKey &&
275
+ generatedSql === undefined) {
276
+ timestamps.push(annotation(imports.hibernate('CreationTimestamp')));
277
+ }
278
+ if (field.isAutoUpdated) {
279
+ if (field.type === 'dateTime' && depth === 0 && !role.isKey) {
280
+ timestamps.push(annotation(imports.hibernate('UpdateTimestamp')));
281
+ }
282
+ else {
283
+ context.warn(`${label}: Hibernate can refresh a date-time column only; the ${field.type} column was written as an ordinary column.`);
284
+ }
285
+ }
286
+ // Initializer: a new object already shows the default, and Hibernate has a value to insert -----
287
+ const initializer = generatedSql === undefined &&
288
+ depth === 0 &&
289
+ !role.isKey &&
290
+ !uuidGenerator &&
291
+ !timestamps.some((item) => item.name === 'CreationTimestamp')
292
+ ? initializerOf(context, imports, field, scalar, defaults)
293
+ : undefined;
294
+ // Types ----------------------------------------------------------------------------------------
295
+ const nullable = role.isKey ? false : field.isNullable;
296
+ const hasDatabaseDefault = sqlDefault !== undefined &&
297
+ initializer === undefined &&
298
+ !timestamps.some((item) => item.name === 'CreationTimestamp');
299
+ const usePrimitive = scalar.primitive !== undefined &&
300
+ !nullable &&
301
+ !role.isKey &&
302
+ depth === 0 &&
303
+ plan === undefined &&
304
+ !hasDatabaseDefault &&
305
+ !uuidGenerator &&
306
+ generatedSql === undefined &&
307
+ timestamps.length === 0;
308
+ const type = usePrimitive
309
+ ? (scalar.primitive ?? scalar.boxed)
310
+ : scalar.boxed;
311
+ const annotations = [];
312
+ if (role.isKey) {
313
+ annotations.push(annotation(imports.persistence('Id')));
314
+ }
315
+ annotations.push(...generators, ...scalar.extra);
316
+ annotations.push(annotation(imports.persistence('Column'), columnArguments(field, scalar, nullable, role, generatedSql !== undefined)));
317
+ if (sqlDefault !== undefined && generatedSql === undefined) {
318
+ annotations.push(annotation(imports.hibernate('ColumnDefault'), [
319
+ [undefined, javaString(sqlDefault)],
320
+ ]));
321
+ }
322
+ annotations.push(...timestamps);
323
+ if (generatedSql !== undefined) {
324
+ annotations.push(annotation(imports.hibernate('GeneratedColumn'), [
325
+ [undefined, javaString(generatedSql)],
326
+ ]));
327
+ }
328
+ const attribute = {
329
+ name,
330
+ type,
331
+ annotations,
332
+ imports,
333
+ ...(initializer === undefined ? {} : { initializer }),
334
+ ...(type === 'boolean' ? { isPrimitiveBoolean: true } : {}),
335
+ };
336
+ return {
337
+ attribute,
338
+ boxedType: scalar.boxed,
339
+ dynamicInsert: hasDatabaseDefault && !keyGenerated,
340
+ };
341
+ }
342
+ //# sourceMappingURL=jpaColumns.js.map