@kaspernj/api-maker 1.0.121 → 1.0.122

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.121",
19
+ "version": "1.0.122",
20
20
  "description": "",
21
21
  "main": "index.js",
22
22
  "repository": {
@@ -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`)
@@ -205,7 +205,7 @@ module.exports = class ApiMakerCollection {
205
205
  modelClass() {
206
206
  const modelName = digg(this.args.modelClass.modelClassData(), "name")
207
207
 
208
- return digg(require("@kaspernj/api-maker/src/models.js.erb"), modelName)
208
+ return digg(require("@kaspernj/api-maker/src/models"), modelName)
209
209
  }
210
210
 
211
211
  clone() {
@@ -18,14 +18,14 @@ module.exports = class ApiMakerDeserializer {
18
18
  return Money.fromInteger(cents, currency)
19
19
  } else if (object.api_maker_type == "model") {
20
20
  const modelClassName = inflection.classify(digg(object, "model_name"))
21
- const modelClass = digg(require("@kaspernj/api-maker/src/models.js.erb"), modelClassName)
21
+ const modelClass = digg(require("@kaspernj/api-maker/src/models"), modelClassName)
22
22
  const data = ApiMakerDeserializer.parse(digg(object, "serialized"))
23
23
  const model = new modelClass({data, isNewRecord: false})
24
24
 
25
25
  return model
26
26
  } else if (object.api_maker_type == "resource") {
27
27
  const modelClassName = inflection.classify(digg(object, "name"))
28
- const modelClass = digg(require("@kaspernj/api-maker/src/models.js.erb"), modelClassName)
28
+ const modelClass = digg(require("@kaspernj/api-maker/src/models"), modelClassName)
29
29
 
30
30
  return modelClass
31
31
  } else {
package/src/devise.cjs CHANGED
@@ -50,7 +50,7 @@ module.exports = class ApiMakerDevise {
50
50
 
51
51
  const postData = {username, password, args}
52
52
  const response = await Services.current().sendRequest("Devise::SignIn", postData)
53
- const modelClass = digg(require("@kaspernj/api-maker/src/models.js.erb"), inflection.camelize(args.scope))
53
+ const modelClass = digg(require("@kaspernj/api-maker/src/models"), inflection.camelize(args.scope))
54
54
  const modelInstance = new modelClass(digg(response, "model_data"))
55
55
 
56
56
  await CanCan.current().resetAbilities()
@@ -109,7 +109,7 @@ module.exports = class ApiMakerDevise {
109
109
  return null
110
110
 
111
111
  const parsedScopeData = Deserializer.parse(scopeData)
112
- const modelClass = digg(require("@kaspernj/api-maker/src/models.js.erb"), inflection.camelize(scope))
112
+ const modelClass = digg(require("@kaspernj/api-maker/src/models"), inflection.camelize(scope))
113
113
  const modelInstance = new modelClass({data: parsedScopeData})
114
114
 
115
115
  return modelInstance
@@ -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,319 @@
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
+ className,
142
+ foreignKey,
143
+ ModelClass,
144
+ modelMethodName,
145
+ modelRecipesLoader,
146
+ optionsAs,
147
+ optionsThrough,
148
+ relationshipName,
149
+ resourceName
150
+ })
151
+ this.defineHasManyLoadMethod({foreignKey, loadMethodName, ModelClass, modelClassData, modelRecipesLoader, relationshipName, resourceName})
152
+ } else if (type == "has_one") {
153
+ this.defineHasOneGetMethd({ModelClass, modelMethodName, relationshipName})
154
+ this.defineHasOneLoadMethod({
155
+ activeRecordPrimaryKey,
156
+ foreignKey,
157
+ loadMethodName,
158
+ ModelClass,
159
+ modelClassData,
160
+ modelRecipesLoader,
161
+ optionsThrough,
162
+ relationshipName,
163
+ resourceName
164
+ })
165
+ } else {
166
+ throw new Error(`Unknown relationship type: ${type}`)
167
+ }
168
+ }
169
+ }
170
+
171
+ defineBelongsToGetMethod({ModelClass, modelMethodName, relationshipName}) {
172
+ ModelClass.prototype[modelMethodName] = function () {
173
+ return this._readBelongsToReflection({reflectionName: relationshipName})
174
+ }
175
+ }
176
+
177
+ defineBelongsToLoadMethod({foreignKey, klassPrimaryKey, ModelClass, modelRecipesLoader, loadMethodName, optionsPrimaryKey, relationshipName, resourceName}) {
178
+ ModelClass.prototype[loadMethodName] = function () {
179
+ const foreignKeyMethodName = inflection.camelize(foreignKey, true)
180
+
181
+ if (!(foreignKeyMethodName in this)) throw new Error(`Foreign key method wasn't defined: ${foreignKeyMethodName}`)
182
+
183
+ const id = this[foreignKeyMethodName]()
184
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
185
+ const ransack = {}
186
+ const ransackIdSearchKey = `${optionsPrimaryKey || klassPrimaryKey}_eq`
187
+
188
+ ransack[ransackIdSearchKey] = id
189
+
190
+ return this._loadBelongsToReflection(
191
+ {reflectionName: relationshipName, model: this, modelClass},
192
+ {ransack}
193
+ )
194
+ }
195
+ }
196
+
197
+ defineHasManyGetMethod({className, foreignKey, ModelClass, modelMethodName, modelRecipesLoader, optionsAs, optionsThrough, relationshipName, resourceName}) {
198
+ ModelClass.prototype[modelMethodName] = function () {
199
+ const id = this.primaryKey()
200
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
201
+ const ransack = {}
202
+
203
+ ransack[`${foreignKey}_eq`] = id
204
+
205
+ const hasManyParameters = {
206
+ reflectionName: relationshipName,
207
+ model: this,
208
+ modelName: className,
209
+ modelClass
210
+ }
211
+
212
+ let queryParameters
213
+
214
+ if (optionsThrough) {
215
+ queryParameters = {
216
+ params: {
217
+ through: {
218
+ model: className,
219
+ id: this.primaryKey(),
220
+ reflection: relationshipName
221
+ }
222
+ }
223
+ }
224
+ } else {
225
+ const ransack = {}
226
+
227
+ ransack[`${foreignKey}_eq`] = this.primaryKey()
228
+
229
+ if (optionsAs) {
230
+ ransack[`${optionsAs}_type_eq`] = activeRecordName
231
+ }
232
+
233
+ queryParameters = {ransack}
234
+ }
235
+
236
+ return new Collection(hasManyParameters, queryParameters)
237
+ }
238
+ }
239
+
240
+ defineHasManyLoadMethod({foreignKey, loadMethodName, ModelClass, modelClassData, modelRecipesLoader, optionsThrough, relationshipName, resourceName}) {
241
+ ModelClass.prototype[loadMethodName] = function () {
242
+ const id = this.primaryKey()
243
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
244
+
245
+ if (optionsThrough) {
246
+ const modelClassName = digg(modelClassData, "className")
247
+
248
+ return this._loadHasManyReflection(
249
+ {
250
+ reflectionName: relationshipName,
251
+ model: this,
252
+ modelClass
253
+ },
254
+ {
255
+ params: {
256
+ through: {
257
+ model: modelClassName,
258
+ id,
259
+ reflection: relationshipName
260
+ }
261
+ }
262
+ }
263
+ )
264
+ } else {
265
+ const ransack = {}
266
+
267
+ ransack[`${foreignKey}_eq`] = id
268
+
269
+ return this._loadHasManyReflection(
270
+ {
271
+ reflectionName: relationshipName,
272
+ model: this,
273
+ modelClass
274
+ },
275
+ {ransack}
276
+ )
277
+ }
278
+ }
279
+ }
280
+
281
+ defineHasOneGetMethd({ModelClass, modelMethodName, relationshipName}) {
282
+ ModelClass.prototype[modelMethodName] = function () {
283
+ return this._readHasOneReflection({reflectionName: relationshipName})
284
+ }
285
+ }
286
+
287
+ defineHasOneLoadMethod({activeRecordPrimaryKey, foreignKey, loadMethodName, ModelClass, modelClassData, modelRecipesLoader, optionsThrough, relationshipName, resourceName}) {
288
+ ModelClass.prototype[loadMethodName] = function () {
289
+ const primaryKeyMethodName = inflection.camelize(activeRecordPrimaryKey, true)
290
+
291
+ if (!(primaryKeyMethodName in this)) throw new Error(`Primary key method wasn't defined: ${primaryKeyMethodName}`)
292
+
293
+ const id = this[primaryKeyMethodName]()
294
+ const modelClass = modelRecipesLoader.getModelClass(resourceName)
295
+
296
+ if (optionsThrough) {
297
+ const modelClassName = digg(modelClassData, "className")
298
+
299
+ return this._loadHasOneReflection(
300
+ {reflectionName: relationshipName, model: this, modelClass},
301
+ {params: {through: {model: modelClassName, id, reflection: relationshipName}}}
302
+ )
303
+ } else {
304
+ const ransack = {}
305
+
306
+ ransack[`${foreignKey}_eq`] = id
307
+
308
+ return this._loadHasOneReflection(
309
+ {
310
+ reflectionName: relationshipName,
311
+ model: this,
312
+ modelClass
313
+ },
314
+ {ransack}
315
+ )
316
+ }
317
+ }
318
+ }
319
+ }
@@ -0,0 +1 @@
1
+ module.exports = <%= ApiMaker::ModelClassesJavaScriptGeneratorService.execute!.to_json %>
@@ -23,7 +23,7 @@ module.exports = class ModelsResponseReader {
23
23
 
24
24
  for(const modelType in this.response.data) {
25
25
  const modelClassName = inflection.classify(modelType)
26
- const modelClass = digg(require("@kaspernj/api-maker/src/models.js.erb"), modelClassName)
26
+ const modelClass = digg(require("@kaspernj/api-maker/src/models"), modelClassName)
27
27
  const collectionName = modelClass.modelClassData().collectionName
28
28
 
29
29
  for(const modelId of this.response.data[modelType]) {
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/preloaded.cjs CHANGED
@@ -12,7 +12,7 @@ module.exports = class ApiMakerPreloaded {
12
12
 
13
13
  for (const preloadedType in this.response.preloaded) {
14
14
  const modelClassName = inflection.classify(preloadedType)
15
- const modelClass = digg(require("@kaspernj/api-maker/src/models.js.erb"), modelClassName)
15
+ const modelClass = digg(require("@kaspernj/api-maker/src/models"), modelClassName)
16
16
 
17
17
  for(const preloadedId in this.response.preloaded[preloadedType]) {
18
18
  const preloadedData = this.response.preloaded[preloadedType][preloadedId]
@@ -65,7 +65,7 @@ class ValidationError {
65
65
  getModelClass() {
66
66
  const modelName = inflection.classify(digg(this, "modelName"))
67
67
 
68
- return digg(require("@kaspernj/api-maker/src/models.js.erb"), modelName)
68
+ return digg(require("@kaspernj/api-maker/src/models"), modelName)
69
69
  }
70
70
 
71
71
  setHandled() {
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! %>