velocious 1.0.94 → 1.0.96
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/database/query/index.js +46 -27
- package/src/database/query-parser/select-parser.js +10 -2
- package/src/database/record/index.js +11 -11
- package/src/database/record/relationships/base.js +11 -3
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +94 -1
package/package.json
CHANGED
|
@@ -15,37 +15,51 @@ import restArgsError from "../../utils/rest-args-error.js"
|
|
|
15
15
|
* @typedef {Record<string, boolean|NestedPreloadRecord>} NestedPreloadRecord
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* A generic query over some model type.
|
|
20
|
+
*/
|
|
18
21
|
export default class VelociousDatabaseQuery {
|
|
19
22
|
/**
|
|
20
23
|
* @param {object} args
|
|
21
|
-
* @
|
|
22
|
-
* @param {
|
|
23
|
-
* @
|
|
24
|
-
* @param {
|
|
25
|
-
* @param {string[]} args.groups
|
|
26
|
-
* @template {import("./join-base.js").default} TjoinBase
|
|
27
|
-
* @param {TjoinBase[]} args.joins
|
|
24
|
+
* @param {import("../drivers/base.js").default} args.driver
|
|
25
|
+
* @param {Array<import("./from-base.js").default>} [args.froms]
|
|
26
|
+
* @param {string[]} [args.groups]
|
|
27
|
+
* @param {Array<import("./join-base.js").default>} [args.joins]
|
|
28
28
|
* @param {import("../handler.js").default} args.handler
|
|
29
|
-
* @param {number} args.limit
|
|
30
|
-
* @
|
|
31
|
-
* @param {
|
|
32
|
-
* @param {
|
|
33
|
-
* @
|
|
34
|
-
* @param {TorderBase[]} args.orders
|
|
35
|
-
* @param {number} args.page
|
|
29
|
+
* @param {number | null} [args.limit]
|
|
30
|
+
* @param {typeof import("../record/index.js").default} args.modelClass
|
|
31
|
+
* @param {number | null} [args.offset]
|
|
32
|
+
* @param {Array<import("./order-base.js").default>} [args.orders]
|
|
33
|
+
* @param {number | null} [args.page]
|
|
36
34
|
* @param {number} args.perPage
|
|
37
|
-
* @param {NestedPreloadRecord} args.preload
|
|
38
|
-
* @param {
|
|
39
|
-
* @
|
|
40
|
-
* @param {TwhereBase[]} args.wheres
|
|
35
|
+
* @param {NestedPreloadRecord} [args.preload]
|
|
36
|
+
* @param {Array<import("./select-base.js").default>} [args.selects]
|
|
37
|
+
* @param {Array<import("./where-base.js").default>} [args.wheres]
|
|
41
38
|
*/
|
|
42
|
-
constructor({
|
|
39
|
+
constructor({
|
|
40
|
+
driver,
|
|
41
|
+
froms = [],
|
|
42
|
+
groups = [],
|
|
43
|
+
joins = [],
|
|
44
|
+
handler,
|
|
45
|
+
limit = null,
|
|
46
|
+
modelClass,
|
|
47
|
+
offset = null,
|
|
48
|
+
orders = [],
|
|
49
|
+
page = null,
|
|
50
|
+
perPage,
|
|
51
|
+
preload = {},
|
|
52
|
+
selects = [],
|
|
53
|
+
wheres = [],
|
|
54
|
+
...restArgs
|
|
55
|
+
}) {
|
|
43
56
|
if (!driver) throw new Error("No driver given to query")
|
|
44
57
|
if (!handler) throw new Error("No handler given to query")
|
|
45
58
|
|
|
46
59
|
restArgsError(restArgs)
|
|
47
60
|
|
|
48
61
|
this.driver = driver
|
|
62
|
+
|
|
49
63
|
this.handler = handler
|
|
50
64
|
this.logger = new Logger(this)
|
|
51
65
|
this.modelClass = modelClass
|
|
@@ -147,6 +161,11 @@ export default class VelociousDatabaseQuery {
|
|
|
147
161
|
*/
|
|
148
162
|
getOptions() { return this.driver.options() }
|
|
149
163
|
|
|
164
|
+
/**
|
|
165
|
+
* @returns {Array<import("./select-base.js").default>}
|
|
166
|
+
*/
|
|
167
|
+
getSelects() { return this._selects }
|
|
168
|
+
|
|
150
169
|
/**
|
|
151
170
|
* @returns {Promise<void>}
|
|
152
171
|
*/
|
|
@@ -160,7 +179,7 @@ export default class VelociousDatabaseQuery {
|
|
|
160
179
|
|
|
161
180
|
/**
|
|
162
181
|
* @param {number|string} recordId
|
|
163
|
-
* @returns {Promise<
|
|
182
|
+
* @returns {Promise<import("../record/index.js").default>}
|
|
164
183
|
*/
|
|
165
184
|
async find(recordId) {
|
|
166
185
|
const conditions = {}
|
|
@@ -179,7 +198,7 @@ export default class VelociousDatabaseQuery {
|
|
|
179
198
|
|
|
180
199
|
/**
|
|
181
200
|
* @param {object} conditions
|
|
182
|
-
* @returns {Promise<
|
|
201
|
+
* @returns {Promise<import("../record/index.js").default|null>}
|
|
183
202
|
*/
|
|
184
203
|
async findBy(conditions) {
|
|
185
204
|
const newConditions = {}
|
|
@@ -195,7 +214,7 @@ export default class VelociousDatabaseQuery {
|
|
|
195
214
|
|
|
196
215
|
/**
|
|
197
216
|
* @param {...Parameters<this["findOrInitializeBy"]>} args
|
|
198
|
-
* @returns {Promise<
|
|
217
|
+
* @returns {Promise<import("../record/index.js").default>}
|
|
199
218
|
*/
|
|
200
219
|
async findOrCreateBy(...args) {
|
|
201
220
|
const record = await this.findOrInitializeBy(...args)
|
|
@@ -209,7 +228,7 @@ export default class VelociousDatabaseQuery {
|
|
|
209
228
|
|
|
210
229
|
/**
|
|
211
230
|
* @param {object} conditions
|
|
212
|
-
* @returns {Promise<
|
|
231
|
+
* @returns {Promise<import("../record/index.js").default>}
|
|
213
232
|
*/
|
|
214
233
|
async findByOrFail(conditions) {
|
|
215
234
|
const newConditions = {}
|
|
@@ -232,7 +251,7 @@ export default class VelociousDatabaseQuery {
|
|
|
232
251
|
/**
|
|
233
252
|
* @param {object} conditions
|
|
234
253
|
* @param {function() : void} callback
|
|
235
|
-
* @returns {Promise<
|
|
254
|
+
* @returns {Promise<import("../record/index.js").default>}
|
|
236
255
|
*/
|
|
237
256
|
async findOrInitializeBy(conditions, callback) {
|
|
238
257
|
const record = await this.findBy(conditions)
|
|
@@ -249,7 +268,7 @@ export default class VelociousDatabaseQuery {
|
|
|
249
268
|
}
|
|
250
269
|
|
|
251
270
|
/**
|
|
252
|
-
* @returns {Promise<
|
|
271
|
+
* @returns {Promise<import("../record/index.js").default>}
|
|
253
272
|
*/
|
|
254
273
|
async first() {
|
|
255
274
|
const newQuery = this.clone().limit(1).reorder(`${this.driver.quoteTable(this.modelClass.tableName())}.${this.driver.quoteColumn(this.modelClass.orderableColumn())}`)
|
|
@@ -298,7 +317,7 @@ export default class VelociousDatabaseQuery {
|
|
|
298
317
|
}
|
|
299
318
|
|
|
300
319
|
/**
|
|
301
|
-
* @returns {Promise<
|
|
320
|
+
* @returns {Promise<import("../record/index.js").default>}
|
|
302
321
|
*/
|
|
303
322
|
async last() {
|
|
304
323
|
const primaryKey = this.modelClass.primaryKey()
|
|
@@ -435,7 +454,7 @@ export default class VelociousDatabaseQuery {
|
|
|
435
454
|
|
|
436
455
|
/**
|
|
437
456
|
* Converts query results to array of model instances
|
|
438
|
-
* @returns {Promise<Array<
|
|
457
|
+
* @returns {Promise<Array<import("../record/index.js").default>>}
|
|
439
458
|
*/
|
|
440
459
|
async toArray() {
|
|
441
460
|
const models = []
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import {digs} from "diggerize"
|
|
2
|
+
import restArgsError from "../../utils/rest-args-error.js"
|
|
2
3
|
|
|
3
4
|
export default class VelociousDatabaseQueryParserSelectParser {
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @param {object} args
|
|
7
|
+
* @param {boolean} args.pretty
|
|
8
|
+
* @param {import("../query/index.js").default} args.query
|
|
9
|
+
*/
|
|
10
|
+
constructor({pretty, query, ...restArgs}) {
|
|
11
|
+
restArgsError(restArgs)
|
|
12
|
+
|
|
5
13
|
this.pretty = pretty
|
|
6
14
|
this.query = query
|
|
7
15
|
}
|
|
@@ -34,7 +42,7 @@ export default class VelociousDatabaseQueryParserSelectParser {
|
|
|
34
42
|
}
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
if (query.
|
|
45
|
+
if (query.getSelects().length == 0) {
|
|
38
46
|
if (query.modelClass) {
|
|
39
47
|
sql += `${query.modelClass.connection().quoteTable(query.modelClass.tableName())}.*`
|
|
40
48
|
} else {
|
|
@@ -44,8 +44,7 @@ class ValidationError extends Error {
|
|
|
44
44
|
|
|
45
45
|
class VelociousDatabaseRecord {
|
|
46
46
|
/**
|
|
47
|
-
* @
|
|
48
|
-
* @returns {Record<string, T>}
|
|
47
|
+
* @returns {Record<string, import("./validators/base.js").default>}
|
|
49
48
|
*/
|
|
50
49
|
static validatorTypes() {
|
|
51
50
|
if (!this._validatorTypes) this._validatorTypes = {}
|
|
@@ -55,16 +54,14 @@ class VelociousDatabaseRecord {
|
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
56
|
* @param {string} name
|
|
58
|
-
* @
|
|
59
|
-
* @param {T} validatorClass
|
|
57
|
+
* @param {import("./validators/base.js").default} validatorClass
|
|
60
58
|
*/
|
|
61
59
|
static registerValidatorType(name, validatorClass) {
|
|
62
60
|
this.validatorTypes()[name] = validatorClass
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
/**
|
|
66
|
-
* @
|
|
67
|
-
* @returns {T}
|
|
64
|
+
* @returns {import("./validators/base.js").default}
|
|
68
65
|
*/
|
|
69
66
|
static getValidatorType(validatorName) {
|
|
70
67
|
if (!(validatorName in this.validatorTypes())) throw new Error(`Validator type ${validatorName} not found`)
|
|
@@ -152,6 +149,10 @@ class VelociousDatabaseRecord {
|
|
|
152
149
|
return this.getRelationshipByName(relationshipName)
|
|
153
150
|
}
|
|
154
151
|
|
|
152
|
+
this.prototype[`${relationshipName}Loaded`] = function() {
|
|
153
|
+
return this.getRelationshipByName(relationshipName).loaded()
|
|
154
|
+
}
|
|
155
|
+
|
|
155
156
|
this.prototype[`load${inflection.camelize(relationshipName)}`] = async function() {
|
|
156
157
|
await this.getRelationshipByName(relationshipName).load()
|
|
157
158
|
}
|
|
@@ -189,8 +190,7 @@ class VelociousDatabaseRecord {
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
/**
|
|
192
|
-
* @
|
|
193
|
-
* @returns {T}
|
|
193
|
+
* @returns {import("./relationships/base.js").default}
|
|
194
194
|
*/
|
|
195
195
|
static getRelationshipByName(relationshipName) {
|
|
196
196
|
if (!this._relationships) this._relationships = {}
|
|
@@ -203,7 +203,7 @@ class VelociousDatabaseRecord {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
/**
|
|
206
|
-
* @returns {Array}
|
|
206
|
+
* @returns {Array<import("./relationships/base.js").default>}
|
|
207
207
|
*/
|
|
208
208
|
static getRelationships() {
|
|
209
209
|
if (this._relationships) return Object.values(this._relationships)
|
|
@@ -269,7 +269,7 @@ class VelociousDatabaseRecord {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/**
|
|
272
|
-
* @param {
|
|
272
|
+
* @param {Record<string, any>} attributes
|
|
273
273
|
* @returns {Promise<InstanceType<typeof this>>}
|
|
274
274
|
*/
|
|
275
275
|
static async create(attributes) {
|
|
@@ -1050,7 +1050,7 @@ class VelociousDatabaseRecord {
|
|
|
1050
1050
|
|
|
1051
1051
|
/**
|
|
1052
1052
|
* Assigns the given attributes to the record.
|
|
1053
|
-
* @param {
|
|
1053
|
+
* @param {Record<string, any>} attributesToAssign
|
|
1054
1054
|
* @returns {void}
|
|
1055
1055
|
*/
|
|
1056
1056
|
assign(attributesToAssign) {
|
|
@@ -67,6 +67,13 @@ export default class VelociousDatabaseRecordBaseRelationship {
|
|
|
67
67
|
*/
|
|
68
68
|
getRelationshipName() { return this.relationshipName }
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* @returns {boolean}
|
|
72
|
+
*/
|
|
73
|
+
getPolymorphic() {
|
|
74
|
+
return this._polymorphic
|
|
75
|
+
}
|
|
76
|
+
|
|
70
77
|
/**
|
|
71
78
|
* @returns {string} The name of the foreign key, e.g. "id" etc.
|
|
72
79
|
*/
|
|
@@ -78,11 +85,12 @@ export default class VelociousDatabaseRecordBaseRelationship {
|
|
|
78
85
|
getType() { return this.type }
|
|
79
86
|
|
|
80
87
|
/**
|
|
81
|
-
* @
|
|
82
|
-
* @returns {typeof T} The target model class for this relationship, e.g. if the relationship is "posts" then the target model class is the Post class.
|
|
88
|
+
* @returns {typeof import("../index.js").default} The target model class for this relationship, e.g. if the relationship is "posts" then the target model class is the Post class.
|
|
83
89
|
*/
|
|
84
90
|
getTargetModelClass() {
|
|
85
|
-
if (this.
|
|
91
|
+
if (this.getPolymorphic()) {
|
|
92
|
+
return null
|
|
93
|
+
} else if (this.className) {
|
|
86
94
|
return this.modelClass._getConfiguration().getModelClass(this.className)
|
|
87
95
|
} else if (this.klass) {
|
|
88
96
|
return this.klass
|
|
@@ -25,7 +25,7 @@ export default class DbGenerateModel extends BaseCommand {
|
|
|
25
25
|
|
|
26
26
|
let fileContent = `import Record from "velocious/src/database/record/index.js"\n\n`
|
|
27
27
|
|
|
28
|
-
fileContent += `export default class ${modelNameCamelized} extends Record {\n`
|
|
28
|
+
fileContent += `export default class ${modelNameCamelized}Base extends Record {\n`
|
|
29
29
|
|
|
30
30
|
const columns = await modelClass._getTable().getColumns()
|
|
31
31
|
let methodsCount = 0
|
|
@@ -72,6 +72,99 @@ export default class DbGenerateModel extends BaseCommand {
|
|
|
72
72
|
methodsCount++
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
for (const relationship of modelClass.getRelationships()) {
|
|
76
|
+
let fileName, fullFilePath
|
|
77
|
+
|
|
78
|
+
if (relationship.getPolymorphic()) {
|
|
79
|
+
fileName = "velocious/src/database/record/index.js"
|
|
80
|
+
} else {
|
|
81
|
+
fileName = inflection.dasherize(inflection.underscore(relationship.getTargetModelClass().name))
|
|
82
|
+
fullFilePath = `src/models/${fileName}.js`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (methodsCount > 0) {
|
|
86
|
+
fileContent += "\n"
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (relationship.getType() == "belongsTo" || relationship.getType() == "hasOne") {
|
|
90
|
+
let modelFilePath
|
|
91
|
+
|
|
92
|
+
if (fullFilePath && await fileExists(fullFilePath)) {
|
|
93
|
+
modelFilePath = `../models/${fileName}.js`
|
|
94
|
+
} else {
|
|
95
|
+
modelFilePath = "velocious/src/database/record/index.js"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fileContent += " /**\n"
|
|
99
|
+
fileContent += " * @interface\n"
|
|
100
|
+
fileContent += ` * @returns {import("${modelFilePath}").default}\n`
|
|
101
|
+
fileContent += " */\n"
|
|
102
|
+
fileContent += ` ${relationship.getRelationshipName()}() { return this.getRelationshipByName("${relationship.getRelationshipName()}").loaded() }\n`
|
|
103
|
+
|
|
104
|
+
fileContent += "\n"
|
|
105
|
+
fileContent += " /**\n"
|
|
106
|
+
fileContent += " * @interface\n"
|
|
107
|
+
fileContent += ` * @returns {import("${modelFilePath}").default}\n`
|
|
108
|
+
fileContent += " */\n"
|
|
109
|
+
fileContent += ` build${inflection.camelize(relationship.getRelationshipName())}() { throw new Error("Not implemented") }\n`
|
|
110
|
+
|
|
111
|
+
fileContent += "\n"
|
|
112
|
+
fileContent += " /**\n"
|
|
113
|
+
fileContent += " * @interface\n"
|
|
114
|
+
fileContent += " * @returns {Promise<void>}\n"
|
|
115
|
+
fileContent += " */\n"
|
|
116
|
+
fileContent += ` load${inflection.camelize(relationship.getRelationshipName())}() { throw new Error("Not implemented") }\n`
|
|
117
|
+
|
|
118
|
+
fileContent += "\n"
|
|
119
|
+
fileContent += " /**\n"
|
|
120
|
+
fileContent += " * @interface\n"
|
|
121
|
+
fileContent += ` * @param {import("${modelFilePath}").default} newModel\n`
|
|
122
|
+
fileContent += ` * @returns {void}\n`
|
|
123
|
+
fileContent += " */\n"
|
|
124
|
+
fileContent += ` set${inflection.camelize(relationship.getRelationshipName())}() { throw new Error("Not implemented") }\n`
|
|
125
|
+
} else if (relationship.getType() == "hasMany") {
|
|
126
|
+
let recordImport
|
|
127
|
+
|
|
128
|
+
if (fullFilePath && await fileExists(fullFilePath)) {
|
|
129
|
+
recordImport = `../models/${fileName}.js`
|
|
130
|
+
} else {
|
|
131
|
+
recordImport = "velocious/src/database/record/index.js"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
fileContent += " /**\n"
|
|
135
|
+
fileContent += " * @interface\n"
|
|
136
|
+
fileContent += ` * @returns {import("velocious/src/database/query/index.js").default<import("${recordImport}").default>}\n`
|
|
137
|
+
fileContent += " */\n"
|
|
138
|
+
fileContent += ` ${relationship.getRelationshipName()}() { return this.getRelationshipByName("${relationship.getRelationshipName()}") }\n`
|
|
139
|
+
|
|
140
|
+
fileContent += "\n"
|
|
141
|
+
fileContent += " /**\n"
|
|
142
|
+
fileContent += " * @interface\n"
|
|
143
|
+
fileContent += ` * @returns {Array<import("${recordImport}").default>}\n`
|
|
144
|
+
fileContent += " */\n"
|
|
145
|
+
fileContent += ` ${relationship.getRelationshipName()}Loaded() { return this.getRelationshipByName("${relationship.getRelationshipName()}").loaded() }\n`
|
|
146
|
+
|
|
147
|
+
fileContent += "\n"
|
|
148
|
+
fileContent += " /**\n"
|
|
149
|
+
fileContent += " * @interface\n"
|
|
150
|
+
fileContent += " * @returns {Promise<void>}\n"
|
|
151
|
+
fileContent += " */\n"
|
|
152
|
+
fileContent += ` load${inflection.camelize(relationship.getRelationshipName())}() { throw new Error("Not implemented") }\n`
|
|
153
|
+
|
|
154
|
+
fileContent += "\n"
|
|
155
|
+
fileContent += " /**\n"
|
|
156
|
+
fileContent += " * @interface\n"
|
|
157
|
+
fileContent += ` * @param {Array<import("${recordImport}").default>} newModels\n`
|
|
158
|
+
fileContent += " * @returns {void>}\n"
|
|
159
|
+
fileContent += " */\n"
|
|
160
|
+
fileContent += ` set${inflection.camelize(relationship.getRelationshipName())}() { throw new Error("Not implemented") }\n`
|
|
161
|
+
} else {
|
|
162
|
+
throw new Error(`Unknown relationship type: ${relationship.getType()}`)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
methodsCount++
|
|
166
|
+
}
|
|
167
|
+
|
|
75
168
|
fileContent += "}\n"
|
|
76
169
|
|
|
77
170
|
await fs.writeFile(modelPath, fileContent)
|