velocious 1.0.101 → 1.0.103
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/spec/database/drivers/create-sql/create-index-sql-spec.js +24 -0
- package/src/configuration-types.js +7 -1
- package/src/configuration.js +2 -2
- package/src/database/drivers/base-column.js +2 -2
- package/src/database/drivers/base-columns-index.js +6 -0
- package/src/database/drivers/base.js +60 -22
- package/src/database/drivers/mssql/index.js +70 -22
- package/src/database/drivers/mssql/sql/create-database.js +9 -2
- package/src/database/drivers/mssql/table.js +14 -4
- package/src/database/drivers/mysql/column.js +6 -0
- package/src/database/drivers/mysql/columns-index.js +3 -6
- package/src/database/drivers/mysql/foreign-key.js +2 -0
- package/src/database/drivers/mysql/index.js +43 -16
- package/src/database/drivers/mysql/query-parser.js +2 -0
- package/src/database/drivers/mysql/query.js +7 -2
- package/src/database/drivers/mysql/table.js +6 -0
- package/src/database/drivers/pgsql/index.js +78 -11
- package/src/database/drivers/sqlite/base.js +77 -25
- package/src/database/drivers/sqlite/column.js +8 -0
- package/src/database/drivers/sqlite/sql/alter-table.js +25 -20
- package/src/database/drivers/sqlite/sql/create-index.js +2 -0
- package/src/database/drivers/sqlite/sql/create-table.js +2 -0
- package/src/database/drivers/sqlite/sql/delete.js +4 -2
- package/src/database/drivers/sqlite/sql/drop-table.js +2 -0
- package/src/database/drivers/sqlite/sql/insert.js +2 -0
- package/src/database/drivers/sqlite/sql/update.js +2 -0
- package/src/database/drivers/sqlite/table.js +14 -0
- package/src/database/migration/index.js +6 -4
- package/src/database/pool/base-methods-forward.js +2 -2
- package/src/database/query/alter-table-base.js +1 -1
- package/src/database/query/base.js +2 -2
- package/src/database/query/create-database-base.js +8 -4
- package/src/database/query/create-index-base.js +12 -7
- package/src/database/query/create-table-base.js +4 -4
- package/src/database/query/drop-table-base.js +8 -8
- package/src/database/query/index.js +31 -18
- package/src/database/query/insert-base.js +18 -3
- package/src/database/query-parser/base-query-parser.js +2 -2
- package/src/database/record/index.js +444 -172
- package/src/database/record/instance-relationships/base.js +41 -44
- package/src/database/record/instance-relationships/belongs-to.js +15 -3
- package/src/database/record/instance-relationships/has-many.js +49 -28
- package/src/database/record/instance-relationships/has-one.js +22 -7
- package/src/database/record/relationships/base.js +33 -43
- package/src/database/record/relationships/belongs-to.js +13 -3
- package/src/database/record/relationships/has-many.js +8 -2
- package/src/database/record/relationships/has-one.js +8 -2
- package/src/database/record/validators/base.js +14 -2
- package/src/database/record/validators/presence.js +7 -0
- package/src/database/table-data/table-column.js +3 -3
- package/src/environment-handlers/node.js +1 -2
|
@@ -1,14 +1,30 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
export default class VelociousDatabaseRecordBaseInstanceRelationship {
|
|
4
|
+
/** @type {boolean | undefined} */
|
|
5
|
+
_autoSave = undefined
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {object} args
|
|
9
|
+
* @param {import("../index.js").default} args.model
|
|
10
|
+
* @param {import("../relationships/base.js").default} args.relationship
|
|
11
|
+
*/
|
|
2
12
|
constructor({model, relationship}) {
|
|
3
|
-
this._autoSave = null
|
|
4
13
|
this._dirty = false
|
|
5
14
|
this.model = model
|
|
6
15
|
this.relationship = relationship
|
|
7
16
|
}
|
|
8
17
|
|
|
9
18
|
/**
|
|
10
|
-
* @
|
|
19
|
+
* @abstract
|
|
20
|
+
* @param {Record<string, any>} attributes
|
|
21
|
+
* @returns {import("../index.js").default}
|
|
11
22
|
*/
|
|
23
|
+
build(attributes) { // eslint-disable-line no-unused-vars
|
|
24
|
+
throw new Error("'build' not implemented")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** @returns {boolean | undefined} Whether the relationship should be auto-saved before saving the parent model */
|
|
12
28
|
getAutoSave() { return this._autoSave }
|
|
13
29
|
|
|
14
30
|
/**
|
|
@@ -23,20 +39,21 @@ export default class VelociousDatabaseRecordBaseInstanceRelationship {
|
|
|
23
39
|
*/
|
|
24
40
|
setDirty(newValue) { this._dirty = newValue }
|
|
25
41
|
|
|
26
|
-
/**
|
|
27
|
-
* @returns {boolean} Whether the relationship is dirty (has been modified)
|
|
28
|
-
*/
|
|
42
|
+
/** @returns {boolean} Whether the relationship is dirty (has been modified) */
|
|
29
43
|
getDirty() { return this._dirty }
|
|
30
44
|
|
|
31
45
|
/**
|
|
32
|
-
* @
|
|
46
|
+
* @abstract
|
|
47
|
+
* @returns {Promise<void>}
|
|
33
48
|
*/
|
|
49
|
+
load() {
|
|
50
|
+
throw new Error("'load' not implemented")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** @returns {boolean} Whether the relationship has been preloaded */
|
|
34
54
|
isLoaded() { return Boolean(this._loaded) }
|
|
35
55
|
|
|
36
|
-
/**
|
|
37
|
-
* @template T extends import("../index.js").default
|
|
38
|
-
* @returns {T|Array<T>} The loaded model or models (depending on relationship type)
|
|
39
|
-
*/
|
|
56
|
+
/** @returns {import("../index.js").default | Array<import("../index.js").default> | undefined} The loaded model or models (depending on relationship type) */
|
|
40
57
|
loaded() {
|
|
41
58
|
if (!this._preloaded && this.model.isPersisted()) {
|
|
42
59
|
throw new Error(`${this.model.constructor.name}#${this.relationship.getRelationshipName()} hasn't been preloaded`)
|
|
@@ -45,53 +62,33 @@ export default class VelociousDatabaseRecordBaseInstanceRelationship {
|
|
|
45
62
|
return this._loaded
|
|
46
63
|
}
|
|
47
64
|
|
|
48
|
-
/**
|
|
49
|
-
* @template T extends import("../index.js").default
|
|
50
|
-
* @param {T|Array<T>} model
|
|
51
|
-
*/
|
|
65
|
+
/** @param {import("../index.js").default|Array<import("../index.js").default>} model */
|
|
52
66
|
setLoaded(model) { this._loaded = model }
|
|
53
67
|
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
-
* @returns {T|Array<T>} The loaded model or models (depending on relationship type)
|
|
57
|
-
*/
|
|
58
|
-
getPreloaded() { return this._preloaded }
|
|
68
|
+
/** @returns {import("../index.js").default | import("../index.js").default[] | undefined} */
|
|
69
|
+
getLoadedOrUndefined() { return this._loaded }
|
|
59
70
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
* @param {T|Array<T>} preloadedModelOrModels
|
|
63
|
-
*/
|
|
64
|
-
setPreloaded(preloadedModelOrModels) { this._preloaded = preloadedModelOrModels }
|
|
71
|
+
/** @returns {boolean} The loaded model or models (depending on relationship type) */
|
|
72
|
+
getPreloaded() { return this._preloaded || false }
|
|
65
73
|
|
|
66
|
-
/**
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
/** @param {boolean} isPreloaded */
|
|
75
|
+
setPreloaded(isPreloaded) { this._preloaded = isPreloaded }
|
|
76
|
+
|
|
77
|
+
/** @returns {string} The foreign key for this relationship */
|
|
69
78
|
getForeignKey() { return this.getRelationship().getForeignKey() }
|
|
70
79
|
|
|
71
|
-
/**
|
|
72
|
-
* @template T extends import("../index.js").default
|
|
73
|
-
* @returns {T} model
|
|
74
|
-
*/
|
|
80
|
+
/** @returns {import("../index.js").default} model */
|
|
75
81
|
getModel() { return this.model }
|
|
76
82
|
|
|
77
|
-
/**
|
|
78
|
-
* @returns {string} The primary key for this relationship's model
|
|
79
|
-
*/
|
|
83
|
+
/** @returns {string} The primary key for this relationship's model */
|
|
80
84
|
getPrimaryKey() { return this.getRelationship().getPrimaryKey() }
|
|
81
85
|
|
|
82
|
-
/**
|
|
83
|
-
* @template T extends import("../relationships/base.js").default
|
|
84
|
-
* @returns {T} The relationship object that this instance relationship is based on
|
|
85
|
-
*/
|
|
86
|
+
/** @returns {import("../relationships/base.js").default} The relationship object that this instance relationship is based on */
|
|
86
87
|
getRelationship() { return this.relationship }
|
|
87
88
|
|
|
88
|
-
/**
|
|
89
|
-
* @returns {typeof import("../index.js").default} The model class that this instance relationship
|
|
90
|
-
*/
|
|
89
|
+
/** @returns {typeof import("../index.js").default | undefined} The model class that this instance relationship */
|
|
91
90
|
getTargetModelClass() { return this.getRelationship().getTargetModelClass() }
|
|
92
91
|
|
|
93
|
-
/**
|
|
94
|
-
* @returns {string} The type of relationship (e.g. "has_many", "belongs_to", etc.)
|
|
95
|
-
*/
|
|
92
|
+
/** @returns {string} The type of relationship (e.g. "has_many", "belongs_to", etc.) */
|
|
96
93
|
getType() { return this.getRelationship().getType() }
|
|
97
94
|
}
|
|
@@ -1,21 +1,33 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BaseInstanceRelationship from "./base.js"
|
|
2
4
|
|
|
3
5
|
export default class VelociousDatabaseRecordBelongsToInstanceRelationship extends BaseInstanceRelationship {
|
|
6
|
+
/**
|
|
7
|
+
* @param {Record<string, any>} data
|
|
8
|
+
* @returns {import("../index.js").default}
|
|
9
|
+
*/
|
|
4
10
|
build(data) {
|
|
5
|
-
const
|
|
6
|
-
|
|
11
|
+
const TargetModelClass = this.getTargetModelClass()
|
|
12
|
+
|
|
13
|
+
if (!TargetModelClass) throw new Error("Can't build a new record without a target model")
|
|
14
|
+
|
|
15
|
+
const newInstance = new TargetModelClass(data)
|
|
7
16
|
|
|
8
17
|
this._loaded = newInstance
|
|
9
18
|
|
|
10
19
|
return newInstance
|
|
11
20
|
}
|
|
12
21
|
|
|
13
|
-
|
|
22
|
+
getLoadedOrUndefined() { return this._loaded }
|
|
14
23
|
|
|
15
24
|
async load() {
|
|
16
25
|
const foreignKey = this.getForeignKey()
|
|
17
26
|
const foreignModelID = this.getModel().readColumn(foreignKey)
|
|
18
27
|
const TargetModelClass = this.getTargetModelClass()
|
|
28
|
+
|
|
29
|
+
if (!TargetModelClass) throw new Error("Can't load without a target model")
|
|
30
|
+
|
|
19
31
|
const foreignModel = await TargetModelClass.find(foreignModelID)
|
|
20
32
|
|
|
21
33
|
this.setLoaded(foreignModel)
|
|
@@ -1,21 +1,30 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BaseInstanceRelationship from "./base.js"
|
|
2
4
|
|
|
3
5
|
export default class VelociousDatabaseRecordHasManyInstanceRelationship extends BaseInstanceRelationship {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @param {Record<string, any>} data
|
|
8
|
+
* @returns {import("../index.js").default}
|
|
9
|
+
*/
|
|
9
10
|
build(data) {
|
|
10
11
|
// Spawn new model of the targeted class
|
|
11
12
|
const targetModelClass = this.getTargetModelClass()
|
|
13
|
+
|
|
14
|
+
if (!targetModelClass) throw new Error("Can't build a new record without a taget model class")
|
|
15
|
+
|
|
12
16
|
const newInstance = new targetModelClass(data)
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
// Add it to the loaded models of this relationship
|
|
16
|
-
if (this._loaded ===
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
if (this._loaded === undefined) {
|
|
21
|
+
/** @type {import("../index.js").default[]} */
|
|
22
|
+
this._loaded = [newInstance]
|
|
23
|
+
} else if (Array.isArray(this._loaded)) {
|
|
24
|
+
this._loaded.push(newInstance)
|
|
25
|
+
} else {
|
|
26
|
+
throw new Error(`Loaded had an unexpected type: ${typeof this._loaded}`)
|
|
27
|
+
}
|
|
19
28
|
|
|
20
29
|
|
|
21
30
|
// Set loaded on the models inversed relationship
|
|
@@ -38,6 +47,10 @@ export default class VelociousDatabaseRecordHasManyInstanceRelationship extends
|
|
|
38
47
|
const primaryKey = this.getPrimaryKey()
|
|
39
48
|
const primaryModelID = this.getModel().readColumn(primaryKey)
|
|
40
49
|
const TargetModelClass = this.getTargetModelClass()
|
|
50
|
+
|
|
51
|
+
if (!TargetModelClass) throw new Error("Cannot load without a target model class")
|
|
52
|
+
|
|
53
|
+
/** @type {Record<string, any>} */
|
|
41
54
|
const whereArgs = {}
|
|
42
55
|
|
|
43
56
|
whereArgs[foreignKey] = primaryModelID
|
|
@@ -49,47 +62,55 @@ export default class VelociousDatabaseRecordHasManyInstanceRelationship extends
|
|
|
49
62
|
this.setPreloaded(true)
|
|
50
63
|
}
|
|
51
64
|
|
|
65
|
+
/**
|
|
66
|
+
* @returns {import("../index.js").default | Array<import("../index.js").default> | undefined} The loaded model or models (depending on relationship type)
|
|
67
|
+
*/
|
|
52
68
|
loaded() {
|
|
53
69
|
if (!this._preloaded && this.model.isPersisted()) {
|
|
54
70
|
throw new Error(`${this.model.constructor.name}#${this.relationship.getRelationshipName()} hasn't been preloaded`)
|
|
55
71
|
}
|
|
56
72
|
|
|
57
|
-
if (this._loaded ===
|
|
73
|
+
if (this._loaded === undefined && this.model.isNewRecord()) {
|
|
58
74
|
return []
|
|
59
75
|
}
|
|
60
76
|
|
|
61
77
|
return this._loaded
|
|
62
78
|
}
|
|
63
79
|
|
|
64
|
-
|
|
65
|
-
|
|
80
|
+
/**
|
|
81
|
+
* @param {import("../index.js").default[]} models
|
|
82
|
+
* @returns {void}
|
|
83
|
+
*/
|
|
66
84
|
addToLoaded(models) {
|
|
67
|
-
if (
|
|
85
|
+
if (!models) {
|
|
86
|
+
throw new Error("Need to give something")
|
|
87
|
+
} else if (Array.isArray(models)) {
|
|
68
88
|
for (const model of models) {
|
|
69
|
-
if (this._loaded ===
|
|
70
|
-
|
|
71
|
-
this._loaded
|
|
89
|
+
if (this._loaded === undefined) {
|
|
90
|
+
this._loaded = [model]
|
|
91
|
+
} else if (Array.isArray(this._loaded)) {
|
|
92
|
+
this._loaded.push(model)
|
|
93
|
+
} else {
|
|
94
|
+
throw new Error(`Unexpected loaded type: ${typeof this._loaded}`)
|
|
95
|
+
}
|
|
72
96
|
}
|
|
73
97
|
} else {
|
|
74
|
-
if (this._loaded ===
|
|
75
|
-
|
|
76
|
-
this._loaded
|
|
98
|
+
if (this._loaded === undefined) {
|
|
99
|
+
this._loaded = [models]
|
|
100
|
+
} else if (Array.isArray(this._loaded)) {
|
|
101
|
+
this._loaded.push(models)
|
|
102
|
+
} else {
|
|
103
|
+
throw new Error(`Unexpected loaded type: ${typeof this._loaded}`)
|
|
104
|
+
}
|
|
77
105
|
}
|
|
78
106
|
}
|
|
79
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @param {import("../index.js").default[]} models
|
|
110
|
+
*/
|
|
80
111
|
setLoaded(models) {
|
|
81
112
|
if (!Array.isArray(models)) throw new Error(`Argument given to setLoaded wasn't an array: ${typeof models}`)
|
|
82
113
|
|
|
83
114
|
this._loaded = models
|
|
84
115
|
}
|
|
85
|
-
|
|
86
|
-
setPreloaded(preloaded) {
|
|
87
|
-
if (preloaded && !Array.isArray(this._loaded)) {
|
|
88
|
-
throw new Error("Trying to set preloaded without a loaded value")
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
this._preloaded = preloaded
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
getTargetModelClass() { return this.relationship.getTargetModelClass() }
|
|
95
116
|
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BaseInstanceRelationship from "./base.js"
|
|
2
4
|
|
|
3
5
|
export default class VelociousDatabaseRecordHasOneInstanceRelationship extends BaseInstanceRelationship {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this._loaded = null
|
|
7
|
-
}
|
|
6
|
+
/** @type {import("../index.js").default | undefined} */
|
|
7
|
+
_loaded = undefined
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @param {Record<string, any>} data
|
|
11
|
+
* @returns {import("../index.js").default}
|
|
12
|
+
*/
|
|
9
13
|
build(data) {
|
|
10
|
-
const
|
|
11
|
-
|
|
14
|
+
const TargetModelClass = this.getTargetModelClass()
|
|
15
|
+
|
|
16
|
+
if (!TargetModelClass) throw new Error("Can't build a new record without a target model class")
|
|
17
|
+
|
|
18
|
+
const newInstance = new TargetModelClass(data)
|
|
12
19
|
|
|
13
20
|
this._loaded = newInstance
|
|
14
21
|
|
|
@@ -20,6 +27,10 @@ export default class VelociousDatabaseRecordHasOneInstanceRelationship extends B
|
|
|
20
27
|
const primaryKey = this.getPrimaryKey()
|
|
21
28
|
const primaryModelID = this.getModel().readColumn(primaryKey)
|
|
22
29
|
const TargetModelClass = this.getTargetModelClass()
|
|
30
|
+
|
|
31
|
+
if (!TargetModelClass) throw new Error("Can't load without a target model class")
|
|
32
|
+
|
|
33
|
+
/** @type {Record<string, any>} */
|
|
23
34
|
const whereArgs = {}
|
|
24
35
|
|
|
25
36
|
whereArgs[foreignKey] = primaryModelID
|
|
@@ -31,6 +42,9 @@ export default class VelociousDatabaseRecordHasOneInstanceRelationship extends B
|
|
|
31
42
|
this.setPreloaded(true)
|
|
32
43
|
}
|
|
33
44
|
|
|
45
|
+
/**
|
|
46
|
+
* @returns {import("../index.js").default | Array<import("../index.js").default> | undefined} The loaded model or models (depending on relationship type)
|
|
47
|
+
*/
|
|
34
48
|
loaded() {
|
|
35
49
|
if (!this._preloaded && this.model.isPersisted()) {
|
|
36
50
|
throw new Error(`${this.model.constructor.name}#${this.relationship.getRelationshipName()} hasn't been preloaded`)
|
|
@@ -39,8 +53,9 @@ export default class VelociousDatabaseRecordHasOneInstanceRelationship extends B
|
|
|
39
53
|
return this._loaded
|
|
40
54
|
}
|
|
41
55
|
|
|
42
|
-
|
|
56
|
+
getLoadedOrUndefined() { return this._loaded }
|
|
43
57
|
|
|
58
|
+
/** @param {import("../index.js").default|Array<import("../index.js").default>} model */
|
|
44
59
|
setLoaded(model) {
|
|
45
60
|
if (Array.isArray(model)) throw new Error(`Argument given to setLoaded was an array: ${typeof model}`)
|
|
46
61
|
|
|
@@ -1,32 +1,34 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import restArgsError from "../../../utils/rest-args-error.js"
|
|
2
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {object} RelationshipBaseArgsType
|
|
7
|
+
* @property {string} [className]
|
|
8
|
+
* @property {string} [dependent]
|
|
9
|
+
* @property {string | undefined} [foreignKey]
|
|
10
|
+
* @property {string} [inverseOf]
|
|
11
|
+
* @property {typeof import("../index.js").default} [klass]
|
|
12
|
+
* @property {typeof import("../index.js").default} modelClass
|
|
13
|
+
* @property {string} [primaryKey]
|
|
14
|
+
* @property {boolean} [polymorphic]
|
|
15
|
+
* @property {string} relationshipName
|
|
16
|
+
* @property {string} [through]
|
|
17
|
+
* @property {string} type
|
|
18
|
+
*/
|
|
19
|
+
|
|
3
20
|
export default class VelociousDatabaseRecordBaseRelationship {
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
* @param {string} args.className
|
|
7
|
-
* @param {import("../../../configuration.js").default} args.configuration
|
|
8
|
-
* @param {string} args.dependent
|
|
9
|
-
* @param {boolean|object} args.foreignKey
|
|
10
|
-
* @param {string} args.inverseOf
|
|
11
|
-
* @param {typeof import("../index.js").default} args.klass
|
|
12
|
-
* @param {typeof import("../index.js").default} args.modelClass
|
|
13
|
-
* @param {string} args.primaryKey
|
|
14
|
-
* @param {boolean} args.polymorphic
|
|
15
|
-
* @param {string} args.relationshipName
|
|
16
|
-
* @param {string} args.through
|
|
17
|
-
* @param {string} args.type
|
|
18
|
-
*/
|
|
19
|
-
constructor({className, configuration, dependent, foreignKey, inverseOf, klass, modelClass, primaryKey = "id", polymorphic, relationshipName, through, type, ...restArgs}) { // eslint-disable-line no-unused-vars
|
|
21
|
+
/** @param {RelationshipBaseArgsType} args */
|
|
22
|
+
constructor({className, dependent, foreignKey, inverseOf, klass, modelClass, primaryKey = "id", polymorphic, relationshipName, through, type, ...restArgs}) {
|
|
20
23
|
restArgsError(restArgs)
|
|
21
24
|
|
|
22
25
|
if (!modelClass) throw new Error(`'modelClass' wasn't given for ${relationshipName}`)
|
|
23
26
|
if (!className && !klass) throw new Error(`Neither 'className' or 'klass' was given for ${modelClass.name}#${relationshipName}`)
|
|
24
27
|
|
|
25
28
|
this.className = className
|
|
26
|
-
this.configuration = configuration
|
|
27
29
|
this._dependent = dependent
|
|
28
30
|
this.foreignKey = foreignKey
|
|
29
|
-
this._inverseOf
|
|
31
|
+
this._inverseOf = inverseOf
|
|
30
32
|
this.klass = klass
|
|
31
33
|
this.modelClass = modelClass
|
|
32
34
|
this._polymorphic = polymorphic
|
|
@@ -36,9 +38,9 @@ export default class VelociousDatabaseRecordBaseRelationship {
|
|
|
36
38
|
this.type = type
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
getConfiguration() { return this.modelClass._getConfiguration() }
|
|
42
|
+
|
|
43
|
+
/** @returns {string | undefined} What will be done when the parent record is destroyed. E.g. "destroy", "nullify", "restrict" etc. */
|
|
42
44
|
getDependent() { return this._dependent }
|
|
43
45
|
|
|
44
46
|
/**
|
|
@@ -51,47 +53,35 @@ export default class VelociousDatabaseRecordBaseRelationship {
|
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
55
|
* @abstract
|
|
54
|
-
* @returns {string} The name of the inverse relationship, e.g. "posts", "comments" etc.
|
|
56
|
+
* @returns {string | undefined} The name of the inverse relationship, e.g. "posts", "comments" etc.
|
|
55
57
|
*/
|
|
56
58
|
getInverseOf() {
|
|
57
59
|
throw new Error("getInverseOf not implemented")
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
/**
|
|
61
|
-
* @returns {typeof import("../index.js").default}
|
|
62
|
-
*/
|
|
62
|
+
/** @returns {typeof import("../index.js").default} */
|
|
63
63
|
getModelClass() { return this.modelClass }
|
|
64
64
|
|
|
65
|
-
/**
|
|
66
|
-
* @returns {string} The name of the relationship, e.g. "posts", "user", "comments" etc.
|
|
67
|
-
*/
|
|
65
|
+
/** @returns {string} The name of the relationship, e.g. "posts", "user", "comments" etc. */
|
|
68
66
|
getRelationshipName() { return this.relationshipName }
|
|
69
67
|
|
|
70
|
-
/**
|
|
71
|
-
* @returns {boolean}
|
|
72
|
-
*/
|
|
68
|
+
/** @returns {boolean} */
|
|
73
69
|
getPolymorphic() {
|
|
74
|
-
return this._polymorphic
|
|
70
|
+
return this._polymorphic || false
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
/**
|
|
78
|
-
* @returns {string} The name of the foreign key, e.g. "id" etc.
|
|
79
|
-
*/
|
|
73
|
+
/** @returns {string} The name of the foreign key, e.g. "id" etc. */
|
|
80
74
|
getPrimaryKey() { return this._primaryKey }
|
|
81
75
|
|
|
82
|
-
/**
|
|
83
|
-
* @returns {string} The type of the relationship, e.g. "has_many", "belongs_to", "has_one", "has_and_belongs_to_many" etc.
|
|
84
|
-
*/
|
|
76
|
+
/** @returns {string} The type of the relationship, e.g. "has_many", "belongs_to", "has_one", "has_and_belongs_to_many" etc. */
|
|
85
77
|
getType() { return this.type }
|
|
86
78
|
|
|
87
|
-
/**
|
|
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.
|
|
89
|
-
*/
|
|
79
|
+
/** @returns {typeof import("../index.js").default | undefined} The target model class for this relationship, e.g. if the relationship is "posts" then the target model class is the Post class. */
|
|
90
80
|
getTargetModelClass() {
|
|
91
81
|
if (this.getPolymorphic()) {
|
|
92
|
-
return
|
|
82
|
+
return undefined
|
|
93
83
|
} else if (this.className) {
|
|
94
|
-
return this.
|
|
84
|
+
return this.getConfiguration().getModelClass(this.className)
|
|
95
85
|
} else if (this.klass) {
|
|
96
86
|
return this.klass
|
|
97
87
|
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BaseRelationship from "./base.js"
|
|
2
4
|
import * as inflection from "inflection"
|
|
3
5
|
|
|
4
6
|
export default class VelociousDatabaseRecordBelongsToRelationship extends BaseRelationship {
|
|
7
|
+
/** @returns {string} */
|
|
5
8
|
getForeignKey() {
|
|
6
9
|
if (!this.foreignKey) {
|
|
7
|
-
|
|
10
|
+
const targetModelClass = this.getTargetModelClass()
|
|
11
|
+
|
|
12
|
+
if (!targetModelClass) throw new Error("Can't calculate foreign key without a target model class")
|
|
13
|
+
|
|
14
|
+
this.foreignKey = `${inflection.underscore(targetModelClass.name)}_id`
|
|
8
15
|
}
|
|
9
16
|
|
|
10
17
|
return this.foreignKey
|
|
11
18
|
}
|
|
12
19
|
|
|
20
|
+
/** @returns {string | undefined} */
|
|
13
21
|
getInverseOf() {
|
|
14
22
|
if (!this._inverseOf && !this._autoGenerateInverseOfAttempted) {
|
|
15
23
|
this._autoGenerateInverseOfAttempted = true
|
|
@@ -17,9 +25,11 @@ export default class VelociousDatabaseRecordBelongsToRelationship extends BaseRe
|
|
|
17
25
|
// Only make auto-inverse-of if the relationships name matches the target model class's name
|
|
18
26
|
const targetClassSimpleName = `${this.getRelationshipName().substring(0, 1).toUpperCase()}${this.getRelationshipName().substring(1, this.getRelationshipName().length)}`
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
const targetModelClass = this.getTargetModelClass()
|
|
29
|
+
|
|
30
|
+
if (targetModelClass && targetClassSimpleName == targetModelClass.name) {
|
|
21
31
|
// Only make auto-inverse-of if the expected relationship exist in a has-one or has-many form
|
|
22
|
-
const targetClassRelationshipNames =
|
|
32
|
+
const targetClassRelationshipNames = targetModelClass.getRelationshipNames()
|
|
23
33
|
const autoGeneratedHasOneInverseOfName = `${this.modelClass.name.substring(0, 1).toLowerCase()}${this.modelClass.name.substring(1, this.modelClass.name.length)}`
|
|
24
34
|
const autoGeneratedHasManyInverseOfName = inflection.pluralize(autoGeneratedHasOneInverseOfName)
|
|
25
35
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BaseRelationship from "./base.js"
|
|
2
4
|
import * as inflection from "inflection"
|
|
3
5
|
|
|
4
6
|
export default class VelociousDatabaseRecordHasManyRelationship extends BaseRelationship {
|
|
7
|
+
/** @returns {string} */
|
|
5
8
|
getForeignKey() {
|
|
6
9
|
if (!this.foreignKey) {
|
|
7
10
|
this.foreignKey = `${inflection.underscore(this.modelClass.name)}_id`
|
|
@@ -10,6 +13,7 @@ export default class VelociousDatabaseRecordHasManyRelationship extends BaseRela
|
|
|
10
13
|
return this.foreignKey
|
|
11
14
|
}
|
|
12
15
|
|
|
16
|
+
/** @returns {string | undefined} */
|
|
13
17
|
getInverseOf() {
|
|
14
18
|
if (!this._inverseOf && !this._autoGenerateInverseOfAttempted) {
|
|
15
19
|
this._autoGenerateInverseOfAttempted = true
|
|
@@ -17,9 +21,11 @@ export default class VelociousDatabaseRecordHasManyRelationship extends BaseRela
|
|
|
17
21
|
// Only make auto-inverse-of if the relationships name matches the target model class's name
|
|
18
22
|
const targetClassSimpleName = inflection.singularize(`${this.getRelationshipName().substring(0, 1).toUpperCase()}${this.getRelationshipName().substring(1, this.getRelationshipName().length)}`)
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
const targetModelClass = this.getTargetModelClass()
|
|
25
|
+
|
|
26
|
+
if (targetModelClass && targetClassSimpleName == targetModelClass.name) {
|
|
21
27
|
// Only make auto-inverse-of if the expected relationship exist in a has-one or has-many form
|
|
22
|
-
const targetClassRelationshipNames =
|
|
28
|
+
const targetClassRelationshipNames = targetModelClass.getRelationshipNames()
|
|
23
29
|
const autoGeneratedBelongsToInverseOfName = `${this.modelClass.name.substring(0, 1).toLowerCase()}${this.modelClass.name.substring(1, this.modelClass.name.length)}`
|
|
24
30
|
|
|
25
31
|
if (targetClassRelationshipNames.includes(autoGeneratedBelongsToInverseOfName)) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BaseRelationship from "./base.js"
|
|
2
4
|
import * as inflection from "inflection"
|
|
3
5
|
|
|
4
6
|
export default class VelociousDatabaseRecordHasOneRelationship extends BaseRelationship {
|
|
7
|
+
/** @returns {string} */
|
|
5
8
|
getForeignKey() {
|
|
6
9
|
if (!this.foreignKey) {
|
|
7
10
|
this.foreignKey = `${inflection.underscore(this.modelClass.name)}_id`
|
|
@@ -10,6 +13,7 @@ export default class VelociousDatabaseRecordHasOneRelationship extends BaseRelat
|
|
|
10
13
|
return this.foreignKey
|
|
11
14
|
}
|
|
12
15
|
|
|
16
|
+
/** @returns {string | undefined} */
|
|
13
17
|
getInverseOf() {
|
|
14
18
|
if (!this._inverseOf && !this._autoGenerateInverseOfAttempted) {
|
|
15
19
|
this._autoGenerateInverseOfAttempted = true
|
|
@@ -17,9 +21,11 @@ export default class VelociousDatabaseRecordHasOneRelationship extends BaseRelat
|
|
|
17
21
|
// Only make auto-inverse-of if the relationships name matches the target model class's name
|
|
18
22
|
const targetClassSimpleName = `${this.getRelationshipName().substring(0, 1).toUpperCase()}${this.getRelationshipName().substring(1, this.getRelationshipName().length)}`
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
const targetModelClass = this.getTargetModelClass()
|
|
25
|
+
|
|
26
|
+
if (targetModelClass && targetClassSimpleName == targetModelClass.name) {
|
|
21
27
|
// Only make auto-inverse-of if the expected relationship exist in a has-one or has-many form
|
|
22
|
-
const targetClassRelationshipNames =
|
|
28
|
+
const targetClassRelationshipNames = targetModelClass.getRelationshipNames()
|
|
23
29
|
const autoGeneratedBelongsToInverseOfName = `${this.modelClass.name.substring(0, 1).toLowerCase()}${this.modelClass.name.substring(1, this.modelClass.name.length)}`
|
|
24
30
|
|
|
25
31
|
if (targetClassRelationshipNames.includes(autoGeneratedBelongsToInverseOfName)) {
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
export default class VelociousDatabaseRecordValidatorsBase {
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} args
|
|
6
|
+
* @param {string} args.attributeName
|
|
7
|
+
* @param {Record<string, any>} args.args
|
|
8
|
+
*/
|
|
9
|
+
constructor({attributeName, args}) {
|
|
10
|
+
this.attributeName = attributeName
|
|
11
|
+
this.args = args
|
|
12
|
+
}
|
|
13
|
+
|
|
2
14
|
/**
|
|
3
15
|
* @abstract
|
|
4
|
-
* @template T extends import("../index.js").default
|
|
5
16
|
* @param {object} args
|
|
6
|
-
* @param {
|
|
17
|
+
* @param {import("../index.js").default} args.model
|
|
7
18
|
* @param {string} args.attributeName
|
|
19
|
+
* @returns {Promise<void>}
|
|
8
20
|
*/
|
|
9
21
|
async validate({model, attributeName}) { // eslint-disable-line no-unused-vars
|
|
10
22
|
throw new Error("validate not implemented")
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import Base from "./base.js"
|
|
2
4
|
|
|
3
5
|
export default class VelociousDatabaseRecordValidatorsPresence extends Base {
|
|
6
|
+
/**
|
|
7
|
+
* @param {object} args
|
|
8
|
+
* @param {import("../index.js").default} args.model
|
|
9
|
+
* @param {string} args.attributeName
|
|
10
|
+
*/
|
|
4
11
|
async validate({model, attributeName}) {
|
|
5
12
|
const attributeValue = model.readAttribute(attributeName)?.trim()
|
|
6
13
|
|
|
@@ -97,7 +97,7 @@ export default class TableColumn {
|
|
|
97
97
|
getForeignKey() { return this.args?.foreignKey }
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* @param {boolean | object} newForeignKey
|
|
100
|
+
* @param {boolean | object | undefined} newForeignKey
|
|
101
101
|
* @returns {void}
|
|
102
102
|
*/
|
|
103
103
|
setForeignKey(newForeignKey) { this.args.foreignKey = newForeignKey }
|
|
@@ -138,7 +138,7 @@ export default class TableColumn {
|
|
|
138
138
|
getMaxLength() { return this.args?.maxLength }
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
|
-
* @param {number} newMaxLength
|
|
141
|
+
* @param {number | undefined} newMaxLength
|
|
142
142
|
* @returns {void}
|
|
143
143
|
*/
|
|
144
144
|
setMaxLength(newMaxLength) { this.args.maxLength = newMaxLength }
|
|
@@ -171,7 +171,7 @@ export default class TableColumn {
|
|
|
171
171
|
getType() { return this.args?.type }
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
|
-
* @param {string} newType
|
|
174
|
+
* @param {string | undefined} newType
|
|
175
175
|
* @returns {void}
|
|
176
176
|
*/
|
|
177
177
|
setType(newType) { this.args.type = newType }
|
|
@@ -206,8 +206,7 @@ export default class VelociousEnvironmentHandlerNode extends Base{
|
|
|
206
206
|
|
|
207
207
|
/**
|
|
208
208
|
* @param {string} filePath
|
|
209
|
-
* @
|
|
210
|
-
* @returns {Promise<T>}
|
|
209
|
+
* @returns {Promise<import("../database/migration/index.js").default>}
|
|
211
210
|
*/
|
|
212
211
|
async requireMigration(filePath) {
|
|
213
212
|
const migrationImport = await import(filePath)
|