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.
Files changed (52) hide show
  1. package/package.json +1 -1
  2. package/spec/database/drivers/create-sql/create-index-sql-spec.js +24 -0
  3. package/src/configuration-types.js +7 -1
  4. package/src/configuration.js +2 -2
  5. package/src/database/drivers/base-column.js +2 -2
  6. package/src/database/drivers/base-columns-index.js +6 -0
  7. package/src/database/drivers/base.js +60 -22
  8. package/src/database/drivers/mssql/index.js +70 -22
  9. package/src/database/drivers/mssql/sql/create-database.js +9 -2
  10. package/src/database/drivers/mssql/table.js +14 -4
  11. package/src/database/drivers/mysql/column.js +6 -0
  12. package/src/database/drivers/mysql/columns-index.js +3 -6
  13. package/src/database/drivers/mysql/foreign-key.js +2 -0
  14. package/src/database/drivers/mysql/index.js +43 -16
  15. package/src/database/drivers/mysql/query-parser.js +2 -0
  16. package/src/database/drivers/mysql/query.js +7 -2
  17. package/src/database/drivers/mysql/table.js +6 -0
  18. package/src/database/drivers/pgsql/index.js +78 -11
  19. package/src/database/drivers/sqlite/base.js +77 -25
  20. package/src/database/drivers/sqlite/column.js +8 -0
  21. package/src/database/drivers/sqlite/sql/alter-table.js +25 -20
  22. package/src/database/drivers/sqlite/sql/create-index.js +2 -0
  23. package/src/database/drivers/sqlite/sql/create-table.js +2 -0
  24. package/src/database/drivers/sqlite/sql/delete.js +4 -2
  25. package/src/database/drivers/sqlite/sql/drop-table.js +2 -0
  26. package/src/database/drivers/sqlite/sql/insert.js +2 -0
  27. package/src/database/drivers/sqlite/sql/update.js +2 -0
  28. package/src/database/drivers/sqlite/table.js +14 -0
  29. package/src/database/migration/index.js +6 -4
  30. package/src/database/pool/base-methods-forward.js +2 -2
  31. package/src/database/query/alter-table-base.js +1 -1
  32. package/src/database/query/base.js +2 -2
  33. package/src/database/query/create-database-base.js +8 -4
  34. package/src/database/query/create-index-base.js +12 -7
  35. package/src/database/query/create-table-base.js +4 -4
  36. package/src/database/query/drop-table-base.js +8 -8
  37. package/src/database/query/index.js +31 -18
  38. package/src/database/query/insert-base.js +18 -3
  39. package/src/database/query-parser/base-query-parser.js +2 -2
  40. package/src/database/record/index.js +444 -172
  41. package/src/database/record/instance-relationships/base.js +41 -44
  42. package/src/database/record/instance-relationships/belongs-to.js +15 -3
  43. package/src/database/record/instance-relationships/has-many.js +49 -28
  44. package/src/database/record/instance-relationships/has-one.js +22 -7
  45. package/src/database/record/relationships/base.js +33 -43
  46. package/src/database/record/relationships/belongs-to.js +13 -3
  47. package/src/database/record/relationships/has-many.js +8 -2
  48. package/src/database/record/relationships/has-one.js +8 -2
  49. package/src/database/record/validators/base.js +14 -2
  50. package/src/database/record/validators/presence.js +7 -0
  51. package/src/database/table-data/table-column.js +3 -3
  52. 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
- * @returns {boolean} Whether the relationship should be auto-saved before saving the parent model
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
- * @returns {boolean} Whether the relationship has been preloaded
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
- * @template T extends import("../index.js").default
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
- * @template T extends import("../index.js").default
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
- * @returns {string} The foreign key for this relationship
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 targetModelClass = this.getTargetModelClass()
6
- const newInstance = new targetModelClass(data)
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
- getLoadedOrNull() { return this._loaded }
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
- constructor(args) {
5
- super(args)
6
- this._loaded = null
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 === null) this._loaded = []
17
-
18
- this._loaded.push(newInstance)
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 === null && this.model.isNewRecord()) {
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
- getLoadedOrNull() { return this._loaded }
65
-
80
+ /**
81
+ * @param {import("../index.js").default[]} models
82
+ * @returns {void}
83
+ */
66
84
  addToLoaded(models) {
67
- if (Array.isArray(models)) {
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 === null) this._loaded = []
70
-
71
- this._loaded.push(model)
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 === null) this._loaded = []
75
-
76
- this._loaded.push(models)
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
- constructor(args) {
5
- super(args)
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 targetModelClass = this.getTargetModelClass()
11
- const newInstance = new targetModelClass(data)
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
- getLoadedOrNull() { return this._loaded }
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
- * @param {object} args
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
- * @returns {string} What will be done when the parent record is destroyed. E.g. "destroy", "nullify", "restrict" etc.
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 null
82
+ return undefined
93
83
  } else if (this.className) {
94
- return this.modelClass._getConfiguration().getModelClass(this.className)
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
- this.foreignKey = `${inflection.underscore(this.getTargetModelClass().name)}_id`
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
- if (targetClassSimpleName == this.getTargetModelClass().name) {
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 = this.getTargetModelClass().getRelationshipNames()
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
- if (targetClassSimpleName == this.getTargetModelClass().name) {
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 = this.getTargetModelClass().getRelationshipNames()
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
- if (targetClassSimpleName == this.getTargetModelClass().name) {
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 = this.getTargetModelClass().getRelationshipNames()
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 {T} args.model
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
- * @template T extends import ("../migration/index.js").default
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)