functional-models 1.0.28 → 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.
Files changed (41) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +9 -15
  3. package/cucumber.js +10 -0
  4. package/features/arrayFields.feature +7 -7
  5. package/features/basic-ts.feature +13 -0
  6. package/features/functions.feature +2 -3
  7. package/package.json +33 -10
  8. package/src/constants.ts +15 -0
  9. package/src/{errors.js → errors.ts} +6 -4
  10. package/src/index.ts +11 -0
  11. package/src/interfaces.ts +323 -0
  12. package/src/{lazy.js → lazy.ts} +7 -9
  13. package/src/methods.ts +30 -0
  14. package/src/models.ts +183 -0
  15. package/src/properties.ts +375 -0
  16. package/src/serialization.ts +39 -0
  17. package/src/{utils.js → utils.ts} +16 -26
  18. package/src/validation.ts +390 -0
  19. package/{features/stepDefinitions/steps.js → stepDefinitions/oldSteps.ts} +76 -53
  20. package/stepDefinitions/tssteps.ts +107 -0
  21. package/test/src/errors.test.ts +31 -0
  22. package/test/src/{lazy.test.js → lazy.test.ts} +4 -4
  23. package/test/src/methods.test.ts +45 -0
  24. package/test/src/models.test.ts +417 -0
  25. package/test/src/{properties.test.js → properties.test.ts} +251 -58
  26. package/test/src/serialization.test.ts +80 -0
  27. package/test/src/{utils.test.js → utils.test.ts} +29 -7
  28. package/test/src/{validation.test.js → validation.test.ts} +278 -210
  29. package/tsconfig.json +100 -0
  30. package/src/constants.js +0 -19
  31. package/src/functions.js +0 -7
  32. package/src/index.js +0 -10
  33. package/src/models.js +0 -152
  34. package/src/properties.js +0 -313
  35. package/src/serialization.js +0 -50
  36. package/src/validation.js +0 -285
  37. package/test/base/index.test.js +0 -5
  38. package/test/src/functions.test.js +0 -45
  39. package/test/src/index.test.js +0 -5
  40. package/test/src/models.test.js +0 -380
  41. package/test/src/serialization.test.js +0 -127
package/.eslintignore CHANGED
@@ -2,3 +2,4 @@ dist/
2
2
  node_modules/
3
3
  test/
4
4
  features/
5
+ stepDefinitions/
package/.eslintrc CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "extends": ["eslint:recommended", "prettier"],
3
- "plugins": ["import", "functional"],
3
+ "plugins": ["import", "functional", "@typescript-eslint"],
4
4
  "env": {
5
5
  "browser": true,
6
6
  "node": true,
@@ -8,6 +8,8 @@
8
8
  "es6": true
9
9
  },
10
10
  "rules": {
11
+ "@typescript-eslint/no-unused-vars": "error",
12
+
11
13
  "no-await-in-loop": ["error"],
12
14
  "no-console": ["error", { "allow": ["warn", "error", "info"] }],
13
15
  "no-constant-condition": ["error"],
@@ -91,15 +93,7 @@
91
93
  "linebreak-style": 0,
92
94
  "no-underscore-dangle": 0,
93
95
  "no-unused-labels": 0,
94
- "no-unused-vars": [
95
- "error",
96
- {
97
- "vars": "all",
98
- "argsIgnorePattern": "(_+)|(action)",
99
- "args": "after-used",
100
- "ignoreRestSiblings": false
101
- }
102
- ],
96
+ "no-unused-vars": 0,
103
97
  "object-shorthand": 0,
104
98
  "prefer-rest-params": 0,
105
99
  "semi": ["error", "never"],
@@ -114,13 +108,13 @@
114
108
  "functional/no-method-signature": ["error"],
115
109
  "functional/prefer-readonly-type": ["error"],
116
110
  "functional/no-class": ["error"],
117
- "functional/no-mixed-type": ["error"],
111
+ "functional/no-mixed-type": 0,
118
112
  "functional/no-this-expression": ["error"],
119
- "functional/prefer-type-literal": ["error"],
113
+ "functional/prefer-type-literal": 0,
120
114
  "functional/no-conditional-statement": 0,
121
115
  "functional/no-expression-statement": 0,
122
116
  "functional/no-loop-statement": ["error"],
123
- "functional/no-return-void": ["error"],
117
+ "functional/no-return-void": 0,
124
118
  "functional/no-promise-reject": 0,
125
119
  "functional/no-throw-statement": 0,
126
120
  "functional/no-try-statement": ["error"],
@@ -156,7 +150,7 @@
156
150
  "import/first": ["error"],
157
151
  "import/exports-last": ["error"],
158
152
  "import/no-duplicates": ["error"],
159
- "import/no-namespace": ["error"],
153
+ "import/no-namespace": 0,
160
154
  "import/extensions": ["error"],
161
155
  "import/order": ["error"],
162
156
  "import/newline-after-import": ["error"],
@@ -182,5 +176,5 @@
182
176
  "jsx": true
183
177
  }
