@kaspernj/api-maker 1.0.120 → 1.0.124

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 CHANGED
@@ -16,7 +16,7 @@
16
16
  ]
17
17
  },
18
18
  "name": "@kaspernj/api-maker",
19
- "version": "1.0.120",
19
+ "version": "1.0.124",
20
20
  "description": "",
21
21
  "main": "index.js",
22
22
  "repository": {
@@ -48,7 +48,7 @@
48
48
  "@babel/preset-react": "^7.12.10",
49
49
  "babel-jest": "^27.0.6",
50
50
  "eslint": "^7.26.0",
51
- "eslint-find-rules": "^3.6.1",
51
+ "eslint-find-rules": "^4.0.0",
52
52
  "eslint-plugin-jest": "^24.3.6",
53
53
  "eslint-plugin-react": "^7.23.2",
54
54
  "i18n-on-steroids": "^1.0.2",
@@ -659,11 +659,9 @@ module.exports = class BaseModel {
659
659
  return this.modelData[attributeName]
660
660
  } else if (this.isNewRecord()) {
661
661
  // Return null if this is a new record and the attribute name is a recognized attribute
662
- const attributes = this.modelClassData().attributes
663
- for(const attribute of attributes) {
664
- if (attribute.name == attributeName)
665
- return null
666
- }
662
+ const attributes = digg(this.modelClassData(), "attributes")
663
+
664
+ if (attributeName in attributes) return null
667
665
  }
668
666
 
669
667
  throw new AttributeNotLoadedError(`No such attribute: ${digg(this.modelClassData(), "name")}#${attributeName}`)
@@ -698,26 +696,31 @@ module.exports = class BaseModel {
698
696
  }
699
697
  }
700
698
 
