@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.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/build/ComposedEntityCacheAdapter.d.ts +1 -1
  3. package/build/ComposedEntityCacheAdapter.js +1 -1
  4. package/build/ComposedSecondaryEntityCache.d.ts +1 -1
  5. package/build/ComposedSecondaryEntityCache.js +1 -1
  6. package/build/EnforcingEntityLoader.d.ts +10 -10
  7. package/build/EnforcingEntityLoader.js +8 -8
  8. package/build/EnforcingEntityLoader.js.map +1 -1
  9. package/build/Entity.d.ts +5 -5
  10. package/build/Entity.js +5 -5
  11. package/build/EntityAssociationLoader.d.ts +4 -4
  12. package/build/EntityCacheAdapter.d.ts +1 -1
  13. package/build/EntityCompanion.d.ts +1 -1
  14. package/build/EntityCompanion.js +1 -1
  15. package/build/EntityCompanionProvider.d.ts +9 -9
  16. package/build/EntityCompanionProvider.js +3 -3
  17. package/build/EntityConfiguration.d.ts +2 -2
  18. package/build/EntityDatabaseAdapter.d.ts +25 -6
  19. package/build/EntityDatabaseAdapter.js +8 -2
  20. package/build/EntityDatabaseAdapter.js.map +1 -1
  21. package/build/EntityFieldDefinition.d.ts +2 -2
  22. package/build/EntityFields.d.ts +9 -22
  23. package/build/EntityFields.js +10 -29
  24. package/build/EntityFields.js.map +1 -1
  25. package/build/EntityLoader.d.ts +10 -10
  26. package/build/EntityLoader.js +8 -8
  27. package/build/EntityLoader.js.map +1 -1
  28. package/build/EntityMutationTriggerConfiguration.d.ts +1 -1
  29. package/build/EntityMutationTriggerConfiguration.js +1 -1
  30. package/build/EntityMutator.d.ts +1 -1
  31. package/build/EntityMutator.js +1 -1
  32. package/build/EntityPrivacyPolicy.d.ts +6 -6
  33. package/build/EntityPrivacyPolicy.js +6 -6
  34. package/build/EntityQueryContext.d.ts +23 -3
  35. package/build/EntityQueryContext.js +43 -6
  36. package/build/EntityQueryContext.js.map +1 -1
  37. package/build/EntityQueryContextProvider.d.ts +10 -2
  38. package/build/EntityQueryContextProvider.js +18 -1
  39. package/build/EntityQueryContextProvider.js.map +1 -1
  40. package/build/EntitySecondaryCacheLoader.d.ts +1 -1
  41. package/build/EntitySecondaryCacheLoader.js +1 -1
  42. package/build/GenericSecondaryEntityCache.d.ts +1 -1
  43. package/build/GenericSecondaryEntityCache.js +1 -1
  44. package/build/ReadonlyEntity.d.ts +1 -1
  45. package/build/ReadonlyEntity.js +1 -1
  46. package/build/ViewerContext.d.ts +2 -2
  47. package/build/ViewerContext.js +2 -2
  48. package/build/ViewerScopedEntityCompanion.d.ts +2 -2
  49. package/build/ViewerScopedEntityCompanion.js +2 -2
  50. package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
  51. package/build/ViewerScopedEntityLoaderFactory.js +1 -1
  52. package/build/ViewerScopedEntityMutatorFactory.d.ts +1 -1
  53. package/build/ViewerScopedEntityMutatorFactory.js +1 -1
  54. package/build/__tests__/EntityFields-test.js +0 -4
  55. package/build/__tests__/EntityFields-test.js.map +1 -1
  56. package/build/__tests__/EntityQueryContext-test.js +39 -0
  57. package/build/__tests__/EntityQueryContext-test.js.map +1 -1
  58. package/build/internal/EntityDataManager.d.ts +5 -5
  59. package/build/internal/EntityDataManager.js +3 -3
  60. package/build/internal/EntityDataManager.js.map +1 -1
  61. package/build/internal/ReadThroughEntityCache.d.ts +2 -2
  62. package/build/internal/ReadThroughEntityCache.js +2 -2
  63. package/build/metrics/IEntityMetricsAdapter.d.ts +10 -10
  64. package/build/rules/PrivacyPolicyRule.d.ts +1 -1
  65. package/build/rules/PrivacyPolicyRule.js +1 -1
  66. package/build/utils/collections/maps.d.ts +1 -1
  67. package/build/utils/collections/maps.js +1 -1
  68. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -2
  69. package/build/utils/testing/StubQueryContextProvider.d.ts +2 -1
  70. package/build/utils/testing/StubQueryContextProvider.js +5 -0
  71. package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
  72. package/package.json +3 -2
  73. package/src/ComposedEntityCacheAdapter.ts +1 -1
  74. package/src/ComposedSecondaryEntityCache.ts +1 -1
  75. package/src/EnforcingEntityLoader.ts +14 -10
  76. package/src/Entity.ts +5 -5
  77. package/src/EntityAssociationLoader.ts +4 -4
  78. package/src/EntityCacheAdapter.ts +1 -1
  79. package/src/EntityCompanion.ts +1 -1
  80. package/src/EntityCompanionProvider.ts +9 -9
  81. package/src/EntityConfiguration.ts +2 -2
  82. package/src/EntityDatabaseAdapter.ts +43 -6
  83. package/src/EntityFieldDefinition.ts +2 -2
  84. package/src/EntityFields.ts +9 -28
  85. package/src/EntityLoader.ts +10 -9
  86. package/src/EntityMutationTriggerConfiguration.ts +1 -1
  87. package/src/EntityMutator.ts +1 -1
  88. package/src/EntityPrivacyPolicy.ts +6 -6
  89. package/src/EntityQueryContext.ts +63 -3
  90. package/src/EntityQueryContextProvider.ts +34 -2
  91. package/src/EntitySecondaryCacheLoader.ts +1 -1
  92. package/src/GenericSecondaryEntityCache.ts +1 -1
  93. package/src/ReadonlyEntity.ts +1 -1
  94. package/src/ViewerContext.ts +2 -2
  95. package/src/ViewerScopedEntityCompanion.ts +2 -2
  96. package/src/ViewerScopedEntityLoaderFactory.ts +1 -1
  97. package/src/ViewerScopedEntityMutatorFactory.ts +1 -1
  98. package/src/__tests__/EntityFields-test.ts +0 -12
  99. package/src/__tests__/EntityQueryContext-test.ts +50 -0
  100. package/src/internal/EntityDataManager.ts +5 -4
  101. package/src/internal/ReadThroughEntityCache.ts +2 -2
  102. package/src/metrics/IEntityMetricsAdapter.ts +10 -10
  103. package/src/rules/PrivacyPolicyRule.ts +1 -1
  104. package/src/utils/collections/maps.ts +1 -1
  105. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +1 -1
  106. 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":";;;;;AAAA,kGAA0E;AAE1E,MAAM,wBAAyB,SAAQ,oCAA0B;IACrD,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;CACF;AAED,kBAAe,IAAI,wBAAwB,EAAE,CAAC"}
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.26.1",
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 {@link EntityCacheAdapter} that composes other {@link EntityCacheAdapter} instances.
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 {@link ISecondaryEntityCache} that composes other {@link ISecondaryEntityCache} instances.
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 { FieldEqualityCondition, QuerySelectionModifiers } from './EntityDatabaseAdapter';
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view one or more of the returned entities
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view one or more of the returned entities
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view the returned entity
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view the returned entity
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view the returned entity
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view one or more of the returned entities
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view one or more of the returned entities
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 {@link EntityNotAuthorizedError} when viewer is not authorized to view one or more of the returned entities
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: QuerySelectionModifiers<TFields> = {}
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 {@link ViewerContext}, has permission to read.
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
- * {@link EntityPrivacyPolicy}.
17
+ * EntityPrivacyPolicy.
18
18
  *