184
178
  },
185
- "parser": "babel-eslint"
179
+ "parser": "@typescript-eslint/parser"
186
180
  }
package/cucumber.js ADDED
@@ -0,0 +1,10 @@
1
+ const common = [
2
+ 'features/**/*.feature',
3
+ '--require-module ts-node/register',
4
+ '--require ./stepDefinitions/*.ts',
5
+ '--format progress-bar',
6
+ ].join(' ')
7
+
8
+ module.exports = {
9
+ default: common,
10
+ }
@@ -3,7 +3,7 @@ Feature: Array Property
3
3
  Scenario: A model that has an array property is created holding an array of integers and is checked and validated
4
4
  Given ArrayModel1 model is used
5
5
  When ArrayModelData1 data is inserted
6
- Then the getArrayProperty property is called on the model
6
+ Then the ArrayProperty property is called on the model
7
7
  Then the array values match
8
8
  | array | [1,2,3,4,5]|
9
9
  Then functions.validate is called
@@ -12,41 +12,41 @@ Feature: Array Property
12
12
  Scenario: A model that has an array property but has a non-array inserted into it fails validation
13
13
  Given ArrayModel1 model is used
14
14
  When ArrayModelData2 data is inserted
15
- Then the getArrayProperty property is called on the model
15
+ Then the ArrayProperty property is called on the model
16
16
  Then functions.validate is called
17
17
  Then an array of 1 errors is shown
18
18
 
19
19
  Scenario: A model that has an array property for integers but an array of strings is inserted into it, it should fail validation
20
20
  Given ArrayModel1 model is used
21
21
  When ArrayModelData3 data is inserted
22
- Then the getArrayProperty property is called on the model
22
+ Then the ArrayProperty property is called on the model
23
23
  Then functions.validate is called
24
24
  Then an array of 1 errors is shown
25
25
 
26
26
  Scenario: A model that has an array property that has mixed values it should not fail validation.
27
27
  Given ArrayModel2 model is used
28
28
  When ArrayModelData4 data is inserted
29
- Then the getArrayProperty property is called on the model
29
+ Then the ArrayProperty property is called on the model
30
30
  Then functions.validate is called
31
31
  Then an array of 0 errors is shown
32
32
 
33
33
  Scenario: A model that uses the arrayProperty property that has mixed values it should not fail validation.
34
34
  Given ArrayModel3 model is used
35
35
  When ArrayModelData4 data is inserted
36
- Then the getArrayProperty property is called on the model
36
+ Then the ArrayProperty property is called on the model
37
37
  Then functions.validate is called
38
38
  Then an array of 0 errors is shown
39
39
 
40
40
  Scenario: A model that uses the arrayProperty with the choice validator should pass validation with no errors.
41
41
  Given ArrayModel4 model is used
42
42
  When ArrayModelData5 data is inserted
43
- Then the getArrayProperty property is called on the model
43
+ Then the ArrayProperty property is called on the model
44
44
  Then functions.validate is called
45
45
  Then an array of 0 errors is shown
46
46
 
47
47
  Scenario: A model that uses the arrayProperty with the choice validator should fail validation when one value is outside the choices
48
48
  Given ArrayModel4 model is used
49
49
  When ArrayModelData6 data is inserted
50
- Then the getArrayProperty property is called on the model
50
+ Then the ArrayProperty property is called on the model
51
51
  Then functions.validate is called
52
52
  Then an array of 1 errors is shown
