functional-models 1.0.18 → 1.0.23

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
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "functional-models",
3
- "version": "1.0.18",
3
+ "version": "1.0.23",
4
4
  "description": "A library for creating JavaScript function based models.",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "nyc --all mocha --recursive ./test/**/*.test.js",
7
+ "test": "nyc --all mocha --recursive './test/**/*.test.js'",
8
8
  "feature-tests": "./node_modules/@cucumber/cucumber/bin/cucumber-js",
9
9
  "coverage": "nyc --all --reporter=lcov npm test"
10
10
  },
@@ -49,7 +49,6 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "get-random-values": "^1.2.2",
52
- "lazy-property": "^1.0.0",
53
52
  "lodash": "^4.17.21"
54
53
  }
55
54
  }
package/src/models.js CHANGED
@@ -2,14 +2,16 @@ const merge = require('lodash/merge')
2
2
  const { toObj } = require('./serialization')
3
3
  const { createPropertyTitle } = require('./utils')
4
4
  const { createModelValidator } = require('./validation')
5
+ const { UniqueId } = require('./properties')
5
6
 
6
7
  const MODEL_DEF_KEYS = ['meta', 'functions']
7
- const PROTECTED_KEYS = ['model']
8
8
 
9
9
  const Model = (
10
10
  modelName,
11
11
  keyToProperty,
12
12
  {
13
+ primaryKey = 'id',
14
+ getPrimaryKeyProperty=() => UniqueId({required: true}),
13
15
  instanceCreatedCallback = null,
14
16
  modelFunctions = {},
15
17
  instanceFunctions = {},
@@ -25,11 +27,11 @@ const Model = (
25
27
  */
26
28
  // eslint-disable-next-line functional/no-let
27
29
  let model = null
28
- PROTECTED_KEYS.forEach(key => {
29
- if (key in keyToProperty) {
30
- throw new Error(`Cannot use ${key}. This is a protected value.`)
31
- }
32
- })
30
+ keyToProperty = {
31
+ // this key exists over keyToProperty, so it can be overrided if desired.
32
+ [primaryKey]: getPrimaryKeyProperty(),
33
+ ...keyToProperty,
34
+ }
33
35
  const instanceProperties = Object.entries(keyToProperty).filter(
34
36
  ([key, _]) => MODEL_DEF_KEYS.includes(key) === false
35
37
  )
@@ -78,6 +80,7 @@ const Model = (
78
80
  },
79
81
  functions: {
80
82
  toObj: toObj(loadedInternals),
83
+ getPrimaryKey: loadedInternals[createPropertyTitle(primaryKey)],
81
84
  validate: {
82
85
  model: () =>
83
86
  createModelValidator(loadedInternals, modelValidators)(instance),
@@ -125,6 +128,7 @@ const Model = (
125
128
  create,
126
129
  getName: () => modelName,
127
130
  getProperties: () => properties,
131
+ getPrimaryKeyName: () => primaryKey,
128
132
  })
129
133
  return model
130
134
  }
package/src/properties.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const identity = require('lodash/identity')
2
+ const get = require('lodash/get')
2
3
  const isFunction = require('lodash/isFunction')
3
4
  const merge = require('lodash/merge')
4
5
  const {
@@ -57,8 +58,8 @@ const Property = (config = {}, additionalMetadata = {}) => {
57
58
  },
58
59
  getValidator: valueGetter => {
59
60
  const validator = createPropertyValidator(config)
60
- const _propertyValidatorWrapper = async () => {
61
- return validator(await valueGetter())
61
+ const _propertyValidatorWrapper = async (instance, instanceData) => {
62
+ return validator(await valueGetter(), instance, instanceData)
62
63
  }
63
64
  return _propertyValidatorWrapper
64
65
  },
@@ -106,17 +107,26 @@ const ReferenceProperty = (model, config = {}) => {
106
107
  if (!instanceValues) {
107
108
  return null
108
109
  }
109
- return instanceValues && instanceValues.id
110
- ? instanceValues.id
111
- : instanceValues.getId
112
- ? instanceValues.getId()
113
- : instanceValues
110
+ const theModel = _getModel()
111
+ const primaryKey = theModel.getPrimaryKeyName()
112
+ if (instanceValues[primaryKey]) {
113
+ return instanceValues[primaryKey]
114
+ }
115
+ const primaryKeyFunc = get(instanceValues, 'functions.getPrimaryKey')
116
+ if (primaryKeyFunc) {
117
+ return primaryKeyFunc()
118
+ }
119
+ return instanceValues
114
120
  }
121
+
115
122
  const valueIsModelInstance =
116
123
  Boolean(instanceValues) && Boolean(instanceValues.functions)
117
124
 
118
125
  const _getInstanceReturn = objToUse => {
119
- const instance = valueIsModelInstance
126
+ // We need to determine if the object we just go is an actual model instance to determine if we need to make one.
127
+ const objIsModelInstance =
128
+ Boolean(objToUse) && Boolean(objToUse.functions)
129
+ const instance = objIsModelInstance
120
130
  ? objToUse
121
131
  : _getModel().create(objToUse)
122
132
  return merge({}, instance, {
@@ -131,7 +141,8 @@ const ReferenceProperty = (model, config = {}) => {
131
141
  }
132
142
  if (config.fetcher) {
133
143
  const id = await _getId()
134
- const obj = await config.fetcher(_getModel(), id)
144
+ const model = _getModel()
145
+ const obj = await config.fetcher(model, id)
135
146
  return _getInstanceReturn(obj)
136
147
  }
137
148
  return _getId(instanceValues)
package/src/validation.js CHANGED
@@ -208,11 +208,11 @@ const createPropertyValidator = config => {
208
208
  : validators.includes(isRequired)
209
209
  const validator =
210
210
  validators.length > 0 ? aggregateValidator(validators) : emptyValidator
211
- const _propertyValidator = async value => {
211
+ const _propertyValidator = async (value, instance, instanceData) => {
212
212
  if (!value && !isRequiredValue) {
213
213
  return []
214
214
  }
215
- const errors = await validator(value)
215
+ const errors = await validator(value, instance, instanceData)
216
216
  return [...new Set(flatMap(errors))]
217
217
  }
218
218
  return _propertyValidator
@@ -223,20 +223,22 @@ const createModelValidator = (properties, modelValidators = []) => {
223
223
  const keysAndFunctions = Object.entries(
224
224
  get(properties, 'functions.validate', {})
225
225
  )
226
+ const instanceData = await (modelValidators.length > 0
227
+ ? instance.functions.toObj()
228
+ : {})
226
229
  const data = await Promise.all(
227
230
  keysAndFunctions.map(async ([key, validator]) => {
228
231
  if (key === 'model') {
229
232
  return [key, []]
230
233
  }
231
- return [key, await validator()]
234
+ return [key, await validator(instance, instanceData)]
232
235
  })
233
236
  )
234
- const instanceData = await (modelValidators.length > 0
235
- ? instance.functions.toObj()
236
- : {})
237
- const modelValidationErrors = (await Promise.all(
238
- modelValidators.map(validator => validator(instance, instanceData))
239
- )).filter(x=>x)
237
+ const modelValidationErrors = (
238
+ await Promise.all(
239
+ modelValidators.map(validator => validator(instance, instanceData))
240
+ )
241
+ ).filter(x => x)
240
242
  const propertyErrors = data
241
243
  .filter(([_, errors]) => Boolean(errors) && errors.length > 0)
242
244
  .reduce((acc, [key, errors]) => {
@@ -60,7 +60,57 @@ describe('/src/models.js', () => {
60
60
  )
61
61
  assert.isFunction(model.myString)
62
62
  })
63
+ describe('#getPrimaryKeyName()', () => {
64
+ it('should return "primaryKey" when this value is passed in as the primaryKey', () => {
65
+ const expected = 'primaryKey'
66
+ const model = Model(
67
+ 'ModelName',
68
+ {},
69
+ {
70
+ primaryKey: expected,
71
+ modelFunctions: {
72
+ myString: model => () => {
73
+ return 'To String'
74
+ },
75
+ },
76
+ }
77
+ )
78
+ const actual = model.getPrimaryKeyName()
79
+ assert.equal(actual, expected)
80
+ })
81
+ })
63
82
  describe('#create()', () => {
83
+ it('should have an "getId" field when no primaryKey is passed', () => {
84
+ const model = Model(
85
+ 'ModelName',
86
+ {},
87
+ {
88
+ instanceFunctions: {
89
+ toString: instance => () => {
90
+ return 'An instance'
91
+ },
92
+ },
93
+ }
94
+ )
95
+ const instance = model.create({})
96
+ assert.isFunction(instance.getId)
97
+ })
98
+ it('should have an "getMyPrimaryKeyId" field when "myPrimaryKeyId" is passed as the "primaryKey" is passed', () => {
99
+ const model = Model(
100
+ 'ModelName',
101
+ {},
102
+ {
103
+ primaryKey: 'myPrimaryKeyId',
104
+ instanceFunctions: {
105
+ toString: instance => () => {
106
+ return 'An instance'
107
+ },
108
+ },
109
+ }
110
+ )
111
+ const instance = model.create({})
112
+ assert.isFunction(instance.getMyPrimaryKeyId)
113
+ })
64
114
  it('should find instance.functions.toString when in instanceFunctions', () => {
65
115
  const model = Model(
66
116
  'ModelName',
@@ -234,5 +284,42 @@ describe('/src/models.js', () => {
234
284
  Model('name', { model: 'weeee' }).create()
235
285
  })
236
286
  })
287
+ describe('#functions.getPrimaryKey()', () => {
288
+ it('should return the id field when no primaryKey is passed', async () => {
289
+ const model = Model(
290
+ 'ModelName',
291
+ {},
292
+ {
293
+ instanceFunctions: {
294
+ toString: instance => () => {
295
+ return 'An instance'
296
+ },
297
+ },
298
+ }
299
+ )
300
+ const expected = 'my-primary-key'
301
+ const instance = model.create({id: expected})
302
+ const actual = await instance.functions.getPrimaryKey()
303
+ assert.equal(actual, expected)
304
+ })
305
+ it('should return the primaryKey field when "primaryKey" is passed as primaryKey', async () => {
306
+ const model = Model(
307
+ 'ModelName',
308
+ {},
309
+ {
310
+ primaryKey: 'primaryKey',
311
+ instanceFunctions: {
312
+ toString: instance => () => {
313
+ return 'An instance'
314
+ },
315
+ },
316
+ }
317
+ )
318
+ const expected = 'my-primary-key'
319
+ const instance = model.create({primaryKey: expected})
320
+ const actual = await instance.functions.getPrimaryKey()
321
+ assert.equal(actual, expected)
322
+ })
323
+ })
237
324
  })
238
325
  })
@@ -408,7 +408,10 @@ describe('/src/validation.js', () => {
408
408
  },
409
409
  },
410
410
  }
411
- const validator = createModelValidator(properties, [modelValidator1, modelValidator2])
411
+ const validator = createModelValidator(properties, [
412
+ modelValidator1,
413
+ modelValidator2,
414
+ ])
412
415
  const instance = testModel3.create({
413
416
  id: 'test-id',
414
417
  name: 'my-name',