velocious 1.0.579 → 1.0.581

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 (49) hide show
  1. package/README.md +25 -0
  2. package/build/cli/command-arguments.js +45 -0
  3. package/build/cli/index.js +10 -0
  4. package/build/configuration-types.js +3 -0
  5. package/build/database/drivers/base.js +92 -2
  6. package/build/database/drivers/sqlite/base.js +7 -2
  7. package/build/database/generation-context.js +121 -0
  8. package/build/database/initializer-from-require-context.js +7 -0
  9. package/build/environment-handlers/node/cli/commands/db/schema/dump.js +25 -0
  10. package/build/environment-handlers/node/cli/commands/db/schema/load.js +37 -8
  11. package/build/environment-handlers/node/cli/commands/generate/base-models.js +82 -13
  12. package/build/src/cli/command-arguments.d.ts +27 -0
  13. package/build/src/cli/command-arguments.d.ts.map +1 -0
  14. package/build/src/cli/command-arguments.js +38 -0
  15. package/build/src/cli/index.d.ts.map +1 -1
  16. package/build/src/cli/index.js +9 -1
  17. package/build/src/configuration-types.d.ts +18 -0
  18. package/build/src/configuration-types.d.ts.map +1 -1
  19. package/build/src/configuration-types.js +4 -1
  20. package/build/src/database/drivers/base.d.ts +38 -0
  21. package/build/src/database/drivers/base.d.ts.map +1 -1
  22. package/build/src/database/drivers/base.js +82 -3
  23. package/build/src/database/drivers/sqlite/base.d.ts.map +1 -1
  24. package/build/src/database/drivers/sqlite/base.js +6 -3
  25. package/build/src/database/generation-context.d.ts +62 -0
  26. package/build/src/database/generation-context.d.ts.map +1 -0
  27. package/build/src/database/generation-context.js +102 -0
  28. package/build/src/database/initializer-from-require-context.d.ts.map +1 -1
  29. package/build/src/database/initializer-from-require-context.js +6 -1
  30. package/build/src/environment-handlers/node/cli/commands/db/schema/dump.d.ts.map +1 -1
  31. package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +22 -1
  32. package/build/src/environment-handlers/node/cli/commands/db/schema/load.d.ts +11 -0
  33. package/build/src/environment-handlers/node/cli/commands/db/schema/load.d.ts.map +1 -1
  34. package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +33 -7
  35. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts +14 -0
  36. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
  37. package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +371 -308
  38. package/build/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +1 -1
  40. package/src/cli/command-arguments.js +45 -0
  41. package/src/cli/index.js +10 -0
  42. package/src/configuration-types.js +3 -0
  43. package/src/database/drivers/base.js +92 -2
  44. package/src/database/drivers/sqlite/base.js +7 -2
  45. package/src/database/generation-context.js +121 -0
  46. package/src/database/initializer-from-require-context.js +7 -0
  47. package/src/environment-handlers/node/cli/commands/db/schema/dump.js +25 -0
  48. package/src/environment-handlers/node/cli/commands/db/schema/load.js +37 -8
  49. package/src/environment-handlers/node/cli/commands/generate/base-models.js +82 -13
@@ -1,4 +1,6 @@
1
1
  import BaseCommand from "../../../../../../cli/base-command.js"
2
+ import commandArguments from "../../../../../../cli/command-arguments.js"
3
+ import DatabaseGenerationContext from "../../../../../../database/generation-context.js"
2
4
  import fileExists from "../../../../../../utils/file-exists.js"
3
5
  import path from "path"
4
6
 