@@ -0,0 +1,13 @@
1
+ Feature: Basic Typescript
2
+
3
+ Scenario: A model with properties, instance methods, and model methods works as expected.
4
+ Given model TE_FULL_TEST is used
5
+ When a model instanced is created is called on model with TE_FULL_TEST_1
6
+ And toObj is called on the model instance
7
+ And instance method myMethod is called
8
+ And model method myModelMethod is called
9
+ And validate is called on model instance
10
+ Then the results match TE_FULL_TEST_1 obj data
11
+ And the result of instance method is InstanceMethod
12
+ And the result of model method is ModelMethod
13
+ And the model instance validated successfully
@@ -3,9 +3,8 @@ Feature: Functions
3
3
  Scenario: A model with 2 properties (name, id), 2 model functions (modelWrapper, toString), and 2 instance functions (toString, toJson)
4
4
  Given FunctionModel1 model is used
5
5
  When FunctionModelData1 data is inserted
6
- Then getName property is found
7
- And getId property is found
6
+ Then name property is found
7
+ And id property is found
8
8
  And toString instance function is found
9
9
  And toJson instance function is found
10
10
  And modelWrapper model function is found
11
- And toString model function is found
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "functional-models",
3
- "version": "1.0.28",
3
+ "version": "1.1.0",
4
4
  "description": "A library for creating JavaScript function based models.",
5
- "main": "index.js",
5
+ "main": "src/index.js",
6
6
  "scripts": {
7
- "test": "nyc --all mocha --recursive './test/**/*.test.js'",
8
- "feature-tests": "./node_modules/@cucumber/cucumber/bin/cucumber-js",
7
+ "test": "mocha -r ts-node/register test/**/*.test.ts",
8
+ "test:coverage": "nyc npm run test",
9
+ "feature-tests": "./node_modules/.bin/cucumber-js -p default",
9
10
  "coverage": "nyc --all --reporter=lcov npm test"
10
11
  },
11
12
  "repository": {
@@ -27,18 +28,37 @@
27
28
  },
28
29
  "homepage": "https://github.com/monolithst/functional-models#readme",
29
30
  "nyc": {
31
+ "extends": "@istanbuljs/nyc-config-typescript",
32
+ "check-coverage": true,
30
33
  "all": true,
34
+ "include": [
35
+ "src/**/!(*.test.*).[tj]s?(x)"
36
+ ],
31
37
  "exclude": [
32
- "coverage/",
33
- "features/stepDefinitions/*",
34
- "test/*"
35
- ]
38
+ "src/_tests_/**/*.*"
39
+ ],
40
+ "reporter": [
41
+ "html",
42
+ "lcov",
43
+ "text",
44
+ "text-summary"
45
+ ],
46
+ "report-dir": "coverage"
36
47
  },
37
48
  "devDependencies": {
49
+ "@cucumber/cucumber": "^8.0.0-rc.1",
50
+ "@istanbuljs/nyc-config-typescript": "^1.0.2",
51
+ "@types/async-lock": "^1.1.3",
52
+ "@types/chai": "^4.2.22",
53
+ "@types/chai-as-promised": "^7.1.4",
54
+ "@types/lodash": "^4.14.176",
55
+ "@types/mocha": "^9.0.0",
56
+ "@types/proxyquire": "^1.3.28",
57
+ "@types/sinon": "^10.0.6",
58
+ "@typescript-eslint/eslint-plugin": "^5.6.0",
38
59
  "babel-eslint": "^10.1.0",
39
60
  "chai": "^4.3.0",
40
61
  "chai-as-promised": "^7.1.1",
41
- "cucumber": "^7.0.0-rc.0",
42
62
  "eslint": "^7.19.0",
43
63
  "eslint-config-prettier": "^7.2.0",
44
64
  "eslint-plugin-functional": "^3.2.1",
@@ -46,9 +66,12 @@
46
66
  "mocha": "^8.2.1",
47
67
  "nyc": "^15.1.0",
48
68
  "proxyquire": "^2.1.3",
49
- "sinon": "^11.1.2"
69
+ "sinon": "^11.1.2",
70
+ "ts-node": "^10.4.0",
71
+ "typescript": "^4.4.4"
50
72
  },
