velocious 1.0.87 → 1.0.89
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.
- package/package.json +1 -1
- package/src/cli/base-command.js +25 -2
- package/src/cli/commands/destroy/migration.js +1 -29
- package/src/cli/commands/generate/migration.js +1 -27
- package/src/cli/commands/generate/model.js +1 -27
- package/src/cli/index.js +1 -1
- package/src/database/initializer-from-require-context.js +16 -5
- package/src/database/table-data/index.js +20 -0
- package/src/database/table-data/table-column.js +76 -1
- package/src/database/table-data/table-foreign-key.js +36 -0
- package/src/database/table-data/table-index.js +17 -0
- package/src/database/table-data/table-reference.js +4 -0
- package/src/database/use-database.js +6 -3
- package/src/environment-handlers/base.js +14 -0
- package/src/environment-handlers/browser.js +12 -0
- package/src/environment-handlers/node/cli/commands/destroy/migration.js +35 -0
- package/src/environment-handlers/node/cli/commands/generate/migration.js +33 -0
- package/src/environment-handlers/node/cli/commands/generate/model.js +33 -0
- package/src/environment-handlers/node.js +15 -0
- package/src/testing/test-files-finder.js +5 -0
- package/src/testing/test.js +31 -0
package/package.json
CHANGED
package/src/cli/base-command.js
CHANGED
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
import restArgsError from "../utils/rest-args-error.js"
|
|
2
2
|
|
|
3
3
|
export default class VelociousCliBaseCommand {
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} args
|
|
6
|
+
* @param {object} args.args
|
|
7
|
+
*/
|
|
8
|
+
constructor({args = {}, ...restArgs}) {
|
|
5
9
|
restArgsError(restArgs)
|
|
6
10
|
|
|
7
11
|
this.args = args
|
|
8
12
|
this._configuration = args.configuration
|
|
9
|
-
this._environmentHandler =
|
|
13
|
+
this._environmentHandler = args.configuration.getEnvironmentHandler()
|
|
10
14
|
this.processArgs = args.processArgs
|
|
11
15
|
}
|
|
12
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
13
20
|
directory() { return this.getConfiguration().getDirectory() }
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @interface
|
|
24
|
+
*/
|
|
25
|
+
execute() {
|
|
26
|
+
throw new Error("execute not implemented")
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @returns {import("../configuration.js").default}
|
|
31
|
+
*/
|
|
14
32
|
getConfiguration() { return this._configuration }
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @template T extends import("../environment-handlers/base.js").default
|
|
36
|
+
* @returns {T}
|
|
37
|
+
*/
|
|
15
38
|
getEnvironmentHandler() { return this._environmentHandler }
|
|
16
39
|
}
|
|
@@ -1,35 +1,7 @@
|
|
|
1
1
|
import BaseCommand from "../../base-command.js"
|
|
2
|
-
import fs from "fs/promises"
|
|
3
2
|
|
|
4
3
|
export default class DbDestroyMigration extends BaseCommand {
|
|
5
4
|
async execute() {
|
|
6
|
-
|
|
7
|
-
const migrationDir = `${this.getConfiguration().getDirectory()}/src/database/migrations`
|
|
8
|
-
const migrationFiles = await fs.readdir(migrationDir)
|
|
9
|
-
const destroyed = []
|
|
10
|
-
|
|
11
|
-
for (const migrationFile of migrationFiles) {
|
|
12
|
-
const match = migrationFile.match(/^(\d{14})-(.+)\.js$/)
|
|
13
|
-
|
|
14
|
-
if (!match) {
|
|
15
|
-
continue
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const fileName = match[2]
|
|
19
|
-
|
|
20
|
-
if (fileName != migrationName) continue
|
|
21
|
-
|
|
22
|
-
const fullFilePath = `${migrationDir}/${migrationFile}`
|
|
23
|
-
destroyed.push(fileName)
|
|
24
|
-
|
|
25
|
-
if (!this.args.testing) {
|
|
26
|
-
console.log(`Destroy src/database/migrations/${migrationFile}`)
|
|
27
|
-
await fs.unlink(fullFilePath)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (this.args.testing) {
|
|
32
|
-
return {destroyed}
|
|
33
|
-
}
|
|
5
|
+
return await this.getConfiguration().getEnvironmentHandler().cliCommandsMigrationDestroy(this)
|
|
34
6
|
}
|
|
35
7
|
}
|
|
@@ -1,33 +1,7 @@
|
|
|
1
1
|
import BaseCommand from "../../base-command.js"
|
|
2
|
-
import fileExists from "../../../utils/file-exists.js"
|
|
3
|
-
import fs from "fs/promises"
|
|
4
|
-
import * as inflection from "inflection"
|
|
5
|
-
import strftime from "strftime"
|
|
6
2
|
|
|
7
3
|
export default class DbGenerateMigration extends BaseCommand {
|
|
8
4
|
async execute() {
|
|
9
|
-
|
|
10
|
-
const migrationNameCamelized = inflection.camelize(migrationName.replaceAll("-", "_"))
|
|
11
|
-
const date = new Date()
|
|
12
|
-
const migrationNumber = strftime("%Y%m%d%H%M%S")
|
|
13
|
-
const migrationFileName = `${migrationNumber}-${migrationName}.js`
|
|
14
|
-
const velociousPath = await this.getEnvironmentHandler().getVelociousPath()
|
|
15
|
-
const templateFilePath = `${velociousPath}/src/templates/generate-migration.js`
|
|
16
|
-
const migrationContentBuffer = await fs.readFile(templateFilePath)
|
|
17
|
-
const migrationContent = migrationContentBuffer.toString().replaceAll("__MIGRATION_NAME__", migrationNameCamelized)
|
|
18
|
-
const migrationDir = `${process.cwd()}/src/database/migrations`
|
|
19
|
-
const migrationPath = `${migrationDir}/${migrationFileName}`
|
|
20
|
-
|
|
21
|
-
if (this.args.testing) {
|
|
22
|
-
return {date, migrationContent, migrationName, migrationNameCamelized, migrationNumber, migrationPath}
|
|
23
|
-
} else {
|
|
24
|
-
if (!await fileExists(migrationDir)) {
|
|
25
|
-
await fs.mkdir(migrationDir, {recursive: true})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
await fs.writeFile(migrationPath, migrationContent)
|
|
29
|
-
|
|
30
|
-
console.log(`create src/database/migrations/${migrationFileName}`)
|
|
31
|
-
}
|
|
5
|
+
return await this.getConfiguration().getEnvironmentHandler().cliCommandsMigrationGenerate(this)
|
|
32
6
|
}
|
|
33
7
|
}
|
|
@@ -1,33 +1,7 @@
|
|
|
1
1
|
import BaseCommand from "../../base-command.js"
|
|
2
|
-
import fileExists from "../../../utils/file-exists.js"
|
|
3
|
-
import fs from "fs/promises"
|
|
4
|
-
import * as inflection from "inflection"
|
|
5
2
|
|
|
6
3
|
export default class DbGenerateModel extends BaseCommand {
|
|
7
4
|
async execute() {
|
|
8
|
-
|
|
9
|
-
const modelNameCamelized = inflection.camelize(modelName.replaceAll("-", "_"))
|
|
10
|
-
const date = new Date()
|
|
11
|
-
const modelFileName = `${inflection.dasherize(inflection.underscore(modelName))}.js`
|
|
12
|
-
const velociousPath = await this.getEnvironmentHandler().getVelociousPath()
|
|
13
|
-
const templateFilePath = `${velociousPath}/src/templates/generate-model.js`
|
|
14
|
-
const modelContentBuffer = await fs.readFile(templateFilePath)
|
|
15
|
-
const modelContent = modelContentBuffer.toString().replaceAll("__MODEL_NAME__", modelNameCamelized)
|
|
16
|
-
const modelsDir = `${process.cwd()}/src/models`
|
|
17
|
-
const modelPath = `${modelsDir}/${modelFileName}`
|
|
18
|
-
|
|
19
|
-
if (await fileExists(modelPath)) throw new Error(`Model file already exists: ${modelPath}`)
|
|
20
|
-
|
|
21
|
-
if (this.args.testing) {
|
|
22
|
-
return {date, modelContent, modelName, modelNameCamelized, modelPath}
|
|
23
|
-
} else {
|
|
24
|
-
if (!await fileExists(modelsDir)) {
|
|
25
|
-
await fs.mkdir(modelsDir, {recursive: true})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
await fs.writeFile(modelPath, modelContent)
|
|
29
|
-
|
|
30
|
-
console.log(`create src/models/${modelFileName}`)
|
|
31
|
-
}
|
|
5
|
+
return await this.getConfiguration().getEnvironmentHandler().cliCommandsModelGenerate(this)
|
|
32
6
|
}
|
|
33
7
|
}
|
package/src/cli/index.js
CHANGED
|
@@ -23,7 +23,7 @@ export default class VelociousCli {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const CommandClass = await this.environmentHandler.requireCommand({commandParts: parsedCommandParts})
|
|
26
|
-
const commandInstance = new CommandClass({args: this.args
|
|
26
|
+
const commandInstance = new CommandClass({args: this.args})
|
|
27
27
|
|
|
28
28
|
if (commandInstance.initialize) {
|
|
29
29
|
await commandInstance.initialize()
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
constructor({requireContext, ...restProps}) {
|
|
3
|
-
const restPropsKeys = Object.keys(restProps)
|
|
1
|
+
import restArgsError from "../utils/rest-args-error.js"
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
export default class VelociousDatabaseInitializerFromRequireContext {
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} args
|
|
6
|
+
* @param {object} args.requireContext
|
|
7
|
+
*/
|
|
8
|
+
constructor({requireContext, ...restArgs}) {
|
|
9
|
+
restArgsError(restArgs)
|
|
6
10
|
|
|
7
11
|
this.requireContext = requireContext
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @param {object} args
|
|
16
|
+
* @param {import("../configuration.js").default} args.configuration
|
|
17
|
+
* @returns {Promise<void>}
|
|
18
|
+
*/
|
|
19
|
+
async initialize({configuration, ...restArgs}) {
|
|
20
|
+
restArgsError(restArgs)
|
|
21
|
+
|
|
11
22
|
for (const fileName of this.requireContext.keys()) {
|
|
12
23
|
const modelClassImport = this.requireContext(fileName)
|
|
13
24
|
|
|
@@ -8,6 +8,10 @@ export default class TableData {
|
|
|
8
8
|
_indexes = []
|
|
9
9
|
_references = []
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} name
|
|
13
|
+
* @param {object} args
|
|
14
|
+
*/
|
|
11
15
|
constructor(name, args = {}) {
|
|
12
16
|
if (!name) throw new Error(`Invalid table name: ${name}`)
|
|
13
17
|
|
|
@@ -15,6 +19,10 @@ export default class TableData {
|
|
|
15
19
|
this._name = name
|
|
16
20
|
}
|
|
17
21
|
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} name
|
|
24
|
+
* @param {object} args
|
|
25
|
+
*/
|
|
18
26
|
addColumn(name, args = {}) {
|
|
19
27
|
if (name instanceof TableColumn) {
|
|
20
28
|
this._columns.push(name)
|
|
@@ -33,8 +41,20 @@ export default class TableData {
|
|
|
33
41
|
addIndex(index) { this._indexes.push(index) }
|
|
34
42
|
getIndexes() { return this._indexes }
|
|
35
43
|
|
|
44
|
+
/**
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
36
47
|
getName() { return this._name }
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} newName
|
|
51
|
+
* @returns {void}
|
|
52
|
+
*/
|
|
37
53
|
setName(newName) { this._name = newName }
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @returns {boolean}
|
|
57
|
+
*/
|
|
38
58
|
getIfNotExists() { return this.args.ifNotExists }
|
|
39
59
|
getReferences() { return this._references }
|
|
40
60
|
|
|
@@ -3,6 +3,21 @@ import restArgsError from "../../utils/rest-args-error.js"
|
|
|
3
3
|
import TableForeignKey from "./table-foreign-key.js"
|
|
4
4
|
|
|
5
5
|
export default class TableColumn {
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} name
|
|
8
|
+
* @param {object} args
|
|
9
|
+
* @param {boolean} args.autoIncrement
|
|
10
|
+
* @param {any} args.default
|
|
11
|
+
* @param {boolean} args.dropColumn
|
|
12
|
+
* @param {boolean|object} args.foreignKey
|
|
13
|
+
* @param {boolean|object} args.index
|
|
14
|
+
* @param {boolean} args.isNewColumn
|
|
15
|
+
* @param {number} args.maxLength
|
|
16
|
+
* @param {string} args.name
|
|
17
|
+
* @param {boolean} args.null
|
|
18
|
+
* @param {boolean} args.primaryKey
|
|
19
|
+
* @param {string} args.type
|
|
20
|
+
*/
|
|
6
21
|
constructor(name, args) {
|
|
7
22
|
if (args) {
|
|
8
23
|
const {autoIncrement, default: columnDefault, dropColumn, foreignKey, index, isNewColumn, maxLength, name, null: argsNull, primaryKey, type, ...restArgs} = args // eslint-disable-line no-unused-vars
|
|
@@ -50,6 +65,9 @@ export default class TableColumn {
|
|
|
50
65
|
*/
|
|
51
66
|
setAutoIncrement(newAutoIncrement) { this.args.autoIncrement = newAutoIncrement }
|
|
52
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @returns {any}
|
|
70
|
+
*/
|
|
53
71
|
getDefault() { return this.args?.default }
|
|
54
72
|
|
|
55
73
|
/**
|
|
@@ -62,22 +80,70 @@ export default class TableColumn {
|
|
|
62
80
|
*/
|
|
63
81
|
getDropColumn() { return this.args?.dropColumn || false }
|
|
64
82
|
|
|
83
|
+
/**
|
|
84
|
+
* @returns {boolean|object}
|
|
85
|
+
*/
|
|
65
86
|
getForeignKey() { return this.args?.foreignKey }
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {boolean|object} newForeignKey
|
|
90
|
+
* @returns {void}
|
|
91
|
+
*/
|
|
66
92
|
setForeignKey(newForeignKey) { this.args.foreignKey = newForeignKey }
|
|
67
93
|
|
|
94
|
+
/**
|
|
95
|
+
* @returns {boolean|object}
|
|
96
|
+
*/
|
|
68
97
|
getIndex() { return this.args?.index }
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @param {boolean|object} newIndex
|
|
101
|
+
* @returns {void}
|
|
102
|
+
*/
|
|
69
103
|
setIndex(newIndex) { this.args.index = newIndex }
|
|
70
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @returns {number}
|
|
107
|
+
*/
|
|
71
108
|
getMaxLength() { return this.args?.maxLength }
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {number} newMaxLength
|
|
112
|
+
* @returns {void}
|
|
113
|
+
*/
|
|
72
114
|
setMaxLength(newMaxLength) { this.args.maxLength = newMaxLength }
|
|
73
115
|
|
|
116
|
+
/**
|
|
117
|
+
* @returns {boolean}
|
|
118
|
+
*/
|
|
74
119
|
getNull() { return this.args?.null }
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @param {boolean} nullable
|
|
123
|
+
* @returns {void}
|
|
124
|
+
*/
|
|
75
125
|
setNull(nullable) { this.args.null = nullable }
|
|
76
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
77
130
|
getPrimaryKey() { return this.args?.primaryKey }
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {boolean} newPrimaryKey
|
|
134
|
+
* @returns {void}
|
|
135
|
+
*/
|
|
78
136
|
setPrimaryKey(newPrimaryKey) { this.args.primaryKey = newPrimaryKey }
|
|
79
137
|
|
|
138
|
+
/**
|
|
139
|
+
* @returns {string}
|
|
140
|
+
*/
|
|
80
141
|
getType() { return this.args?.type }
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string} newType
|
|
145
|
+
* @returns {void}
|
|
146
|
+
*/
|
|
81
147
|
setType(newType) { this.args.type = newType }
|
|
82
148
|
|
|
83
149
|
/**
|
|
@@ -85,7 +151,16 @@ export default class TableColumn {
|
|
|
85
151
|
*/
|
|
86
152
|
isNewColumn() { return this.args?.isNewColumn || false }
|
|
87
153
|
|
|
88
|
-
|
|
154
|
+
/**
|
|
155
|
+
* @param {object} args
|
|
156
|
+
* @param {boolean} args.forAlterTable
|
|
157
|
+
* @template T extends import("../drivers/base.js").default
|
|
158
|
+
* @param {T} args.driver
|
|
159
|
+
* @returns {string}
|
|
160
|
+
*/
|
|
161
|
+
getSQL({forAlterTable, driver, ...restArgs}) {
|
|
162
|
+
restArgsError(restArgs)
|
|
163
|
+
|
|
89
164
|
const databaseType = driver.getType()
|
|
90
165
|
const options = driver.options()
|
|
91
166
|
let maxlength = this.getMaxLength()
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import restArgsError from "../../utils/rest-args-error.js"
|
|
2
2
|
|
|
3
3
|
export default class TableForeignKey {
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} args
|
|
6
|
+
* @param {string} args.columnName
|
|
7
|
+
* @param {boolean} args.isNewForeignKey
|
|
8
|
+
* @param {string} args.name
|
|
9
|
+
* @param {string} args.tableName
|
|
10
|
+
* @param {string} args.referencedColumnName
|
|
11
|
+
* @param {string} args.referencedTableName
|
|
12
|
+
*/
|
|
4
13
|
constructor({columnName, isNewForeignKey, name, tableName, referencedColumnName, referencedTableName, ...restArgs}) {
|
|
5
14
|
restArgsError(restArgs)
|
|
6
15
|
|
|
@@ -12,12 +21,39 @@ export default class TableForeignKey {
|
|
|
12
21
|
this._referencedTableName = referencedTableName
|
|
13
22
|
}
|
|
14
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
15
27
|
getColumnName() { return this._columnName }
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
16
32
|
getIsNewForeignKey() { return this._isNewForeignKey }
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
17
37
|
getTableName() { return this._tableName }
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
18
42
|
getReferencedColumnName() { return this._referencedColumnName }
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
19
47
|
getReferencedTableName() { return this._referencedTableName }
|
|
20
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
21
52
|
getName() { return this._name }
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} newName
|
|
56
|
+
* @returns {void}
|
|
57
|
+
*/
|
|
22
58
|
setName(newName) { this._name = newName }
|
|
23
59
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import restArgsError from "../../utils/rest-args-error.js"
|
|
2
2
|
|
|
3
3
|
export default class TableIndex {
|
|
4
|
+
/**
|
|
5
|
+
* @param {Array<string>} columns
|
|
6
|
+
* @param {object} args
|
|
7
|
+
* @param {string} args.name
|
|
8
|
+
* @param {boolean} args.unique
|
|
9
|
+
*/
|
|
4
10
|
constructor(columns, args) {
|
|
5
11
|
if (args) {
|
|
6
12
|
const {name, unique, ...restArgs} = args // eslint-disable-line no-unused-vars
|
|
@@ -12,7 +18,18 @@ export default class TableIndex {
|
|
|
12
18
|
this.columns = columns
|
|
13
19
|
}
|
|
14
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @returns {Array<string>}
|
|
23
|
+
*/
|
|
15
24
|
getColumns() { return this.columns }
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
16
29
|
getName() { return this.args?.name }
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @returns {boolean}
|
|
33
|
+
*/
|
|
17
34
|
getUnique() { return Boolean(this.args?.unique) }
|
|
18
35
|
}
|
|
@@ -5,7 +5,12 @@ import Configuration from "../configuration.js"
|
|
|
5
5
|
import Migrator from "./migrator.js"
|
|
6
6
|
import restArgsError from "../utils/rest-args-error.js"
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* @param {object} args
|
|
10
|
+
* @param {object} args.migrationsRequireContextCallback
|
|
11
|
+
* @returns {Promise<{loaded: boolean}>}
|
|
12
|
+
*/
|
|
13
|
+
export default function loadMigrations({migrationsRequireContextCallback, ...restArgs}) {
|
|
9
14
|
const instance = React.useMemo(() => ({running: false}), [])
|
|
10
15
|
const {isServer} = useEnvSense()
|
|
11
16
|
const [loaded, setLoaded] = React.useState(false)
|
|
@@ -38,5 +43,3 @@ const loadMigrations = function loadMigrations({migrationsRequireContextCallback
|
|
|
38
43
|
|
|
39
44
|
return {loaded}
|
|
40
45
|
}
|
|
41
|
-
|
|
42
|
-
export default loadMigrations
|
|
@@ -9,6 +9,20 @@ export default class VelociousEnvironmentHandlerBase {
|
|
|
9
9
|
*/
|
|
10
10
|
async findMigrations() { throw new Error("findMigrations not implemneted") }
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* @template T extends import("../cli/base-command.js").default
|
|
14
|
+
* @param {T} command
|
|
15
|
+
* @param {typeof T} CommandClass
|
|
16
|
+
* @returns {any}
|
|
17
|
+
*/
|
|
18
|
+
async forwardCommand(command, CommandClass) {
|
|
19
|
+
const newCommand = new CommandClass({
|
|
20
|
+
args: command.args
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return await newCommand.execute()
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
/**
|
|
13
27
|
* @interface
|
|
14
28
|
*/
|
|
@@ -15,6 +15,18 @@ export default class VelociousEnvironmentsHandlerBrowser extends Base {
|
|
|
15
15
|
this.migrationsRequireContextCallback = migrationsRequireContextCallback
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
async cliCommandsMigrationGenerate(_command) { // eslint-disable-line no-unused-vars
|
|
19
|
+
throw new Error("Unsupported on browser")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async cliCommandsMigrationDestroy(_command) { // eslint-disable-line no-unused-vars
|
|
23
|
+
throw new Error("Unsupported on browser")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async cliCommandsModelGenerate(_command) { // eslint-disable-line no-unused-vars
|
|
27
|
+
throw new Error("Unsupported on browser")
|
|
28
|
+
}
|
|
29
|
+
|
|
18
30
|
/**
|
|
19
31
|
* @returns {object}
|
|
20
32
|
*/
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import BaseCommand from "../../../../../cli/base-command.js"
|
|
2
|
+
import fs from "fs/promises"
|
|
3
|
+
|
|
4
|
+
export default class DbDestroyMigration extends BaseCommand {
|
|
5
|
+
async execute() {
|
|
6
|
+
const migrationName = this.processArgs[1]
|
|
7
|
+
const migrationDir = `${this.getConfiguration().getDirectory()}/src/database/migrations`
|
|
8
|
+
const migrationFiles = await fs.readdir(migrationDir)
|
|
9
|
+
const destroyed = []
|
|
10
|
+
|
|
11
|
+
for (const migrationFile of migrationFiles) {
|
|
12
|
+
const match = migrationFile.match(/^(\d{14})-(.+)\.js$/)
|
|
13
|
+
|
|
14
|
+
if (!match) {
|
|
15
|
+
continue
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const fileName = match[2]
|
|
19
|
+
|
|
20
|
+
if (fileName != migrationName) continue
|
|
21
|
+
|
|
22
|
+
const fullFilePath = `${migrationDir}/${migrationFile}`
|
|
23
|
+
destroyed.push(fileName)
|
|
24
|
+
|
|
25
|
+
if (!this.args.testing) {
|
|
26
|
+
console.log(`Destroy src/database/migrations/${migrationFile}`)
|
|
27
|
+
await fs.unlink(fullFilePath)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (this.args.testing) {
|
|
32
|
+
return {destroyed}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import BaseCommand from "../../../../../cli/base-command.js"
|
|
2
|
+
import fileExists from "../../../../../utils/file-exists.js"
|
|
3
|
+
import fs from "fs/promises"
|
|
4
|
+
import * as inflection from "inflection"
|
|
5
|
+
import strftime from "strftime"
|
|
6
|
+
|
|
7
|
+
export default class DbGenerateMigration extends BaseCommand {
|
|
8
|
+
async execute() {
|
|
9
|
+
const migrationName = this.processArgs[1]
|
|
10
|
+
const migrationNameCamelized = inflection.camelize(migrationName.replaceAll("-", "_"))
|
|
11
|
+
const date = new Date()
|
|
12
|
+
const migrationNumber = strftime("%Y%m%d%H%M%S")
|
|
13
|
+
const migrationFileName = `${migrationNumber}-${migrationName}.js`
|
|
14
|
+
const velociousPath = await this.getEnvironmentHandler().getVelociousPath()
|
|
15
|
+
const templateFilePath = `${velociousPath}/src/templates/generate-migration.js`
|
|
16
|
+
const migrationContentBuffer = await fs.readFile(templateFilePath)
|
|
17
|
+
const migrationContent = migrationContentBuffer.toString().replaceAll("__MIGRATION_NAME__", migrationNameCamelized)
|
|
18
|
+
const migrationDir = `${process.cwd()}/src/database/migrations`
|
|
19
|
+
const migrationPath = `${migrationDir}/${migrationFileName}`
|
|
20
|
+
|
|
21
|
+
if (this.args.testing) {
|
|
22
|
+
return {date, migrationContent, migrationName, migrationNameCamelized, migrationNumber, migrationPath}
|
|
23
|
+
} else {
|
|
24
|
+
if (!await fileExists(migrationDir)) {
|
|
25
|
+
await fs.mkdir(migrationDir, {recursive: true})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await fs.writeFile(migrationPath, migrationContent)
|
|
29
|
+
|
|
30
|
+
console.log(`create src/database/migrations/${migrationFileName}`)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import BaseCommand from "../../../../../cli/base-command.js"
|
|
2
|
+
import fileExists from "../../../../../utils/file-exists.js"
|
|
3
|
+
import fs from "fs/promises"
|
|
4
|
+
import * as inflection from "inflection"
|
|
5
|
+
|
|
6
|
+
export default class DbGenerateModel extends BaseCommand {
|
|
7
|
+
async execute() {
|
|
8
|
+
const modelName = this.processArgs[1]
|
|
9
|
+
const modelNameCamelized = inflection.camelize(modelName.replaceAll("-", "_"))
|
|
10
|
+
const date = new Date()
|
|
11
|
+
const modelFileName = `${inflection.dasherize(inflection.underscore(modelName))}.js`
|
|
12
|
+
const velociousPath = await this.getEnvironmentHandler().getVelociousPath()
|
|
13
|
+
const templateFilePath = `${velociousPath}/src/templates/generate-model.js`
|
|
14
|
+
const modelContentBuffer = await fs.readFile(templateFilePath)
|
|
15
|
+
const modelContent = modelContentBuffer.toString().replaceAll("__MODEL_NAME__", modelNameCamelized)
|
|
16
|
+
const modelsDir = `${process.cwd()}/src/models`
|
|
17
|
+
const modelPath = `${modelsDir}/${modelFileName}`
|
|
18
|
+
|
|
19
|
+
if (await fileExists(modelPath)) throw new Error(`Model file already exists: ${modelPath}`)
|
|
20
|
+
|
|
21
|
+
if (this.args.testing) {
|
|
22
|
+
return {date, modelContent, modelName, modelNameCamelized, modelPath}
|
|
23
|
+
} else {
|
|
24
|
+
if (!await fileExists(modelsDir)) {
|
|
25
|
+
await fs.mkdir(modelsDir, {recursive: true})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await fs.writeFile(modelPath, modelContent)
|
|
29
|
+
|
|
30
|
+
console.log(`create src/models/${modelFileName}`)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import Base from "./base.js"
|
|
2
|
+
import CliCommandsDestroyMigration from "./node/cli/commands/destroy/migration.js"
|
|
3
|
+
import CliCommandsGenerateMigration from "./node/cli/commands/generate/migration.js"
|
|
4
|
+
import CliCommandsGenerateModel from "./node/cli/commands/generate/model.js"
|
|
2
5
|
import {dirname} from "path"
|
|
3
6
|
import {fileURLToPath} from "url"
|
|
4
7
|
import fs from "fs/promises"
|
|
@@ -42,6 +45,18 @@ export default class VelociousEnvironmentHandlerNode extends Base{
|
|
|
42
45
|
return commands
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
async cliCommandsMigrationGenerate(command) {
|
|
49
|
+
return await this.forwardCommand(command, CliCommandsGenerateMigration)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async cliCommandsMigrationDestroy(command) {
|
|
53
|
+
return await this.forwardCommand(command, CliCommandsDestroyMigration)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async cliCommandsModelGenerate(command) {
|
|
57
|
+
return await this.forwardCommand(command, CliCommandsGenerateModel)
|
|
58
|
+
}
|
|
59
|
+
|
|
45
60
|
/**
|
|
46
61
|
* @param {Array<string>} commandParts
|
|
47
62
|
* @template T extends import ("./base-command.js").default
|
|
@@ -83,6 +83,11 @@ export default class TestFilesFinder {
|
|
|
83
83
|
})
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* @param {string} file
|
|
88
|
+
* @param {string} localPath
|
|
89
|
+
* @returns {boolean}
|
|
90
|
+
*/
|
|
86
91
|
isFileMatchingRequirements(file, localPath) {
|
|
87
92
|
if (this.testArgs.length > 0) {
|
|
88
93
|
for (const testArg of this.testArgs) {
|
package/src/testing/test.js
CHANGED
|
@@ -11,12 +11,20 @@ const tests = {
|
|
|
11
11
|
|
|
12
12
|
let currentPath = [tests]
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @param {function() : void} callback
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
14
18
|
function beforeEach(callback) {
|
|
15
19
|
const currentTest = currentPath[currentPath.length - 1]
|
|
16
20
|
|
|
17
21
|
currentTest.beforeEaches.push({callback})
|
|
18
22
|
}
|
|
19
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @param {function() : void} callback
|
|
26
|
+
* @returns {void}
|
|
27
|
+
*/
|
|
20
28
|
function afterEach(callback) {
|
|
21
29
|
const currentTest = currentPath[currentPath.length - 1]
|
|
22
30
|
|
|
@@ -32,6 +40,7 @@ class ExpectToChange {
|
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
/**
|
|
43
|
+
* @param {number} count
|
|
35
44
|
* @returns {Expect}
|
|
36
45
|
*/
|
|
37
46
|
by(count) {
|
|
@@ -48,6 +57,9 @@ class ExpectToChange {
|
|
|
48
57
|
this.newCount = await this.changeCallback()
|
|
49
58
|
}
|
|
50
59
|
|
|
60
|
+
/**
|
|
61
|
+
* @returns {void}
|
|
62
|
+
*/
|
|
51
63
|
async execute() {
|
|
52
64
|
const difference = this.newCount - this.oldCount
|
|
53
65
|
|
|
@@ -58,6 +70,9 @@ class ExpectToChange {
|
|
|
58
70
|
}
|
|
59
71
|
|
|
60
72
|
class Expect {
|
|
73
|
+
/**
|
|
74
|
+
* @param {any} object
|
|
75
|
+
*/
|
|
61
76
|
constructor(object) {
|
|
62
77
|
this._object = object
|
|
63
78
|
this.expectations = []
|
|
@@ -80,6 +95,7 @@ class Expect {
|
|
|
80
95
|
}
|
|
81
96
|
|
|
82
97
|
/**
|
|
98
|
+
* @param {any} result
|
|
83
99
|
* @returns {void}
|
|
84
100
|
*/
|
|
85
101
|
toBe(result) {
|
|
@@ -154,6 +170,7 @@ class Expect {
|
|
|
154
170
|
}
|
|
155
171
|
|
|
156
172
|
/**
|
|
173
|
+
* @param {any} valueToContain
|
|
157
174
|
* @returns {void}
|
|
158
175
|
*/
|
|
159
176
|
toContain(valueToContain) {
|
|
@@ -165,6 +182,7 @@ class Expect {
|
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
/**
|
|
185
|
+
* @param {any} result
|
|
168
186
|
* @returns {void}
|
|
169
187
|
*/
|
|
170
188
|
toEqual(result) {
|
|
@@ -192,6 +210,7 @@ class Expect {
|
|
|
192
210
|
}
|
|
193
211
|
|
|
194
212
|
/**
|
|
213
|
+
* @param {RegExp} regex
|
|
195
214
|
* @returns {void}
|
|
196
215
|
*/
|
|
197
216
|
toMatch(regex) {
|
|
@@ -209,6 +228,8 @@ class Expect {
|
|
|
209
228
|
}
|
|
210
229
|
|
|
211
230
|
/**
|
|
231
|
+
* @template T extends Error
|
|
232
|
+
* @param {string|T} expectedError
|
|
212
233
|
* @returns {void}
|
|
213
234
|
*/
|
|
214
235
|
async toThrowError(expectedError) {
|
|
@@ -243,6 +264,9 @@ class Expect {
|
|
|
243
264
|
}
|
|
244
265
|
}
|
|
245
266
|
|
|
267
|
+
/**
|
|
268
|
+
* @returns {any}
|
|
269
|
+
*/
|
|
246
270
|
async execute() {
|
|
247
271
|
for (const expectation of this.expectations) {
|
|
248
272
|
await expectation.runBefore()
|
|
@@ -290,6 +314,8 @@ class Expect {
|
|
|
290
314
|
|
|
291
315
|
/**
|
|
292
316
|
* @param {string} description
|
|
317
|
+
* @param {object|() => Promise<void>} arg1
|
|
318
|
+
* @param {undefined|() => Promise<void>} arg2
|
|
293
319
|
* @returns {void}
|
|
294
320
|
*/
|
|
295
321
|
async function describe(description, arg1, arg2) {
|
|
@@ -325,6 +351,7 @@ async function describe(description, arg1, arg2) {
|
|
|
325
351
|
}
|
|
326
352
|
|
|
327
353
|
/**
|
|
354
|
+
* @param {any} arg
|
|
328
355
|
* @returns {Expect}
|
|
329
356
|
*/
|
|
330
357
|
function expect(arg) {
|
|
@@ -333,6 +360,8 @@ function expect(arg) {
|
|
|
333
360
|
|
|
334
361
|
/**
|
|
335
362
|
* @param {string} description
|
|
363
|
+
* @param {object|() => Promise<void>} arg1
|
|
364
|
+
* @param {undefined|() => Promise<void>} arg2
|
|
336
365
|
* @returns {void}
|
|
337
366
|
*/
|
|
338
367
|
function it(description, arg1, arg2) {
|
|
@@ -356,6 +385,8 @@ function it(description, arg1, arg2) {
|
|
|
356
385
|
|
|
357
386
|
/**
|
|
358
387
|
* @param {string} description
|
|
388
|
+
* @param {object|() => Promise<void>} arg1
|
|
389
|
+
* @param {undefined|() => Promise<void>} arg2
|
|
359
390
|
* @returns {void}
|
|
360
391
|
*/
|
|
361
392
|
function fit(description, arg1, arg2) {
|