@kaspernj/api-maker 1.0.121 → 1.0.125

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.125",
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",
@@ -152,6 +152,10 @@ module.exports = class BaseModel {
152
152
  }
153
153
  }
154
154
 
155
+ static all() {
156
+ return this.ransack()
157
+ }
158
+
155
159
  async create(attributes, options) {
156
160
  if (attributes) this.assignAttributes(attributes)
157
161
  const paramKey = this.modelClassData().paramKey
@@ -659,11 +663,9 @@ module.exports = class BaseModel {
659
663
  return this.modelData[attributeName]
660
664
  } else if (this.isNewRecord()) {
661
665
  // 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
- }
666
+ const attributes = digg(this.modelClassData(), "attributes")
667
+
668
+ if (attributeName in attributes) return null
667
669
  }
668
670
 
669
671
  throw new AttributeNotLoadedError(`No such attribute: ${digg(this.modelClassData(), "name")}#${attributeName}`)
@@ -698,26 +700,31 @@ module.exports = class BaseModel {
698
700
  }
699
701
  }
700
702
 
701
- _readBelongsToReflection(args) {
702
- if (!(args.reflectionName in this.relationshipsCache)) {
703
+ _readBelongsToReflection({reflectionName}) {
704
+ if (!(reflectionName in this.relationshipsCache)) {
703
705
  if (this.isNewRecord())
704
706
  return null
705
707
 
706
- throw new NotLoadedError(`${digg(this.modelClassData(), "name")}#${args.reflectionName} hasn't been loaded yet`)
708
+ const loadedRelationships = Object.keys(this.relationshipsCache)
709
+ const modelClassName = digg(this.modelClassData(), "name")
710
+
711
+ throw new NotLoadedError(`${modelClassName}#${reflectionName} hasn't been loaded yet. Only these were loaded: ${loadedRelationships.join(", ")}`)
707
712
  }
708
713
 
709
- return this.relationshipsCache[args.reflectionName]
714
+ return this.relationshipsCache[reflectionName]
710
715
  }
711
716
 
712
717
  async _loadHasManyReflection(args, queryArgs = {}) {
713
718
  if (args.reflectionName in this.relationshipsCache) {
714
719
  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
720
  }
721
+
722
+ const collection = new Collection(args, queryArgs)
723
+ const models = await collection.toArray()
724
+
725
+ this.relationshipsCache[args.reflectionName] = models
726
+
727
+ return models
721
728
  }
722
729
 
723
730
  async _loadHasOneReflection(args, queryArgs = {}) {
@@ -726,20 +733,25 @@ module.exports = class BaseModel {
726
733
  } else {
727
734
  const collection = new Collection(args, queryArgs)
728
735
  const model = await collection.first()
736
+
729
737
  this.relationshipsCache[args.reflectionName] = model
738
+
730
739
  return model
731
740
  }
732
741
  }
733
742
 
734
- _readHasOneReflection(args) {
735
- if (!(args.reflectionName in this.relationshipsCache)) {
743
+ _readHasOneReflection({reflectionName}) {
744
+ if (!(reflectionName in this.relationshipsCache)) {
736
745
  if (this.isNewRecord())
737
746
  return null
738
747
 
739
- throw new NotLoadedError(`${digg(this.modelClassData(), "name")}#${args.reflectionName} hasn't been loaded yet`)
748
+ const loadedRelationships = Object.keys(this.relationshipsCache)
749
+ const modelClassName = digg(this.modelClassData(), "name")
750
+
751
+ throw new NotLoadedError(`${modelClassName}#${reflectionName} hasn't been loaded yet. Only these were loaded: ${loadedRelationships.join(", ")}`)
740
752
  }
741
753
 
742
- return this.relationshipsCache[args.reflectionName]
754
+ return this.relationshipsCache[reflectionName]
743
755
  }
744
756
 
745
757
  _readModelDataFromArgs(args) {
@@ -754,9 +766,11 @@ module.exports = class BaseModel {
754
766
  return
755
767
  }
756
768
 
769
+ const relationships = digg(this.modelClassData(), "relationships")
770
+
757
771
  for (const relationshipName in this.preloadedRelationships) {
758
772
  const relationshipData = this.preloadedRelationships[relationshipName]
759
- const relationshipClassData = this.modelClassData().relationships.find((relationship) => digg(relationship, "name") == relationshipName)
773
+ const relationshipClassData = relationships.find((relationship) => digg(relationship, "name") == relationshipName)
760
774
 
761
775
  if (!relationshipClassData) {
762
776
  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,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 %>
@@ -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! %>