@expo/entity 0.26.1 → 0.28.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/LICENSE +21 -0
- package/build/ComposedEntityCacheAdapter.d.ts +1 -1
- package/build/ComposedEntityCacheAdapter.js +1 -1
- package/build/ComposedSecondaryEntityCache.d.ts +1 -1
- package/build/ComposedSecondaryEntityCache.js +1 -1
- package/build/EnforcingEntityLoader.d.ts +10 -10
- package/build/EnforcingEntityLoader.js +8 -8
- package/build/EnforcingEntityLoader.js.map +1 -1
- package/build/Entity.d.ts +5 -5
- package/build/Entity.js +5 -5
- package/build/EntityAssociationLoader.d.ts +4 -4
- package/build/EntityCacheAdapter.d.ts +1 -1
- package/build/EntityCompanion.d.ts +1 -1
- package/build/EntityCompanion.js +1 -1
- package/build/EntityCompanionProvider.d.ts +9 -9
- package/build/EntityCompanionProvider.js +3 -3
- package/build/EntityConfiguration.d.ts +2 -2
- package/build/EntityDatabaseAdapter.d.ts +25 -6
- package/build/EntityDatabaseAdapter.js +8 -2
- package/build/EntityDatabaseAdapter.js.map +1 -1
- package/build/EntityFieldDefinition.d.ts +2 -2
- package/build/EntityFields.d.ts +9 -22
- package/build/EntityFields.js +10 -29
- package/build/EntityFields.js.map +1 -1
- package/build/EntityLoader.d.ts +10 -10
- package/build/EntityLoader.js +8 -8
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityMutationTriggerConfiguration.d.ts +1 -1
- package/build/EntityMutationTriggerConfiguration.js +1 -1
- package/build/EntityMutator.d.ts +1 -1
- package/build/EntityMutator.js +1 -1
- package/build/EntityPrivacyPolicy.d.ts +6 -6
- package/build/EntityPrivacyPolicy.js +6 -6
- package/build/EntityQueryContext.d.ts +23 -3
- package/build/EntityQueryContext.js +43 -6
- package/build/EntityQueryContext.js.map +1 -1
- package/build/EntityQueryContextProvider.d.ts +10 -2
- package/build/EntityQueryContextProvider.js +18 -1
- package/build/EntityQueryContextProvider.js.map +1 -1
- package/build/EntitySecondaryCacheLoader.d.ts +1 -1
- package/build/EntitySecondaryCacheLoader.js +1 -1
- package/build/GenericSecondaryEntityCache.d.ts +1 -1
- package/build/GenericSecondaryEntityCache.js +1 -1
- package/build/ReadonlyEntity.d.ts +1 -1
- package/build/ReadonlyEntity.js +1 -1
- package/build/ViewerContext.d.ts +2 -2
- package/build/ViewerContext.js +2 -2
- package/build/ViewerScopedEntityCompanion.d.ts +2 -2
- package/build/ViewerScopedEntityCompanion.js +2 -2
- package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
- package/build/ViewerScopedEntityLoaderFactory.js +1 -1
- package/build/ViewerScopedEntityMutatorFactory.d.ts +1 -1
- package/build/ViewerScopedEntityMutatorFactory.js +1 -1
- package/build/__tests__/EntityFields-test.js +0 -4
- package/build/__tests__/EntityFields-test.js.map +1 -1
- package/build/__tests__/EntityQueryContext-test.js +39 -0
- package/build/__tests__/EntityQueryContext-test.js.map +1 -1
- package/build/internal/EntityDataManager.d.ts +5 -5
- package/build/internal/EntityDataManager.js +3 -3
- package/build/internal/EntityDataManager.js.map +1 -1
- package/build/internal/ReadThroughEntityCache.d.ts +2 -2
- package/build/internal/ReadThroughEntityCache.js +2 -2
- package/build/metrics/IEntityMetricsAdapter.d.ts +10 -10
- package/build/rules/PrivacyPolicyRule.d.ts +1 -1
- package/build/rules/PrivacyPolicyRule.js +1 -1
- package/build/utils/collections/maps.d.ts +1 -1
- package/build/utils/collections/maps.js +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -2
- package/build/utils/testing/StubQueryContextProvider.d.ts +2 -1
- package/build/utils/testing/StubQueryContextProvider.js +5 -0
- package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
- package/package.json +3 -2
- package/src/ComposedEntityCacheAdapter.ts +1 -1
- package/src/ComposedSecondaryEntityCache.ts +1 -1
- package/src/EnforcingEntityLoader.ts +14 -10
- package/src/Entity.ts +5 -5
- package/src/EntityAssociationLoader.ts +4 -4
- package/src/EntityCacheAdapter.ts +1 -1
- package/src/EntityCompanion.ts +1 -1
- package/src/EntityCompanionProvider.ts +9 -9
- package/src/EntityConfiguration.ts +2 -2
- package/src/EntityDatabaseAdapter.ts +43 -6
- package/src/EntityFieldDefinition.ts +2 -2
- package/src/EntityFields.ts +9 -28
- package/src/EntityLoader.ts +10 -9
- package/src/EntityMutationTriggerConfiguration.ts +1 -1
- package/src/EntityMutator.ts +1 -1
- package/src/EntityPrivacyPolicy.ts +6 -6
- package/src/EntityQueryContext.ts +63 -3
- package/src/EntityQueryContextProvider.ts +34 -2
- package/src/EntitySecondaryCacheLoader.ts +1 -1
- package/src/GenericSecondaryEntityCache.ts +1 -1
- package/src/ReadonlyEntity.ts +1 -1
- package/src/ViewerContext.ts +2 -2
- package/src/ViewerScopedEntityCompanion.ts +2 -2
- package/src/ViewerScopedEntityLoaderFactory.ts +1 -1
- package/src/ViewerScopedEntityMutatorFactory.ts +1 -1
- package/src/__tests__/EntityFields-test.ts +0 -12
- package/src/__tests__/EntityQueryContext-test.ts +50 -0
- package/src/internal/EntityDataManager.ts +5 -4
- package/src/internal/ReadThroughEntityCache.ts +2 -2
- package/src/metrics/IEntityMetricsAdapter.ts +10 -10
- package/src/rules/PrivacyPolicyRule.ts +1 -1
- package/src/utils/collections/maps.ts +1 -1
- package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +1 -1
- package/src/utils/testing/StubQueryContextProvider.ts +7 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StubQueryContextProvider.js","sourceRoot":"","sources":["../../../src/utils/testing/StubQueryContextProvider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StubQueryContextProvider.js","sourceRoot":"","sources":["../../../src/utils/testing/StubQueryContextProvider.ts"],"names":[],"mappings":";;;;;;AAAA,kGAA0E;AAE1E,MAAa,wBAAyB,SAAQ,oCAA0B;IAC5D,iBAAiB;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAES,uBAAuB;QAG/B,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;IAES,6BAA6B,CACrC,oBAAyB;QAEzB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;CACF;AAhBD,4DAgBC;AAED,kBAAe,IAAI,wBAAwB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/entity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "A privacy-first data model",
|
|
5
5
|
"files": [
|
|
6
6
|
"build",
|
|
@@ -32,5 +32,6 @@
|
|
|
32
32
|
"es6-error": "^4.1.1",
|
|
33
33
|
"invariant": "^2.2.4",
|
|
34
34
|
"uuid": "^8.3.0"
|
|
35
|
-
}
|
|
35
|
+
},
|
|
36
|
+
"gitHead": "dbf1e030394d1f2bdf58d858cb455be9136a1b14"
|
|
36
37
|
}
|
|
@@ -5,7 +5,7 @@ import EntityConfiguration from './EntityConfiguration';
|
|
|
5
5
|
import { CacheStatus, CacheLoadResult } from './internal/ReadThroughEntityCache';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* A
|
|
8
|
+
* A EntityCacheAdapter that composes other EntityCacheAdapter instances.
|
|
9
9
|
*/
|
|
10
10
|
export default class ComposedEntityCacheAdapter<TFields> extends EntityCacheAdapter<TFields> {
|
|
11
11
|
/**
|
|
@@ -3,7 +3,7 @@ import nullthrows from 'nullthrows';
|
|
|
3
3
|
import { ISecondaryEntityCache } from './EntitySecondaryCacheLoader';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A
|
|
6
|
+
* A ISecondaryEntityCache that composes other ISecondaryEntityCache instances.
|
|
7
7
|
*/
|
|
8
8
|
export default class ComposedSecondaryEntityCache<TLoadParams, TFields>
|
|
9
9
|
implements ISecondaryEntityCache<TFields, TLoadParams>
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
FieldEqualityCondition,
|
|
3
|
+
QuerySelectionModifiers,
|
|
4
|
+
QuerySelectionModifiersWithOrderByRaw,
|
|
5
|
+
} from './EntityDatabaseAdapter';
|
|
2
6
|
import EntityLoader from './EntityLoader';
|
|
3
7
|
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
4
8
|
import ReadonlyEntity from './ReadonlyEntity';
|
|
@@ -36,7 +40,7 @@ export default class EnforcingEntityLoader<
|
|
|
36
40
|
|
|
37
41
|
/**
|
|
38
42
|
* Enforcing version of entity loader method by the same name.
|
|
39
|
-
* @throws
|
|
43
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
40
44
|
*/
|
|
41
45
|
async loadManyByFieldEqualingManyAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
42
46
|
fieldName: N,
|
|
@@ -53,7 +57,7 @@ export default class EnforcingEntityLoader<
|
|
|
53
57
|
|
|
54
58
|
/**
|
|
55
59
|
* Enforcing version of entity loader method by the same name.
|
|
56
|
-
* @throws
|
|
60
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
57
61
|
*/
|
|
58
62
|
async loadManyByFieldEqualingAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
59
63
|
fieldName: N,
|
|
@@ -68,7 +72,7 @@ export default class EnforcingEntityLoader<
|
|
|
68
72
|
|
|
69
73
|
/**
|
|
70
74
|
* Enforcing version of entity loader method by the same name.
|
|
71
|
-
* @throws
|
|
75
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view the returned entity
|
|
72
76
|
* @throws when multiple entities are found matching the condition
|
|
73
77
|
*/
|
|
74
78
|
async loadByFieldEqualingAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
@@ -84,7 +88,7 @@ export default class EnforcingEntityLoader<
|
|
|
84
88
|
|
|
85
89
|
/**
|
|
86
90
|
* Enforcing version of entity loader method by the same name.
|
|
87
|
-
* @throws
|
|
91
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view the returned entity
|
|
88
92
|
*/
|
|
89
93
|
async loadByIDAsync(id: TID): Promise<TEntity> {
|
|
90
94
|
const entityResult = await this.entityLoader.loadByIDAsync(id);
|
|
@@ -93,7 +97,7 @@ export default class EnforcingEntityLoader<
|
|
|
93
97
|
|
|
94
98
|
/**
|
|
95
99
|
* Enforcing version of entity loader method by the same name.
|
|
96
|
-
* @throws
|
|
100
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view the returned entity
|
|
97
101
|
* @throws when multiple entities are found matching the condition
|
|
98
102
|
*/
|
|
99
103
|
async loadByIDNullableAsync(id: TID): Promise<TEntity | null> {
|
|
@@ -103,7 +107,7 @@ export default class EnforcingEntityLoader<
|
|
|
103
107
|
|
|
104
108
|
/**
|
|
105
109
|
* Enforcing version of entity loader method by the same name.
|
|
106
|
-
* @throws
|
|
110
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
107
111
|
*/
|
|
108
112
|
async loadManyByIDsAsync(ids: readonly TID[]): Promise<ReadonlyMap<TID, TEntity>> {
|
|
109
113
|
const entityResults = await this.entityLoader.loadManyByIDsAsync(ids);
|
|
@@ -112,7 +116,7 @@ export default class EnforcingEntityLoader<
|
|
|
112
116
|
|
|
113
117
|
/**
|
|
114
118
|
* Enforcing version of entity loader method by the same name.
|
|
115
|
-
* @throws
|
|
119
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
116
120
|
*/
|
|
117
121
|
async loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
118
122
|
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
|
|
@@ -127,12 +131,12 @@ export default class EnforcingEntityLoader<
|
|
|
127
131
|
|
|
128
132
|
/**
|
|
129
133
|
* Enforcing version of entity loader method by the same name.
|
|
130
|
-
* @throws
|
|
134
|
+
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
131
135
|
*/
|
|
132
136
|
async loadManyByRawWhereClauseAsync(
|
|
133
137
|
rawWhereClause: string,
|
|
134
138
|
bindings: any[] | object,
|
|
135
|
-
querySelectionModifiers:
|
|
139
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {}
|
|
136
140
|
): Promise<readonly TEntity[]> {
|
|
137
141
|
const entityResults = await this.entityLoader.loadManyByRawWhereClauseAsync(
|
|
138
142
|
rawWhereClause,
|
package/src/Entity.ts
CHANGED
|
@@ -11,19 +11,19 @@ import ViewerContext from './ViewerContext';
|
|
|
11
11
|
* Entity is a privacy-first data model.
|
|
12
12
|
*
|
|
13
13
|
* A instance of an entity represents a single "row" of persisted data in a database that a
|
|
14
|
-
* viewer, represented by the corresponding
|
|
14
|
+
* viewer, represented by the corresponding ViewerContext, has permission to read.
|
|
15
15
|
*
|
|
16
16
|
* Create, read, update, and delete permissions for an entity are declaratively defined using an
|
|
17
|
-
*
|
|
17
|
+
* EntityPrivacyPolicy.
|
|
18
18
|
*
|
|
19
|
-
* Entites are loaded through an
|
|
19
|
+
* Entites are loaded through an EntityLoader, which is responsible for
|
|
20
20
|
* orchestrating fetching, caching, and authorization of reading "rows".
|
|
21
21
|
*
|
|
22
|
-
* Entities are mutated and deleted through an
|
|
22
|
+
* Entities are mutated and deleted through an EntityMutator, which is responsible for
|
|
23
23
|
* orchestrating database writes, cache invalidation, and authorization of writing "rows".
|
|
24
24
|
*
|
|
25
25
|
* All concrete entity implementations should extend this class and provide their
|
|
26
|
-
* own
|
|
26
|
+
* own EntityCompanionDefinition.
|
|
27
27
|
*/
|
|
28
28
|
export default abstract class Entity<
|
|
29
29
|
TFields,
|
|
@@ -251,7 +251,7 @@ export default class EntityAssociationLoader<
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
/**
|
|
254
|
-
* Load an associated entity by folding a sequence of
|
|
254
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
255
255
|
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
256
256
|
* @param loadDirectives - associated entity load directives instructing each step of the fold
|
|
257
257
|
* @param queryContext - query context in which to perform the loads
|
|
@@ -285,7 +285,7 @@ export default class EntityAssociationLoader<
|
|
|
285
285
|
): Promise<Result<TEntity2> | null>;
|
|
286
286
|
|
|
287
287
|
/**
|
|
288
|
-
* Load an associated entity by folding a sequence of
|
|
288
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
289
289
|
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
290
290
|
* @param loadDirectives - associated entity load directives instructing each step of the fold
|
|
291
291
|
* @param queryContext - query context in which to perform the loads
|
|
@@ -340,7 +340,7 @@ export default class EntityAssociationLoader<
|
|
|
340
340
|
): Promise<Result<TEntity3> | null>;
|
|
341
341
|
|
|
342
342
|
/**
|
|
343
|
-
* Load an associated entity by folding a sequence of
|
|
343
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
344
344
|
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
345
345
|
* @param loadDirectives - associated entity load directives instructing each step of the fold
|
|
346
346
|
* @param queryContext - query context in which to perform the loads
|
|
@@ -416,7 +416,7 @@ export default class EntityAssociationLoader<
|
|
|
416
416
|
): Promise<Result<TEntity4> | null>;
|
|
417
417
|
|
|
418
418
|
/**
|
|
419
|
-
* Load an associated entity by folding a sequence of
|
|
419
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
420
420
|
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
421
421
|
* @param loadDirectives - associated entity load directives instructing each step of the fold
|
|
422
422
|
* @param queryContext - query context in which to perform the loads
|
|
@@ -32,7 +32,7 @@ export default abstract class EntityCacheAdapter<TFields> {
|
|
|
32
32
|
/**
|
|
33
33
|
* Negatively cache objects that could not be found in the cache or DB.
|
|
34
34
|
* @param fieldName - object field being queried
|
|
35
|
-
* @param fieldValues - fieldValues for objects reported as
|
|
35
|
+
* @param fieldValues - fieldValues for objects reported as CacheStatus.NEGATIVE
|
|
36
36
|
* in the cache and not found in the DB.
|
|
37
37
|
*/
|
|
38
38
|
public abstract cacheDBMissesAsync<N extends keyof TFields>(
|
package/src/EntityCompanion.ts
CHANGED
|
@@ -132,7 +132,7 @@ export default class EntityCompanion<
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
* Get the
|
|
135
|
+
* Get the IEntityMetricsAdapter for this companion.
|
|
136
136
|
*/
|
|
137
137
|
getMetricsAdapter(): IEntityMetricsAdapter {
|
|
138
138
|
return this.metricsAdapter;
|
|
@@ -109,15 +109,15 @@ export class EntityCompanionDefinition<
|
|
|
109
109
|
TSelectedFields
|
|
110
110
|
>;
|
|
111
111
|
/**
|
|
112
|
-
* The
|
|
112
|
+
* The EntityConfiguration for this entity.
|
|
113
113
|
*/
|
|
114
114
|
entityConfiguration: EntityConfiguration<TFields>;
|
|
115
115
|
/**
|
|
116
|
-
* The
|
|
116
|
+
* The EntityPrivacyPolicy class for this entity.
|
|
117
117
|
*/
|
|
118
118
|
privacyPolicyClass: IPrivacyPolicyClass<TPrivacyPolicy>;
|
|
119
119
|
/**
|
|
120
|
-
* An optional list of
|
|
120
|
+
* An optional list of EntityMutationValidator for this entity.
|
|
121
121
|
*/
|
|
122
122
|
mutationValidators?: () => EntityMutationValidator<
|
|
123
123
|
TFields,
|
|
@@ -127,7 +127,7 @@ export class EntityCompanionDefinition<
|
|
|
127
127
|
TSelectedFields
|
|
128
128
|
>[];
|
|
129
129
|
/**
|
|
130
|
-
* An optional list of
|
|
130
|
+
* An optional list of EntityMutationTrigger for this entity.
|
|
131
131
|
*/
|
|
132
132
|
mutationTriggers?: () => EntityMutationTriggerConfiguration<
|
|
133
133
|
TFields,
|
|
@@ -137,8 +137,8 @@ export class EntityCompanionDefinition<
|
|
|
137
137
|
TSelectedFields
|
|
138
138
|
>;
|
|
139
139
|
/**
|
|
140
|
-
* An optional subset of fields defined in the
|
|
141
|
-
* For use when multiple types of entities are backed by a single table (
|
|
140
|
+
* An optional subset of fields defined in the EntityConfiguration which belong to this entity.
|
|
141
|
+
* For use when multiple types of entities are backed by a single table (EntityConfiguration) yet
|
|
142
142
|
* only expose a subset of the fields.
|
|
143
143
|
*/
|
|
144
144
|
entitySelectedFields?: TSelectedFields[];
|
|
@@ -155,11 +155,11 @@ export class EntityCompanionDefinition<
|
|
|
155
155
|
/**
|
|
156
156
|
* An instance of the Entity framework.
|
|
157
157
|
*
|
|
158
|
-
* Required to create a
|
|
158
|
+
* Required to create a ViewerContext, which is the application entry point
|
|
159
159
|
* into the framework.
|
|
160
160
|
*
|
|
161
161
|
* Internally, this is a lazy entity companion factory that instantiates and caches one
|
|
162
|
-
*
|
|
162
|
+
* EntityCompanion for each type of Entity.
|
|
163
163
|
*/
|
|
164
164
|
export default class EntityCompanionProvider {
|
|
165
165
|
private readonly companionMap: Map<string, EntityCompanion<any, any, any, any, any, any>> =
|
|
@@ -169,7 +169,7 @@ export default class EntityCompanionProvider {
|
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
171
|
* Instantiate an Entity framework.
|
|
172
|
-
* @param metricsAdapter - An
|
|
172
|
+
* @param metricsAdapter - An IEntityMetricsAdapter for collecting metrics on this instance
|
|
173
173
|
* @param databaseAdapterFlavors - Database adapter configurations for this instance
|
|
174
174
|
* @param cacheAdapterFlavors - Cache adapter configurations for this instance
|
|
175
175
|
*/
|
|
@@ -41,12 +41,12 @@ export default class EntityConfiguration<TFields> {
|
|
|
41
41
|
tableName: string;
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Map from each entity field to an
|
|
44
|
+
* Map from each entity field to an EntityFieldDefinition specifying information about the field.
|
|
45
45
|
*/
|
|
46
46
|
schema: Record<keyof TFields, EntityFieldDefinition<any>>;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* List of other entity types that reference this type in
|
|
49
|
+
* List of other entity types that reference this type in EntityFieldDefinition associations.
|
|
50
50
|
*/
|
|
51
51
|
getInboundEdges?: () => IEntityClass<any, any, any, any, any, any>[];
|
|
52
52
|
|
|
@@ -7,16 +7,32 @@ import {
|
|
|
7
7
|
FieldTransformerMap,
|
|
8
8
|
} from './internal/EntityFieldTransformationUtils';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Equality operand that is used for selecting entities with a field with a single value.
|
|
12
|
+
*/
|
|
13
|
+
export interface SingleValueFieldEqualityCondition<
|
|
14
|
+
TFields,
|
|
15
|
+
N extends keyof TFields = keyof TFields
|
|
16
|
+
> {
|
|
11
17
|
fieldName: N;
|
|
12
18
|
fieldValue: TFields[N];
|
|
13
19
|
}
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Equality operand that is used for selecting entities with a field matching one of multiple values.
|
|
23
|
+
*/
|
|
24
|
+
export interface MultiValueFieldEqualityCondition<
|
|
25
|
+
TFields,
|
|
26
|
+
N extends keyof TFields = keyof TFields
|
|
27
|
+
> {
|
|
16
28
|
fieldName: N;
|
|
17
29
|
fieldValues: readonly TFields[N][];
|
|
18
30
|
}
|
|
19
31
|
|
|
32
|
+
/**
|
|
33
|
+
* A single equality operand for use in a selection clause.
|
|
34
|
+
* See EntityLoader.loadManyByFieldEqualityConjunctionAsync documentation for examples.
|
|
35
|
+
*/
|
|
20
36
|
export type FieldEqualityCondition<TFields, N extends keyof TFields = keyof TFields> =
|
|
21
37
|
| SingleValueFieldEqualityCondition<TFields, N>
|
|
22
38
|
| MultiValueFieldEqualityCondition<TFields, N>;
|
|
@@ -68,6 +84,14 @@ export interface QuerySelectionModifiers<TFields> {
|
|
|
68
84
|
limit?: number;
|
|
69
85
|
}
|
|
70
86
|
|
|
87
|
+
export interface QuerySelectionModifiersWithOrderByRaw<TFields>
|
|
88
|
+
extends QuerySelectionModifiers<TFields> {
|
|
89
|
+
/**
|
|
90
|
+
* Order the entities by a raw SQL `ORDER BY` clause.
|
|
91
|
+
*/
|
|
92
|
+
orderByRaw?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
71
95
|
export interface TableQuerySelectionModifiers {
|
|
72
96
|
orderBy:
|
|
73
97
|
| {
|
|
@@ -79,6 +103,10 @@ export interface TableQuerySelectionModifiers {
|
|
|
79
103
|
limit: number | undefined;
|
|
80
104
|
}
|
|
81
105
|
|
|
106
|
+
export interface TableQuerySelectionModifiersWithOrderByRaw extends TableQuerySelectionModifiers {
|
|
107
|
+
orderByRaw: string | undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
82
110
|
/**
|
|
83
111
|
* A database adapter is an interface by which entity objects can be
|
|
84
112
|
* fetched, inserted, updated, and deleted from a database. This base class
|
|
@@ -149,7 +177,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
|
|
|
149
177
|
*
|
|
150
178
|
* @param queryContext - query context with which to perform the fetch
|
|
151
179
|
* @param fieldEqualityOperands - list of field equality where clause operand specifications
|
|
152
|
-
* @param querySelectionModifiers - limit, offset, and
|
|
180
|
+
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
|
|
153
181
|
* @returns array of objects matching the query
|
|
154
182
|
*/
|
|
155
183
|
async fetchManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(
|
|
@@ -207,14 +235,14 @@ export default abstract class EntityDatabaseAdapter<TFields> {
|
|
|
207
235
|
queryContext: EntityQueryContext,
|
|
208
236
|
rawWhereClause: string,
|
|
209
237
|
bindings: any[] | object,
|
|
210
|
-
querySelectionModifiers:
|
|
238
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>
|
|
211
239
|
): Promise<readonly Readonly<TFields>[]> {
|
|
212
240
|
const results = await this.fetchManyByRawWhereClauseInternalAsync(
|
|
213
241
|
queryContext.getQueryInterface(),
|
|
214
242
|
this.entityConfiguration.tableName,
|
|
215
243
|
rawWhereClause,
|
|
216
244
|
bindings,
|
|
217
|
-
this.
|
|
245
|
+
this.convertToTableQueryModifiersWithOrderByRaw(querySelectionModifiers)
|
|
218
246
|
);
|
|
219
247
|
|
|
220
248
|
return results.map((result) =>
|
|
@@ -227,7 +255,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
|
|
|
227
255
|
tableName: string,
|
|
228
256
|
rawWhereClause: string,
|
|
229
257
|
bindings: any[] | object,
|
|
230
|
-
querySelectionModifiers:
|
|
258
|
+
querySelectionModifiers: TableQuerySelectionModifiersWithOrderByRaw
|
|
231
259
|
): Promise<object[]>;
|
|
232
260
|
|
|
233
261
|
/**
|
|
@@ -363,6 +391,15 @@ export default abstract class EntityDatabaseAdapter<TFields> {
|
|
|
363
391
|
id: any
|
|
364
392
|
): Promise<number>;
|
|
365
393
|
|
|
394
|
+
private convertToTableQueryModifiersWithOrderByRaw(
|
|
395
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>
|
|
396
|
+
): TableQuerySelectionModifiersWithOrderByRaw {
|
|
397
|
+
return {
|
|
398
|
+
...this.convertToTableQueryModifiers(querySelectionModifiers),
|
|
399
|
+
orderByRaw: querySelectionModifiers.orderByRaw,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
366
403
|
private convertToTableQueryModifiers(
|
|
367
404
|
querySelectionModifiers: QuerySelectionModifiers<TFields>
|
|
368
405
|
): TableQuerySelectionModifiers {
|
|
@@ -87,8 +87,8 @@ export interface EntityAssociationDefinition<
|
|
|
87
87
|
* application requirements, and sometimes even a mix-and-match is the right choice.
|
|
88
88
|
*
|
|
89
89
|
* - If referential integrity is critical to your application, database foreign key constraints
|
|
90
|
-
* combined with
|
|
91
|
-
*
|
|
90
|
+
* combined with EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY or
|
|
91
|
+
* EntityEdgeDeletionBehavior.SET_NULL_INVALIDATE_CACHE_ONLY are recommended.
|
|
92
92
|
* - If the database being used doesn't support foreign keys, then using the entity framework for referential
|
|
93
93
|
* integrity is recommended.
|
|
94
94
|
*/
|
package/src/EntityFields.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { validate as validateUUID } from 'uuid';
|
|
|
3
3
|
import { EntityFieldDefinition } from './EntityFieldDefinition';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* EntityFieldDefinition for a column with a JS string type.
|
|
7
7
|
*/
|
|
8
8
|
export class StringField extends EntityFieldDefinition<string> {
|
|
9
9
|
protected validateInputValueInternal(value: string): boolean {
|
|
@@ -12,7 +12,7 @@ export class StringField extends EntityFieldDefinition<string> {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* EntityFieldDefinition for a column with a JS string type.
|
|
16
16
|
* Enforces that the string is a valid UUID.
|
|
17
17
|
*/
|
|
18
18
|
export class UUIDField extends StringField {
|
|
@@ -22,7 +22,7 @@ export class UUIDField extends StringField {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* EntityFieldDefinition for a column with a JS Date type.
|
|
26
26
|
*/
|
|
27
27
|
export class DateField extends EntityFieldDefinition<Date> {
|
|
28
28
|
protected validateInputValueInternal(value: Date): boolean {
|
|
@@ -31,7 +31,7 @@ export class DateField extends EntityFieldDefinition<Date> {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* EntityFieldDefinition for a column with a JS boolean type.
|
|
35
35
|
*/
|
|
36
36
|
export class BooleanField extends EntityFieldDefinition<boolean> {
|
|
37
37
|
protected validateInputValueInternal(value: boolean): boolean {
|
|
@@ -40,7 +40,7 @@ export class BooleanField extends EntityFieldDefinition<boolean> {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* EntityFieldDefinition for a column with a JS number type.
|
|
44
44
|
* Enforces that the number is an integer.
|
|
45
45
|
*/
|
|
46
46
|
export class IntField extends EntityFieldDefinition<number> {
|
|
@@ -50,7 +50,7 @@ export class IntField extends EntityFieldDefinition<number> {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* EntityFieldDefinition for a column with a JS number type.
|
|
54
54
|
* Enforces that the number is a float (which includes integers in JS).
|
|
55
55
|
*/
|
|
56
56
|
export class FloatField extends EntityFieldDefinition<number> {
|
|
@@ -60,7 +60,7 @@ export class FloatField extends EntityFieldDefinition<number> {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* EntityFieldDefinition for a column with a JS string array type.
|
|
64
64
|
* Enforces that every member of the string array is a string.
|
|
65
65
|
*/
|
|
66
66
|
export class StringArrayField extends EntityFieldDefinition<string[]> {
|
|
@@ -70,7 +70,7 @@ export class StringArrayField extends EntityFieldDefinition<string[]> {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* EntityFieldDefinition for a column with a JS JSON object type.
|
|
74
74
|
*/
|
|
75
75
|
export class JSONObjectField extends EntityFieldDefinition<object> {
|
|
76
76
|
protected validateInputValueInternal(value: object): boolean {
|
|
@@ -79,29 +79,10 @@ export class JSONObjectField extends EntityFieldDefinition<object> {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
82
|
+
* EntityFieldDefinition for a enum column with a JS string or number type.
|
|
83
83
|
*/
|
|
84
84
|
export class EnumField extends EntityFieldDefinition<string | number> {
|
|
85
85
|
protected validateInputValueInternal(value: string | number): boolean {
|
|
86
86
|
return typeof value === 'number' || typeof value === 'string';
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* {@link EntityFieldDefinition} for a column with a JS JSON array type.
|
|
92
|
-
*/
|
|
93
|
-
export class JSONArrayField extends EntityFieldDefinition<any[]> {
|
|
94
|
-
protected validateInputValueInternal(value: any[]): boolean {
|
|
95
|
-
return Array.isArray(value);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* {@link EntityFieldDefinition} for a column that may be a JS JSON array type.
|
|
101
|
-
* Does not do any validation.
|
|
102
|
-
*/
|
|
103
|
-
export class MaybeJSONArrayField extends EntityFieldDefinition<any | any[]> {
|
|
104
|
-
protected validateInputValueInternal(_value: any): boolean {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
}
|
package/src/EntityLoader.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
FieldEqualityCondition,
|
|
9
9
|
QuerySelectionModifiers,
|
|
10
10
|
isSingleValueFieldEqualityCondition,
|
|
11
|
+
QuerySelectionModifiersWithOrderByRaw,
|
|
11
12
|
} from './EntityDatabaseAdapter';
|
|
12
13
|
import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
|
|
13
14
|
import { EntityQueryContext } from './EntityQueryContext';
|
|
@@ -21,7 +22,7 @@ import { mapMap, mapMapAsync } from './utils/collections/maps';
|
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* The primary interface for loading entities. All normal loads are batched,
|
|
24
|
-
* cached, and authorized against the entity's
|
|
25
|
+
* cached, and authorized against the entity's EntityPrivacyPolicy.
|
|
25
26
|
*/
|
|
26
27
|
export default class EntityLoader<
|
|
27
28
|
TFields,
|
|
@@ -182,16 +183,16 @@ export default class EntityLoader<
|
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
/**
|
|
185
|
-
* Loads many entities matching the
|
|
186
|
+
* Loads many entities matching the selection constructed from the conjunction of specified operands.
|
|
186
187
|
* Entities loaded using this method are not batched or cached.
|
|
187
188
|
*
|
|
188
189
|
* @example
|
|
189
190
|
* fieldEqualityOperands:
|
|
190
191
|
* `[{fieldName: 'hello', fieldValue: 1}, {fieldName: 'world', fieldValues: [2, 3]}]`
|
|
191
|
-
* Entities returned:
|
|
192
|
+
* Entities returned with a SQL EntityDatabaseAdapter:
|
|
192
193
|
* `WHERE hello = 1 AND world = ANY({2, 3})`
|
|
193
194
|
*
|
|
194
|
-
* @param fieldEqualityOperands - list of field equality
|
|
195
|
+
* @param fieldEqualityOperands - list of field equality selection operand specifications
|
|
195
196
|
* @param querySelectionModifiers - limit, offset, and orderBy for the query
|
|
196
197
|
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
197
198
|
*/
|
|
@@ -244,12 +245,12 @@ export default class EntityLoader<
|
|
|
244
245
|
* bindings: `[1]`
|
|
245
246
|
* Entites returned `WHERE id = 1`
|
|
246
247
|
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
248
|
+
* http://knexjs.org/#Builder-whereRaw
|
|
249
|
+
* http://knexjs.org/#Raw-Bindings
|
|
249
250
|
*
|
|
250
251
|
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
251
252
|
* @param bindings - array of positional bindings or object of named bindings
|
|
252
|
-
* @param querySelectionModifiers - limit, offset, and
|
|
253
|
+
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
|
|
253
254
|
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
254
255
|
* @throws Error when rawWhereClause or bindings are invalid
|
|
255
256
|
*
|
|
@@ -258,7 +259,7 @@ export default class EntityLoader<
|
|
|
258
259
|
async loadManyByRawWhereClauseAsync(
|
|
259
260
|
rawWhereClause: string,
|
|
260
261
|
bindings: any[] | object,
|
|
261
|
-
querySelectionModifiers:
|
|
262
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {}
|
|
262
263
|
): Promise<readonly Result<TEntity>[]> {
|
|
263
264
|
const fieldObjects = await this.dataManager.loadManyByRawWhereClauseAsync(
|
|
264
265
|
this.queryContext,
|
|
@@ -286,7 +287,7 @@ export default class EntityLoader<
|
|
|
286
287
|
}
|
|
287
288
|
|
|
288
289
|
/**
|
|
289
|
-
* Invalidate all caches for an entity's fields. Exposed primarily for internal use by
|
|
290
|
+
* Invalidate all caches for an entity's fields. Exposed primarily for internal use by EntityMutator.
|
|
290
291
|
* @param objectFields - entity data object to be invalidated
|
|
291
292
|
*/
|
|
292
293
|
async invalidateFieldsAsync(objectFields: Readonly<TFields>): Promise<void> {
|
|
@@ -85,7 +85,7 @@ export abstract class EntityMutationTrigger<
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* A non-transactional trigger is like a
|
|
88
|
+
* A non-transactional trigger is like a EntityMutationTrigger but used for afterCommit triggers
|
|
89
89
|
* since they explicitly occur outside of the transaction.
|
|
90
90
|
*/
|
|
91
91
|
export abstract class EntityNonTransactionalMutationTrigger<
|
package/src/EntityMutator.ts
CHANGED
|
@@ -700,7 +700,7 @@ export class DeleteMutator<
|
|
|
700
700
|
/**
|
|
701
701
|
* Finds all entities referencing the specified entity and either deletes them, nullifies
|
|
702
702
|
* their references to the specified entity, or invalidates the cache depending on the
|
|
703
|
-
*
|
|
703
|
+
* OnDeleteBehavior of the field referencing the specified entity.
|
|
704
704
|
*
|
|
705
705
|
* @remarks
|
|
706
706
|
* This works by doing reverse fan-out queries:
|
|
@@ -20,7 +20,7 @@ export type EntityPrivacyPolicyEvaluationContext = {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Evaluation mode for a
|
|
23
|
+
* Evaluation mode for a EntityPrivacyPolicy. Useful when transitioning to
|
|
24
24
|
* using Entity for privacy.
|
|
25
25
|
*/
|
|
26
26
|
export enum EntityPrivacyPolicyEvaluationMode {
|
|
@@ -75,7 +75,7 @@ export enum EntityAuthorizationAction {
|
|
|
75
75
|
*
|
|
76
76
|
* @remarks
|
|
77
77
|
*
|
|
78
|
-
* A privacy policy declares lists of
|
|
78
|
+
* A privacy policy declares lists of PrivacyPolicyRule for create, read, update, and delete actions
|
|
79
79
|
* for an entity and provides logic for authorizing an entity against rules.
|
|
80
80
|
*
|
|
81
81
|
* Evaluation of a list of rules is performed according the following example. This allows constructing of
|
|
@@ -149,7 +149,7 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
149
149
|
* @param queryContext - query context in which to perform the create authorization
|
|
150
150
|
* @param entity - entity to authorize
|
|
151
151
|
* @returns entity if authorized
|
|
152
|
-
* @throws
|
|
152
|
+
* @throws EntityNotAuthorizedError when not authorized
|
|
153
153
|
*/
|
|
154
154
|
async authorizeCreateAsync(
|
|
155
155
|
viewerContext: TViewerContext,
|
|
@@ -175,7 +175,7 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
175
175
|
* @param queryContext - query context in which to perform the read authorization
|
|
176
176
|
* @param entity - entity to authorize
|
|
177
177
|
* @returns entity if authorized
|
|
178
|
-
* @throws
|
|
178
|
+
* @throws EntityNotAuthorizedError when not authorized
|
|
179
179
|
*/
|
|
180
180
|
async authorizeReadAsync(
|
|
181
181
|
viewerContext: TViewerContext,
|
|
@@ -201,7 +201,7 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
201
201
|
* @param queryContext - query context in which to perform the update authorization
|
|
202
202
|
* @param entity - entity to authorize
|
|
203
203
|
* @returns entity if authorized
|
|
204
|
-
* @throws
|
|
204
|
+
* @throws EntityNotAuthorizedError when not authorized
|
|
205
205
|
*/
|
|
206
206
|
async authorizeUpdateAsync(
|
|
207
207
|
viewerContext: TViewerContext,
|
|
@@ -227,7 +227,7 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
227
227
|
* @param queryContext - query context in which to perform the delete authorization
|
|
228
228
|
* @param entity - entity to authorize
|
|
229
229
|
* @returns entity if authorized
|
|
230
|
-
* @throws
|
|
230
|
+
* @throws EntityNotAuthorizedError when not authorized
|
|
231
231
|
*/
|
|
232
232
|
async authorizeDeleteAsync(
|
|
233
233
|
viewerContext: TViewerContext,
|