functional-models 1.0.25 → 1.1.0
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/.eslintignore +1 -0
- package/.eslintrc +9 -15
- package/cucumber.js +10 -0
- package/features/arrayFields.feature +7 -7
- package/features/basic-ts.feature +13 -0
- package/features/functions.feature +2 -3
- package/package.json +34 -10
- package/src/constants.ts +15 -0
- package/src/errors.ts +18 -0
- package/src/index.ts +11 -0
- package/src/interfaces.ts +323 -0
- package/src/lazy.ts +24 -0
- package/src/methods.ts +30 -0
- package/src/models.ts +183 -0
- package/src/properties.ts +375 -0
- package/src/serialization.ts +39 -0
- package/src/utils.ts +42 -0
- package/src/validation.ts +390 -0
- package/{features/stepDefinitions/steps.js → stepDefinitions/oldSteps.ts} +76 -53
- package/stepDefinitions/tssteps.ts +107 -0
- package/test/src/errors.test.ts +31 -0
- package/test/src/{lazy.test.js → lazy.test.ts} +4 -4
- package/test/src/methods.test.ts +45 -0
- package/test/src/models.test.ts +417 -0
- package/test/src/{properties.test.js → properties.test.ts} +257 -64
- package/test/src/serialization.test.ts +80 -0
- package/test/src/{utils.test.js → utils.test.ts} +29 -7
- package/test/src/{validation.test.js → validation.test.ts} +278 -210
- package/tsconfig.json +100 -0
- package/src/functions.js +0 -7
- package/src/index.js +0 -7
- package/src/lazy.js +0 -19
- package/src/models.js +0 -150
- package/src/properties.js +0 -261
- package/src/serialization.js +0 -47
- package/src/utils.js +0 -42
- package/src/validation.js +0 -274
- package/test/base/index.test.js +0 -5
- package/test/src/functions.test.js +0 -45
- package/test/src/index.test.js +0 -5
- package/test/src/models.test.js +0 -380
- package/test/src/serialization.test.js +0 -127
package/src/validation.js
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
const isEmpty = require('lodash/isEmpty')
|
|
2
|
-
const merge = require('lodash/merge')
|
|
3
|
-
const isFunction = require('lodash/isFunction')
|
|
4
|
-
const flatMap = require('lodash/flatMap')
|
|
5
|
-
const get = require('lodash/get')
|
|
6
|
-
|
|
7
|
-
const TYPE_PRIMATIVES = {
|
|
8
|
-
boolean: 'boolean',
|
|
9
|
-
string: 'string',
|
|
10
|
-
object: 'object',
|
|
11
|
-
number: 'number',
|
|
12
|
-
integer: 'integer',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const _trueOrError = (method, error) => value => {
|
|
16
|
-
if (method(value) === false) {
|
|
17
|
-
return error
|
|
18
|
-
}
|
|
19
|
-
return undefined
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const _typeOrError = (type, errorMessage) => value => {
|
|
23
|
-
if (typeof value !== type) {
|
|
24
|
-
return errorMessage
|
|
25
|
-
}
|
|
26
|
-
return undefined
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const isType = type => value => {
|
|
30
|
-
return _typeOrError(type, `Must be a ${type}`)(value)
|
|
31
|
-
}
|
|
32
|
-
const isNumber = isType('number')
|
|
33
|
-
const isInteger = _trueOrError(Number.isInteger, 'Must be an integer')
|
|
34
|
-
|
|
35
|
-
const isBoolean = isType('boolean')
|
|
36
|
-
const isString = isType('string')
|
|
37
|
-
const isArray = _trueOrError(v => Array.isArray(v), 'Value is not an array')
|
|
38
|
-
|
|
39
|
-
const PRIMATIVE_TO_SPECIAL_TYPE_VALIDATOR = {
|
|
40
|
-
[TYPE_PRIMATIVES.boolean]: isBoolean,
|
|
41
|
-
[TYPE_PRIMATIVES.string]: isString,
|
|
42
|
-
[TYPE_PRIMATIVES.integer]: isInteger,
|
|
43
|
-
[TYPE_PRIMATIVES.number]: isNumber,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const arrayType = type => value => {
|
|
47
|
-
const arrayError = isArray(value)
|
|
48
|
-
if (arrayError) {
|
|
49
|
-
return arrayError
|
|
50
|
-
}
|
|
51
|
-
const validator = PRIMATIVE_TO_SPECIAL_TYPE_VALIDATOR[type] || isType(type)
|
|
52
|
-
return value.reduce((acc, v) => {
|
|
53
|
-
if (acc) {
|
|
54
|
-
return acc
|
|
55
|
-
}
|
|
56
|
-
return validator(v)
|
|
57
|
-
}, undefined)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const meetsRegex =
|
|
61
|
-
(regex, flags, errorMessage = 'Format was invalid') =>
|
|
62
|
-
value => {
|
|
63
|
-
const reg = new RegExp(regex, flags)
|
|
64
|
-
return _trueOrError(v => reg.test(v), errorMessage)(value)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const choices = choiceArray => value => {
|
|
68
|
-
if (Array.isArray(value)) {
|
|
69
|
-
const bad = value.find(v => !choiceArray.includes(v))
|
|
70
|
-
if (bad) {
|
|
71
|
-
return `${bad} is not a valid choice`
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
if (choiceArray.includes(value) === false) {
|
|
75
|
-
return `${value} is not a valid choice`
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return undefined
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const isDate = value => {
|
|
82
|
-
if (!value) {
|
|
83
|
-
return 'Date value is empty'
|
|
84
|
-
}
|
|
85
|
-
if (!value.toISOString) {
|
|
86
|
-
return 'Value is not a date'
|
|
87
|
-
}
|
|
88
|
-
return undefined
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const isRequired = value => {
|
|
92
|
-
if (value === true || value === false) {
|
|
93
|
-
return undefined
|
|
94
|
-
}
|
|
95
|
-
if (isNumber(value) === undefined) {
|
|
96
|
-
return undefined
|
|
97
|
-
}
|
|
98
|
-
const empty = isEmpty(value)
|
|
99
|
-
if (empty) {
|
|
100
|
-
if (isDate(value)) {
|
|
101
|
-
return 'A value is required'
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return undefined
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const maxNumber = max => value => {
|
|
108
|
-
const numberError = isNumber(value)
|
|
109
|
-
if (numberError) {
|
|
110
|
-
return numberError
|
|
111
|
-
}
|
|
112
|
-
if (value > max) {
|
|
113
|
-
return `The maximum is ${max}`
|
|
114
|
-
}
|
|
115
|
-
return undefined
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const minNumber = min => value => {
|
|
119
|
-
const numberError = isNumber(value)
|
|
120
|
-
if (numberError) {
|
|
121
|
-
return numberError
|
|
122
|
-
}
|
|
123
|
-
if (value < min) {
|
|
124
|
-
return `The minimum is ${min}`
|
|
125
|
-
}
|
|
126
|
-
return undefined
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const maxTextLength = max => value => {
|
|
130
|
-
const stringError = isString(value)
|
|
131
|
-
if (stringError) {
|
|
132
|
-
return stringError
|
|
133
|
-
}
|
|
134
|
-
if (value.length > max) {
|
|
135
|
-
return `The maximum length is ${max}`
|
|
136
|
-
}
|
|
137
|
-
return undefined
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const minTextLength = min => value => {
|
|
141
|
-
const stringError = isString(value)
|
|
142
|
-
if (stringError) {
|
|
143
|
-
return stringError
|
|
144
|
-
}
|
|
145
|
-
if (value.length < min) {
|
|
146
|
-
return `The minimum length is ${min}`
|
|
147
|
-
}
|
|
148
|
-
return undefined
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const referenceTypeMatch = referencedModel => {
|
|
152
|
-
return value => {
|
|
153
|
-
// This needs to stay here, as it delays the creation long enough for
|
|
154
|
-
// self referencing types.
|
|
155
|
-
const model = isFunction(referencedModel)
|
|
156
|
-
? referencedModel()
|
|
157
|
-
: referencedModel
|
|
158
|
-
// Assumption: By the time this is received, value === a model instance.
|
|
159
|
-
const eModel = model.getName()
|
|
160
|
-
const aModel = value.meta.getModel().getName()
|
|
161
|
-
if (eModel !== aModel) {
|
|
162
|
-
return `Model should be ${eModel} instead, recieved ${aModel}`
|
|
163
|
-
}
|
|
164
|
-
return undefined
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const aggregateValidator = methodOrMethods => {
|
|
169
|
-
const toDo = Array.isArray(methodOrMethods)
|
|
170
|
-
? methodOrMethods
|
|
171
|
-
: [methodOrMethods]
|
|
172
|
-
|
|
173
|
-
const _aggregativeValidator = async (...args) => {
|
|
174
|
-
const values = await Promise.all(
|
|
175
|
-
toDo.map(method => {
|
|
176
|
-
return method(...args)
|
|
177
|
-
})
|
|
178
|
-
)
|
|
179
|
-
return values.filter(x => x)
|
|
180
|
-
}
|
|
181
|
-
return _aggregativeValidator
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const emptyValidator = () => []
|
|
185
|
-
|
|
186
|
-
const _boolChoice = method => value => {
|
|
187
|
-
return value ? method : undefined
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const CONFIG_TO_VALIDATE_METHOD = {
|
|
191
|
-
required: _boolChoice(isRequired),
|
|
192
|
-
isInteger: _boolChoice(isInteger),
|
|
193
|
-
isNumber: _boolChoice(isNumber),
|
|
194
|
-
isString: _boolChoice(isString),
|
|
195
|
-
isArray: _boolChoice(isArray),
|
|
196
|
-
choices,
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const createPropertyValidator = config => {
|
|
200
|
-
const validators = [
|
|
201
|
-
...Object.entries(config).map(([key, value]) => {
|
|
202
|
-
return (CONFIG_TO_VALIDATE_METHOD[key] || (() => undefined))(value)
|
|
203
|
-
}),
|
|
204
|
-
...(config.validators ? config.validators : []),
|
|
205
|
-
].filter(x => x)
|
|
206
|
-
const isRequiredValue = config.required
|
|
207
|
-
? true
|
|
208
|
-
: validators.includes(isRequired)
|
|
209
|
-
const validator =
|
|
210
|
-
validators.length > 0 ? aggregateValidator(validators) : emptyValidator
|
|
211
|
-
const _propertyValidator = async (value, instance, instanceData) => {
|
|
212
|
-
if (!value && !isRequiredValue) {
|
|
213
|
-
return []
|
|
214
|
-
}
|
|
215
|
-
const errors = await validator(value, instance, instanceData)
|
|
216
|
-
return [...new Set(flatMap(errors))]
|
|
217
|
-
}
|
|
218
|
-
return _propertyValidator
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const createModelValidator = (properties, modelValidators = []) => {
|
|
222
|
-
const _modelValidator = async instance => {
|
|
223
|
-
if (!instance) {
|
|
224
|
-
throw new Error(`Instance cannot be empty`)
|
|
225
|
-
}
|
|
226
|
-
const keysAndFunctions = Object.entries(
|
|
227
|
-
get(properties, 'functions.validators', {})
|
|
228
|
-
)
|
|
229
|
-
const instanceData = await instance.functions.toObj()
|
|
230
|
-
const propertyValidationErrors = await Promise.all(
|
|
231
|
-
keysAndFunctions.map(async ([key, validator]) => {
|
|
232
|
-
return [key, await validator(instance, instanceData)]
|
|
233
|
-
})
|
|
234
|
-
)
|
|
235
|
-
const modelValidationErrors = (
|
|
236
|
-
await Promise.all(
|
|
237
|
-
modelValidators.map(validator => validator(instance, instanceData))
|
|
238
|
-
)
|
|
239
|
-
).filter(x => x)
|
|
240
|
-
const propertyErrors = propertyValidationErrors
|
|
241
|
-
.filter(([_, errors]) => Boolean(errors) && errors.length > 0)
|
|
242
|
-
.reduce((acc, [key, errors]) => {
|
|
243
|
-
return { ...acc, [key]: errors }
|
|
244
|
-
}, {})
|
|
245
|
-
return modelValidationErrors.length > 0
|
|
246
|
-
? merge(propertyErrors, { overall: modelValidationErrors })
|
|
247
|
-
: propertyErrors
|
|
248
|
-
}
|
|
249
|
-
return _modelValidator
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
module.exports = {
|
|
253
|
-
isNumber,
|
|
254
|
-
isBoolean,
|
|
255
|
-
isString,
|
|
256
|
-
isInteger,
|
|
257
|
-
isType,
|
|
258
|
-
isDate,
|
|
259
|
-
isArray,
|
|
260
|
-
isRequired,
|
|
261
|
-
maxNumber,
|
|
262
|
-
minNumber,
|
|
263
|
-
choices,
|
|
264
|
-
maxTextLength,
|
|
265
|
-
minTextLength,
|
|
266
|
-
meetsRegex,
|
|
267
|
-
aggregateValidator,
|
|
268
|
-
emptyValidator,
|
|
269
|
-
createPropertyValidator,
|
|
270
|
-
createModelValidator,
|
|
271
|
-
arrayType,
|
|
272
|
-
referenceTypeMatch,
|
|
273
|
-
TYPE_PRIMATIVES,
|
|
274
|
-
}
|
package/test/base/index.test.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
const assert = require('chai').assert
|
|
2
|
-
const sinon = require('sinon')
|
|
3
|
-
const { Function } = require('../../src/functions')
|
|
4
|
-
|
|
5
|
-
describe('/src/functions.js', () => {
|
|
6
|
-
describe('#Function()', () => {
|
|
7
|
-
it('should return "Hello-world" when passed in', () => {
|
|
8
|
-
const method = sinon.stub().callsFake(input => {
|
|
9
|
-
return `${input}-world`
|
|
10
|
-
})
|
|
11
|
-
const myFunction = Function(method)
|
|
12
|
-
const wrappedObj = 'Hello'
|
|
13
|
-
const wrappedFunc = myFunction(wrappedObj)
|
|
14
|
-
const actual = wrappedFunc()
|
|
15
|
-
const expected = 'Hello-world'
|
|
16
|
-
assert.equal(actual, expected)
|
|
17
|
-
})
|
|
18
|
-
it('should call the method when Function()()() called', () => {
|
|
19
|
-
const method = sinon.stub().callsFake(input => {
|
|
20
|
-
return `${input}-world`
|
|
21
|
-
})
|
|
22
|
-
const myFunction = Function(method)
|
|
23
|
-
const wrappedObj = 'Hello'
|
|
24
|
-
const wrappedFunc = myFunction(wrappedObj)
|
|
25
|
-
const result = wrappedFunc()
|
|
26
|
-
sinon.assert.calledOnce(method)
|
|
27
|
-
})
|
|
28
|
-
it('should not call the method when Function()() called', () => {
|
|
29
|
-
const method = sinon.stub().callsFake(input => {
|
|
30
|
-
return `${input}-world`
|
|
31
|
-
})
|
|
32
|
-
const myFunction = Function(method)
|
|
33
|
-
const wrappedObj = 'Hello'
|
|
34
|
-
const wrappedFunc = myFunction(wrappedObj)
|
|
35
|
-
sinon.assert.notCalled(method)
|
|
36
|
-
})
|
|
37
|
-
it('should not call the method when Function() called', () => {
|
|
38
|
-
const method = sinon.stub().callsFake(input => {
|
|
39
|
-
return `${input}-world`
|
|
40
|
-
})
|
|
41
|
-
const myFunction = Function(method)
|
|
42
|
-
sinon.assert.notCalled(method)
|
|
43
|
-
})
|
|
44
|
-
})
|
|
45
|
-
})
|
package/test/src/index.test.js
DELETED
package/test/src/models.test.js
DELETED
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
const _ = require('lodash')
|
|
2
|
-
const sinon = require('sinon')
|
|
3
|
-
const assert = require('chai').assert
|
|
4
|
-
const { Model } = require('../../src/models')
|
|
5
|
-
const { Property, TextProperty, ReferenceProperty } = require('../../src/properties')
|
|
6
|
-
|
|
7
|
-
const TEST_MODEL_1 = Model('MyModel', )
|
|
8
|
-
|
|
9
|
-
describe('/src/models.js', () => {
|
|
10
|
-
describe('#Model()', () => {
|
|
11
|
-
it('should pass a functional instance to the instanceFunctions by the time the function is called by a client', () => {
|
|
12
|
-
const model = Model(
|
|
13
|
-
'ModelName',
|
|
14
|
-
{},
|
|
15
|
-
{
|
|
16
|
-
instanceFunctions: {
|
|
17
|
-
func1: instance => () => {
|
|
18
|
-
return instance.functions.func2()
|
|
19
|
-
},
|
|
20
|
-
func2: instance => () => {
|
|
21
|
-
return 'from instance func2'
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
}
|
|
25
|
-
)
|
|
26
|
-
const instance = model.create({})
|
|
27
|
-
const actual = instance.functions.func1()
|
|
28
|
-
const expected = 'from instance func2'
|
|
29
|
-
assert.deepEqual(actual, expected)
|
|
30
|
-
})
|
|
31
|
-
it('should the clients arguments before the model is passed', () => {
|
|
32
|
-
const model = Model(
|
|
33
|
-
'ModelName',
|
|
34
|
-
{},
|
|
35
|
-
{
|
|
36
|
-
modelFunctions: {
|
|
37
|
-
func1: (input, model) => {
|
|
38
|
-
return `${input} ${model.func2()}`
|
|
39
|
-
},
|
|
40
|
-
func2: model => {
|
|
41
|
-
return 'from func2'
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
}
|
|
45
|
-
)
|
|
46
|
-
const actual = model.func1('hello')
|
|
47
|
-
const expected = 'hello from func2'
|
|
48
|
-
assert.deepEqual(actual, expected)
|
|
49
|
-
})
|
|
50
|
-
it('should pass a functional model to the modelFunction by the time the function is called by a client', () => {
|
|
51
|
-
const model = Model(
|
|
52
|
-
'ModelName',
|
|
53
|
-
{},
|
|
54
|
-
{
|
|
55
|
-
modelFunctions: {
|
|
56
|
-
func1: model => {
|
|
57
|
-
return model.func2()
|
|
58
|
-
},
|
|
59
|
-
func2: model => {
|
|
60
|
-
return 'from func2'
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
}
|
|
64
|
-
)
|
|
65
|
-
const actual = model.func1()
|
|
66
|
-
const expected = 'from func2'
|
|
67
|
-
assert.deepEqual(actual, expected)
|
|
68
|
-
})
|
|
69
|
-
it('should find model.myString when modelExtension has myString function in it', () => {
|
|
70
|
-
const model = Model(
|
|
71
|
-
'ModelName',
|
|
72
|
-
{},
|
|
73
|
-
{
|
|
74
|
-
modelFunctions: {
|
|
75
|
-
myString: model => () => {
|
|
76
|
-
return 'To String'
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
}
|
|
80
|
-
)
|
|
81
|
-
assert.isFunction(model.myString)
|
|
82
|
-
})
|
|
83
|
-
describe('#getPrimaryKeyName()', () => {
|
|
84
|
-
it('should return "primaryKey" when this value is passed in as the primaryKey', () => {
|
|
85
|
-
const expected = 'primaryKey'
|
|
86
|
-
const model = Model(
|
|
87
|
-
'ModelName',
|
|
88
|
-
{},
|
|
89
|
-
{
|
|
90
|
-
primaryKey: expected,
|
|
91
|
-
modelFunctions: {
|
|
92
|
-
myString: model => () => {
|
|
93
|
-
return 'To String'
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
|
-
const actual = model.getPrimaryKeyName()
|
|
99
|
-
assert.equal(actual, expected)
|
|
100
|
-
})
|
|
101
|
-
})
|
|
102
|
-
describe('#create()', () => {
|
|
103
|
-
it('should have a meta.references.getTheReferenceId when the property has meta.getReferencedId and the key is theReference', () => {
|
|
104
|
-
const model = Model(
|
|
105
|
-
'ModelName',
|
|
106
|
-
{
|
|
107
|
-
theReference: ReferenceProperty(TEST_MODEL_1),
|
|
108
|
-
},
|
|
109
|
-
)
|
|
110
|
-
const instance = model.create({})
|
|
111
|
-
assert.isFunction(instance.meta.references.getTheReferenceId)
|
|
112
|
-
})
|
|
113
|
-
it('should have an "getId" field when no primaryKey is passed', () => {
|
|
114
|
-
const model = Model(
|
|
115
|
-
'ModelName',
|
|
116
|
-
{},
|
|
117
|
-
{
|
|
118
|
-
instanceFunctions: {
|
|
119
|
-
toString: instance => () => {
|
|
120
|
-
return 'An instance'
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
}
|
|
124
|
-
)
|
|
125
|
-
const instance = model.create({})
|
|
126
|
-
assert.isFunction(instance.getId)
|
|
127
|
-
})
|
|
128
|
-
it('should have an "getMyPrimaryKeyId" field when "myPrimaryKeyId" is passed as the "primaryKey" is passed', () => {
|
|
129
|
-
const model = Model(
|
|
130
|
-
'ModelName',
|
|
131
|
-
{},
|
|
132
|
-
{
|
|
133
|
-
primaryKey: 'myPrimaryKeyId',
|
|
134
|
-
instanceFunctions: {
|
|
135
|
-
toString: instance => () => {
|
|
136
|
-
return 'An instance'
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
)
|
|
141
|
-
const instance = model.create({})
|
|
142
|
-
assert.isFunction(instance.getMyPrimaryKeyId)
|
|
143
|
-
})
|
|
144
|
-
it('should find instance.functions.toString when in instanceFunctions', () => {
|
|
145
|
-
const model = Model(
|
|
146
|
-
'ModelName',
|
|
147
|
-
{},
|
|
148
|
-
{
|
|
149
|
-
instanceFunctions: {
|
|
150
|
-
toString: instance => () => {
|
|
151
|
-
return 'An instance'
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
}
|
|
155
|
-
)
|
|
156
|
-
const instance = model.create({})
|
|
157
|
-
assert.isFunction(instance.functions.toString)
|
|
158
|
-
})
|
|
159
|
-
it('should call the instanceCreatedCallback function when create() is called', () => {
|
|
160
|
-
const input = {
|
|
161
|
-
myProperty: Property({ required: true }),
|
|
162
|
-
}
|
|
163
|
-
const callback = sinon.stub()
|
|
164
|
-
const model = Model('name', input, {
|
|
165
|
-
instanceCreatedCallback: callback,
|
|
166
|
-
})
|
|
167
|
-
model.create({ myProperty: 'value' })
|
|
168
|
-
sinon.assert.calledOnce(callback)
|
|
169
|
-
})
|
|
170
|
-
it('should not throw an exception if nothing is passed into function', () => {
|
|
171
|
-
const input = {
|
|
172
|
-
myProperty: Property({ required: true }),
|
|
173
|
-
}
|
|
174
|
-
const model = Model('name', input)
|
|
175
|
-
assert.doesNotThrow(() => {
|
|
176
|
-
model.create()
|
|
177
|
-
})
|
|
178
|
-
})
|
|
179
|
-
it('should return an object that contains meta.getModel().getProperties().myProperty', () => {
|
|
180
|
-
const input = {
|
|
181
|
-
myProperty: Property({ required: true }),
|
|
182
|
-
}
|
|
183
|
-
const model = Model('name', input)
|
|
184
|
-
const instance = model.create({ myProperty: 'value' })
|
|
185
|
-
const actual = instance.meta.getModel().getProperties().myProperty
|
|
186
|
-
assert.isOk(actual)
|
|
187
|
-
})
|
|
188
|
-
it('should combine the meta within the instance values', () => {
|
|
189
|
-
const input = {
|
|
190
|
-
myProperty: Property({ required: true }),
|
|
191
|
-
}
|
|
192
|
-
const model = Model('name', input)
|
|
193
|
-
const instance = model.create({
|
|
194
|
-
myProperty: 'value',
|
|
195
|
-
meta: { random: () => 'random' },
|
|
196
|
-
})
|
|
197
|
-
const actual = instance.meta.random()
|
|
198
|
-
const expected = 'random'
|
|
199
|
-
assert.equal(actual, expected)
|
|
200
|
-
})
|
|
201
|
-
it('should flow through the additional special functions within the keyValues', () => {
|
|
202
|
-
const input = {
|
|
203
|
-
myProperty: Property({ required: true }),
|
|
204
|
-
functions: {
|
|
205
|
-
custom: () => 'works',
|
|
206
|
-
},
|
|
207
|
-
}
|
|
208
|
-
const model = Model('name', input)
|
|
209
|
-
const instance = model.create({ myProperty: 'value' })
|
|
210
|
-
const actual = instance.functions.custom()
|
|
211
|
-
const expected = 'works'
|
|
212
|
-
assert.equal(actual, expected)
|
|
213
|
-
})
|
|
214
|
-
it('should return an object that contains meta.getModel().getName()===test-the-name', () => {
|
|
215
|
-
const input = {
|
|
216
|
-
myProperty: Property({ required: true }),
|
|
217
|
-
}
|
|
218
|
-
const model = Model('test-the-name', input)
|
|
219
|
-
const instance = model.create({ myProperty: 'value' })
|
|
220
|
-
const actual = instance.meta.getModel().getName()
|
|
221
|
-
const expected = 'test-the-name'
|
|
222
|
-
assert.deepEqual(actual, expected)
|
|
223
|
-
})
|
|
224
|
-
it('should return an object that contains meta.getModel().getProperties().myProperty', () => {
|
|
225
|
-
const input = {
|
|
226
|
-
myProperty: Property({ required: true }),
|
|
227
|
-
}
|
|
228
|
-
const model = Model('name', input)
|
|
229
|
-
const instance = model.create({ myProperty: 'value' })
|
|
230
|
-
const actual = instance.meta.getModel().getProperties().myProperty
|
|
231
|
-
assert.isOk(actual)
|
|
232
|
-
})
|
|
233
|
-
it('should use the value passed in when Property.defaultValue and Property.value are not set', async () => {
|
|
234
|
-
const input = {
|
|
235
|
-
myProperty: Property({ required: true }),
|
|
236
|
-
}
|
|
237
|
-
const model = Model('name', input)
|
|
238
|
-
const instance = model.create({ myProperty: 'passed-in' })
|
|
239
|
-
const actual = await instance.getMyProperty()
|
|
240
|
-
const expected = 'passed-in'
|
|
241
|
-
assert.deepEqual(actual, expected)
|
|
242
|
-
})
|
|
243
|
-
it('should use the value for Property.value when even if Property.defaultValue is set and a value is passed in', async () => {
|
|
244
|
-
const input = {
|
|
245
|
-
myProperty: Property({
|
|
246
|
-
value: 'value',
|
|
247
|
-
defaultValue: 'default-value',
|
|
248
|
-
}),
|
|
249
|
-
}
|
|
250
|
-
const model = Model('name', input)
|
|
251
|
-
const instance = model.create({ myProperty: 'passed-in' })
|
|
252
|
-
const actual = await instance.getMyProperty()
|
|
253
|
-
const expected = 'value'
|
|
254
|
-
assert.deepEqual(actual, expected)
|
|
255
|
-
})
|
|
256
|
-
it('should use the value for Property.value when even if Property.defaultValue is not set and a value is passed in', async () => {
|
|
257
|
-
const input = {
|
|
258
|
-
myProperty: Property({ value: 'value' }),
|
|
259
|
-
}
|
|
260
|
-
const model = Model('name', input)
|
|
261
|
-
const instance = model.create({ myProperty: 'passed-in' })
|
|
262
|
-
const actual = await instance.getMyProperty()
|
|
263
|
-
const expected = 'value'
|
|
264
|
-
assert.deepEqual(actual, expected)
|
|
265
|
-
})
|
|
266
|
-
it('should use the value for Property.defaultValue when Property.value is not set and no value is passed in', async () => {
|
|
267
|
-
const input = {
|
|
268
|
-
myProperty: Property({ defaultValue: 'defaultValue' }),
|
|
269
|
-
}
|
|
270
|
-
const model = Model('name', input)
|
|
271
|
-
const instance = model.create({})
|
|
272
|
-
const actual = await instance.getMyProperty()
|
|
273
|
-
const expected = 'defaultValue'
|
|
274
|
-
assert.deepEqual(actual, expected)
|
|
275
|
-
})
|
|
276
|
-
it('should use the value for Property.defaultValue when Property.value is not set and null is passed as a value', async () => {
|
|
277
|
-
const input = {
|
|
278
|
-
myProperty: Property({ defaultValue: 'defaultValue' }),
|
|
279
|
-
}
|
|
280
|
-
const model = Model('name', input)
|
|
281
|
-
const instance = model.create({ myProperty: null })
|
|
282
|
-
const actual = await instance.getMyProperty()
|
|
283
|
-
const expected = 'defaultValue'
|
|
284
|
-
assert.deepEqual(actual, expected)
|
|
285
|
-
})
|
|
286
|
-
it('should return a model with getId and getType for the provided valid keyToProperty', () => {
|
|
287
|
-
const input = {
|
|
288
|
-
id: Property({ required: true }),
|
|
289
|
-
type: Property(),
|
|
290
|
-
}
|
|
291
|
-
const model = Model('name', input)
|
|
292
|
-
const actual = model.create({ id: 'my-id', type: 'my-type' })
|
|
293
|
-
assert.isOk(actual.getId)
|
|
294
|
-
assert.isOk(actual.getType)
|
|
295
|
-
})
|
|
296
|
-
it('should return a model where validate returns one error for id', async () => {
|
|
297
|
-
const input = {
|
|
298
|
-
id: Property({ required: true }),
|
|
299
|
-
type: Property(),
|
|
300
|
-
}
|
|
301
|
-
const model = Model('name', input)
|
|
302
|
-
const instance = model.create({ type: 'my-type' })
|
|
303
|
-
const actual = await instance.functions.validate()
|
|
304
|
-
const expected = 1
|
|
305
|
-
assert.equal(Object.values(actual).length, expected)
|
|
306
|
-
})
|
|
307
|
-
it('should return a model where validate returns one error for the missing text property', async () => {
|
|
308
|
-
const input = {
|
|
309
|
-
id: Property({ required: true }),
|
|
310
|
-
text: TextProperty({required: true}),
|
|
311
|
-
}
|
|
312
|
-
const model = Model('name', input)
|
|
313
|
-
const instance = model.create({ id: 'my-id' })
|
|
314
|
-
const actual = await instance.functions.validate()
|
|
315
|
-
const expected = 1
|
|
316
|
-
assert.equal(Object.values(actual).length, expected)
|
|
317
|
-
})
|
|
318
|
-
})
|
|
319
|
-
it('should return an object with a function "create" when called once with valid data', () => {
|
|
320
|
-
const actual = Model('name', {})
|
|
321
|
-
assert.isFunction(actual.create)
|
|
322
|
-
})
|
|
323
|
-
it('should throw an exception if a key "model" is passed in', () => {
|
|
324
|
-
assert.throws(() => {
|
|
325
|
-
Model('name', { model: 'weeee' }).create()
|
|
326
|
-
})
|
|
327
|
-
})
|
|
328
|
-
describe('#meta.references.getMyReferencedId()', () => {
|
|
329
|
-
it('should return the id from the ReferenceProperty', () => {
|
|
330
|
-
const model = Model(
|
|
331
|
-
'ModelName',
|
|
332
|
-
{
|
|
333
|
-
myReference: ReferenceProperty(TEST_MODEL_1),
|
|
334
|
-
},
|
|
335
|
-
)
|
|
336
|
-
const instance = model.create({ myReference: 'unit-test-id' })
|
|
337
|
-
const actual = instance.meta.references.getMyReferenceId()
|
|
338
|
-
const expected = 'unit-test-id'
|
|
339
|
-
assert.deepEqual(actual, expected)
|
|
340
|
-
})
|
|
341
|
-
})
|
|
342
|
-
describe('#functions.getPrimaryKey()', () => {
|
|
343
|
-
it('should return the id field when no primaryKey is passed', async () => {
|
|
344
|
-
const model = Model(
|
|
345
|
-
'ModelName',
|
|
346
|
-
{},
|
|
347
|
-
{
|
|
348
|
-
instanceFunctions: {
|
|
349
|
-
toString: instance => () => {
|
|
350
|
-
return 'An instance'
|
|
351
|
-
},
|
|
352
|
-
},
|
|
353
|
-
}
|
|
354
|
-
)
|
|
355
|
-
const expected = 'my-primary-key'
|
|
356
|
-
const instance = model.create({ id: expected })
|
|
357
|
-
const actual = await instance.functions.getPrimaryKey()
|
|
358
|
-
assert.equal(actual, expected)
|
|
359
|
-
})
|
|
360
|
-
it('should return the primaryKey field when "primaryKey" is passed as primaryKey', async () => {
|
|
361
|
-
const model = Model(
|
|
362
|
-
'ModelName',
|
|
363
|
-
{},
|
|
364
|
-
{
|
|
365
|
-
primaryKey: 'primaryKey',
|
|
366
|
-
instanceFunctions: {
|
|
367
|
-
toString: instance => () => {
|
|
368
|
-
return 'An instance'
|
|
369
|
-
},
|
|
370
|
-
},
|
|
371
|
-
}
|
|
372
|
-
)
|
|
373
|
-
const expected = 'my-primary-key'
|
|
374
|
-
const instance = model.create({ primaryKey: expected })
|
|
375
|
-
const actual = await instance.functions.getPrimaryKey()
|
|
376
|
-
assert.equal(actual, expected)
|
|
377
|
-
})
|
|
378
|
-
})
|
|
379
|
-
})
|
|
380
|
-
})
|