joist-codegen 0.1.538 → 1.0.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 (59) hide show
  1. package/build/EntityDbMetadata.d.ts +71 -23
  2. package/build/EntityDbMetadata.js +229 -63
  3. package/build/EntityDbMetadata.js.map +1 -1
  4. package/build/EntityDbMetadata.test.js +5 -5
  5. package/build/EntityDbMetadata.test.js.map +1 -1
  6. package/build/assignTags.d.ts +1 -1
  7. package/build/assignTags.js +2 -2
  8. package/build/assignTags.js.map +1 -1
  9. package/build/config.d.ts +8 -1
  10. package/build/config.js +25 -13
  11. package/build/config.js.map +1 -1
  12. package/build/config.test.d.ts +1 -0
  13. package/build/config.test.js +37 -0
  14. package/build/config.test.js.map +1 -0
  15. package/build/generateEntitiesFile.d.ts +2 -1
  16. package/build/generateEntitiesFile.js +6 -3
  17. package/build/generateEntitiesFile.js.map +1 -1
  18. package/build/generateEntityCodegenFile.d.ts +2 -4
  19. package/build/generateEntityCodegenFile.js +278 -90
  20. package/build/generateEntityCodegenFile.js.map +1 -1
  21. package/build/generateEnumFile.d.ts +2 -3
  22. package/build/generateEnumFile.js +15 -10
  23. package/build/generateEnumFile.js.map +1 -1
  24. package/build/generateFactoriesFiles.js +4 -4
  25. package/build/generateFactoriesFiles.js.map +1 -1
  26. package/build/generateInitialEntityFile.js +7 -2
  27. package/build/generateInitialEntityFile.js.map +1 -1
  28. package/build/generateMetadataFile.js +96 -69
  29. package/build/generateMetadataFile.js.map +1 -1
  30. package/build/generatePgEnumFile.d.ts +4 -0
  31. package/build/generatePgEnumFile.js +18 -0
  32. package/build/generatePgEnumFile.js.map +1 -0
  33. package/build/index.d.ts +24 -8
  34. package/build/index.js +116 -40
  35. package/build/index.js.map +1 -1
  36. package/build/symbols.d.ts +62 -51
  37. package/build/symbols.js +64 -52
  38. package/build/symbols.js.map +1 -1
  39. package/build/utils.d.ts +4 -2
  40. package/build/utils.js +20 -11
  41. package/build/utils.js.map +1 -1
  42. package/package.json +26 -14
  43. package/jest.config.js +0 -10
  44. package/package.json.bak +0 -28
  45. package/src/EntityDbMetadata.test.ts +0 -42
  46. package/src/EntityDbMetadata.ts +0 -322
  47. package/src/assignTags.ts +0 -45
  48. package/src/config.ts +0 -82
  49. package/src/generateEntitiesFile.ts +0 -26
  50. package/src/generateEntityCodegenFile.ts +0 -414
  51. package/src/generateEnumFile.ts +0 -63
  52. package/src/generateFactoriesFiles.ts +0 -29
  53. package/src/generateInitialEntityFile.ts +0 -12
  54. package/src/generateMetadataFile.ts +0 -175
  55. package/src/index.ts +0 -180
  56. package/src/symbols.ts +0 -53
  57. package/src/utils.ts +0 -88
  58. package/tsconfig.json +0 -21
  59. package/tsconfig.tsbuildinfo +0 -3377
