@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
|
@@ -12,7 +12,7 @@ export type PreCommitCallback = (
|
|
|
12
12
|
* Entity framework representation of transactional and non-transactional database
|
|
13
13
|
* query execution units.
|
|
14
14
|
*
|
|
15
|
-
* The behavior of
|
|
15
|
+
* The behavior of EntityMutator and EntityLoader
|
|
16
16
|
* differs when in a transactional context.
|
|
17
17
|
*/
|
|
18
18
|
export abstract class EntityQueryContext {
|
|
@@ -31,7 +31,7 @@ export abstract class EntityQueryContext {
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Entity framework representation of a non-transactional query execution unit.
|
|
34
|
-
* When supplied to
|
|
34
|
+
* When supplied to EntityMutator and EntityLoader methods, they will be
|
|
35
35
|
* run independently of any running transaction (though mutations start their own
|
|
36
36
|
* independent transactions internally when not being run in a transaction).
|
|
37
37
|
*/
|
|
@@ -56,7 +56,7 @@ export class EntityNonTransactionalQueryContext extends EntityQueryContext {
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Entity framework representation of a transactional query execution unit. When supplied
|
|
59
|
-
* to
|
|
59
|
+
* to EntityMutator and EntityLoader methods, those methods and their
|
|
60
60
|
* dependent triggers and validators will run within the transaction.
|
|
61
61
|
*/
|
|
62
62
|
export class EntityTransactionalQueryContext extends EntityQueryContext {
|
|
@@ -65,6 +65,13 @@ export class EntityTransactionalQueryContext extends EntityQueryContext {
|
|
|
65
65
|
|
|
66
66
|
private readonly preCommitCallbacks: { callback: PreCommitCallback; order: number }[] = [];
|
|
67
67
|
|
|
68
|
+
constructor(
|
|
69
|
+
queryInterface: any,
|
|
70
|
+
private readonly entityQueryContextProvider: EntityQueryContextProvider
|
|
71
|
+
) {
|
|
72
|
+
super(queryInterface);
|
|
73
|
+
}
|
|
74
|
+
|
|
68
75
|
/**
|
|
69
76
|
* Schedule a pre-commit callback. These will be run within the transaction right before it is
|
|
70
77
|
* committed, and will be run in the order specified. Ordering of callbacks scheduled with the
|
|
@@ -129,4 +136,57 @@ export class EntityTransactionalQueryContext extends EntityQueryContext {
|
|
|
129
136
|
): Promise<T> {
|
|
130
137
|
return await transactionScope(this);
|
|
131
138
|
}
|
|
139
|
+
|
|
140
|
+
async runInNestedTransactionAsync<T>(
|
|
141
|
+
transactionScope: (innerQueryContext: EntityTransactionalQueryContext) => Promise<T>
|
|
142
|
+
): Promise<T> {
|
|
143
|
+
return await this.entityQueryContextProvider.runInNestedTransactionAsync(
|
|
144
|
+
this,
|
|
145
|
+
transactionScope
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Entity framework representation of a nested transactional query execution unit. When supplied
|
|
152
|
+
* to EntityMutator and EntityLoader methods, those methods and their
|
|
153
|
+
* dependent triggers and validators will run within the nested transaction.
|
|
154
|
+
*
|
|
155
|
+
* This exists to forward post-commit callbacks to the parent query context.
|
|
156
|
+
*/
|
|
157
|
+
export class EntityNestedTransactionalQueryContext extends EntityTransactionalQueryContext {
|
|
158
|
+
private readonly postCommitInvalidationCallbacksToTransfer: PostCommitCallback[] = [];
|
|
159
|
+
private readonly postCommitCallbacksToTransfer: PostCommitCallback[] = [];
|
|
160
|
+
|
|
161
|
+
constructor(
|
|
162
|
+
queryInterface: any,
|
|
163
|
+
private readonly parentQueryContext: EntityTransactionalQueryContext,
|
|
164
|
+
entityQueryContextProvider: EntityQueryContextProvider
|
|
165
|
+
) {
|
|
166
|
+
super(queryInterface, entityQueryContextProvider);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public override appendPostCommitCallback(callback: PostCommitCallback): void {
|
|
170
|
+
this.postCommitInvalidationCallbacksToTransfer.push(callback);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public override appendPostCommitInvalidationCallback(callback: PostCommitCallback): void {
|
|
174
|
+
this.postCommitCallbacksToTransfer.push(callback);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public override runPostCommitCallbacksAsync(): Promise<void> {
|
|
178
|
+
throw new Error(
|
|
179
|
+
'Must not call runPostCommitCallbacksAsync on EntityNestedTransactionalQueryContext'
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public transferPostCommitCallbacksToParent(): void {
|
|
184
|
+
for (const callback of this.postCommitInvalidationCallbacksToTransfer) {
|
|
185
|
+
this.parentQueryContext.appendPostCommitInvalidationCallback(callback);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
for (const callback of this.postCommitCallbacksToTransfer) {
|
|
189
|
+
this.parentQueryContext.appendPostCommitCallback(callback);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
132
192
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EntityTransactionalQueryContext,
|
|
3
3
|
EntityNonTransactionalQueryContext,
|
|
4
|
+
EntityNestedTransactionalQueryContext,
|
|
4
5
|
} from './EntityQueryContext';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -20,12 +21,16 @@ export default abstract class EntityQueryContextProvider {
|
|
|
20
21
|
protected abstract getQueryInterface(): any;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
* Vend a transaction runner for use in
|
|
24
|
+
* Vend a transaction runner for use in runInTransactionAsync.
|
|
24
25
|
*/
|
|
25
26
|
protected abstract createTransactionRunner<T>(): (
|
|
26
27
|
transactionScope: (queryInterface: any) => Promise<T>
|
|
27
28
|
) => Promise<T>;
|
|
28
29
|
|
|
30
|
+
protected abstract createNestedTransactionRunner<T>(
|
|
31
|
+
outerQueryInterface: any
|
|
32
|
+
): (transactionScope: (queryInterface: any) => Promise<T>) => Promise<T>;
|
|
33
|
+
|
|
29
34
|
/**
|
|
30
35
|
* Start a transaction and execute the provided transaction-scoped closure within the transaction.
|
|
31
36
|
* @param transactionScope - async callback to execute within the transaction
|
|
@@ -36,7 +41,7 @@ export default abstract class EntityQueryContextProvider {
|
|
|
36
41
|
const [returnedValue, queryContext] = await this.createTransactionRunner<
|
|
37
42
|
[T, EntityTransactionalQueryContext]
|
|
38
43
|
>()(async (queryInterface) => {
|
|
39
|
-
const queryContext = new EntityTransactionalQueryContext(queryInterface);
|
|
44
|
+
const queryContext = new EntityTransactionalQueryContext(queryInterface, this);
|
|
40
45
|
const result = await transactionScope(queryContext);
|
|
41
46
|
await queryContext.runPreCommitCallbacksAsync();
|
|
42
47
|
return [result, queryContext];
|
|
@@ -44,4 +49,31 @@ export default abstract class EntityQueryContextProvider {
|
|
|
44
49
|
await queryContext.runPostCommitCallbacksAsync();
|
|
45
50
|
return returnedValue;
|
|
46
51
|
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Start a nested transaction from the specified parent transaction and execure the
|
|
55
|
+
* provided nested-transaction-scoped closure within the nested transaction.
|
|
56
|
+
* @param outerQueryContext - the query context of the parent transaction
|
|
57
|
+
* @param transactionScope - async callback to execute within the nested transaction
|
|
58
|
+
*/
|
|
59
|
+
async runInNestedTransactionAsync<T>(
|
|
60
|
+
outerQueryContext: EntityTransactionalQueryContext,
|
|
61
|
+
transactionScope: (innerQueryContext: EntityNestedTransactionalQueryContext) => Promise<T>
|
|
62
|
+
): Promise<T> {
|
|
63
|
+
const [returnedValue, innerQueryContext] = await this.createNestedTransactionRunner<
|
|
64
|
+
[T, EntityNestedTransactionalQueryContext]
|
|
65
|
+
>(outerQueryContext.getQueryInterface())(async (innerQueryInterface) => {
|
|
66
|
+
const innerQueryContext = new EntityNestedTransactionalQueryContext(
|
|
67
|
+
innerQueryInterface,
|
|
68
|
+
outerQueryContext,
|
|
69
|
+
this
|
|
70
|
+
);
|
|
71
|
+
const result = await transactionScope(innerQueryContext);
|
|
72
|
+
await innerQueryContext.runPreCommitCallbacksAsync();
|
|
73
|
+
return [result, innerQueryContext];
|
|
74
|
+
});
|
|
75
|
+
// post-commit callbacks are appended to parent transaction instead of run, but only after the transaction has succeeded
|
|
76
|
+
innerQueryContext.transferPostCommitCallbacksToParent();
|
|
77
|
+
return returnedValue;
|
|
78
|
+
}
|
|
47
79
|
}
|
|
@@ -40,7 +40,7 @@ export interface ISecondaryEntityCache<TFields, TLoadParams> {
|
|
|
40
40
|
* when the underlying data of a cache key could be stale.
|
|
41
41
|
*
|
|
42
42
|
* This is most commonly used to further optimize hot paths that cannot make use of normal entity cache loading
|
|
43
|
-
* due to use of a non-unique-field-based
|
|
43
|
+
* due to use of a non-unique-field-based EntityLoader method like `loadManyByFieldEqualityConjunctionAsync` or
|
|
44
44
|
* `loadManyByRawWhereClauseAsync`.
|
|
45
45
|
*/
|
|
46
46
|
export default abstract class EntitySecondaryCacheLoader<
|
|
@@ -8,7 +8,7 @@ import { filterMap, zipToMap } from './utils/collections/maps';
|
|
|
8
8
|
/**
|
|
9
9
|
* A custom secondary read-through entity cache is a way to add a custom second layer of caching for a particular
|
|
10
10
|
* single entity load. One common way this may be used is to add a second layer of caching in a hot path that makes
|
|
11
|
-
* a call to
|
|
11
|
+
* a call to EntityLoader.loadManyByFieldEqualityConjunctionAsync is guaranteed to return at most one entity.
|
|
12
12
|
*/
|
|
13
13
|
export default abstract class GenericSecondaryEntityCache<TFields, TLoadParams>
|
|
14
14
|
implements ISecondaryEntityCache<TFields, TLoadParams>
|
package/src/ReadonlyEntity.ts
CHANGED
package/src/ViewerContext.ts
CHANGED
|
@@ -7,9 +7,9 @@ import ViewerScopedEntityCompanion from './ViewerScopedEntityCompanion';
|
|
|
7
7
|
import ViewerScopedEntityCompanionProvider from './ViewerScopedEntityCompanionProvider';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* A viewer context encapsulates all information necessary to evaluate an
|
|
10
|
+
* A viewer context encapsulates all information necessary to evaluate an EntityPrivacyPolicy.
|
|
11
11
|
*
|
|
12
|
-
* In combination with an
|
|
12
|
+
* In combination with an EntityCompanionProvider, a viewer context is the
|
|
13
13
|
* entry point into the Entity framework.
|
|
14
14
|
*/
|
|
15
15
|
export default class ViewerContext {
|
|
@@ -8,7 +8,7 @@ import ViewerScopedEntityMutatorFactory from './ViewerScopedEntityMutatorFactory
|
|
|
8
8
|
import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Provides a simpler API for loading and mutating entities by injecting the
|
|
11
|
+
* Provides a simpler API for loading and mutating entities by injecting the ViewerContext
|
|
12
12
|
* from the viewer-scoped entity companion provider.
|
|
13
13
|
*/
|
|
14
14
|
export default class ViewerScopedEntityCompanion<
|
|
@@ -79,7 +79,7 @@ export default class ViewerScopedEntityCompanion<
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Get the
|
|
82
|
+
* Get the IEntityMetricsAdapter for this companion.
|
|
83
83
|
*/
|
|
84
84
|
getMetricsAdapter(): IEntityMetricsAdapter {
|
|
85
85
|
return this.entityCompanion.getMetricsAdapter();
|
|
@@ -6,7 +6,7 @@ import ReadonlyEntity from './ReadonlyEntity';
|
|
|
6
6
|
import ViewerContext from './ViewerContext';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Provides a cleaner API for loading entities by passing through the
|
|
9
|
+
* Provides a cleaner API for loading entities by passing through the ViewerContext.
|
|
10
10
|
*/
|
|
11
11
|
export default class ViewerScopedEntityLoaderFactory<
|
|
12
12
|
TFields,
|
|
@@ -6,7 +6,7 @@ import ReadonlyEntity from './ReadonlyEntity';
|
|
|
6
6
|
import ViewerContext from './ViewerContext';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Provides a cleaner API for mutating entities by passing through the
|
|
9
|
+
* Provides a cleaner API for mutating entities by passing through the ViewerContext.
|
|
10
10
|
*/
|
|
11
11
|
export default class ViewerScopedEntityMutatorFactory<
|
|
12
12
|
TFields,
|
|
@@ -11,8 +11,6 @@ import {
|
|
|
11
11
|
StringArrayField,
|
|
12
12
|
JSONObjectField,
|
|
13
13
|
EnumField,
|
|
14
|
-
JSONArrayField,
|
|
15
|
-
MaybeJSONArrayField,
|
|
16
14
|
} from '../EntityFields';
|
|
17
15
|
import describeFieldTestCase from '../utils/testing/describeFieldTestCase';
|
|
18
16
|
|
|
@@ -71,13 +69,3 @@ describeFieldTestCase(
|
|
|
71
69
|
);
|
|
72
70
|
describeFieldTestCase(new JSONObjectField({ columnName: 'wat' }), [{}], [true, 'hello']);
|
|
73
71
|
describeFieldTestCase(new EnumField({ columnName: 'wat' }), ['hello', 1], [true]);
|
|
74
|
-
describeFieldTestCase(
|
|
75
|
-
new JSONArrayField({ columnName: 'wat' }),
|
|
76
|
-
[[[1, 2]] as any, [['hello']] as any], // jest test cases need extra wrapping array
|
|
77
|
-
[1, 'hello']
|
|
78
|
-
);
|
|
79
|
-
describeFieldTestCase(
|
|
80
|
-
new MaybeJSONArrayField({ columnName: 'wat' }),
|
|
81
|
-
[1, 'hello', [['hello']]], // jest test cases need extra wrapping array
|
|
82
|
-
[]
|
|
83
|
-
);
|
|
@@ -78,5 +78,55 @@ describe(EntityQueryContext, () => {
|
|
|
78
78
|
expect(postCommitCallback).toHaveBeenCalledTimes(0);
|
|
79
79
|
expect(postCommitInvalidationCallback).toHaveBeenCalledTimes(0);
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
it('calls callbacks correctly for nested transactions', async () => {
|
|
83
|
+
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
84
|
+
const viewerContext = new ViewerContext(companionProvider);
|
|
85
|
+
|
|
86
|
+
const preCommitCallback = jest.fn(async (): Promise<void> => {});
|
|
87
|
+
const preCommitNestedCallback = jest.fn(async (): Promise<void> => {});
|
|
88
|
+
const preCommitNestedCallbackThrow = jest.fn(async (): Promise<void> => {
|
|
89
|
+
throw new Error('wat');
|
|
90
|
+
});
|
|
91
|
+
const postCommitInvalidationCallback = jest.fn(async (): Promise<void> => {});
|
|
92
|
+
const postCommitCallback = jest.fn(async (): Promise<void> => {});
|
|
93
|
+
|
|
94
|
+
await viewerContext.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
95
|
+
'postgres',
|
|
96
|
+
async (queryContext) => {
|
|
97
|
+
queryContext.appendPostCommitCallback(postCommitCallback);
|
|
98
|
+
queryContext.appendPostCommitInvalidationCallback(postCommitInvalidationCallback);
|
|
99
|
+
queryContext.appendPreCommitCallback(preCommitCallback, 0);
|
|
100
|
+
|
|
101
|
+
await Promise.all([
|
|
102
|
+
queryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
103
|
+
innerQueryContext.appendPostCommitCallback(postCommitCallback);
|
|
104
|
+
innerQueryContext.appendPostCommitInvalidationCallback(
|
|
105
|
+
postCommitInvalidationCallback
|
|
106
|
+
);
|
|
107
|
+
innerQueryContext.appendPreCommitCallback(preCommitNestedCallback, 0);
|
|
108
|
+
}),
|
|
109
|
+
(async () => {
|
|
110
|
+
try {
|
|
111
|
+
await queryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
112
|
+
// these two shouldn't be called
|
|
113
|
+
innerQueryContext.appendPostCommitCallback(postCommitCallback);
|
|
114
|
+
innerQueryContext.appendPostCommitInvalidationCallback(
|
|
115
|
+
postCommitInvalidationCallback
|
|
116
|
+
);
|
|
117
|
+
innerQueryContext.appendPreCommitCallback(preCommitNestedCallbackThrow, 0);
|
|
118
|
+
});
|
|
119
|
+
} catch {}
|
|
120
|
+
})(),
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
expect(preCommitCallback).toHaveBeenCalledTimes(1);
|
|
126
|
+
expect(preCommitNestedCallback).toHaveBeenCalledTimes(1);
|
|
127
|
+
expect(preCommitNestedCallbackThrow).toHaveBeenCalledTimes(1);
|
|
128
|
+
expect(postCommitCallback).toHaveBeenCalledTimes(2);
|
|
129
|
+
expect(postCommitInvalidationCallback).toHaveBeenCalledTimes(2);
|
|
130
|
+
});
|
|
81
131
|
});
|
|
82
132
|
});
|
|
@@ -3,6 +3,7 @@ import DataLoader from 'dataloader';
|
|
|
3
3
|
import EntityDatabaseAdapter, {
|
|
4
4
|
FieldEqualityCondition,
|
|
5
5
|
QuerySelectionModifiers,
|
|
6
|
+
QuerySelectionModifiersWithOrderByRaw,
|
|
6
7
|
} from '../EntityDatabaseAdapter';
|
|
7
8
|
import { EntityQueryContext } from '../EntityQueryContext';
|
|
8
9
|
import EntityQueryContextProvider from '../EntityQueryContextProvider';
|
|
@@ -20,9 +21,9 @@ import ReadThroughEntityCache from './ReadThroughEntityCache';
|
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* A data manager is responsible for orchestrating multiple sources of entity
|
|
23
|
-
* data including local caches,
|
|
24
|
+
* data including local caches, EntityCacheAdapter, and EntityDatabaseAdapter.
|
|
24
25
|
*
|
|
25
|
-
* It is also responsible for invalidating all sources of data when mutated using
|
|
26
|
+
* It is also responsible for invalidating all sources of data when mutated using EntityMutator.
|
|
26
27
|
*/
|
|
27
28
|
export default class EntityDataManager<TFields> {
|
|
28
29
|
private readonly fieldDataLoaders: Map<
|
|
@@ -173,14 +174,14 @@ export default class EntityDataManager<TFields> {
|
|
|
173
174
|
* @param queryContext - query context in which to perform the load
|
|
174
175
|
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
175
176
|
* @param bindings - array of positional bindings or object of named bindings
|
|
176
|
-
* @param querySelectionModifiers - limit, offset, and
|
|
177
|
+
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
|
|
177
178
|
* @returns array of objects matching the query
|
|
178
179
|
*/
|
|
179
180
|
async loadManyByRawWhereClauseAsync(
|
|
180
181
|
queryContext: EntityQueryContext,
|
|
181
182
|
rawWhereClause: string,
|
|
182
183
|
bindings: any[] | object,
|
|
183
|
-
querySelectionModifiers:
|
|
184
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>
|
|
184
185
|
): Promise<readonly Readonly<TFields>[]> {
|
|
185
186
|
return await timeAndLogLoadEventAsync(
|
|
186
187
|
this.metricsAdapter,
|
|
@@ -23,8 +23,8 @@ export type CacheLoadResult<TFields> =
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* A read-through entity cache is responsible for coordinating
|
|
27
|
-
*
|
|
26
|
+
* A read-through entity cache is responsible for coordinating EntityDatabaseAdapter and
|
|
27
|
+
* EntityCacheAdapter within the EntityDataManager.
|
|
28
28
|
*/
|
|
29
29
|
export default class ReadThroughEntityCache<TFields> {
|
|
30
30
|
constructor(
|
|
@@ -10,16 +10,16 @@ export enum EntityMetricsLoadType {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Event about a single call to an
|
|
13
|
+
* Event about a single call to an EntityLoader method.
|
|
14
14
|
*/
|
|
15
15
|
export interface EntityMetricsLoadEvent {
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* EntityMetricsLoadType for this load.
|
|
18
18
|
*/
|
|
19
19
|
type: EntityMetricsLoadType;
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Class name of the
|
|
22
|
+
* Class name of the Entity being loaded.
|
|
23
23
|
*/
|
|
24
24
|
entityClassName: string;
|
|
25
25
|
|
|
@@ -42,12 +42,12 @@ export enum EntityMetricsMutationType {
|
|
|
42
42
|
|
|
43
43
|
export interface EntityMetricsMutationEvent {
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* EntityMetricsMutationType for this mutation.
|
|
46
46
|
*/
|
|
47
47
|
type: EntityMetricsMutationType;
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Class name of the
|
|
50
|
+
* Class name of the Entity being mutated.
|
|
51
51
|
*/
|
|
52
52
|
entityClassName: string;
|
|
53
53
|
|
|
@@ -76,7 +76,7 @@ export enum IncrementLoadCountEventType {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
* Event used to record dataloader, cache, and database load counts in
|
|
79
|
+
* Event used to record dataloader, cache, and database load counts in EntityDataManager.
|
|
80
80
|
*/
|
|
81
81
|
export interface IncrementLoadCountEvent {
|
|
82
82
|
/**
|
|
@@ -90,7 +90,7 @@ export interface IncrementLoadCountEvent {
|
|
|
90
90
|
fieldValueCount: number;
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* Class name of the
|
|
93
|
+
* Class name of the Entity being loaded.
|
|
94
94
|
*/
|
|
95
95
|
entityClassName: string;
|
|
96
96
|
}
|
|
@@ -101,11 +101,11 @@ export enum EntityMetricsAuthorizationResult {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/**
|
|
104
|
-
* Event used to record a singe
|
|
104
|
+
* Event used to record a singe EntityPrivacyPolicy authorization.
|
|
105
105
|
*/
|
|
106
106
|
export interface EntityMetricsAuthorizationEvent {
|
|
107
107
|
/**
|
|
108
|
-
* Class name of the
|
|
108
|
+
* Class name of the Entity being authorized.
|
|
109
109
|
*/
|
|
110
110
|
entityClassName: string;
|
|
111
111
|
action: EntityAuthorizationAction;
|
|
@@ -119,7 +119,7 @@ export interface EntityMetricsAuthorizationEvent {
|
|
|
119
119
|
*/
|
|
120
120
|
export default interface IEntityMetricsAdapter {
|
|
121
121
|
/**
|
|
122
|
-
* Called when a
|
|
122
|
+
* Called when a EntityPrivacyPolicy authorization succeeds or fails.
|
|
123
123
|
* @param authorizationEvent - info about the authorization event
|
|
124
124
|
*/
|
|
125
125
|
logAuthorizationEvent(authorizationEvent: EntityMetricsAuthorizationEvent): void;
|
|
@@ -32,7 +32,7 @@ export enum RuleEvaluationResult {
|
|
|
32
32
|
* rule in the privacy policy. If all rules in the policy SKIP, the policy is denied.
|
|
33
33
|
*
|
|
34
34
|
* Returning DENY from a rule is useful in a few notable cases:
|
|
35
|
-
* - Preventing a CRUD action on an entity (
|
|
35
|
+
* - Preventing a CRUD action on an entity (AlwaysDenyPrivacyPolicyRule)
|
|
36
36
|
* - Blocking. For example, a user blocks another user from seeing their posts, and the rule
|
|
37
37
|
* would be named something like `DenyIfViewerHasBeenBlockedPrivacyPolicyRule`.
|
|
38
38
|
*/
|
|
@@ -60,7 +60,7 @@ export const mapMapAsync = async function <K, V, M>(
|
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Create a new Map by associating the value of each key with mapper executed for each key in the source map.
|
|
63
|
-
* The opposite of
|
|
63
|
+
* The opposite of mapMap. In the event two source keys map to the same result key, the second source key's
|
|
64
64
|
* value will overwrite the first, in which case the cardinality of the returned map may be smaller than the
|
|
65
65
|
* source map's.
|
|
66
66
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import EntityQueryContextProvider from '../../EntityQueryContextProvider';
|
|
2
2
|
|
|
3
|
-
class StubQueryContextProvider extends EntityQueryContextProvider {
|
|
3
|
+
export class StubQueryContextProvider extends EntityQueryContextProvider {
|
|
4
4
|
protected getQueryInterface(): any {
|
|
5
5
|
return {};
|
|
6
6
|
}
|
|
@@ -10,6 +10,12 @@ class StubQueryContextProvider extends EntityQueryContextProvider {
|
|
|
10
10
|
) => Promise<T> {
|
|
11
11
|
return (transactionScope) => Promise.resolve(transactionScope({}));
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
protected createNestedTransactionRunner<T>(
|
|
15
|
+
_outerQueryInterface: any
|
|
16
|
+
): (transactionScope: (queryInterface: any) => Promise<T>) => Promise<T> {
|
|
17
|
+
return (transactionScope) => Promise.resolve(transactionScope({}));
|
|
18
|
+
}
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
export default new StubQueryContextProvider();
|