@@ -8,6 +10,29 @@ export default class DbSchemaDump extends BaseCommand {
8
10
  * Runs execute.
9
11
  * @returns {Promise<void>} */
10
12
  async execute() {
13
+ const parsedArguments = commandArguments({
14
+ definition: {valueOptions: ["--tenant"]},
15
+ processArgs: this.processArgs || []
16
+ })
17
+ const tenantDatabaseIdentifier = parsedArguments.tenant
18
+
19
+ if (typeof tenantDatabaseIdentifier === "string") {
20
+ const context = await DatabaseGenerationContext.resolve({
21
+ configuration: this.getConfiguration(),
22
+ databaseIdentifier: tenantDatabaseIdentifier
23
+ })
24
+
25
+ await context.run({name: "DB selected tenant schema dump", callback: async (db) => {
26
+ const dbs = {[context.databaseIdentifier()]: db}
27
+ const shouldGenerate = await this.shouldGenerateStructureSql({dbs})
28
+
29
+ if (!shouldGenerate) return
30
+
31
+ await this.getEnvironmentHandler().afterMigrations({dbs, reason: "schemaDump"})
32
+ }})
33
+ return
34
+ }
35
+
11
36
  await this.getConfiguration().ensureConnections({name: "DB schema dump"}, async (dbs) => {
12
37
  const shouldGenerate = await this.shouldGenerateStructureSql({dbs})
13
38
 
@@ -1,4 +1,6 @@
1
1
  import BaseCommand from "../../../../../../cli/base-command.js"
2
+ import commandArguments from "../../../../../../cli/command-arguments.js"
3
+ import DatabaseGenerationContext from "../../../../../../database/generation-context.js"
2
4
  import fs from "fs/promises"
3
5
  import path from "path"
4
6
  import StructureSqlLoader from "../../../../../../database/structure-sql-loader.js"
@@ -9,17 +11,44 @@ export default class DbSchemaLoad extends BaseCommand {
9
11
  * Runs execute.
10
12
  * @returns {Promise<void>} */
11
13
  async execute() {
12
- await this.getConfiguration().ensureConnections({name: "DB schema load"}, async (dbs) => {
13
- const dbDir = path.join(this.directory(), "db")
14
- const loader = new StructureSqlLoader()
14
+ const parsedArguments = commandArguments({
15
+ definition: {valueOptions: ["--tenant"]},
16
+ processArgs: this.processArgs || []
17
+ })
18
+ const tenantDatabaseIdentifier = parsedArguments.tenant
15
19
 
16
- for (const identifier of Object.keys(dbs)) {
17
- const db = dbs[identifier]
18
- const structureFilePath = path.join(dbDir, `structure-${identifier}.sql`)
19
- const structureSql = await fs.readFile(structureFilePath, "utf8")
20
+ if (typeof tenantDatabaseIdentifier === "string") {
21
+ const context = await DatabaseGenerationContext.resolve({
22
+ configuration: this.getConfiguration(),
23
+ databaseIdentifier: tenantDatabaseIdentifier
24
+ })
20
25
 
21
- await loader.load({db, structureSql})
26
+ await context.run({name: "DB selected tenant schema load", callback: async (db) => {
27
+ await this.loadStructureSql({db, identifier: context.databaseIdentifier()})
28
+ }})
29
+ return
30
+ }
31
+
32
+ await this.getConfiguration().ensureConnections({name: "DB schema load"}, async (dbs) => {
33
+ for (const identifier of Object.keys(dbs)) {
34
+ await this.loadStructureSql({db: dbs[identifier], identifier})
22
35
  }
23
36
  })
24
37
  }
38
+
39
+ /**
40
+ * Loads one identifier's explicit structure file into one selected connection.
41
+ * @param {object} args - Load arguments.
42
+ * @param {import("../../../../../../database/drivers/base.js").default} args.db - Target connection.
43
+ * @param {string} args.identifier - Logical database identifier used in the file name.
44
+ * @returns {Promise<void>} - Resolves after loading.
45
+ */
46
+ async loadStructureSql({db, identifier}) {
47
+ const dbDir = path.join(this.directory(), "db")
48
+ const loader = new StructureSqlLoader()
49
+ const structureFilePath = path.join(dbDir, `structure-${identifier}.sql`)
50
+ const structureSql = await fs.readFile(structureFilePath, "utf8")
51
+
52
+ await loader.load({db, structureSql})
53
+ }
25
54
  }
@@ -1,6 +1,8 @@
1
1
  // @ts-check
2
2
 
3
3
  import BaseCommand from "../../../../../cli/base-command.js"
4
+ import commandArguments from "../../../../../cli/command-arguments.js"
5
+ import DatabaseGenerationContext from "../../../../../database/generation-context.js"
4
6
  import deburrColumnName from "../../../../../utils/deburr-column-name.js"
5
7
  import fileExists from "../../../../../utils/file-exists.js"
6
8
  import fs from "fs/promises"
@@ -62,15 +64,64 @@ function generatedRelationshipMethod({abstract = false, body, name, param, retur
62
64
 
63
65
  export default class DbGenerateModel extends BaseCommand {
64
66
  async execute() {
67
+ const parsedArguments = commandArguments({
68
+ definition: {
69
+ booleanOptions: ["--allow-missing-tables"],
70
+ valueOptions: ["--tenant"]
71
+ },
72
+ processArgs: this.processArgs || []
73
+ })
74
+ const allowMissingTables = parsedArguments["allow-missing-tables"] === true
75
+ const tenantDatabaseIdentifier = parsedArguments.tenant
76
+
77
+ if (typeof tenantDatabaseIdentifier === "string") {
78
+ const context = await DatabaseGenerationContext.resolve({
79
+ configuration: this.getConfiguration(),
80
+ databaseIdentifier: tenantDatabaseIdentifier
81
+ })
82
+ const selectedModelClasses = Object.values(this.getConfiguration().getModelClasses()).filter((modelClass) => {
83
+ const databaseIdentifier = modelClass.getDatabaseIdentifier({
84
+ enforceTenantDatabaseScope: false,
85
+ tenant: context.tenant()
86
+ })
87
+
88
+ if (databaseIdentifier !== context.databaseIdentifier()) return false
89
+
90
+ return modelClass.getDatabaseIdentifier({tenant: context.tenant()}) === context.databaseIdentifier()
91
+ })
92
+
93
+ try {
94
+ return await context.run({name: "Generate selected tenant base models", callback: async (connection) => {
95
+ await this.generateBaseModels({allowMissingTables, connections: {[context.databaseIdentifier()]: connection}, context})
96
+ }})
97
+ } finally {
98
+ for (const modelClass of selectedModelClasses) modelClass.resetRecordMetadata()
99
+ }
100
+ }
101
+
65
102
  await this.getConfiguration().initializeModels()
66
103
 
67
- const enforceTenantDatabaseScopes = this.getConfiguration().getEnforceTenantDatabaseScopes()
104
+ return await this.getConfiguration().ensureConnections({name: "Generate base models"}, async (connections) => {
105
+ await this.generateBaseModels({allowMissingTables, connections})
106
+ })
107
+ }
68
108
 
109
+ /**
110
+ * Generates model bases from explicit connections.
111
+ * @param {object} args - Generation arguments.
112
+ * @param {boolean} args.allowMissingTables - Whether absent tables are skipped.
113
+ * @param {Record<string, import("../../../../../database/drivers/base.js").default>} args.connections - Connections keyed by logical identifier.
114
+ * @param {DatabaseGenerationContext} [args.context] - Selected tenant database context.
115
+ * @returns {Promise<void>} - Resolves after writing generated bases.
116
+ */
117
+ async generateBaseModels({allowMissingTables, connections, context}) {
69
118
  const rootDirectory = this.directory()
70
119
  const modelsDir = `${rootDirectory}/src/models`
71
120
  const baseModelsDir = `${rootDirectory}/src/model-bases`
72
121
  const modelClasses = this.getConfiguration().getModelClasses()
73
- const allowMissingTables = Boolean(this.processArgs?.includes("--allow-missing-tables"))
122
+ const regenerateCommand = context
123
+ ? `${BASE_MODELS_REGENERATE_COMMAND} --tenant ${context.databaseIdentifier()}`
124
+ : BASE_MODELS_REGENERATE_COMMAND
74
125
  let devMode = false
75
126
 
76
127
  if (baseModelsDir.includes("/spec/dummy/src/model-bases")) {
@@ -81,13 +132,33 @@ export default class DbGenerateModel extends BaseCommand {
81
132
  await fs.mkdir(baseModelsDir, {recursive: true})
82
133
  }
83
134
 
84
- this.getConfiguration().setEnforceTenantDatabaseScopes(false)
85
-
86
- try {
87
- await this.getConfiguration().ensureConnections({name: "Generate base models"}, async () => {
88
- for (const modelClassName in modelClasses) {
135
+ for (const modelClassName in modelClasses) {
89
136
  const modelClass = modelClasses[modelClassName]
90
- const table = await modelClass.connection().getTableByName(modelClass.tableName(), {throwError: !allowMissingTables})
137
+ let databaseIdentifier
138
+
139
+ if (context) {
140
+ databaseIdentifier = modelClass.getDatabaseIdentifier({
141
+ enforceTenantDatabaseScope: false,
142
+ tenant: context.tenant()
143
+ })
144
+
145
+ if (databaseIdentifier !== context.databaseIdentifier()) continue
146
+
147
+ databaseIdentifier = modelClass.getDatabaseIdentifier({tenant: context.tenant()})
148
+ } else {
149
+ databaseIdentifier = modelClass.getConfiguredDatabaseIdentifier()
150
+ }
151
+
152
+ if (context && databaseIdentifier !== context.databaseIdentifier()) continue
153
+
154
+ const connection = connections[databaseIdentifier]
155
+
156
+ // Default generation continues to ignore inactive tenant-only identifiers.
157
+ if (!connection) continue
158
+
159
+ if (context) modelClass.resetRecordMetadata()
160
+
161
+ const table = await connection.getTableByName(modelClass.tableName(), {throwError: !allowMissingTables})
91
162
 
92
163
  if (!table) {
93
164
  console.warn(`Skipping base model for '${modelClass.name}': table '${modelClass.tableName()}' was not found (--allow-missing-tables). Keeping any existing base model.`)
@@ -95,6 +166,8 @@ export default class DbGenerateModel extends BaseCommand {
95
166
  continue
96
167
  }
97
168
 
169
+ await modelClass.ensureInitialized({configuration: this.getConfiguration(), connection})
170
+
98
171
  const modelName = inflection.dasherize(modelClassName)
99
172
  const modelNameCamelized = inflection.camelize(modelName.replaceAll("-", "_"))
100
173
  const modelBaseFileName = `${inflection.dasherize(inflection.underscore(modelName))}.js`
@@ -111,7 +184,7 @@ export default class DbGenerateModel extends BaseCommand {
111
184
  sourceModelFilePath = "velocious/build/src/database/record/index.js"
112
185
  }
113
186
 
114
- let fileContent = generatedFileBanner(BASE_MODELS_REGENERATE_COMMAND)
187
+ let fileContent = generatedFileBanner(regenerateCommand)
115
188
  let velociousPath
116
189
 
117
190
  if (devMode) {
@@ -454,10 +527,6 @@ export default class DbGenerateModel extends BaseCommand {
454
527
  fileContent += "}\n"
455
528
 
456
529
  await fs.writeFile(modelPath, fileContent)
457
- }
458
- })
459
- } finally {
460
- this.getConfiguration().setEnforceTenantDatabaseScopes(enforceTenantDatabaseScopes)
461
530
  }
462
531
  }
463
532