19
- * Entites are loaded through an {@link EntityLoader}, which is responsible for
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 {@link EntityMutator}, which is responsible for
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 {@link EntityCompanionDefinition}.
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 {@link EntityLoadThroughDirective}. At each
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 {@link EntityLoadThroughDirective}. At each
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 {@link EntityLoadThroughDirective}. At each
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 {@link EntityLoadThroughDirective}. At each
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 {@link CacheStatus.NEGATIVE}
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>(
@@ -132,7 +132,7 @@ export default class EntityCompanion<
132
132
  }
133
133
 
134
134
  /**
135
- * Get the {@link IEntityMetricsAdapter} for this companion.
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 {@link EntityConfiguration} for this entity.
112
+ * The EntityConfiguration for this entity.
113
113
  */
114
114
  entityConfiguration: EntityConfiguration<TFields>;
115
115
  /**
116
- * The {@link EntityPrivacyPolicy} class for this entity.
116
+ * The EntityPrivacyPolicy class for this entity.
117
117
  */
118
118
  privacyPolicyClass: IPrivacyPolicyClass<TPrivacyPolicy>;
119
119
  /**
120
- * An optional list of {@link EntityMutationValidator} for this entity.
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 {@link EntityMutationTrigger} for this entity.
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 {@link EntityConfiguration} which belong to this entity.
141
- * For use when multiple types of entities are backed by a single table ({@link EntityConfiguration}) yet
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 {@link ViewerContext}, which is the application entry point
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
- * {@link EntityCompanion} for each type of {@link Entity}.
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 {@link IEntityMetricsAdapter} for collecting metrics on this instance
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 {@link EntityFieldDefinition} specifying information about the field.
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 {@link EntityFieldDefinition} associations.
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
- interface SingleValueFieldEqualityCondition<TFields, N extends keyof TFields = keyof TFields> {
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
- interface MultiValueFieldEqualityCondition<TFields, N extends keyof TFields = keyof TFields> {
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 orderBy for the query
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: QuerySelectionModifiers<TFields>
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.convertToTableQueryModifiers(querySelectionModifiers)
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: TableQuerySelectionModifiers
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 {@link EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY} or
91
- * {@link EntityEdgeDeletionBehavior.SET_NULL_INVALIDATE_CACHE_ONLY} are recommended.
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
  */