701
- _readBelongsToReflection(args) {
702
- if (!(args.reflectionName in this.relationshipsCache)) {
699
+ _readBelongsToReflection({reflectionName}) {
700
+ if (!(reflectionName in this.relationshipsCache)) {
703
701
  if (this.isNewRecord())
704
702
  return null
705
703
 
706
- throw new NotLoadedError(`${digg(this.modelClassData(), "name")}#${args.reflectionName} hasn't been loaded yet`)
704
+ const loadedRelationships = Object.keys(this.relationshipsCache)
705
+ const modelClassName = digg(this.modelClassData(), "name")
706
+
707
+ throw new NotLoadedError(`${modelClassName}#${reflectionName} hasn't been loaded yet. Only these were loaded: ${loadedRelationships.join(", ")}`)
707
708
  }
708
709
 
709
- return this.relationshipsCache[args.reflectionName]
710
+ return this.relationshipsCache[reflectionName]
710
711
  }
711
712
 
712
713
  async _loadHasManyReflection(args, queryArgs = {}) {
713
714
  if (args.reflectionName in this.relationshipsCache) {
714
715
  return this.relationshipsCache[args.reflectionName]
715
- } else {
716
- const collection = new Collection(args, queryArgs)
717
- const model = await collection.toArray()
718
- this.relationshipsCache[args.reflectionName] = model
719
- return model
720
716
  }
717
+
718
+ const collection = new Collection(args, queryArgs)
719
+ const models = await collection.toArray()
720
+
721
+ this.relationshipsCache[args.reflectionName] = models
722
+
723
+ return models
721
724
  }
722
725
 
723
726
  async _loadHasOneReflection(args, queryArgs = {}) {
@@ -726,20 +729,25 @@ module.exports = class BaseModel {
726
729
  } else {
727
730
  const collection = new Collection(args, queryArgs)
728
731
  const model = await collection.first()
732
+
729
733
  this.relationshipsCache[args.reflectionName] = model
734
+
730
735
  return model
731
736
  }
732
737
  }
733
738
 
734
- _readHasOneReflection(args) {
735
- if (!(args.reflectionName in this.relationshipsCache)) {
739
+ _readHasOneReflection({reflectionName}) {
740
+ if (!(reflectionName in this.relationshipsCache)) {
736
741
  if (this.isNewRecord())
737
742
  return null
738
743
 
739
- throw new NotLoadedError(`${digg(this.modelClassData(), "name")}#${args.reflectionName} hasn't been loaded yet`)
744
+ const loadedRelationships = Object.keys(this.relationshipsCache)
745
+ const modelClassName = digg(this.modelClassData(), "name")
746
+
747
+ throw new NotLoadedError(`${modelClassName}#${reflectionName} hasn't been loaded yet. Only these were loaded: ${loadedRelationships.join(", ")}`)
740
748
  }
741
749
 
742
- return this.relationshipsCache[args.reflectionName]
750
+ return this.relationshipsCache[reflectionName]
743
751
  }
744
752
 
745
753
  _readModelDataFromArgs(args) {
@@ -754,9 +762,11 @@ module.exports = class BaseModel {
754
762
  return
755
763
  }
756
764
 
765
+ const relationships = digg(this.modelClassData(), "relationships")
766
+
757
767
  for (const relationshipName in this.preloadedRelationships) {
758
768
  const relationshipData = this.preloadedRelationships[relationshipName]
759
- const relationshipClassData = this.modelClassData().relationships.find((relationship) => digg(relationship, "name") == relationshipName)
769
+ const relationshipClassData = relationships.find((relationship) => digg(relationship, "name") == relationshipName)
760
770
 
761
771
  if (!relationshipClassData) {
762
772
  throw new Error(`Could not find the relation ${relationshipName} on the ${digg(this.modelClassData(), "name")} model`)
@@ -0,0 +1,28 @@
1
+ const {digs} = require("diggerize")
2
+ const ModelRecipesModelLoader = require("./model-recipes-model-loader.cjs")
3
+
4
+ module.exports = class ModelRecipesLoader {
5
+ constructor({recipes}) {
6
+ this.modelClasses = {}
7
+ this.recipes = recipes
8
+ }
9
+
10
+ getModelClass(name) {
11
+ return digg(this, "modelClasses", name)
12
+ }
13
+
14
+ load() {
15
+ const {recipes} = digs(this, "recipes")
16
+ const {models} = digs(recipes, "models")
17
+
18
+ for (const modelName in models) {
19
+ const modelRecipe = models[modelName]
20
+ const modelClassLoader = new ModelRecipesModelLoader({modelRecipe, modelRecipesLoader: this})
21
+ const modelClass = modelClassLoader.createClass()
22
+
23
+ this.modelClasses[modelName] = modelClass
24
+ }
25
+
26
+ return this.modelClasses
27
+ }
28
+ }
@@ -0,0 +1,325 @@
1
+ const BaseModel = require("./base-model.cjs")
2
+ const Collection = require("./collection.cjs")
3
+ const {digg} = require("diggerize")
4
+ const inflection = require("inflection")
5
+
6
+ module.exports = class ApiMakerModelRecipesModelLoader {
7
+ constructor({modelRecipe, modelRecipesLoader}) {
8
+ if (!modelRecipe) throw new Error("No 'modelRecipe' was given")
9
+
10
+ this.modelRecipesLoader = modelRecipesLoader
11
+ this.modelRecipe = modelRecipe
12
+ }
13
+
14
+ createClass() {
15
+ const {modelRecipe} = digs(this, "modelRecipe")
16
+ const {
17
+ attributes,
18
+ collection_commands: collectionCommands,
19
+ member_commands: memberCommands,
20
+ model_class_data: modelClassData,
21
+ relationships
22
+ } = digs(
23
+ modelRecipe,
24
+ "attributes",
25
+ "collection_commands",
26
+ "member_commands",
27
+ "model_class_data",
28
+ "relationships"
29
+ )
30
+ const {name: modelClassName} = digs(modelClassData, "name")
31
+ const ModelClass = class ApiMakerModel extends BaseModel { }
32
+
33
+ Object.defineProperty(ModelClass, "name", {writable: false, value: modelClassName})
34
+
35
+ ModelClass.prototype.constructor.modelClassData = () => modelClassData
36
+
37
+ this.addAttributeMethodsToModelClass(ModelClass, attributes)
38
+ this.addRelationshipsToModelClass(ModelClass, modelClassData, relationships)
39
+ this.addCollectionCommandsToModelClass(ModelClass, collectionCommands)
40
+ this.addMemberCommandsToModelClass(ModelClass, memberCommands)
41
+
42
+ return ModelClass
43
+ }
44
+
45
+ addAttributeMethodsToModelClass(ModelClass, attributes) {
46
+ for (const attributeName in attributes) {
47
+ const attribute = attributes[attributeName]
48
+ const {name} = digs(attribute, "name")
49
+ const methodName = inflection.camelize(name, true)
50
+ const hasMethodName = inflection.camelize(`has_${name}`, true)
51
+
52
+ ModelClass.prototype[methodName] = function () { return this.readAttributeUnderscore(attributeName) }
53
+ ModelClass.prototype[hasMethodName] = function () {
54
+ const value = this[methodName]()
55
+
56
+ return this._isPresent(value)
57
+ }
58
+ }
59
+ }
60
+
61
+ addCollectionCommandsToModelClass(ModelClass, collectionCommands) {
62
+ for (const collectionCommandName in collectionCommands) {
63
+ const methodName = inflection.camelize(collectionCommandName, true)
64
+
65
+ ModelClass[methodName] = function (args, commandArgs = {}) {
66
+ return this._callCollectionCommand(
67
+ {
68
+ args,
69
+ command: collectionCommandName,
70
+ collectionName: digg(this.modelClassData(), "collectionName"),
71
+ type: "collection"
72
+ },
73
+ commandArgs
74
+ )
75
+ }
76
+ }
77
+ }
78
+
79
+ addMemberCommandsToModelClass(ModelClass, memberCommands) {
80
+ for (const memberCommandName in memberCommands) {
81
+ const methodName = inflection.camelize(memberCommandName, true)
82
+
83
+ ModelClass.prototype[methodName] = function (args, commandArgs = {}) {
84
+ return this._callMemberCommand(
85
+ {
86
+ args,
87
+ command: memberCommandName,
88
+ primaryKey: this.primaryKey(),
89
+ collectionName: this.modelClassData().collectionName,
90
+ type: "member"
91
+ },
92
+ commandArgs
93
+ )
94
+ }
95
+ }
96
+ }
97
+
98
+ addRelationshipsToModelClass(ModelClass, modelClassData, relationships) {
99
+ const {modelRecipesLoader} = digs(this, "modelRecipesLoader")
100
+
101
+ for (const relationshipName in relationships) {
102
+ const relationship = relationships[relationshipName]
103
+ const {
104
+ active_record: {
105
+ name: activeRecordName,
106
+ primary_key: activeRecordPrimaryKey
107
+ },
108
+ class_name: className,
109
+ foreign_key: foreignKey,
110
+ klass: {primary_key: klassPrimaryKey},
111
+ options: {as: optionsAs, primary_key: optionsPrimaryKey, through: optionsThrough},
112
+ resource_name: resourceName,
113
+ type
114
+ } = digs(
115
+ relationship,
116
+ "active_record",
117
+ "class_name",
118
+ "foreign_key",
119
+ "klass",
120
+ "options",
121
+ "resource_name",
122
+ "type"
123
+ )
124
+ const loadMethodName = inflection.camelize(`load_${relationshipName}`, true)
125
+ const modelMethodName = inflection.camelize(relationshipName, true)
126
+
127
+ if (type == "belongs_to") {
128
+ this.defineBelongsToGetMethod({ModelClass, modelMethodName, relationshipName})
129
+ this.defineBelongsToLoadMethod({
130
+ foreignKey,
131
+ klassPrimaryKey,
132
+ loadMethodName,
133
+ ModelClass,
134
+ modelRecipesLoader,
135
+ optionsPrimaryKey,
136
+ relationshipName,
137
+ resourceName
138
+ })
139
+ } else if (type == "has_many") {
140
+ this.defineHasManyGetMethod({
141
+ activeRecordName,
142
+ className,
143
+ foreignKey,
144
+ ModelClass,
145
+ modelMethodName,
146
+ modelRecipesLoader,
147
+ optionsAs,
148
+ optionsPrimaryKey,
149
+ optionsThrough,
150
+ relationshipName,
151
+ resourceName
152
+ })
153
+ this.defineHasManyLoadMethod({foreignKey, loadMethodName, ModelClass, modelClassData, modelRecipesLoader, relationshipName, resourceName})
154
+ } else if (type == "has_one") {
155
+ this.defineHasOneGetMethd({ModelClass, modelMethodName, relationshipName})
156
+ this.defineHasOneLoadMethod({
157
+ activeRecordPrimaryKey,
158
+ foreignKey,
159
+ loadMethodName,
160
+ ModelClass,
161
+ modelClassData,
162
+ modelRecipesLoader,
163
+ optionsThrough,
164
+ relationshipName,
165
+ resourceName
166
+ })
167
+ } else {
168
+ throw new Error(`Unknown relationship type: ${type}`)
169
+ }
170
+ }
171
+ }
172
+
173
+ defineBelongsToGetMethod({ModelClass, modelMethodName, relationshipName}) {
174
+ ModelClass.prototype[modelMethodName] = function () {
175
+ return this._readBelongsToReflection({reflectionName: relationshipName})
176
+ }
177
+ }
178
+
179
+ defineBelongsToLoadMethod({foreignKey, klassPrimaryKey, ModelClass, modelRecipesLoader, loadMethodName, optionsPrimaryKey, relationshipName, resourceName}) {
180
+ ModelClass.prototype[loadMethodName] = function () {
181
+ const foreignKeyMethodName = inflection.camelize(foreignKey, true)
182
+
183
+ if (!(foreignKeyMethodName in this)) throw new Error(`Foreign key method wasn't defined: ${foreignKeyMethodName}`)
184
+
185
+ const id = this[foreignKeyMethodName]()
186
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
187
+ const ransack = {}
188
+ const ransackIdSearchKey = `${optionsPrimaryKey || klassPrimaryKey}_eq`
189
+
190
+ ransack[ransackIdSearchKey] = id
191
+
192
+ return this._loadBelongsToReflection(
193
+ {reflectionName: relationshipName, model: this, modelClass},
194
+ {ransack}
195
+ )
196
+ }
197
+ }
198
+
199
+ defineHasManyGetMethod({activeRecordName, className, foreignKey, ModelClass, modelMethodName, modelRecipesLoader, optionsAs, optionsPrimaryKey, optionsThrough, relationshipName, resourceName}) {
200
+ ModelClass.prototype[modelMethodName] = function () {
201
+ const id = this.primaryKey()
202
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
203
+ const ransack = {}
204
+
205
+ ransack[`${foreignKey}_eq`] = id
206
+
207
+ const hasManyParameters = {
208
+ reflectionName: relationshipName,
209
+ model: this,
210
+ modelName: className,
211
+ modelClass
212
+ }
213
+
214
+ let queryParameters
215
+
216
+ if (optionsThrough) {
217
+ queryParameters = {
218
+ params: {
219
+ through: {
220
+ model: activeRecordName,
221
+ id: this.primaryKey(),
222
+ reflection: relationshipName
223
+ }
224
+ }
225
+ }
226
+ } else {
227
+ const ransack = {}
228
+ const primaryKeyColumnName = optionsPrimaryKey || digg(ModelClass.modelClassData(), "primaryKey")
229
+ const primaryKeyMethodName = inflection.camelize(primaryKeyColumnName, true)
230
+
231
+ if (!(primaryKeyMethodName in this)) throw new Error(`No such primary key method: ${primaryKeyMethodName}`)
232
+
233
+ ransack[`${foreignKey}_eq`] = this[primaryKeyMethodName]()
234
+
235
+ if (optionsAs) {
236
+ ransack[`${optionsAs}_type_eq`] = activeRecordName
237
+ }
238
+
239
+ queryParameters = {ransack}
240
+ }
241
+
242
+ return new Collection(hasManyParameters, queryParameters)
243
+ }
244
+ }
245
+
246
+ defineHasManyLoadMethod({foreignKey, loadMethodName, ModelClass, modelClassData, modelRecipesLoader, optionsThrough, relationshipName, resourceName}) {
247
+ ModelClass.prototype[loadMethodName] = function () {
248
+ const id = this.primaryKey()
249
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
250
+
251
+ if (optionsThrough) {
252
+ const modelClassName = digg(modelClassData, "className")
253
+
254
+ return this._loadHasManyReflection(
255
+ {
256
+ reflectionName: relationshipName,
257
+ model: this,
258
+ modelClass
259
+ },
260
+ {
261
+ params: {
262
+ through: {
263
+ model: modelClassName,
264
+ id,
265
+ reflection: relationshipName
266
+ }
267
+ }
268
+ }
269
+ )
270
+ } else {
271
+ const ransack = {}
272
+
273
+ ransack[`${foreignKey}_eq`] = id
274
+
275
+ return this._loadHasManyReflection(
276
+ {
277
+ reflectionName: relationshipName,
278
+ model: this,
279
+ modelClass
280
+ },
281
+ {ransack}
282
+ )
283
+ }
284
+ }
285
+ }
286
+
287
+ defineHasOneGetMethd({ModelClass, modelMethodName, relationshipName}) {
288
+ ModelClass.prototype[modelMethodName] = function () {
289
+ return this._readHasOneReflection({reflectionName: relationshipName})
290
+ }
291
+ }
292
+
293
+ defineHasOneLoadMethod({activeRecordPrimaryKey, foreignKey, loadMethodName, ModelClass, modelClassData, modelRecipesLoader, optionsThrough, relationshipName, resourceName}) {
294
+ ModelClass.prototype[loadMethodName] = function () {
295
+ const primaryKeyMethodName = inflection.camelize(activeRecordPrimaryKey, true)
296
+
297
+ if (!(primaryKeyMethodName in this)) throw new Error(`Primary key method wasn't defined: ${primaryKeyMethodName}`)
298
+
299
+ const id = this[primaryKeyMethodName]()
300
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
301
+
302
+ if (optionsThrough) {
303
+ const modelClassName = digg(modelClassData, "className")
304
+
305
+ return this._loadHasOneReflection(
306
+ {reflectionName: relationshipName, model: this, modelClass},
307
+ {params: {through: {model: modelClassName, id, reflection: relationshipName}}}
308
+ )
309
+ } else {
310
+ const ransack = {}
311
+
312
+ ransack[`${foreignKey}_eq`] = id
313
+
314
+ return this._loadHasOneReflection(
315
+ {
316
+ reflectionName: relationshipName,
317
+ model: this,
318
+ modelClass
319
+ },
320
+ {ransack}
321
+ )
322
+ }
323
+ }
324
+ }
325
+ }
@@ -0,0 +1 @@
1
+ module.exports = <%= ApiMaker::ModelClassesJavaScriptGeneratorService.execute!.to_json %>
package/src/models.cjs ADDED
@@ -0,0 +1,9 @@
1
+ /* rails-erb-loader-dependencies api_maker/resources/ */
2
+
3
+ const modelRecipes = require("./model-recipes.cjs.erb")
4
+ const ModelRecipesLoader = require("./model-recipes-loader.cjs")
5
+
6
+ const loader = new ModelRecipesLoader({recipes: modelRecipes})
7
+ const result = loader.load()
8
+
9
+ module.exports = result
package/src/models.js.erb DELETED
@@ -1,6 +0,0 @@
1
- /* rails-erb-loader-dependencies api_maker/resources/ */
2
-
3
- import {BaseModel, Collection} from "@kaspernj/api-maker"
4
- import {digg} from "diggerize"
5
-
6
- <%= ApiMaker::ModelClassesJavaScriptGeneratorService.execute! %>