joist-codegen 0.1.536 → 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 +21 -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 -87
  58. package/tsconfig.json +0 -21
  59. package/tsconfig.tsbuildinfo +0 -3377
package/build/utils.js CHANGED
@@ -3,10 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.sortKeys = exports.fail = exports.trueIfResolved = exports.merge = exports.mapSimpleDbType = exports.tableToEntityName = exports.isJoinTable = exports.isEnumTable = exports.isEntityTable = void 0;
6
+ exports.sortKeys = exports.fail = exports.trueIfResolved = exports.merge = exports.mapSimpleDbTypeToTypescriptType = exports.tableToEntityName = exports.isJoinTable = exports.isEnumTable = exports.isEntityTable = exports.assertNever = void 0;
7
+ const change_case_1 = require("change-case");
7
8
  const is_plain_object_1 = __importDefault(require("is-plain-object"));
8
9
  const pluralize_1 = __importDefault(require("pluralize"));
9
- const change_case_1 = require("change-case");
10
+ function assertNever(x) {
11
+ throw new Error("Unexpected object: " + x);
12
+ }
13
+ exports.assertNever = assertNever;
10
14
  function isEntityTable(t) {
11
15
  const columnNames = t.columns.map((c) => c.name);
12
16
  return includesAllOf(columnNames, ["id", "created_at", "updated_at"]);
@@ -31,35 +35,41 @@ function includesAllOf(set, subset) {
31
35
  }
32
36
  /** Converts `projects` to `Project`. */
33
37
  function tableToEntityName(config, table) {
34
- let entityName = config.__tableToEntityName[table.name];
38
+ let entityName = config.__tableToEntityName?.[table.name];
35
39
  if (!entityName) {
36
40
  const configEntityName = Object.entries(config.entities)
37
41
  .filter(([, conf]) => conf.tableName === table.name)
38
42
  .map(([entityName]) => entityName)[0];
39
- entityName = configEntityName || change_case_1.pascalCase(pluralize_1.default.singular(table.name));
40
- config.__tableToEntityName[table.name] = entityName;
43
+ entityName = configEntityName || (0, change_case_1.pascalCase)(pluralize_1.default.singular(table.name));
44
+ (config.__tableToEntityName ?? (config.__tableToEntityName = {}))[table.name] = entityName;
41
45
  }
42
46
  return entityName;
43
47
  }
44
48
  exports.tableToEntityName = tableToEntityName;
45
49
  /** Maps db types, i.e. `int`, to JS types, i.e. `number`. */
46
- function mapSimpleDbType(dbType) {
50
+ function mapSimpleDbTypeToTypescriptType(dbType) {
47
51
  switch (dbType) {
48
- case "bool":
52
+ case "boolean":
49
53
  return "boolean";
50
54
  case "int":
55
+ case "numeric":
51
56
  return "number";
52
57
  case "text":
58
+ case "citext":
59
+ case "character varying":
53
60
  case "varchar":
61
+ case "uuid":
54
62
  return "string";
55
- case "timestamptz":
63
+ case "timestamp with time zone":
56
64
  case "date":
57
65
  return "Date";
66
+ case "jsonb":
67
+ return "Object";
58
68
  default:
59
- throw new Error(`Unrecognized type ${dbType}`);
69
+ assertNever(dbType);
60
70
  }
61
71
  }
62
- exports.mapSimpleDbType = mapSimpleDbType;
72
+ exports.mapSimpleDbTypeToTypescriptType = mapSimpleDbTypeToTypescriptType;
63
73
  function merge(a, b) {
64
74
  return [...a, ...b];
65
75
  }
@@ -78,7 +88,7 @@ function sortKeys(o) {
78
88
  .sort()
79
89
  .reduce((acc, key) => {
80
90
  const value = o[key];
81
- const newValue = typeof value === "object" && is_plain_object_1.default(value) ? sortKeys(value) : value;
91
+ const newValue = typeof value === "object" && (0, is_plain_object_1.default)(value) ? sortKeys(value) : value;
82
92
  acc[key] = newValue;
83
93
  return acc;
84
94
  }, {});
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,28 +1,40 @@
1
1
  {
2
2
  "name": "joist-codegen",
3
- "version": "0.1.536",
3
+ "version": "1.0.0",
4
4
  "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/stephenh/joist-ts.git",
8
+ "directory": "packages/codegen"
9
+ },
5
10
  "main": "build/index.js",
6
11
  "types": "build/index.d.ts",
12
+ "scripts": {
13
+ "format": "prettier --write '{schema,migrations,src}/**/*.{ts,js,tsx,jsx,graphql}'"
14
+ },
15
+ "files": [
16
+ "build"
17
+ ],
7
18
  "dependencies": {
8
19
  "@types/pluralize": "0.0.29",
9
20
  "change-case": "^4.1.1",
10
- "knex": "^0.21.4",
11
21
  "is-plain-object": "^3.0.1",
12
- "pg": "^8.3.0",
13
- "pg-structure": "^5.10.13",
22
+ "joist-utils": "1.0.0-bump",
23
+ "knex": "^0.95.9",
24
+ "pg": "^8.7.1",
25
+ "pg-structure": "^7.13.0",
14
26
  "pluralize": "^8.0.0",
15
- "ts-poet": "^3.2.2",
16
- "joist-utils": "0.1.536"
27
+ "ts-poet": "^4.8.0"
17
28
  },
18
29
  "devDependencies": {
19
- "@types/jest": "^25.2.1",
20
- "@types/node": "^13.13.4",
21
- "jest": "^26.1.0",
22
- "prettier": "^2.0.5",
23
- "ts-jest": "^26.1.1",
24
- "ts-node-dev": "^1.0.0-pre.50",
25
- "tsconfig-paths": "^3.9.0",
26
- "typescript": "^3.9.5"
30
+ "@swc/jest": "^0.2.16",
31
+ "@types/jest": "^26.0.24",
32
+ "@types/node": "^16.4.10",
33
+ "jest": "^27.0.6",
34
+ "prettier": "^2.5.1",
35
+ "prettier-plugin-organize-imports": "^2.3.4",
36
+ "ts-node-dev": "^1.1.8",
37
+ "tsconfig-paths": "^3.10.1",
38
+ "typescript": "^4.5.2"
27
39
  }
28
40
  }
package/jest.config.js DELETED
@@ -1,10 +0,0 @@
1
- module.exports = {
2
- preset: "ts-jest",
3
- moduleNameMapper: {
4
- "^@src/(.*)": "<rootDir>/src/$1",
5
- },
6
- // globalSetup: "<rootDir>/src/setupTestEnv.js",
7
- testMatch: ["<rootDir>/src/**/*.test.(ts|tsx)"],
8
- testEnvironment: "node",
9
- maxConcurrency: 1,
10
- };
package/package.json.bak DELETED
@@ -1,28 +0,0 @@
1
- {
2
- "name": "joist-codegen",
3
- "version": "0.1.0-bump",
4
- "license": "MIT",
5
- "main": "build/index.js",
6
- "types": "build/index.d.ts",
7
- "dependencies": {
8
- "@types/pluralize": "0.0.29",
9
- "change-case": "^4.1.1",
10
- "knex": "^0.21.4",
11
- "is-plain-object": "^3.0.1",
12
- "pg": "^8.3.0",
13
- "pg-structure": "^5.10.13",
14
- "pluralize": "^8.0.0",
15
- "ts-poet": "^3.2.2",
16
- "joist-utils": "0.1.0-bump"
17
- },
18
- "devDependencies": {
19
- "@types/jest": "^25.2.1",
20
- "@types/node": "^13.13.4",
21
- "jest": "^26.1.0",
22
- "prettier": "^2.0.5",
23
- "ts-jest": "^26.1.1",
24
- "ts-node-dev": "^1.0.0-pre.50",
25
- "tsconfig-paths": "^3.9.0",
26
- "typescript": "^3.9.5"
27
- }
28
- }
@@ -1,42 +0,0 @@
1
- import { defaultConfig } from "./config";
2
- import { collectionName, EntityDbMetadata, makeEntity } from "./EntityDbMetadata";
3
- import { tableToEntityName } from "./utils";
4
-
5
- const relationDummy: any = { targetTable: { m2oRelations: [] } };
6
- const configDummy: any = { relationNameOverrides: {} };
7
-
8
- describe("EntityDbMetadata", () => {
9
- describe("tableToEntityName", () => {
10
- it("singularizes the table names", () => {
11
- expect(tableToEntityName(defaultConfig, { name: "authors" } as any)).toEqual("Author");
12
- });
13
-
14
- it("uses config for the table names", () => {
15
- const config = {
16
- ...defaultConfig,
17
- entities: { Author: { tag: "a", tableName: "TBL_ATHR" } },
18
- };
19
- expect(tableToEntityName(config, { name: "TBL_ATHR" } as any)).toEqual("Author");
20
- });
21
- });
22
-
23
- describe("collectionName", () => {
24
- it("handles base case", () => {
25
- expect(collectionName(configDummy, makeEntity("Author"), makeEntity("Book"), relationDummy).fieldName).toEqual(
26
- "books",
27
- );
28
- });
29
-
30
- it("handles author/mentor", () => {
31
- expect(collectionName(configDummy, makeEntity("Author"), makeEntity("Author"), relationDummy).fieldName).toEqual(
32
- "authors",
33
- );
34
- });
35
-
36
- it("handles book/book review", () => {
37
- expect(
38
- collectionName(configDummy, makeEntity("Book"), makeEntity("BookReview"), relationDummy).fieldName,
39
- ).toEqual("reviews");
40
- });
41
- });
42
- });
@@ -1,322 +0,0 @@
1
- import { camelCase } from "change-case";
2
- import { Column, M2MRelation, M2ORelation, O2MRelation, Table } from "pg-structure";
3
- import { plural, singular } from "pluralize";
4
- import { imp } from "ts-poet";
5
- import { SymbolSpec } from "ts-poet/build/SymbolSpecs";
6
- import { Config, isAsyncDerived, isDerived, isProtected, ormMaintainedFields, relationName } from "./config";
7
- import { ColumnMetaData } from "./generateEntityCodegenFile";
8
- import { isEnumTable, isJoinTable, mapSimpleDbType, tableToEntityName } from "./utils";
9
-
10
- // TODO Populate from config
11
- const columnCustomizations: Record<string, ColumnMetaData> = {};
12
-
13
- /** Codegen-time metadata about a given domain entity. */
14
- export type Entity = {
15
- name: string;
16
- /** The symbol pointing to the entity itself. */
17
- type: SymbolSpec;
18
- /** The name of the entity's runtime metadata const. */
19
- metaName: string;
20
- /** The symbol pointing to the entity's runtime metadata const. */
21
- metaType: SymbolSpec;
22
- /** The symbol pointing to the entity's EntityId type. */
23
- idType: SymbolSpec;
24
- /** The symbol pointing to the entity's Order type. */
25
- orderType: SymbolSpec;
26
- /** The symbol pointing to the entity's config const. */
27
- configConst: SymbolSpec;
28
- optsType: SymbolSpec;
29
- };
30
-
31
- export type PrimitiveField = {
32
- fieldName: string;
33
- columnName: string;
34
- columnType: string;
35
- columnDefault: number | boolean | string | null;
36
- fieldType: string | SymbolSpec;
37
- notNull: boolean;
38
- derived: "orm" | "sync" | "async" | false;
39
- protected: boolean;
40
- };
41
-
42
- export type EnumField = {
43
- fieldName: string;
44
- columnName: string;
45
- enumName: string;
46
- enumType: SymbolSpec;
47
- enumDetailType: SymbolSpec;
48
- notNull: boolean;
49
- };
50
-
51
- /** I.e. a `Book.author` reference pointing to an `Author`. */
52
- export type ManyToOneField = {
53
- fieldName: string;
54
- columnName: string;
55
- otherFieldName: string;
56
- otherEntity: Entity;
57
- notNull: boolean;
58
- };
59
-
60
- /** I.e. a `Author.books` collection. */
61
- export type OneToManyField = {
62
- fieldName: string;
63
- singularName: string;
64
- otherEntity: Entity;
65
- otherFieldName: string;
66
- otherColumnName: string;
67
- otherColumnNotNull: boolean;
68
- };
69
-
70
- /** I.e. a `Author.image` reference when `image.author_id` is unique. */
71
- export type OneToOneField = {
72
- fieldName: string;
73
- otherEntity: Entity;
74
- otherFieldName: string;
75
- otherColumnName: string;
76
- otherColumnNotNull: boolean;
77
- };
78
-
79
- export type ManyToManyField = {
80
- joinTableName: string;
81
- fieldName: string;
82
- singularName: string;
83
- columnName: string;
84
- otherEntity: Entity;
85
- otherFieldName: string;
86
- otherColumnName: string;
87
- };
88
-
89
- /** Adapts the generally-great pg-structure metadata into our specific ORM types. */
90
- export class EntityDbMetadata {
91
- entity: Entity;
92
- primitives: PrimitiveField[];
93
- enums: EnumField[];
94
- manyToOnes: ManyToOneField[];
95
- oneToManys: OneToManyField[];
96
- oneToOnes: OneToOneField[];
97
- manyToManys: ManyToManyField[];
98
- tableName: string;
99
-
100
- constructor(config: Config, table: Table) {
101
- this.entity = makeEntity(tableToEntityName(config, table));
102
- this.primitives = table.columns
103
- .filter((c) => !c.isPrimaryKey && !c.isForeignKey)
104
- .map((column) => newPrimitive(config, this.entity, column, table));
105
- this.enums = table.m2oRelations.filter((r) => isEnumTable(r.targetTable)).map((r) => newEnumField(config, r));
106
- this.manyToOnes = table.m2oRelations
107
- .filter((r) => !isEnumTable(r.targetTable))
108
- .filter((r) => !isMultiColumnForeignKey(r))
109
- .map((r) => newManyToOneField(config, this.entity, r));
110
- this.oneToManys = table.o2mRelations
111
- // ManyToMany join tables also show up as OneToMany tables in pg-structure
112
- .filter((r) => !isJoinTable(r.targetTable))
113
- .filter((r) => !isMultiColumnForeignKey(r))
114
- .filter((r) => !isOneToOneRelation(r))
115
- .map((r) => newOneToMany(config, this.entity, r));
116
- this.oneToOnes = table.o2mRelations
117
- // ManyToMany join tables also show up as OneToMany tables in pg-structure
118
- .filter((r) => !isJoinTable(r.targetTable))
119
- .filter((r) => !isMultiColumnForeignKey(r))
120
- .filter((r) => isOneToOneRelation(r))
121
- .map((r) => newOneToOne(config, this.entity, r));
122
- this.manyToManys = table.m2mRelations
123
- // pg-structure is really loose on what it considers a m2m relationship, i.e. any entity
124
- // that has a foreign key to us, and a foreign key to something else, is automatically
125
- // considered as a join table/m2m between "us" and "something else". Filter these out
126
- // by looking for only true join tables, i.e. tables with only id, fk1, and fk2.
127
- .filter((r) => isJoinTable(r.joinTable))
128
- .filter((r) => !isMultiColumnForeignKey(r))
129
- .map((r) => newManyToManyField(config, this.entity, r));
130
- this.tableName = table.name;
131
- }
132
-
133
- get name(): string {
134
- return this.entity.name;
135
- }
136
- }
137
-
138
- function isMultiColumnForeignKey(r: M2ORelation) {
139
- return r.foreignKey.columns.length > 1;
140
- }
141
-
142
- function isOneToOneRelation(r: O2MRelation) {
143
- // otherColumn will be the images.book_id in the other table
144
- const otherColumn = r.foreignKey.columns[0];
145
- // r.foreignKey.index is the index on _us_ (i.e. our Book primary key), so look up indexes in the target table
146
- const indexes = r.targetTable.columns.find((c) => c.name == otherColumn.name)?.uniqueIndexes || [];
147
- // If the column is the only column in an unique index, it's a one-to-one
148
- return indexes.find((i) => i.columns.length === 1) !== undefined;
149
- }
150
-
151
- function newPrimitive(config: Config, entity: Entity, column: Column, table: Table): PrimitiveField {
152
- const fieldName = camelCase(column.name);
153
- const columnName = column.name;
154
- return {
155
- fieldName,
156
- columnName,
157
- columnType: column.type.shortName || column.type.name,
158
- fieldType: mapType(table.name, columnName, column.type.shortName || column.type.name).fieldType,
159
- notNull: column.notNull,
160
- columnDefault: column.default,
161
- derived: fieldDerived(config, entity, fieldName),
162
- protected: isProtected(config, entity, fieldName),
163
- };
164
- }
165
-
166
- function fieldDerived(config: Config, entity: Entity, fieldName: string): PrimitiveField["derived"] {
167
- if (ormMaintainedFields.includes(fieldName)) {
168
- return "orm";
169
- } else if (isDerived(config, entity, fieldName)) {
170
- return "sync";
171
- } else if (isAsyncDerived(config, entity, fieldName)) {
172
- return "async";
173
- } else {
174
- return false;
175
- }
176
- }
177
-
178
- function newEnumField(config: Config, r: M2ORelation): EnumField {
179
- const column = r.foreignKey.columns[0];
180
- const columnName = column.name;
181
- const fieldName = camelCase(column.name.replace("_id", ""));
182
- const enumName = tableToEntityName(config, r.targetTable);
183
- const enumType = imp(`${enumName}@./entities`);
184
- const enumDetailType = imp(`${plural(enumName)}@./entities`);
185
- const notNull = column.notNull;
186
- return { fieldName, columnName, enumName, enumType, enumDetailType, notNull };
187
- }
188
-
189
- function newManyToOneField(config: Config, entity: Entity, r: M2ORelation): ManyToOneField {
190
- const column = r.foreignKey.columns[0];
191
- const columnName = column.name;
192
- const fieldName = referenceName(config, entity, r);
193
- const otherEntity = makeEntity(tableToEntityName(config, r.targetTable));
194
- const isOneToOne = column.uniqueIndexes.find((i) => i.columns.length === 1) !== undefined;
195
- const otherFieldName = isOneToOne
196
- ? oneToOneName(config, otherEntity, entity)
197
- : collectionName(config, otherEntity, entity, r).fieldName;
198
- const notNull = column.notNull;
199
- return { fieldName, columnName, otherEntity, otherFieldName, notNull };
200
- }
201
-
202
- function newOneToMany(config: Config, entity: Entity, r: O2MRelation): OneToManyField {
203
- const column = r.foreignKey.columns[0];
204
- // source == parent i.e. the reference of the foreign key column
205
- // target == child i.e. the table with the foreign key column in it
206
- const otherEntity = makeEntity(tableToEntityName(config, r.targetTable));
207
- const { singularName, fieldName } = collectionName(config, entity, otherEntity, r);
208
- const otherFieldName = referenceName(config, otherEntity, r);
209
- const otherColumnName = column.name;
210
- const otherColumnNotNull = column.notNull;
211
- return { fieldName, singularName, otherEntity, otherFieldName, otherColumnName, otherColumnNotNull };
212
- }
213
-
214
- function newOneToOne(config: Config, entity: Entity, r: O2MRelation): OneToOneField {
215
- const column = r.foreignKey.columns[0];
216
- // source == parent i.e. the reference of the foreign key column
217
- // target == child i.e. the table with the foreign key column in it
218
- const otherEntity = makeEntity(tableToEntityName(config, r.targetTable));
219
- const fieldName = oneToOneName(config, entity, otherEntity);
220
- const otherFieldName = referenceName(config, otherEntity, r);
221
- const otherColumnName = column.name;
222
- const otherColumnNotNull = column.notNull;
223
- return { fieldName, otherEntity, otherFieldName, otherColumnName, otherColumnNotNull };
224
- }
225
-
226
- function newManyToManyField(config: Config, entity: Entity, r: M2MRelation): ManyToManyField {
227
- const { foreignKey, targetForeignKey, targetTable } = r;
228
- const joinTableName = r.joinTable.name;
229
- const otherEntity = makeEntity(tableToEntityName(config, targetTable));
230
- const fieldName = relationName(
231
- config,
232
- entity,
233
- camelCase(plural(targetForeignKey.columns[0].name.replace("_id", ""))),
234
- );
235
- const otherFieldName = relationName(
236
- config,
237
- otherEntity,
238
- camelCase(plural(foreignKey.columns[0].name.replace("_id", ""))),
239
- );
240
- const columnName = foreignKey.columns[0].name;
241
- const otherColumnName = targetForeignKey.columns[0].name;
242
- const singularName = singular(fieldName);
243
- return { joinTableName, fieldName, singularName, columnName, otherEntity, otherFieldName, otherColumnName };
244
- }
245
-
246
- export function oneToOneName(config: Config, entity: Entity, otherEntity: Entity): string {
247
- return relationName(config, entity, camelCase(otherEntity.name));
248
- }
249
-
250
- export function referenceName(config: Config, entity: Entity, r: M2ORelation | O2MRelation): string {
251
- const column = r.foreignKey.columns[0];
252
- const fieldName = camelCase(column.name.replace("_id", ""));
253
- return relationName(config, entity, fieldName);
254
- }
255
-
256
- /** Returns the collection name to use on `entity` when referring to `otherEntity`s. */
257
- export function collectionName(
258
- config: Config,
259
- entity: Entity,
260
- otherEntity: Entity,
261
- r: M2ORelation | O2MRelation,
262
- ): { fieldName: string; singularName: string } {
263
- // TODO Handle conflicts in names
264
- // I.e. if the other side is `child.project_id`, use `children`.
265
- let fieldName = otherEntity.name;
266
- // check if we have multiple FKs from otherEntity --> entity and prefix with FK name if so
267
- const sourceTable = r instanceof M2ORelation ? r.sourceTable : r.targetTable;
268
- const targetTable = r instanceof M2ORelation ? r.targetTable : r.sourceTable;
269
- if (sourceTable.m2oRelations.filter((r) => r.targetTable === targetTable).length > 1) {
270
- fieldName = `${r.foreignKey.columns[0].name.replace("_id", "")}_${fieldName}`;
271
- }
272
- // If the other side is `book_reviews.book_id`, use `reviews`.
273
- if (fieldName.length > entity.name.length) {
274
- fieldName = fieldName.replace(entity.name, "");
275
- }
276
-
277
- // camelize the name
278
- let singularName = camelCase(fieldName);
279
- fieldName = camelCase(plural(fieldName));
280
-
281
- // If the name is overridden, use that, but also singularize it
282
- const maybeOverriddenName = relationName(config, entity, fieldName);
283
- if (maybeOverriddenName !== fieldName) {
284
- singularName = singular(maybeOverriddenName);
285
- fieldName = maybeOverriddenName;
286
- }
287
-
288
- return { singularName, fieldName };
289
- }
290
-
291
- export function makeEntity(entityName: string): Entity {
292
- return {
293
- name: entityName,
294
- type: entityType(entityName),
295
- metaName: metaName(entityName),
296
- metaType: metaType(entityName),
297
- idType: imp(`${entityName}Id@./entities`, { definedIn: `./${entityName}Codegen` }),
298
- orderType: imp(`${entityName}Order@./entities`, { definedIn: `./${entityName}Codegen` }),
299
- optsType: imp(`${entityName}Opts@./entities`, { definedIn: `./${entityName}Codegen` }),
300
- configConst: imp(`${camelCase(entityName)}Config@./entities`, { definedIn: `./${entityName}Codegen` }),
301
- };
302
- }
303
-
304
- function metaName(entityName: string): string {
305
- return `${camelCase(entityName)}Meta`;
306
- }
307
-
308
- function metaType(entityName: string): SymbolSpec {
309
- return imp(`${metaName(entityName)}@./entities`);
310
- }
311
-
312
- function entityType(entityName: string): SymbolSpec {
313
- return imp(`${entityName}@./entities`);
314
- }
315
-
316
- function mapType(tableName: string, columnName: string, dbColumnType: string): ColumnMetaData {
317
- return (
318
- columnCustomizations[`${tableName}.${columnName}`] || {
319
- fieldType: mapSimpleDbType(dbColumnType),
320
- }
321
- );
322
- }
package/src/assignTags.ts DELETED
@@ -1,45 +0,0 @@
1
- import { snakeCase, camelCase } from "change-case";
2
- import { DbMetadata } from "./index";
3
- import { Config } from "./config";
4
-
5
- /**
6
- * Looks for any entities that don't have tags in `config` yet, and guesses at what a good tag would be.
7
- *
8
- * The current guess is `BookReview` -> `br`. If that guess is already taken, we use the full entity name,
9
- * i.e. `bookReview`. The user can then customize the tags as they want directly in `joist-codegen.json`.
10
- *
11
- * We also mutate `config` by putting the new tag into the `config`'s entity entry.
12
- */
13
- export function assignTags(config: Config, dbMetadata: DbMetadata): void {
14
- const existingTags = Object.fromEntries(
15
- Object.entries(config.entities).map(([name, conf]) => {
16
- return [name, conf.tag];
17
- }),
18
- );
19
-
20
- const existingTagNames = Object.values(existingTags);
21
-
22
- dbMetadata.entities
23
- .filter((e) => !existingTags[e.name])
24
- .forEach((e) => {
25
- const abbreviatedTag = guessTagName(e.name);
26
- const tagName = existingTagNames.includes(abbreviatedTag) ? camelCase(e.name) : abbreviatedTag;
27
- const oc = config.entities[e.name];
28
- if (!oc) {
29
- config.entities[e.name] = { tag: tagName };
30
- } else {
31
- oc.tag = tagName;
32
- }
33
- existingTagNames.push(tagName);
34
- });
35
-
36
- // TODO ensure tags are unique
37
- }
38
-
39
- /** Abbreviates `BookReview` -> `book_review` -> `br`. */
40
- function guessTagName(name: string): string {
41
- return snakeCase(name)
42
- .split("_")
43
- .map((w) => w[0])
44
- .join("");
45
- }