51
73
  "dependencies": {
74
+ "@typescript-eslint/parser": "^5.3.0",
52
75
  "async-lock": "^1.3.0",
53
76
  "get-random-values": "^1.2.2",
54
77
  "lodash": "^4.17.21"
@@ -0,0 +1,15 @@
1
+ enum PROPERTY_TYPES {
2
+ UniqueId = 'UniqueId',
3
+ DateProperty = 'DateProperty',
4
+ ArrayProperty = 'ArrayProperty',
5
+ ReferenceProperty = 'ReferenceProperty',
6
+ IntegerProperty = 'IntegerProperty',
7
+ TextProperty = 'TextProperty',
8
+ ConstantValueProperty = 'ConstantValueProperty',
9
+ NumberProperty = 'NumberProperty',
10
+ ObjectProperty = 'ObjectProperty',
11
+ EmailProperty = 'EmailProperty',
12
+ BooleanProperty = 'BooleanProperty',
13
+ }
14
+
15
+ export { PROPERTY_TYPES }
@@ -1,7 +1,11 @@
1
+ type KeysToErrors = { [s: string]: string[] }
2
+
1
3
  /* eslint-disable functional/no-this-expression */
2
4
  /* eslint-disable functional/no-class */
3
5
  class ValidationError extends Error {
4
- constructor(modelName, keysToErrors) {
6
+ public modelName: String
7
+ public keysToErrors: KeysToErrors
8
+ constructor(modelName: String, keysToErrors: KeysToErrors) {
5
9
  super(`${modelName} did not pass validation`)
6
10
  this.name = 'ValidationError'
7
11
  this.modelName = modelName
@@ -11,6 +15,4 @@ class ValidationError extends Error {
11
15
  /* eslint-enable functional/no-this-expression */
12
16
  /* eslint-enable functional/no-class */
13
17
 
14
- module.exports = {
15
- ValidationError,
16
- }
18
+ export { ValidationError }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ import * as constants from './constants'
2
+ import * as errors from './errors'
3
+ import * as validation from './validation'
4
+ import * as serialization from './serialization'
5
+ import * as utils from './utils'
6
+
7
+ export * from './models'
8
+ export * from './properties'
9
+ export * from './methods'
10
+
11
+ export { constants, errors, validation, serialization, utils }
@@ -0,0 +1,323 @@
1
+ /* eslint-disable no-unused-vars */
2
+
3
+ type MaybeFunction<T> = T | (() => T)
4
+ type MaybePromise<T> = T | Promise<T>
5
+ type Nullable<T> = T | null
6
+ type Maybe<T> = T | undefined | null
7
+ type Arrayable<T> = T | readonly T[]
8
+ type MaybeLazy<T> = Maybe<Promise<T>>
9
+ type MaybeEmpty<T> = T | null | undefined
10
+ type JsonAble =
11
+ | number
12
+ | string
13
+ | boolean
14
+ | null
15
+ | Arrayable<{ readonly [s: string]: JsonAble }>
16
+ type VeryPrimitivesTypes = null | string | number | boolean
17
+ type toObj = () => Promise<JsonAble>
18
+
19
+ type ValueIsOfType<T, V> = {
20
+ readonly [P in keyof T as T[P] extends V ? P : never]: T[P]
21
+ }
22
+
23
+ type ValueIsNotOfType<T, V> = {
24
+ readonly [P in keyof T as T[P] extends V ? never : P]: T[P]
25
+ }
26
+
27
+ type InstanceMethodGetters<T> = {
28
+ readonly [P in keyof T as T[P] extends ModelInstanceMethod
29
+ ? P
30
+ : never]: ModelInstanceMethodClient
31
+ }
32
+
33
+ type ModelMethodGetters<T> = {
34
+ readonly [P in keyof T as T[P] extends ModelMethod
35
+ ? P
36
+ : never]: ModelMethodClient
37
+ }
38
+
39
+ type ModelMethodTypes<T extends FunctionalModel> =
40
+ | ModelMethod
41
+ | ModelInstanceMethod
42
+ | ModelMethodTyped<T>
43
+ | ModelInstanceMethodTyped<T>
44
+
45
+ type PropertyGetters<T extends FunctionalModel> = {
46
+ readonly // NOTE: This is NOT ModelMethodTypes, its getting everything but.
47
+ [Property in keyof T as T[Property] extends ModelMethodTypes<T>
48
+ ? never
49
+ : Property]: () => T[Property] | Promise<T[Property]>
50
+ }
51
+
52
+ type FunctionalModel =
53
+ | {
54
+ readonly [s: string]:
55
+ | Arrayable<number>
56
+ | Arrayable<string>
57
+ | Arrayable<boolean>
58
+ | Arrayable<null>
59
+ | Arrayable<FunctionalModel>
60
+ | Arrayable<Date>
61
+ | Arrayable<undefined>
62
+ | ReferenceValueType<any>
63
+ | ModelInstanceMethod
64
+ | ModelMethod
65
+ }
66
+ | JsonAble
67
+
68
+ type FunctionalType =
69
+ | JsonAble
70
+ | (() => FunctionalType)
71
+ | Arrayable<undefined>
72
+ | Arrayable<Date>
73
+ | Arrayable<FunctionalModel>
74
+ | Arrayable<{ readonly [s: string]: JsonAble }>
75
+
76
+ type ModelInstanceInputData<T extends FunctionalModel> = ValueIsNotOfType<
77
+ T,
78
+ ModelMethodTypes<T>
79
+ >
80
+
81
+ type PropertyValidatorComponentTypeAdvanced<
82
+ TValue,
83
+ TModel extends FunctionalModel
84
+ > = (
85
+ value: TValue,
86
+ instance: ModelInstance<TModel>,
87
+ instanceData: FunctionalModel
88
+ ) => string | undefined
89
+
90
+ type PropertyValidatorComponentType<TValue> = (
91
+ value: TValue,
92
+ instance: ModelInstance<any>,
93
+ instanceData: FunctionalModel
94
+ ) => string | undefined
95
+
96
+ type PropertyValidatorComponentSync = PropertyValidatorComponentType<any>
97
+
98
+ type PropertyValidatorComponentAsync = (
99
+ value: Arrayable<FunctionalModel>,
100
+ instance: ModelInstance<any>,
101
+ instanceData: FunctionalModel
102
+ ) => Promise<string | undefined>
103
+
104
+ type PropertyValidatorComponent =
105
+ | PropertyValidatorComponentSync
106
+ | PropertyValidatorComponentAsync
107
+
108
+ type PropertyValidator = (
109
+ instance: ModelInstance<any>,
110
+ instanceData: FunctionalModel
111
+ ) => Promise<ValidationErrors>
112
+
113
+ type ValidationError = string | undefined
114
+ type ValidationErrors = readonly ValidationError[]
115
+ type ModelError = string
116
+ type ModelErrors = {
117
+ readonly [s: string]: readonly ModelError[]
118
+ }
119
+
120
+ type ModelComponentValidator = (
121
+ instance: ModelInstance<any>,
122
+ instanceData: FunctionalModel,
123
+ options?: object
124
+ ) => Promise<ValidationErrors>
125
+
126
+ type ValueGetter = () =>
127
+ | MaybePromise<Arrayable<FunctionalType>>
128
+ | MaybePromise<ModelInstance<any>>
129
+
130
+ type PropertyInstance<T extends Arrayable<FunctionalType>> = {
131
+ readonly getConfig: () => object
132
+ readonly getChoices: () => readonly VeryPrimitivesTypes[]
133
+ readonly getDefaultValue: () => T
134
+ readonly getConstantValue: () => T
135
+ readonly getPropertyType: () => string
136
+ readonly createGetter: (value: T) => ValueGetter
137
+ readonly getValidator: (valueGetter: ValueGetter) => PropertyValidator
138
+ }
139
+
140
+ type PropertiesList<T> = {
141
+ readonly [P in keyof T as T[P] extends Arrayable<FunctionalType>
142
+ ? P
143
+ : never]: PropertyInstance<any>
144
+ }
145
+
146
+ interface ReferencePropertyInstance<T extends FunctionalModel>
147
+ extends PropertyInstance<ModelInstance<T> | T | MaybeEmpty<PrimaryKeyType>> {
148
+ readonly getReferencedId: (
149
+ instanceValues: ReferenceValueType<T>
150
+ ) => MaybeEmpty<PrimaryKeyType>
151
+ readonly getReferencedModel: () => Model<T>
152
+ }
153
+
154
+ type ReferenceValueType<T extends FunctionalModel> =
155
+ | ModelInstance<T>
156
+ | ModelInstanceInputData<T>
157
+ | string
158
+ | number
159
+ | null
160
+ | undefined
161
+
162
+ type DefaultPropertyValidators = {
163
+ readonly required?: boolean
164
+ readonly isInteger?: boolean
165
+ readonly isNumber?: boolean
166
+ readonly isString?: boolean
167
+ readonly isArray?: boolean
168
+ readonly isBoolean?: boolean
169
+ }
170
+
171
+ type PropertyConfigContents = {
172
+ readonly type?: string
173
+ readonly defaultValue?: Arrayable<FunctionalType>
174
+ readonly value?: Arrayable<FunctionalType>
175
+ readonly choices?: readonly VeryPrimitivesTypes[]
176
+ readonly lazyLoadMethod?: (
177
+ value: Arrayable<FunctionalType>
178
+ ) => MaybeLazy<Arrayable<FunctionalType>>
179
+ readonly valueSelector?: (
180
+ instanceValue: MaybePromise<Arrayable<FunctionalType>>
181
+ ) => Arrayable<FunctionalType>
182
+ readonly validators?: readonly PropertyValidatorComponent[]
183
+ readonly maxLength?: number
184
+ readonly minLength?: number
185
+ readonly maxValue?: number
186
+ readonly minValue?: number
187
+ readonly autoNow?: boolean
188
+ readonly fetcher?: (
189
+ model: Model<any>,
190
+ primaryKey: PrimaryKeyType
191
+ ) => Promise<any>
192
+ }
193
+
194
+ type PropertyConfig =
195
+ | (PropertyConfigContents & DefaultPropertyValidators)
196
+ | undefined
197
+
198
+ type PrimaryKeyPropertyInstanceType =
199
+ | PropertyInstance<string>
200
+ | PropertyInstance<number>
201
+ type PrimaryKeyType = string | number
202
+
203
+ type ModelMethods<T extends FunctionalModel> = ValueIsOfType<
204
+ T,
205
+ ModelMethod | ModelMethodTyped<T>
206
+ >
207
+ type InstanceMethods<T extends FunctionalModel> = ValueIsOfType<
208
+ T,
209
+ ModelInstanceMethod | ModelInstanceMethodTyped<T>
210
+ >
211
+ type ModelDefinition<T extends FunctionalModel> = {
212
+ readonly getPrimaryKeyName?: () => string
213
+ readonly properties: PropertiesList<T> & {
214
+ readonly id?: PrimaryKeyPropertyInstanceType
215
+ }
216
+ readonly instanceMethods?: InstanceMethods<T>
217
+ readonly modelMethods?: ModelMethods<T>
218
+ readonly modelValidators?: readonly ModelComponentValidator[]
219
+ }
220
+
221
+ type Model<T extends FunctionalModel> = {
222
+ readonly getName: () => string
223
+ readonly getPrimaryKeyName: () => string
224
+ readonly getModelDefinition: () => ModelDefinition<T>
225
+ readonly getPrimaryKey: (t: ModelInstanceInputData<T>) => PrimaryKeyType
226
+ readonly create: (
227
+ data: ModelInstanceInputData<T> & { readonly id?: PrimaryKeyType }
228
+ ) => ModelInstance<T>
229
+ readonly methods: ModelMethodGetters<T>
230
+ }
231
+
232
+ type ReferenceFunctions = {
233
+ readonly [s: string]: () => ReferenceValueType<any>
234
+ }
235
+
236
+ type PropertyValidators = {
237
+ readonly [s: string]: PropertyValidator
238
+ }
239
+
240
+ type ModelInstance<T extends FunctionalModel> = {
241
+ readonly get: PropertyGetters<T> & {
242
+ readonly id: () => MaybePromise<PrimaryKeyType>
243
+ }
244
+ readonly methods: InstanceMethodGetters<T>
245
+ readonly references: ReferenceFunctions
246
+ readonly toObj: toObj
247
+ readonly getPrimaryKeyName: () => string
248
+ readonly getPrimaryKey: () => PrimaryKeyType
249
+ readonly validators: PropertyValidators
250
+ readonly validate: (options?: {}) => Promise<ModelErrors>
251
+ readonly getModel: () => Model<T>
252
+ }
253
+
254
+ type ModelMethodTyped<T extends FunctionalModel> = (
255
+ model: Model<T>,
256
+ args?: readonly any[]
257
+ ) => any
258
+ type ModelMethod = ModelMethodTyped<any>
259
+ type ModelMethodClient = (...args: readonly any[]) => any
260
+ type ModelInstanceMethodTyped<T extends FunctionalModel> = (
261
+ instance: ModelInstance<T>,
262
+ args?: readonly any[]
263
+ ) => any
264
+ type ModelInstanceMethod = ModelInstanceMethodTyped<any>
265
+ type ModelInstanceMethodClient = (...args: readonly any[]) => any
266
+
267
+ type ModelOptions = {
268
+ readonly instanceCreatedCallback: Nullable<
269
+ Arrayable<(instance: ModelInstance<any>) => void>
270
+ >
271
+ }
272
+
273
+ type OptionalModelOptions =
274
+ | {
275
+ readonly instanceCreatedCallback?: Nullable<
276
+ Arrayable<(instance: ModelInstance<any>) => void>
277
+ >
278
+ }
279
+ | undefined
280
+
281
+ export {
282
+ MaybeFunction,
283
+ Maybe,
284
+ MaybePromise,
285
+ Nullable,
286
+ Arrayable,
287
+ MaybeLazy,
288
+ JsonAble,
289
+ toObj,
290
+ ModelInstance,
291
+ Model,
292
+ PropertyValidatorComponent,
293
+ PropertyValidatorComponentSync,
294
+ PropertyValidatorComponentAsync,
295
+ PropertyValidatorComponentType,
296
+ PropertyValidator,
297
+ ModelComponentValidator,
298
+ PropertyInstance,
299
+ PropertyConfig,
300
+ FunctionalType,
301
+ ValueGetter,
302
+ ReferenceValueType,
303
+ ModelDefinition,
304
+ ModelOptions,
305
+ ModelMethod,
306
+ OptionalModelOptions,
307
+ ReferencePropertyInstance,
308
+ PropertyGetters,
309
+ PropertyValidators,
310
+ PropertyValidatorComponentTypeAdvanced,
311
+ ModelInstanceMethod,
312
+ ModelInstanceMethodTyped,
313
+ FunctionalModel,
314
+ ModelInstanceInputData,
315
+ ModelMethodTyped,
316
+ ModelMethodGetters,
317
+ InstanceMethodGetters,
318
+ ReferenceFunctions,
319
+ ModelErrors,
320
+ MaybeEmpty,
321
+ PrimaryKeyType,
322
+ }
323
+ /* eslint-enable no-unused-vars */
@@ -1,26 +1,24 @@
1
- const AsyncLock = require('async-lock')
2
- const { createUuid } = require('./utils')
1
+ import AsyncLock from 'async-lock'
2
+ import { createUuid } from './utils'
3
3
 
4
- const lazyValue = method => {
4
+ const lazyValue = (method: Function) => {
5
5
  const key = createUuid()
6
6
  const lock = new AsyncLock()
7
7
  /* eslint-disable functional/no-let */
8
- let value = undefined
8
+ let value: any = undefined
9
9
  let called = false
10
- return async (...args) => {
10
+ return async (...args: readonly any[]) => {
11
11
  return lock.acquire(key, async () => {
12
12
  if (!called) {
13
13
  called = true
14
14
  value = await method(...args)
15
15
  // eslint-disable-next-line require-atomic-updates
16
16
  }
17
- }).then(() => {
17
+
18
18
  return value
19
19
  })
20
20
  }
21
21
  /* eslint-enable functional/no-let */
22
22
  }
23
23
 
24
- module.exports = {
25
- lazyValue,
26
- }
24
+ export { lazyValue }
package/src/methods.ts ADDED
@@ -0,0 +1,30 @@
1
+ import {
2
+ ModelInstanceMethodTyped,
3
+ ModelInstance,
4
+ FunctionalModel,
5
+ Model,
6
+ ModelMethodTyped,
7
+ } from './interfaces'
8
+
9
+ const WrapperInstanceMethod = <T extends FunctionalModel>(
10
+ method: (instance: ModelInstance<T>, args?: readonly any[]) => any
11
+ ) => {
12
+ const r: ModelInstanceMethodTyped<T> = (
13
+ instance: ModelInstance<T>,
14
+ ...args: readonly any[]
15
+ ) => {
16
+ return method(instance, ...args)
17
+ }
18
+ return r
19
+ }
20
+
21
+ const WrapperModelMethod = <T extends FunctionalModel>(
22
+ method: (model: Model<T>, args?: readonly any[]) => any
23
+ ) => {
24
+ const r: ModelMethodTyped<T> = (model: Model<T>, ...args: readonly any[]) => {
25
+ return method(model, ...args)
26
+ }
27
+ return r
28
+ }
29
+
30
+ export { WrapperInstanceMethod, WrapperModelMethod }