@@ -3,7 +3,7 @@ import { validate as validateUUID } from 'uuid';
3
3
  import { EntityFieldDefinition } from './EntityFieldDefinition';
4
4
 
5
5
  /**
6
- * {@link EntityFieldDefinition} for a column with a JS string type.
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
- * {@link EntityFieldDefinition} for a column with a JS string type.
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
- * {@link EntityFieldDefinition} for a column with a JS Date type.
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
- * {@link EntityFieldDefinition} for a column with a JS boolean type.
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
- * {@link EntityFieldDefinition} for a column with a JS number type.
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
- * {@link EntityFieldDefinition} for a column with a JS number type.
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
- * {@link EntityFieldDefinition} for a column with a JS string array type.
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
- * {@link EntityFieldDefinition} for a column with a JS JSON object type.
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
- * {@link EntityFieldDefinition} for a enum column with a JS string or number type.
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
- }
@@ -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 {@link EntityPrivacyPolicy}.
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 conjunction of WHERE clauses constructed from specified operands.
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 WHERE clause operand specifications
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
- * {@link http://knexjs.org/#Builder-whereRaw}
248
- * {@link http://knexjs.org/#Raw-Bindings}
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 orderBy for the query
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: QuerySelectionModifiers<TFields> = {}
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 {@link EntityMutator}.
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 {@link EntityMutationTrigger} but used for afterCommit triggers
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<
@@ -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
- * {@link OnDeleteBehavior} of the field referencing the specified entity.
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 {@link EntityPrivacyPolicy}. Useful when transitioning to
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 {@link PrivacyPolicyRule} for create, read, update, and delete actions
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 {@link EntityNotAuthorizedError} when not authorized
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 {@link EntityNotAuthorizedError} when not authorized
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 {@link EntityNotAuthorizedError} when not authorized
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 {@link EntityNotAuthorizedError} when not authorized
230
+ * @throws EntityNotAuthorizedError when not authorized
231
231
  */
232
232
  async authorizeDeleteAsync(
233
233
  viewerContext: TViewerContext,