package/src/config.ts DELETED
@@ -1,82 +0,0 @@
1
- import { Entity } from "EntityDbMetadata";
2
- import { promises as fs } from "fs";
3
- import prettier, { resolveConfig } from "prettier";
4
- import { sortKeys, trueIfResolved } from "./utils";
5
-
6
- export interface FieldConfig {
7
- derived?: "sync" | "async";
8
- protected?: boolean;
9
- }
10
-
11
- export interface RelationConfig {
12
- name?: string;
13
- }
14
-
15
- export interface EntityConfig {
16
- tag: string;
17
- tableName?: string;
18
- fields?: Record<string, FieldConfig>;
19
- relations?: Record<string, RelationConfig>;
20
- }
21
-
22
- export interface Config {
23
- contextType?: string;
24
- entitiesDirectory: string;
25
- codegenPlugins: string[];
26
- entities: Record<string, EntityConfig>;
27
- // We don't persist this, and instead just use it as a cache
28
- __tableToEntityName: Record<string, string>;
29
- }
30
-
31
- export const defaultConfig: Config = {
32
- entitiesDirectory: "./src/entities",
33
- codegenPlugins: [],
34
- entities: {},
35
- __tableToEntityName: {},
36
- };
37
-
38
- export const ormMaintainedFields = ["createdAt", "updatedAt"];
39
-
40
- export function isDerived(config: Config, entity: Entity, fieldName: string): boolean {
41
- return config.entities[entity.name]?.fields?.[fieldName]?.derived === "sync";
42
- }
43
-
44
- export function isAsyncDerived(config: Config, entity: Entity, fieldName: string): boolean {
45
- return config.entities[entity.name]?.fields?.[fieldName]?.derived === "async";
46
- }
47
-
48
- export function isProtected(config: Config, entity: Entity, fieldName: string): boolean {
49
- return config.entities[entity.name]?.fields?.[fieldName]?.protected === true;
50
- }
51
-
52
- export function relationName(config: Config, entity: Entity, relationName: string): string {
53
- return config.entities?.[entity.name]?.relations?.[relationName]?.name ?? relationName;
54
- }
55
-
56
- const configPath = "./joist-codegen.json";
57
- export async function loadConfig(): Promise<Config> {
58
- const exists = await trueIfResolved(fs.access(configPath));
59
- if (exists) {
60
- const content = await fs.readFile(configPath);
61
- return {
62
- ...defaultConfig,
63
- ...(JSON.parse(content.toString()) as Config),
64
- };
65
- }
66
- return defaultConfig;
67
- }
68
-
69
- /**
70
- * Writes the potentially-updated config entry back to `joist-codegen.json`.
71
- *
72
- * We format the output with prettier so it should both a) look nice and b) be deterministic,
73
- * such that no changes to the config show up as noops to the scm.
74
- */
75
- export async function writeConfig(config: Config): Promise<void> {
76
- const prettierConfig = await resolveConfig("./");
77
- const sorted = sortKeys(config);
78
- delete sorted.__tableToEntityName;
79
- const input = JSON.stringify(sorted);
80
- const content = prettier.format(input.trim(), { parser: "json", ...prettierConfig });
81
- await fs.writeFile(configPath, content);
82
- }
@@ -1,26 +0,0 @@
1
- import { Table } from "pg-structure";
2
- import { code, Code } from "ts-poet";
3
- import { Config } from "./config";
4
- import { EntityDbMetadata } from "./EntityDbMetadata";
5
- import { tableToEntityName } from "./utils";
6
-
7
- export function generateEntitiesFile(config: Config, entities: EntityDbMetadata[], enums: Table[]): Code {
8
- return code`
9
- // organize-imports-ignore
10
-
11
- // This file drives our import order to avoid undefined errors
12
- // when the subclasses extend the base classes, see:
13
- // https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de
14
- ${enums.map((table) => {
15
- return `export * from "./${tableToEntityName(config, table)}";`;
16
- })}
17
- ${entities.map((meta) => {
18
- return `export * from "./${meta.entity.name}Codegen";`;
19
- })}
20
- ${entities.map((meta) => {
21
- return `export * from "./${meta.entity.name}";`;
22
- })}
23
- export * from "./factories";
24
- export * from "./metadata";
25
- `;
26
- }
@@ -1,414 +0,0 @@
1
- import { camelCase, pascalCase } from "change-case";
2
- import { code, Code, imp } from "ts-poet";
3
- import { SymbolSpec } from "ts-poet/build/SymbolSpecs";
4
- import { Config } from "./config";
5
- import { EntityDbMetadata, PrimitiveField } from "./EntityDbMetadata";
6
- import {
7
- BaseEntity,
8
- BooleanFilter,
9
- BooleanGraphQLFilter,
10
- Changes,
11
- Collection,
12
- ConfigApi,
13
- EntityFilter,
14
- EntityGraphQLFilter,
15
- EntityManager,
16
- EnumGraphQLFilter,
17
- FilterOf,
18
- Flavor,
19
- getEm,
20
- GraphQLFilterOf,
21
- hasMany,
22
- hasManyToMany,
23
- hasOne,
24
- hasOneToOne,
25
- Lens,
26
- Loaded,
27
- LoadHint,
28
- loadLens,
29
- newChangesProxy,
30
- newRequiredRule,
31
- OptsOf,
32
- OrderBy,
33
- PartialOrNull,
34
- Reference,
35
- setField,
36
- setOpts,
37
- ValueFilter,
38
- ValueGraphQLFilter,
39
- } from "./symbols";
40
-
41
- export interface ColumnMetaData {
42
- typeConverter?: SymbolSpec;
43
- fieldType: SymbolSpec | string;
44
- }
45
-
46
- /** Creates the base class with the boilerplate annotations. */
47
- export function generateEntityCodegenFile(config: Config, meta: EntityDbMetadata): Code {
48
- const { entity } = meta;
49
- const entityName = entity.name;
50
-
51
- // Add the primitives
52
- const primitives = meta.primitives.map((p) => {
53
- const { fieldName, fieldType, notNull } = p;
54
- const maybeOptional = notNull ? "" : " | undefined";
55
-
56
- let getter: Code;
57
- if (p.derived === "async") {
58
- getter = code`
59
- get ${fieldName}(): ${fieldType}${maybeOptional} {
60
- if (!("${fieldName}" in this.__orm.data)) {
61
- throw new Error("${fieldName} has not been derived yet");
62
- }
63
- return this.__orm.data["${fieldName}"];
64
- }
65
- `;
66
- } else if (p.derived === "sync") {
67
- getter = code`
68
- abstract get ${fieldName}(): ${fieldType}${maybeOptional};
69
- `;
70
- } else {
71
- getter = code`
72
- get ${fieldName}(): ${fieldType}${maybeOptional} {
73
- return this.__orm.data["${fieldName}"];
74
- }
75
- `;
76
- }
77
-
78
- let setter: Code | string;
79
- if (p.protected) {
80
- // TODO Allow making the getter to be protected as well. And so probably remove it
81
- // from the Opts as well. Wonder how that works for required protected fields?
82
- //
83
- // We have to use a method of `set${fieldName}` because TS enforces getters/setters to have
84
- // same access level and currently we're leaving the getter as public.
85
- setter = code`
86
- protected set${pascalCase(fieldName)}(${fieldName}: ${fieldType}${maybeOptional}) {
87
- ${setField}(this, "${fieldName}", ${fieldName});
88
- }
89
- `;
90
- } else if (p.derived) {
91
- setter = "";
92
- } else {
93
- setter = code`
94
- set ${fieldName}(${fieldName}: ${fieldType}${maybeOptional}) {
95
- ${setField}(this, "${fieldName}", ${fieldName});
96
- }
97
- `;
98
- }
99
-
100
- return code`${getter} ${setter}`;
101
- });
102
-
103
- // Add ManyToOne enums
104
- meta.enums.forEach((e) => {
105
- const { fieldName, enumType, notNull } = e;
106
- const maybeOptional = notNull ? "" : " | undefined";
107
- const getter = code`
108
- get ${fieldName}(): ${enumType}${maybeOptional} {
109
- return this.__orm.data["${fieldName}"];
110
- }
111
- `;
112
- const setter = code`
113
- set ${fieldName}(${fieldName}: ${enumType}${maybeOptional}) {
114
- ${setField}(this, "${fieldName}", ${fieldName});
115
- }
116
- `;
117
- // Group enums as primitives
118
- primitives.push(getter);
119
- primitives.push(setter);
120
- });
121
-
122
- // Add ManyToOne entities
123
- const m2o = meta.manyToOnes.map((m2o) => {
124
- const { fieldName, otherEntity, otherFieldName, notNull } = m2o;
125
- const maybeOptional = notNull ? "never" : "undefined";
126
- return code`
127
- readonly ${fieldName}: ${Reference}<${entity.type}, ${otherEntity.type}, ${maybeOptional}> =
128
- ${hasOne}(
129
- ${otherEntity.metaType},
130
- "${fieldName}",
131
- "${otherFieldName}",
132
- );
133
- `;
134
- });
135
-
136
- // Add OneToMany
137
- const o2m = meta.oneToManys.map((o2m) => {
138
- const { fieldName, otherFieldName, otherColumnName, otherEntity } = o2m;
139
- return code`
140
- readonly ${fieldName}: ${Collection}<${entity.type}, ${otherEntity.type}> = ${hasMany}(
141
- ${otherEntity.metaType},
142
- "${fieldName}",
143
- "${otherFieldName}",
144
- "${otherColumnName}"
145
- );
146
- `;
147
- });
148
-
149
- // Add OneToOne
150
- const o2o = meta.oneToOnes.map((o2o) => {
151
- const { fieldName, otherEntity, otherFieldName } = o2o;
152
- return code`
153
- readonly ${fieldName}: ${Reference}<${entity.type}, ${otherEntity.type}, undefined> =
154
- ${hasOneToOne}(
155
- ${otherEntity.metaType},
156
- "${fieldName}",
157
- "${otherFieldName}",
158
- );
159
- `;
160
- });
161
-
162
- // Add ManyToMany
163
- const m2m = meta.manyToManys.map((m2m) => {
164
- const { joinTableName, fieldName, columnName, otherEntity, otherFieldName, otherColumnName } = m2m;
165
- return code`
166
- readonly ${fieldName}: ${Collection}<${entity.type}, ${otherEntity.type}> = ${hasManyToMany}(
167
- "${joinTableName}",
168
- "${fieldName}",
169
- "${columnName}",
170
- ${otherEntity.metaType},
171
- "${otherFieldName}",
172
- "${otherColumnName}",
173
- );
174
- `;
175
- });
176
-
177
- const configName = `${camelCase(entityName)}Config`;
178
- const metadata = imp(`${camelCase(entityName)}Meta@./entities`);
179
-
180
- const defaultValues = generateDefaultValues(config, meta);
181
- const hasDefaultValues = defaultValues.length > 0;
182
- const defaultValuesName = `${camelCase(entityName)}DefaultValues`;
183
-
184
- const contextType = config.contextType ? imp(config.contextType) : "{}";
185
- const factoryMethod = imp(`new${entity.name}@./entities`);
186
-
187
- return code`
188
- export type ${entityName}Id = ${Flavor}<string, "${entityName}">;
189
-
190
- export interface ${entityName}Opts {
191
- ${generateOptsFields(config, meta)}
192
- }
193
-
194
- export interface ${entityName}IdsOpts {
195
- ${generateOptIdsFields(config, meta)}
196
- }
197
-
198
- export interface ${entityName}Filter {
199
- id?: ${ValueFilter}<${entityName}Id, never>;
200
- ${generateFilterFields(meta)}
201
- }
202
-
203
- export interface ${entityName}GraphQLFilter {
204
- id?: ${ValueGraphQLFilter}<${entityName}Id>;
205
- ${generateGraphQLFilterFields(meta)}
206
- }
207
-
208
- export interface ${entityName}Order {
209
- id?: ${OrderBy};
210
- ${generateOrderFields(meta)}
211
- }
212
-
213
- ${hasDefaultValues ? code`export const ${defaultValuesName} = { ${defaultValues} };` : ""}
214
-
215
- export const ${configName} = new ${ConfigApi}<${entity.type}, ${contextType}>();
216
-
217
- ${generateDefaultValidationRules(meta, configName)}
218
-
219
- export abstract class ${entityName}Codegen extends ${BaseEntity} {
220
- readonly __types: {
221
- filterType: ${entityName}Filter;
222
- gqlFilterType: ${entityName}GraphQLFilter;
223
- orderType: ${entityName}Order;
224
- optsType: ${entityName}Opts;
225
- optIdsType: ${entityName}IdsOpts;
226
- factoryOptsType: Parameters<typeof ${factoryMethod}>[1];
227
- } = null!;
228
- ${[o2m, m2o, o2o, m2m]}
229
-
230
- constructor(em: ${EntityManager}, opts: ${entityName}Opts) {
231
- super(em, ${metadata}, ${hasDefaultValues ? `${defaultValuesName}` : "{}"}, opts);
232
- ${setOpts}(this as any as ${entityName}, opts, { calledFromConstructor: true });
233
- }
234
-
235
- get id(): ${entityName}Id | undefined {
236
- return this.__orm.data["id"];
237
- }
238
-
239
- ${primitives}
240
-
241
- set(opts: Partial<${entityName}Opts>): void {
242
- ${setOpts}(this as any as ${entityName}, opts);
243
- }
244
-
245
- setPartial(opts: ${PartialOrNull}<${entityName}Opts>): void {
246
- ${setOpts}(this as any as ${entityName}, opts as ${OptsOf}<${entityName}>, { partial: true });
247
- }
248
-
249
- get changes(): ${Changes}<${entityName}> {
250
- return ${newChangesProxy}(this as any as ${entityName});
251
- }
252
-
253
- async load<U, V>(fn: (lens: ${Lens}<${entity.type}>) => ${Lens}<U, V>): Promise<V> {
254
- return ${loadLens}(this as any as ${entityName}, fn);
255
- }
256
-
257
- async populate<H extends ${LoadHint}<${entityName}>>(hint: H): Promise<${Loaded}<${entityName}, H>> {
258
- return ${getEm}(this).populate(this as any as ${entityName}, hint);
259
- }
260
- }
261
- `;
262
- }
263
-
264
- function fieldHasDefaultValue(config: Config, meta: EntityDbMetadata, field: PrimitiveField): boolean {
265
- let { fieldName, columnDefault, columnType } = field;
266
-
267
- // if there's no default at all, return false
268
- if (columnDefault === null) {
269
- return false;
270
- }
271
-
272
- // even though default is defined as a number | boolean | string | null in reality pg-structure
273
- // only ever returns a string | null so we make sure of that here
274
- columnDefault = columnDefault.toString();
275
-
276
- // if this value should be set elsewhere, return false
277
- if (field.derived !== false) {
278
- return false;
279
- }
280
-
281
- // try to validate that we actually got a primitive value and not arbitrary SQL
282
- return (
283
- (["smallint", "int", "bigint"].includes(columnType) && !isNaN(parseInt(columnDefault))) ||
284
- (["varchar", "text"].includes(columnType) && /^'.*'$/.test(columnDefault)) ||
285
- ("bool" === columnType && ["true", "false"].includes(columnDefault))
286
- );
287
- }
288
-
289
- function generateDefaultValues(config: Config, meta: EntityDbMetadata): Code[] {
290
- return meta.primitives
291
- .filter((field) => fieldHasDefaultValue(config, meta, field))
292
- .map(({ fieldName, columnDefault }) => {
293
- return code`${fieldName}: ${columnDefault},`;
294
- });
295
- }
296
-
297
- function generateDefaultValidationRules(meta: EntityDbMetadata, configName: string): Code[] {
298
- const fields = [...meta.primitives, ...meta.enums, ...meta.manyToOnes];
299
- return fields
300
- .filter((p) => p.notNull)
301
- .map(({ fieldName }) => {
302
- return code`${configName}.addRule(${newRequiredRule}("${fieldName}"));`;
303
- });
304
- }
305
-
306
- // Make our opts type
307
- function generateOptsFields(config: Config, meta: EntityDbMetadata): Code[] {
308
- const primitives = meta.primitives.map((field) => {
309
- const { fieldName, fieldType, notNull, derived } = field;
310
- if (derived) {
311
- return code``;
312
- }
313
- return code`${fieldName}${maybeOptional(
314
- notNull && !fieldHasDefaultValue(config, meta, field),
315
- )}: ${fieldType}${maybeUnionNull(notNull)};`;
316
- });
317
- const enums = meta.enums.map(({ fieldName, enumType, notNull }) => {
318
- return code`${fieldName}${maybeOptional(notNull)}: ${enumType}${maybeUnionNull(notNull)};`;
319
- });
320
- const m2o = meta.manyToOnes.map(({ fieldName, otherEntity, notNull }) => {
321
- return code`${fieldName}${maybeOptional(notNull)}: ${otherEntity.type}${maybeUnionNull(notNull)};`;
322
- });
323
- const o2o = meta.oneToOnes.map(({ fieldName, otherEntity }) => {
324
- return code`${fieldName}?: ${otherEntity.type} | null;`;
325
- });
326
- const o2m = meta.oneToManys.map(({ fieldName, otherEntity }) => {
327
- return code`${fieldName}?: ${otherEntity.type}[];`;
328
- });
329
- const m2m = meta.manyToManys.map(({ fieldName, otherEntity }) => {
330
- return code`${fieldName}?: ${otherEntity.type}[];`;
331
- });
332
- return [...primitives, ...enums, ...m2o, ...o2o, ...o2m, ...m2m];
333
- }
334
-
335
- // We know the OptIds types are only used in partials, so we make everything optional.
336
- // This especially needs to be the case b/c both `book: ...` and `bookId: ...` will be
337
- // in the partial type and of course the caller will only be setting one.
338
- function generateOptIdsFields(config: Config, meta: EntityDbMetadata): Code[] {
339
- const m2o = meta.manyToOnes.map(({ fieldName, otherEntity, notNull }) => {
340
- return code`${fieldName}Id?: ${otherEntity.idType} | null;`;
341
- });
342
- const o2o = meta.oneToOnes.map(({ fieldName, otherEntity }) => {
343
- return code`${fieldName}Id?: ${otherEntity.idType} | null;`;
344
- });
345
- const o2m = meta.oneToManys.map(({ singularName, otherEntity }) => {
346
- return code`${singularName}Ids?: ${otherEntity.idType}[] | null;`;
347
- });
348
- const m2m = meta.manyToManys.map(({ singularName, otherEntity }) => {
349
- return code`${singularName}Ids?: ${otherEntity.idType}[] | null;`;
350
- });
351
- return [...m2o, ...o2o, ...o2m, ...m2m];
352
- }
353
-
354
- function generateFilterFields(meta: EntityDbMetadata): Code[] {
355
- const primitives = meta.primitives.map(({ fieldName, fieldType, notNull }) => {
356
- if (fieldType === "boolean") {
357
- return code`${fieldName}?: ${BooleanFilter}<${nullOrNever(notNull)}>;`;
358
- } else {
359
- return code`${fieldName}?: ${ValueFilter}<${fieldType}, ${nullOrNever(notNull)}>;`;
360
- }
361
- });
362
- const enums = meta.enums.map(({ fieldName, enumType, notNull }) => {
363
- return code`${fieldName}?: ${ValueFilter}<${enumType}, ${nullOrNever(notNull)}>;`;
364
- });
365
- const m2o = meta.manyToOnes.map(({ fieldName, otherEntity, notNull }) => {
366
- return code`${fieldName}?: ${EntityFilter}<${otherEntity.type}, ${otherEntity.idType}, ${FilterOf}<${
367
- otherEntity.type
368
- }>, ${nullOrNever(notNull)}>;`;
369
- });
370
- return [...primitives, ...enums, ...m2o];
371
- }
372
-
373
- function generateGraphQLFilterFields(meta: EntityDbMetadata): Code[] {
374
- const primitives = meta.primitives.map(({ fieldName, fieldType, notNull }) => {
375
- if (fieldType === "boolean") {
376
- return code`${fieldName}?: ${BooleanGraphQLFilter};`;
377
- } else {
378
- return code`${fieldName}?: ${ValueGraphQLFilter}<${fieldType}>;`;
379
- }
380
- });
381
- const enums = meta.enums.map(({ fieldName, enumType, notNull }) => {
382
- return code`${fieldName}?: ${EnumGraphQLFilter}<${enumType}>;`;
383
- });
384
- const m2o = meta.manyToOnes.map(({ fieldName, otherEntity, notNull }) => {
385
- return code`${fieldName}?: ${EntityGraphQLFilter}<${otherEntity.type}, ${otherEntity.idType}, ${GraphQLFilterOf}<${otherEntity.type}>>;`;
386
- });
387
- return [...primitives, ...enums, ...m2o];
388
- }
389
-
390
- function generateOrderFields(meta: EntityDbMetadata): Code[] {
391
- // Make our opts type
392
- const primitives = meta.primitives.map(({ fieldName }) => {
393
- return code`${fieldName}?: ${OrderBy};`;
394
- });
395
- const enums = meta.enums.map(({ fieldName }) => {
396
- return code`${fieldName}?: ${OrderBy};`;
397
- });
398
- const m2o = meta.manyToOnes.map(({ fieldName, otherEntity, notNull }) => {
399
- return code`${fieldName}?: ${otherEntity.orderType};`;
400
- });
401
- return [...primitives, ...enums, ...m2o];
402
- }
403
-
404
- function maybeOptional(notNull: boolean): string {
405
- return notNull ? "" : "?";
406
- }
407
-
408
- function maybeUnionNull(notNull: boolean): string {
409
- return notNull ? "" : " | null";
410
- }
411
-
412
- function nullOrNever(notNull: boolean): string {
413
- return notNull ? "never" : " null | undefined";
414
- }
@@ -1,63 +0,0 @@
1
- import { pascalCase } from "change-case";
2
- import { Table } from "pg-structure";
3
- import pluralize from "pluralize";
4
- import { code, Code } from "ts-poet";
5
- import { Config } from "./config";
6
- import { EntityDbMetadata, EnumRows } from "./index";
7
-
8
- export function generateEnumFile(config: Config, table: Table, enumRows: EnumRows, enumName: string): Code {
9
- const rows = enumRows[table.name];
10
- const detailsName = `${enumName}Details`;
11
- // We're not really an entity, but appropriate EntityDbMetadata's `primitives` filtering
12
- const extraPrimitives = new EntityDbMetadata(config, table).primitives.filter(
13
- (p) => !["code", "name"].includes(p.fieldName),
14
- );
15
- const detailsDefinition = [
16
- "id: number;",
17
- `code: ${enumName};`,
18
- "name: string;",
19
- ...extraPrimitives.map((primitive) => `${primitive.fieldName}: ${primitive.fieldType};`),
20
- ].join(" ");
21
- return code`
22
- export enum ${enumName} {
23
- ${rows.map((row) => `${pascalCase(row.code)} = '${row.code}'`).join(",\n")}
24
- }
25
-
26
- export type ${detailsName} = {${detailsDefinition}};
27
-
28
- const details: Record<${enumName}, ${detailsName}> = {
29
- ${rows
30
- .map((row) => {
31
- const code = pascalCase(row.code);
32
- const safeName = row.name.replace(/(["'])/g, "\\$1");
33
- const extras = extraPrimitives
34
- .map((p) => `${p.fieldName}: ${JSON.stringify((row as any)[p.columnName])}`)
35
- .join(", ");
36
- return `[${enumName}.${code}]: { id: ${row.id}, code: ${enumName}.${code}, name: '${safeName}', ${extras} }`;
37
- })
38
- .join(",")}
39
- };
40
-
41
- export const ${pluralize(enumName)} = {
42
- getByCode(code: ${enumName}): ${detailsName} {
43
- return details[code];
44
- },
45
-
46
- findByCode(code: string): ${detailsName} | undefined {
47
- return details[code as ${enumName}];
48
- },
49
-
50
- findById(id: number): ${detailsName} | undefined {
51
- return Object.values(details).find(d => d.id === id);
52
- },
53
-
54
- getValues(): ReadonlyArray<${enumName}> {
55
- return Object.values(${enumName});
56
- },
57
-
58
- getDetails(): ReadonlyArray<${detailsName}> {
59
- return Object.values(details);
60
- },
61
- };
62
- `;
63
- }
@@ -1,29 +0,0 @@
1
- import { pascalCase } from "change-case";
2
- import { code } from "ts-poet";
3
- import { EntityDbMetadata } from "./EntityDbMetadata";
4
- import { CodeGenFile } from "./index";
5
- import { EntityManager, FactoryOpts, New, newTestInstance } from "./symbols";
6
-
7
- export function generateFactoriesFiles(entities: EntityDbMetadata[]): CodeGenFile[] {
8
- // One-time create an Author.factories.ts for each entity
9
- const entityFiles = entities.map(({ entity }) => {
10
- const name = pascalCase(entity.name);
11
- const contents = code`
12
- export function new${name}(
13
- em: ${EntityManager},
14
- opts?: ${FactoryOpts}<${entity.type}>
15
- ): ${New}<${entity.type}> {
16
- return ${newTestInstance}(em, ${entity.type}, opts);
17
- }`;
18
- return { name: `./${entity.name}.factories.ts`, contents, overwrite: false };
19
- });
20
-
21
- // Everytime create a factories.ts that exports the others
22
- const factoriesFile = {
23
- name: "./factories.ts",
24
- contents: code`${entities.map(({ entity }) => code`export * from "./${entity.name}.factories";`)}`,
25
- overwrite: true,
26
- };
27
-
28
- return [...entityFiles, factoriesFile];
29
- }
@@ -1,12 +0,0 @@
1
- import { code, Code, imp } from "ts-poet";
2
- import { EntityManager } from "./symbols";
3
- import { EntityDbMetadata } from "./EntityDbMetadata";
4
-
5
- /** Creates the placeholder file for our per-entity custom business logic in. */
6
- export function generateInitialEntityFile(meta: EntityDbMetadata): Code {
7
- const entityName = meta.entity.name;
8
- const codegenClass = imp(`${entityName}Codegen@./entities`);
9
- return code`
10
- export class ${entityName} extends ${codegenClass} {}
11
- `;
12
- }