@declaro/data 2.0.0-beta.126 → 2.0.0-beta.128
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/dist/browser/index.js +11 -11
- package/dist/browser/index.js.map +6 -6
- package/dist/node/index.cjs +217 -92
- package/dist/node/index.cjs.map +6 -6
- package/dist/node/index.js +209 -84
- package/dist/node/index.js.map +6 -6
- package/dist/ts/application/model-controller.d.ts +15 -5
- package/dist/ts/application/model-controller.d.ts.map +1 -1
- package/dist/ts/application/read-only-model-controller.d.ts +5 -1
- package/dist/ts/application/read-only-model-controller.d.ts.map +1 -1
- package/dist/ts/domain/services/model-service.d.ts +27 -0
- package/dist/ts/domain/services/model-service.d.ts.map +1 -1
- package/dist/ts/domain/services/read-only-model-service.d.ts +8 -0
- package/dist/ts/domain/services/read-only-model-service.d.ts.map +1 -1
- package/dist/ts/shared/utils/schema-inheritance.test.d.ts +2 -0
- package/dist/ts/shared/utils/schema-inheritance.test.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/animal-schema.d.ts +57 -0
- package/dist/ts/shared/utils/test/animal-schema.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/animal-trait-schema.d.ts +55 -0
- package/dist/ts/shared/utils/test/animal-trait-schema.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/elephant-schema.d.ts +30 -0
- package/dist/ts/shared/utils/test/elephant-schema.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/elephant-trait-schema.d.ts +26 -0
- package/dist/ts/shared/utils/test/elephant-trait-schema.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/application/model-controller.ts +110 -59
- package/src/application/read-only-model-controller.ts +43 -25
- package/src/domain/services/model-service.test.ts +460 -0
- package/src/domain/services/model-service.ts +165 -67
- package/src/domain/services/read-only-model-service.test.ts +230 -0
- package/src/domain/services/read-only-model-service.ts +65 -40
- package/src/shared/utils/schema-inheritance.test.ts +295 -0
- package/src/shared/utils/test/animal-schema.ts +46 -0
- package/src/shared/utils/test/animal-trait-schema.ts +45 -0
- package/src/shared/utils/test/elephant-schema.ts +58 -0
- package/src/shared/utils/test/elephant-trait-schema.ts +53 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.custom-lookup.test.d.ts +0 -1
- package/dist/ts/test/mock/repositories/mock-memory-repository.custom-lookup.test.d.ts.map +0 -1
- package/src/test/mock/repositories/mock-memory-repository.custom-lookup.test.ts +0 -0
|
@@ -1,52 +1,92 @@
|
|
|
1
1
|
import type { AuthValidator } from '@declaro/auth'
|
|
2
2
|
import { PermissionValidator, type AnyModelSchema } from '@declaro/core'
|
|
3
3
|
import type { ModelService, ICreateOptions, IUpdateOptions } from '../domain/services/model-service'
|
|
4
|
+
import type { ILoadOptions } from '../domain/services/read-only-model-service'
|
|
4
5
|
import type { InferDetail, InferFilters, InferInput, InferLookup, InferSummary } from '../shared/utils/schema-inference'
|
|
5
6
|
import { ReadOnlyModelController } from './read-only-model-controller'
|
|
6
7
|
|
|
7
8
|
export class ModelController<TSchema extends AnyModelSchema> extends ReadOnlyModelController<TSchema> {
|
|
8
|
-
constructor(
|
|
9
|
+
constructor(
|
|
10
|
+
protected readonly service: ModelService<TSchema>,
|
|
11
|
+
protected readonly authValidator: AuthValidator,
|
|
12
|
+
) {
|
|
9
13
|
super(service, authValidator)
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
async
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
async createPermissions(input: InferInput<TSchema>, options?: ICreateOptions): Promise<PermissionValidator> {
|
|
17
|
+
return PermissionValidator.create().someOf([
|
|
18
|
+
this.service.getDescriptor('create', '*').toString(),
|
|
19
|
+
this.service.getDescriptor('write', '*').toString(),
|
|
20
|
+
])
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async create(input: InferInput<TSchema>, options?: ICreateOptions): Promise<InferDetail<TSchema>> {
|
|
24
|
+
const permissions = await this.createPermissions(input, options)
|
|
25
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
26
|
+
return this.service.create(input, options)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async updatePermissions(
|
|
30
|
+
lookup: InferLookup<TSchema>,
|
|
31
|
+
input: InferInput<TSchema>,
|
|
32
|
+
options?: IUpdateOptions,
|
|
33
|
+
): Promise<PermissionValidator> {
|
|
34
|
+
return PermissionValidator.create().someOf([
|
|
35
|
+
this.service.getDescriptor('update', '*').toString(),
|
|
36
|
+
this.service.getDescriptor('write', '*').toString(),
|
|
37
|
+
])
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async update(
|
|
41
|
+
lookup: InferLookup<TSchema>,
|
|
42
|
+
input: InferInput<TSchema>,
|
|
43
|
+
options?: IUpdateOptions,
|
|
44
|
+
): Promise<InferDetail<TSchema>> {
|
|
45
|
+
const permissions = await this.updatePermissions(lookup, input, options)
|
|
46
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
47
|
+
return this.service.update(lookup, input, options)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async removePermissions(lookup: InferLookup<TSchema>, options?: ILoadOptions): Promise<PermissionValidator> {
|
|
51
|
+
return PermissionValidator.create().someOf([
|
|
52
|
+
this.service.getDescriptor('remove', '*').toString(),
|
|
53
|
+
this.service.getDescriptor('write', '*').toString(),
|
|
54
|
+
])
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async remove(lookup: InferLookup<TSchema>, options?: ILoadOptions): Promise<InferSummary<TSchema>> {
|
|
58
|
+
const permissions = await this.removePermissions(lookup, options)
|
|
59
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
60
|
+
return this.service.remove(lookup, options)
|
|
20
61
|
}
|
|
21
62
|
|
|
22
|
-
async
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
]),
|
|
28
|
-
)
|
|
29
|
-
return this.service.update(lookup, input)
|
|
63
|
+
async restorePermissions(lookup: InferLookup<TSchema>, options?: ILoadOptions): Promise<PermissionValidator> {
|
|
64
|
+
return PermissionValidator.create().someOf([
|
|
65
|
+
this.service.getDescriptor('restore', '*').toString(),
|
|
66
|
+
this.service.getDescriptor('write', '*').toString(),
|
|
67
|
+
])
|
|
30
68
|
}
|
|
31
69
|
|
|
32
|
-
async
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
this.service.getDescriptor('write', '*').toString(),
|
|
37
|
-
]),
|
|
38
|
-
)
|
|
39
|
-
return this.service.remove(lookup)
|
|
70
|
+
async restore(lookup: InferLookup<TSchema>, options?: ILoadOptions): Promise<InferSummary<TSchema>> {
|
|
71
|
+
const permissions = await this.restorePermissions(lookup, options)
|
|
72
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
73
|
+
return this.service.restore(lookup, options)
|
|
40
74
|
}
|
|
41
75
|
|
|
42
|
-
async
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
76
|
+
async upsertPermissions(
|
|
77
|
+
input: InferInput<TSchema>,
|
|
78
|
+
options?: ICreateOptions | IUpdateOptions,
|
|
79
|
+
): Promise<PermissionValidator> {
|
|
80
|
+
// Create nested validator for (create AND update) permissions
|
|
81
|
+
const createAndUpdateValidator = PermissionValidator.create().allOf([
|
|
82
|
+
this.service.getDescriptor('create', '*').toString(),
|
|
83
|
+
this.service.getDescriptor('update', '*').toString(),
|
|
84
|
+
])
|
|
85
|
+
|
|
86
|
+
return PermissionValidator.create().someOf([
|
|
87
|
+
createAndUpdateValidator,
|
|
88
|
+
this.service.getDescriptor('write', '*').toString(),
|
|
89
|
+
])
|
|
50
90
|
}
|
|
51
91
|
|
|
52
92
|
/**
|
|
@@ -56,16 +96,25 @@ export class ModelController<TSchema extends AnyModelSchema> extends ReadOnlyMod
|
|
|
56
96
|
* @returns The upserted record.
|
|
57
97
|
*/
|
|
58
98
|
async upsert(input: InferInput<TSchema>, options?: ICreateOptions | IUpdateOptions): Promise<InferDetail<TSchema>> {
|
|
99
|
+
const permissions = await this.upsertPermissions(input, options)
|
|
100
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
101
|
+
return this.service.upsert(input, options)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async bulkUpsertPermissions(
|
|
105
|
+
inputs: InferInput<TSchema>[],
|
|
106
|
+
options?: ICreateOptions | IUpdateOptions,
|
|
107
|
+
): Promise<PermissionValidator> {
|
|
59
108
|
// Create nested validator for (create AND update) permissions
|
|
60
109
|
const createAndUpdateValidator = PermissionValidator.create().allOf([
|
|
61
110
|
this.service.getDescriptor('create', '*').toString(),
|
|
62
111
|
this.service.getDescriptor('update', '*').toString(),
|
|
63
112
|
])
|
|
64
113
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
114
|
+
return PermissionValidator.create().someOf([
|
|
115
|
+
createAndUpdateValidator,
|
|
116
|
+
this.service.getDescriptor('write', '*').toString(),
|
|
117
|
+
])
|
|
69
118
|
}
|
|
70
119
|
|
|
71
120
|
/**
|
|
@@ -78,18 +127,19 @@ export class ModelController<TSchema extends AnyModelSchema> extends ReadOnlyMod
|
|
|
78
127
|
inputs: InferInput<TSchema>[],
|
|
79
128
|
options?: ICreateOptions | IUpdateOptions,
|
|
80
129
|
): Promise<InferDetail<TSchema>[]> {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.service.getDescriptor('create', '*').toString(),
|
|
84
|
-
this.service.getDescriptor('update', '*').toString(),
|
|
85
|
-
])
|
|
86
|
-
|
|
87
|
-
this.authValidator.validatePermissions((v) =>
|
|
88
|
-
v.someOf([createAndUpdateValidator, this.service.getDescriptor('write', '*').toString()]),
|
|
89
|
-
)
|
|
130
|
+
const permissions = await this.bulkUpsertPermissions(inputs, options)
|
|
131
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
90
132
|
return this.service.bulkUpsert(inputs, options)
|
|
91
133
|
}
|
|
92
134
|
|
|
135
|
+
async permanentlyDeleteFromTrashPermissions(lookup: InferLookup<TSchema>): Promise<PermissionValidator> {
|
|
136
|
+
return PermissionValidator.create().someOf([
|
|
137
|
+
this.service.getDescriptor('permanently-delete-from-trash', '*').toString(),
|
|
138
|
+
this.service.getDescriptor('permanently-delete', '*').toString(),
|
|
139
|
+
this.service.getDescriptor('empty-trash', '*').toString(),
|
|
140
|
+
])
|
|
141
|
+
}
|
|
142
|
+
|
|
93
143
|
/**
|
|
94
144
|
* Permanently deletes a specific entity from the trash.
|
|
95
145
|
* Requires 'permanently-delete-from-trash', 'permanently-delete', or 'empty-trash' permission.
|
|
@@ -97,16 +147,15 @@ export class ModelController<TSchema extends AnyModelSchema> extends ReadOnlyMod
|
|
|
97
147
|
* @returns The permanently deleted entity summary
|
|
98
148
|
*/
|
|
99
149
|
async permanentlyDeleteFromTrash(lookup: InferLookup<TSchema>): Promise<InferSummary<TSchema>> {
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
this.service.getDescriptor('permanently-delete-from-trash', '*').toString(),
|
|
103
|
-
this.service.getDescriptor('permanently-delete', '*').toString(),
|
|
104
|
-
this.service.getDescriptor('empty-trash', '*').toString(),
|
|
105
|
-
]),
|
|
106
|
-
)
|
|
150
|
+
const permissions = await this.permanentlyDeleteFromTrashPermissions(lookup)
|
|
151
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
107
152
|
return this.service.permanentlyDeleteFromTrash(lookup)
|
|
108
153
|
}
|
|
109
154
|
|
|
155
|
+
async permanentlyDeletePermissions(lookup: InferLookup<TSchema>): Promise<PermissionValidator> {
|
|
156
|
+
return PermissionValidator.create().someOf([this.service.getDescriptor('permanently-delete', '*').toString()])
|
|
157
|
+
}
|
|
158
|
+
|
|
110
159
|
/**
|
|
111
160
|
* Permanently deletes an entity without moving it to trash first.
|
|
112
161
|
* Requires 'permanently-delete' permission.
|
|
@@ -114,12 +163,15 @@ export class ModelController<TSchema extends AnyModelSchema> extends ReadOnlyMod
|
|
|
114
163
|
* @returns The permanently deleted entity summary
|
|
115
164
|
*/
|
|
116
165
|
async permanentlyDelete(lookup: InferLookup<TSchema>): Promise<InferSummary<TSchema>> {
|
|
117
|
-
this.
|
|
118
|
-
|
|
119
|
-
)
|
|
166
|
+
const permissions = await this.permanentlyDeletePermissions(lookup)
|
|
167
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
120
168
|
return this.service.permanentlyDelete(lookup)
|
|
121
169
|
}
|
|
122
170
|
|
|
171
|
+
async emptyTrashPermissions(filters?: InferFilters<TSchema>): Promise<PermissionValidator> {
|
|
172
|
+
return PermissionValidator.create().someOf([this.service.getDescriptor('empty-trash', '*').toString()])
|
|
173
|
+
}
|
|
174
|
+
|
|
123
175
|
/**
|
|
124
176
|
* Empties the trash by permanently deleting entities that have been marked as removed.
|
|
125
177
|
* Requires 'empty-trash' permission.
|
|
@@ -127,9 +179,8 @@ export class ModelController<TSchema extends AnyModelSchema> extends ReadOnlyMod
|
|
|
127
179
|
* @returns The count of entities permanently deleted
|
|
128
180
|
*/
|
|
129
181
|
async emptyTrash(filters?: InferFilters<TSchema>): Promise<number> {
|
|
130
|
-
this.
|
|
131
|
-
|
|
132
|
-
)
|
|
182
|
+
const permissions = await this.emptyTrashPermissions(filters)
|
|
183
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
133
184
|
return this.service.emptyTrash(filters)
|
|
134
185
|
}
|
|
135
186
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AuthValidator } from '@declaro/auth'
|
|
2
2
|
import {} from '@declaro/auth'
|
|
3
|
-
import type
|
|
3
|
+
import { PermissionValidator, type AnyModelSchema } from '@declaro/core'
|
|
4
4
|
import type { ILoadOptions, ISearchOptions, ReadOnlyModelService } from '../domain/services/read-only-model-service'
|
|
5
5
|
import type { InferDetail, InferFilters, InferLookup, InferSearchResults } from '../shared/utils/schema-inference'
|
|
6
6
|
|
|
@@ -10,39 +10,61 @@ export class ReadOnlyModelController<TSchema extends AnyModelSchema> {
|
|
|
10
10
|
protected readonly authValidator: AuthValidator,
|
|
11
11
|
) {}
|
|
12
12
|
|
|
13
|
+
async loadPermissions(lookup: InferLookup<TSchema>): Promise<PermissionValidator> {
|
|
14
|
+
return PermissionValidator.create().someOf([
|
|
15
|
+
this.service.getDescriptor('load', '*').toString(),
|
|
16
|
+
this.service.getDescriptor('read', '*').toString(),
|
|
17
|
+
])
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
async load(lookup: InferLookup<TSchema>, options?: ILoadOptions): Promise<InferDetail<TSchema>> {
|
|
14
|
-
this.
|
|
15
|
-
|
|
16
|
-
this.service.getDescriptor('load', '*').toString(),
|
|
17
|
-
this.service.getDescriptor('read', '*').toString(),
|
|
18
|
-
]),
|
|
19
|
-
)
|
|
21
|
+
const permissions = await this.loadPermissions(lookup)
|
|
22
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
20
23
|
return this.service.load(lookup, options)
|
|
21
24
|
}
|
|
22
25
|
|
|
26
|
+
async loadManyPermissions(lookups: InferLookup<TSchema>[]): Promise<PermissionValidator> {
|
|
27
|
+
return PermissionValidator.create().someOf([
|
|
28
|
+
this.service.getDescriptor('loadMany', '*').toString(),
|
|
29
|
+
this.service.getDescriptor('read', '*').toString(),
|
|
30
|
+
])
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
async loadMany(lookups: InferLookup<TSchema>[], options?: ILoadOptions): Promise<InferDetail<TSchema>[]> {
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
this.service.getDescriptor('loadMany', '*').toString(),
|
|
27
|
-
this.service.getDescriptor('read', '*').toString(),
|
|
28
|
-
]),
|
|
29
|
-
)
|
|
34
|
+
const permissions = await this.loadManyPermissions(lookups)
|
|
35
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
30
36
|
return this.service.loadMany(lookups, options)
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
async searchPermissions(
|
|
40
|
+
input: InferFilters<TSchema>,
|
|
41
|
+
options?: ISearchOptions<TSchema>,
|
|
42
|
+
): Promise<PermissionValidator> {
|
|
43
|
+
return PermissionValidator.create().someOf([
|
|
44
|
+
this.service.getDescriptor('search', '*').toString(),
|
|
45
|
+
this.service.getDescriptor('read', '*').toString(),
|
|
46
|
+
])
|
|
47
|
+
}
|
|
48
|
+
|
|
33
49
|
async search(
|
|
34
50
|
input: InferFilters<TSchema>,
|
|
35
51
|
options?: ISearchOptions<TSchema>,
|
|
36
52
|
): Promise<InferSearchResults<TSchema>> {
|
|
37
|
-
this.
|
|
38
|
-
|
|
39
|
-
this.service.getDescriptor('search', '*').toString(),
|
|
40
|
-
this.service.getDescriptor('read', '*').toString(),
|
|
41
|
-
]),
|
|
42
|
-
)
|
|
53
|
+
const permissions = await this.searchPermissions(input, options)
|
|
54
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
43
55
|
return this.service.search(input, options)
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
async countPermissions(
|
|
59
|
+
input: InferFilters<TSchema>,
|
|
60
|
+
options?: ISearchOptions<TSchema>,
|
|
61
|
+
): Promise<PermissionValidator> {
|
|
62
|
+
return PermissionValidator.create().someOf([
|
|
63
|
+
this.service.getDescriptor('count', '*').toString(),
|
|
64
|
+
this.service.getDescriptor('read', '*').toString(),
|
|
65
|
+
])
|
|
66
|
+
}
|
|
67
|
+
|
|
46
68
|
/**
|
|
47
69
|
* Count the number of records matching the given filters.
|
|
48
70
|
* @param input The filters to apply to the count operation.
|
|
@@ -50,12 +72,8 @@ export class ReadOnlyModelController<TSchema extends AnyModelSchema> {
|
|
|
50
72
|
* @returns The count of matching records.
|
|
51
73
|
*/
|
|
52
74
|
async count(input: InferFilters<TSchema>, options?: ISearchOptions<TSchema>): Promise<number> {
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
this.service.getDescriptor('count', '*').toString(),
|
|
56
|
-
this.service.getDescriptor('read', '*').toString(),
|
|
57
|
-
]),
|
|
58
|
-
)
|
|
75
|
+
const permissions = await this.countPermissions(input, options)
|
|
76
|
+
this.authValidator.validatePermissions((v) => v.extend(permissions))
|
|
59
77
|
return this.service.count(input, options)
|
|
60
78
|
}
|
|
61
79
|
}
|