@expo/entity-database-adapter-knex 0.41.0 → 0.42.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 (63) hide show
  1. package/build/EntityFields.d.ts +3 -3
  2. package/build/EntityFields.js.map +1 -1
  3. package/build/PostgresEntityDatabaseAdapter.d.ts +2 -2
  4. package/build/PostgresEntityDatabaseAdapter.js +31 -5
  5. package/build/PostgresEntityDatabaseAdapter.js.map +1 -1
  6. package/build/PostgresEntityDatabaseAdapterProvider.d.ts +1 -1
  7. package/build/PostgresEntityDatabaseAdapterProvider.js.map +1 -1
  8. package/build/tsconfig.build.tsbuildinfo +1 -0
  9. package/package.json +9 -7
  10. package/src/EntityFields.ts +11 -3
  11. package/src/PostgresEntityDatabaseAdapter.ts +38 -7
  12. package/src/PostgresEntityDatabaseAdapterProvider.ts +3 -3
  13. package/src/__integration-tests__/PostgresEntityIntegration-test.ts +63 -10
  14. package/src/__integration-tests__/PostgresEntityQueryContextProvider-test.ts +2 -2
  15. package/src/__integration-tests__/PostgresInvalidSetup-test.ts +2 -2
  16. package/src/__integration-tests__/errors-test.ts +2 -2
  17. package/src/{testfixtures → __testfixtures__}/ErrorsTestEntity.ts +9 -12
  18. package/src/{testfixtures → __testfixtures__}/InvalidTestEntity.ts +12 -8
  19. package/src/{testfixtures → __testfixtures__}/PostgresTestEntity.ts +13 -9
  20. package/src/{testfixtures → __testfixtures__}/PostgresTriggerTestEntity.ts +29 -27
  21. package/src/{testfixtures → __testfixtures__}/PostgresUniqueTestEntity.ts +26 -24
  22. package/src/{testfixtures → __testfixtures__}/PostgresValidatorTestEntity.ts +28 -26
  23. package/src/{testfixtures → __testfixtures__}/createKnexIntegrationTestEntityCompanionProvider.ts +1 -1
  24. package/src/__tests__/EntityFields-test.ts +1 -1
  25. package/build/__integration-tests__/PostgresEntityIntegration-test.d.ts +0 -1
  26. package/build/__integration-tests__/PostgresEntityIntegration-test.js +0 -463
  27. package/build/__integration-tests__/PostgresEntityIntegration-test.js.map +0 -1
  28. package/build/__integration-tests__/PostgresEntityQueryContextProvider-test.d.ts +0 -1
  29. package/build/__integration-tests__/PostgresEntityQueryContextProvider-test.js +0 -80
  30. package/build/__integration-tests__/PostgresEntityQueryContextProvider-test.js.map +0 -1
  31. package/build/__integration-tests__/PostgresInvalidSetup-test.d.ts +0 -1
  32. package/build/__integration-tests__/PostgresInvalidSetup-test.js +0 -69
  33. package/build/__integration-tests__/PostgresInvalidSetup-test.js.map +0 -1
  34. package/build/__integration-tests__/errors-test.d.ts +0 -1
  35. package/build/__integration-tests__/errors-test.js +0 -127
  36. package/build/__integration-tests__/errors-test.js.map +0 -1
  37. package/build/__tests__/EntityFields-test.d.ts +0 -1
  38. package/build/__tests__/EntityFields-test.js +0 -8
  39. package/build/__tests__/EntityFields-test.js.map +0 -1
  40. package/build/errors/__tests__/wrapNativePostgresCallAsync-test.d.ts +0 -1
  41. package/build/errors/__tests__/wrapNativePostgresCallAsync-test.js +0 -24
  42. package/build/errors/__tests__/wrapNativePostgresCallAsync-test.js.map +0 -1
  43. package/build/testfixtures/ErrorsTestEntity.d.ts +0 -24
  44. package/build/testfixtures/ErrorsTestEntity.js +0 -106
  45. package/build/testfixtures/ErrorsTestEntity.js.map +0 -1
  46. package/build/testfixtures/InvalidTestEntity.d.ts +0 -19
  47. package/build/testfixtures/InvalidTestEntity.js +0 -61
  48. package/build/testfixtures/InvalidTestEntity.js.map +0 -1
  49. package/build/testfixtures/PostgresTestEntity.d.ts +0 -31
  50. package/build/testfixtures/PostgresTestEntity.js +0 -95
  51. package/build/testfixtures/PostgresTestEntity.js.map +0 -1
  52. package/build/testfixtures/PostgresTriggerTestEntity.d.ts +0 -19
  53. package/build/testfixtures/PostgresTriggerTestEntity.js +0 -101
  54. package/build/testfixtures/PostgresTriggerTestEntity.js.map +0 -1
  55. package/build/testfixtures/PostgresUniqueTestEntity.d.ts +0 -19
  56. package/build/testfixtures/PostgresUniqueTestEntity.js +0 -62
  57. package/build/testfixtures/PostgresUniqueTestEntity.js.map +0 -1
  58. package/build/testfixtures/PostgresValidatorTestEntity.d.ts +0 -19
  59. package/build/testfixtures/PostgresValidatorTestEntity.js +0 -77
  60. package/build/testfixtures/PostgresValidatorTestEntity.js.map +0 -1
  61. package/build/testfixtures/createKnexIntegrationTestEntityCompanionProvider.d.ts +0 -3
  62. package/build/testfixtures/createKnexIntegrationTestEntityCompanionProvider.js +0 -29
  63. package/build/testfixtures/createKnexIntegrationTestEntityCompanionProvider.js.map +0 -1
@@ -2,19 +2,19 @@ import { EntityFieldDefinition } from '@expo/entity';
2
2
  /**
3
3
  * EntityFieldDefinition for a Postres column with a JS JSON array type.
4
4
  */
5
- export declare class JSONArrayField extends EntityFieldDefinition<any[]> {
5
+ export declare class JSONArrayField<TRequireExplicitCache extends boolean> extends EntityFieldDefinition<any[], TRequireExplicitCache> {
6
6
  protected validateInputValueInternal(value: any[]): boolean;
7
7
  }
8
8
  /**
9
9
  * EntityFieldDefinition for a Postgres column that may be a JS JSON array type.
10
10
  * Does not do any validation.
11
11
  */
12
- export declare class MaybeJSONArrayField extends EntityFieldDefinition<any | any[]> {
12
+ export declare class MaybeJSONArrayField<TRequireExplicitCache extends boolean> extends EntityFieldDefinition<any | any[], TRequireExplicitCache> {
13
13
  protected validateInputValueInternal(_value: any): boolean;
14
14
  }
15
15
  /**
16
16
  * EntityFieldDefinition for a Postgres BIGINT column.
17
17
  */
18
- export declare class BigIntField extends EntityFieldDefinition<string> {
18
+ export declare class BigIntField<TRequireExplicitCache extends boolean> extends EntityFieldDefinition<string, TRequireExplicitCache> {
19
19
  protected validateInputValueInternal(value: string): boolean;
20
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EntityFields.js","sourceRoot":"","sources":["../src/EntityFields.ts"],"names":[],"mappings":";;;AAAA,yCAAqD;AAErD;;GAEG;AACH,MAAa,cAAe,SAAQ,8BAA4B;IACpD,0BAA0B,CAAC,KAAY;QAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;CACF;AAJD,wCAIC;AAED;;;GAGG;AACH,MAAa,mBAAoB,SAAQ,8BAAkC;IAC/D,0BAA0B,CAAC,MAAW;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAJD,kDAIC;AAED;;GAEG;AACH,MAAa,WAAY,SAAQ,8BAA6B;IAClD,0BAA0B,CAAC,KAAa;QAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC;IACnC,CAAC;CACF;AAJD,kCAIC"}
1
+ {"version":3,"file":"EntityFields.js","sourceRoot":"","sources":["../src/EntityFields.ts"],"names":[],"mappings":";;;AAAA,yCAAqD;AAErD;;GAEG;AACH,MAAa,cAAsD,SAAQ,8BAG1E;IACW,0BAA0B,CAAC,KAAY;QAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;CACF;AAPD,wCAOC;AAED;;;GAGG;AACH,MAAa,mBAEX,SAAQ,8BAAyD;IACvD,0BAA0B,CAAC,MAAW;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAND,kDAMC;AAED;;GAEG;AACH,MAAa,WAAmD,SAAQ,8BAGvE;IACW,0BAA0B,CAAC,KAAa;QAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC;IACnC,CAAC;CACF;AAPD,kCAOC"}
@@ -1,8 +1,8 @@
1
1
  import { EntityDatabaseAdapter, FieldTransformerMap, TableQuerySelectionModifiers, TableFieldSingleValueEqualityCondition, TableFieldMultiValueEqualityCondition, TableQuerySelectionModifiersWithOrderByRaw } from '@expo/entity';
2
2
  import { Knex } from 'knex';
3
- export default class PostgresEntityDatabaseAdapter<TFields extends Record<string, any>> extends EntityDatabaseAdapter<TFields> {
3
+ export default class PostgresEntityDatabaseAdapter<TFields extends Record<string, any>, TIDField extends keyof TFields> extends EntityDatabaseAdapter<TFields, TIDField> {
4
4
  protected getFieldTransformerMap(): FieldTransformerMap;
5
- protected fetchManyWhereInternalAsync(queryInterface: Knex, tableName: string, tableField: string, tableValues: readonly any[]): Promise<object[]>;
5
+ protected fetchManyWhereInternalAsync(queryInterface: Knex, tableName: string, tableColumns: readonly string[], tableTuples: any[][]): Promise<object[]>;
6
6
  private applyQueryModifiersToQueryOrderByRaw;
7
7
  private applyQueryModifiersToQuery;
8
8
  protected fetchManyByFieldEqualityConjunctionInternalAsync(queryInterface: Knex, tableName: string, tableFieldSingleValueEqualityOperands: TableFieldSingleValueEqualityCondition[], tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[], querySelectionModifiers: TableQuerySelectionModifiers): Promise<object[]>;
@@ -32,11 +32,37 @@ class PostgresEntityDatabaseAdapter extends entity_1.EntityDatabaseAdapter {
32
32
  ],
33
33
  ]);
34
34
  }
35
- async fetchManyWhereInternalAsync(queryInterface, tableName, tableField, tableValues) {
36
- return await (0, wrapNativePostgresCallAsync_1.default)(() => queryInterface
37
- .select()
38
- .from(tableName)
39
- .whereRaw('?? = ANY(?)', [tableField, tableValues]));
35
+ async fetchManyWhereInternalAsync(queryInterface, tableName, tableColumns, tableTuples) {
36
+ // For single column queries, use the ANY operator to derive a consistent
37
+ // query shape in the postgres query stats table.
38
+ // This produces a query of the form `SELECT * FROM table WHERE ("id") = ANY(?)`
39
+ // with value bindings of the form `[[1]]`, thus not making different value cardinalities
40
+ // produce different query shapes.
41
+ //
42
+ // But for multi-column queries, we must use the IN operator as the ANY operator
43
+ // does not support anonymous composite types. The solution to keep using the ANY operator would be explicit
44
+ // postgres type casting on each value in each tableTuple, thus creating a unique query shape and defeating the purpose.
45
+ // The same applies to using UNNEST on anonymous composite types.
46
+ // Note that this solution is not possible in entity though since we don't have the postgres column types and they
47
+ // can't be derived dynamically.
48
+ //
49
+ // Therefore, for multi-column quries, we use the IN operator which produces a query of the form
50
+ // `SELECT * FROM table WHERE ("id", "name") IN ((?, ?), (?, ?))` with value bindings of the form
51
+ // `[[1, 'a'], [2, 'b']]`, which will produce a unique query shape in the postgres query stats table for
52
+ // each value cardinality.
53
+ //
54
+ // We could use the IN operator for single column queries as well, but we prefer to use ANY to at least keep some
55
+ // consistency in the query shape for the stats table.
56
+ if (tableColumns.length === 1) {
57
+ return await (0, wrapNativePostgresCallAsync_1.default)(() => queryInterface
58
+ .select()
59
+ .from(tableName)
60
+ .whereRaw(`(??) = ANY(?)`, [
61
+ tableColumns[0],
62
+ tableTuples.map((tableTuple) => tableTuple[0]),
63
+ ]));
64
+ }
65
+ return await (0, wrapNativePostgresCallAsync_1.default)(() => queryInterface.select().from(tableName).whereIn(tableColumns, tableTuples));
40
66
  }
41
67
  applyQueryModifiersToQueryOrderByRaw(query, querySelectionModifiers) {
42
68
  let ret = this.applyQueryModifiersToQuery(query, querySelectionModifiers);
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresEntityDatabaseAdapter.js","sourceRoot":"","sources":["../src/PostgresEntityDatabaseAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostgresEntityDatabaseAdapter.js","sourceRoot":"","sources":["../src/PostgresEntityDatabaseAdapter.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import { IEntityDatabaseAdapterProvider, EntityConfiguration, EntityDatabaseAdapter } from '@expo/entity';
2
2
  export default class PostgresEntityDatabaseAdapterProvider implements IEntityDatabaseAdapterProvider {
3
- getDatabaseAdapter<TFields extends Record<string, any>>(entityConfiguration: EntityConfiguration<TFields>): EntityDatabaseAdapter<TFields>;
3
+ getDatabaseAdapter<TFields extends Record<string, any>, TIDField extends keyof TFields>(entityConfiguration: EntityConfiguration<TFields, TIDField>): EntityDatabaseAdapter<TFields, TIDField>;
4
4
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresEntityDatabaseAdapterProvider.js","sourceRoot":"","sources":["../src/PostgresEntityDatabaseAdapterProvider.ts"],"names":[],"mappings":";;;;;AAMA,oGAA4E;AAE5E,MAAqB,qCAAqC;IAGxD,kBAAkB,CAChB,mBAAiD;QAEjD,OAAO,IAAI,uCAA6B,CAAC,mBAAmB,CAAC,CAAC;IAChE,CAAC;CACF;AARD,wDAQC"}
1
+ {"version":3,"file":"PostgresEntityDatabaseAdapterProvider.js","sourceRoot":"","sources":["../src/PostgresEntityDatabaseAdapterProvider.ts"],"names":[],"mappings":";;;;;AAMA,oGAA4E;AAE5E,MAAqB,qCAAqC;IAGxD,kBAAkB,CAChB,mBAA2D;QAE3D,OAAO,IAAI,uCAA6B,CAAC,mBAAmB,CAAC,CAAC;IAChE,CAAC;CACF;AARD,wDAQC"}
@@ -0,0 +1 @@
1
+ {"root":["../src/entityfields.ts","../src/postgresentitydatabaseadapter.ts","../src/postgresentitydatabaseadapterprovider.ts","../src/postgresentityquerycontextprovider.ts","../src/index.ts","../src/errors/wrapnativepostgrescallasync.ts"],"version":"5.8.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/entity-database-adapter-knex",
3
- "version": "0.41.0",
3
+ "version": "0.42.0",
4
4
  "description": "Knex database adapter for @expo/entity",
5
5
  "files": [
6
6
  "build",
@@ -10,6 +10,7 @@
10
10
  "types": "build/index.d.ts",
11
11
  "scripts": {
12
12
  "tsc": "tsc",
13
+ "build": "tsc -b tsconfig.build.json",
13
14
  "clean": "rm -rf build coverage coverage-integration",
14
15
  "lint": "eslint src",
15
16
  "lint-fix": "eslint src --fix",
@@ -27,23 +28,24 @@
27
28
  "author": "Expo",
28
29
  "license": "MIT",
29
30
  "dependencies": {
30
- "@expo/entity": "^0.41.0",
31
+ "@expo/entity": "^0.42.0",
31
32
  "knex": "^3.1.0"
32
33
  },
33
34
  "devDependencies": {
34
- "@types/jest": "^29.5.12",
35
+ "@expo/entity-testing-utils": "^0.42.0",
36
+ "@types/jest": "^29.5.14",
35
37
  "@types/node": "^20.14.1",
36
38
  "ctix": "^2.7.0",
37
39
  "eslint": "^8.57.1",
38
40
  "eslint-config-universe": "^14.0.0",
39
41
  "eslint-plugin-tsdoc": "^0.3.0",
40
42
  "jest": "^29.7.0",
41
- "pg": "8.13.1",
43
+ "pg": "8.14.1",
42
44
  "prettier": "^3.3.3",
43
45
  "prettier-plugin-organize-imports": "^4.1.0",
44
- "ts-jest": "^29.2.5",
46
+ "ts-jest": "^29.3.1",
45
47
  "ts-mockito": "^2.6.1",
46
- "typescript": "^5.7.3"
48
+ "typescript": "^5.8.3"
47
49
  },
48
- "gitHead": "ee4be736a9a0ba580e9af0194e07c9cd36b1c599"
50
+ "gitHead": "8414d96d948882735687da146e84913397cd8368"
49
51
  }
@@ -3,7 +3,10 @@ import { EntityFieldDefinition } from '@expo/entity';
3
3
  /**
4
4
  * EntityFieldDefinition for a Postres column with a JS JSON array type.
5
5
  */
6
- export class JSONArrayField extends EntityFieldDefinition<any[]> {
6
+ export class JSONArrayField<TRequireExplicitCache extends boolean> extends EntityFieldDefinition<
7
+ any[],
8
+ TRequireExplicitCache
9
+ > {
7
10
  protected validateInputValueInternal(value: any[]): boolean {
8
11
  return Array.isArray(value);
9
12
  }
@@ -13,7 +16,9 @@ export class JSONArrayField extends EntityFieldDefinition<any[]> {
13
16
  * EntityFieldDefinition for a Postgres column that may be a JS JSON array type.
14
17
  * Does not do any validation.
15
18
  */
16
- export class MaybeJSONArrayField extends EntityFieldDefinition<any | any[]> {
19
+ export class MaybeJSONArrayField<
20
+ TRequireExplicitCache extends boolean,
21
+ > extends EntityFieldDefinition<any | any[], TRequireExplicitCache> {
17
22
  protected validateInputValueInternal(_value: any): boolean {
18
23
  return true;
19
24
  }
@@ -22,7 +27,10 @@ export class MaybeJSONArrayField extends EntityFieldDefinition<any | any[]> {
22
27
  /**
23
28
  * EntityFieldDefinition for a Postgres BIGINT column.
24
29
  */
25
- export class BigIntField extends EntityFieldDefinition<string> {
30
+ export class BigIntField<TRequireExplicitCache extends boolean> extends EntityFieldDefinition<
31
+ string,
32
+ TRequireExplicitCache
33
+ > {
26
34
  protected validateInputValueInternal(value: string): boolean {
27
35
  return typeof value === 'string';
28
36
  }
@@ -14,7 +14,8 @@ import wrapNativePostgresCallAsync from './errors/wrapNativePostgresCallAsync';
14
14
 
15
15
  export default class PostgresEntityDatabaseAdapter<
16
16
  TFields extends Record<string, any>,
17
- > extends EntityDatabaseAdapter<TFields> {
17
+ TIDField extends keyof TFields,
18
+ > extends EntityDatabaseAdapter<TFields, TIDField> {
18
19
  protected getFieldTransformerMap(): FieldTransformerMap {
19
20
  return new Map<string, FieldTransformer<any>>([
20
21
  [
@@ -44,14 +45,44 @@ export default class PostgresEntityDatabaseAdapter<
44
45
  protected async fetchManyWhereInternalAsync(
45
46
  queryInterface: Knex,
46
47
  tableName: string,
47
- tableField: string,
48
- tableValues: readonly any[],
48
+ tableColumns: readonly string[],
49
+ tableTuples: any[][],
49
50
  ): Promise<object[]> {
51
+ // For single column queries, use the ANY operator to derive a consistent
52
+ // query shape in the postgres query stats table.
53
+ // This produces a query of the form `SELECT * FROM table WHERE ("id") = ANY(?)`
54
+ // with value bindings of the form `[[1]]`, thus not making different value cardinalities
55
+ // produce different query shapes.
56
+ //
57
+ // But for multi-column queries, we must use the IN operator as the ANY operator
58
+ // does not support anonymous composite types. The solution to keep using the ANY operator would be explicit
59
+ // postgres type casting on each value in each tableTuple, thus creating a unique query shape and defeating the purpose.
60
+ // The same applies to using UNNEST on anonymous composite types.
61
+ // Note that this solution is not possible in entity though since we don't have the postgres column types and they
62
+ // can't be derived dynamically.
63
+ //
64
+ // Therefore, for multi-column quries, we use the IN operator which produces a query of the form
65
+ // `SELECT * FROM table WHERE ("id", "name") IN ((?, ?), (?, ?))` with value bindings of the form
66
+ // `[[1, 'a'], [2, 'b']]`, which will produce a unique query shape in the postgres query stats table for
67
+ // each value cardinality.
68
+ //
69
+ // We could use the IN operator for single column queries as well, but we prefer to use ANY to at least keep some
70
+ // consistency in the query shape for the stats table.
71
+
72
+ if (tableColumns.length === 1) {
73
+ return await wrapNativePostgresCallAsync(() =>
74
+ queryInterface
75
+ .select()
76
+ .from(tableName)
77
+ .whereRaw(`(??) = ANY(?)`, [
78
+ tableColumns[0],
79
+ tableTuples.map((tableTuple) => tableTuple[0]),
80
+ ]),
81
+ );
82
+ }
83
+
50
84
  return await wrapNativePostgresCallAsync(() =>
51
- queryInterface
52
- .select()
53
- .from(tableName)
54
- .whereRaw('?? = ANY(?)', [tableField, tableValues as any[]]),
85
+ queryInterface.select().from(tableName).whereIn(tableColumns, tableTuples),
55
86
  );
56
87
  }
57
88
 
@@ -9,9 +9,9 @@ import PostgresEntityDatabaseAdapter from './PostgresEntityDatabaseAdapter';
9
9
  export default class PostgresEntityDatabaseAdapterProvider
10
10
  implements IEntityDatabaseAdapterProvider
11
11
  {
12
- getDatabaseAdapter<TFields extends Record<string, any>>(
13
- entityConfiguration: EntityConfiguration<TFields>,
14
- ): EntityDatabaseAdapter<TFields> {
12
+ getDatabaseAdapter<TFields extends Record<string, any>, TIDField extends keyof TFields>(
13
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
14
+ ): EntityDatabaseAdapter<TFields, TIDField> {
15
15
  return new PostgresEntityDatabaseAdapter(entityConfiguration);
16
16
  }
17
17
  }
@@ -1,18 +1,14 @@
1
- import {
2
- OrderByOrdering,
3
- createUnitTestEntityCompanionProvider,
4
- ViewerContext,
5
- TransactionIsolationLevel,
6
- } from '@expo/entity';
1
+ import { OrderByOrdering, ViewerContext, TransactionIsolationLevel } from '@expo/entity';
2
+ import { createUnitTestEntityCompanionProvider } from '@expo/entity-testing-utils';
7
3
  import { enforceAsyncResult } from '@expo/results';
8
4
  import { knex, Knex } from 'knex';
9
5
  import nullthrows from 'nullthrows';
10
6
  import { setTimeout } from 'timers/promises';
11
7
 
12
- import PostgresTestEntity from '../testfixtures/PostgresTestEntity';
13
- import PostgresTriggerTestEntity from '../testfixtures/PostgresTriggerTestEntity';
14
- import PostgresValidatorTestEntity from '../testfixtures/PostgresValidatorTestEntity';
15
- import { createKnexIntegrationTestEntityCompanionProvider } from '../testfixtures/createKnexIntegrationTestEntityCompanionProvider';
8
+ import PostgresTestEntity from '../__testfixtures__/PostgresTestEntity';
9
+ import PostgresTriggerTestEntity from '../__testfixtures__/PostgresTriggerTestEntity';
10
+ import PostgresValidatorTestEntity from '../__testfixtures__/PostgresValidatorTestEntity';
11
+ import { createKnexIntegrationTestEntityCompanionProvider } from '../__testfixtures__/createKnexIntegrationTestEntityCompanionProvider';
16
12
 
17
13
  describe('postgres entity integration', () => {
18
14
  let knexInstance: Knex;
@@ -259,6 +255,63 @@ describe('postgres entity integration', () => {
259
255
  });
260
256
  });
261
257
 
258
+ it('supports single field and composite field equality loading', async () => {
259
+ const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
260
+
261
+ const e1 = await enforceAsyncResult(
262
+ PostgresTestEntity.creatorWithAuthorizationResults(vc1)
263
+ .setField('name', 'hello')
264
+ .setField('hasACat', false)
265
+ .setField('hasADog', true)
266
+ .createAsync(),
267
+ );
268
+
269
+ await enforceAsyncResult(
270
+ PostgresTestEntity.creatorWithAuthorizationResults(vc1)
271
+ .setField('name', 'world')
272
+ .setField('hasACat', false)
273
+ .setField('hasADog', true)
274
+ .createAsync(),
275
+ );
276
+
277
+ await enforceAsyncResult(
278
+ PostgresTestEntity.creatorWithAuthorizationResults(vc1)
279
+ .setField('name', 'wat')
280
+ .setField('hasACat', false)
281
+ .setField('hasADog', false)
282
+ .createAsync(),
283
+ );
284
+
285
+ const e1Loaded = await PostgresTestEntity.loader(vc1).loadByIDAsync(e1.getID());
286
+ expect(e1Loaded).not.toBeNull();
287
+
288
+ const results = await PostgresTestEntity.loader(vc1).loadManyByFieldEqualingAsync(
289
+ 'hasACat',
290
+ false,
291
+ );
292
+ expect(results).toHaveLength(3);
293
+
294
+ const compositeResults = await PostgresTestEntity.loader(
295
+ vc1,
296
+ ).loadManyByCompositeFieldEqualingManyAsync(
297
+ ['hasACat', 'hasADog'],
298
+ [
299
+ { hasACat: false, hasADog: true },
300
+ { hasACat: false, hasADog: false },
301
+ ],
302
+ );
303
+ expect(compositeResults.size).toBe(2);
304
+ expect(compositeResults.get({ hasACat: false, hasADog: true })).toHaveLength(2);
305
+ expect(compositeResults.get({ hasACat: false, hasADog: false })).toHaveLength(1);
306
+
307
+ const results2 = await PostgresTestEntity.loader(vc1).loadManyByFieldEqualingManyAsync(
308
+ 'hasADog',
309
+ [true, false],
310
+ );
311
+ expect(results2.get(true)).toHaveLength(2);
312
+ expect(results2.get(false)).toHaveLength(1);
313
+ });
314
+
262
315
  describe('conjunction field equality loading', () => {
263
316
  it('supports single fieldValue and multiple fieldValues', async () => {
264
317
  const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
@@ -3,8 +3,8 @@ import { knex, Knex } from 'knex';
3
3
  import nullthrows from 'nullthrows';
4
4
 
5
5
  import PostgresEntityQueryContextProvider from '../PostgresEntityQueryContextProvider';
6
- import PostgresUniqueTestEntity from '../testfixtures/PostgresUniqueTestEntity';
7
- import { createKnexIntegrationTestEntityCompanionProvider } from '../testfixtures/createKnexIntegrationTestEntityCompanionProvider';
6
+ import PostgresUniqueTestEntity from '../__testfixtures__/PostgresUniqueTestEntity';
7
+ import { createKnexIntegrationTestEntityCompanionProvider } from '../__testfixtures__/createKnexIntegrationTestEntityCompanionProvider';
8
8
 
9
9
  describe(PostgresEntityQueryContextProvider, () => {
10
10
  let knexInstance: Knex;
@@ -3,8 +3,8 @@ import { enforceAsyncResult } from '@expo/results';
3
3
  import { knex, Knex } from 'knex';
4
4
  import nullthrows from 'nullthrows';
5
5
 
6
- import InvalidTestEntity from '../testfixtures/InvalidTestEntity';
7
- import { createKnexIntegrationTestEntityCompanionProvider } from '../testfixtures/createKnexIntegrationTestEntityCompanionProvider';
6
+ import InvalidTestEntity from '../__testfixtures__/InvalidTestEntity';
7
+ import { createKnexIntegrationTestEntityCompanionProvider } from '../__testfixtures__/createKnexIntegrationTestEntityCompanionProvider';
8
8
 
9
9
  describe('postgres entity integration', () => {
10
10
  let knexInstance: Knex;
@@ -11,8 +11,8 @@ import {
11
11
  import { knex, Knex } from 'knex';
12
12
  import nullthrows from 'nullthrows';
13
13
 
14
- import ErrorsTestEntity from '../testfixtures/ErrorsTestEntity';
15
- import { createKnexIntegrationTestEntityCompanionProvider } from '../testfixtures/createKnexIntegrationTestEntityCompanionProvider';
14
+ import ErrorsTestEntity from '../__testfixtures__/ErrorsTestEntity';
15
+ import { createKnexIntegrationTestEntityCompanionProvider } from '../__testfixtures__/createKnexIntegrationTestEntityCompanionProvider';
16
16
 
17
17
  describe('postgres errors', () => {
18
18
  let knexInstance: Knex;
@@ -22,14 +22,10 @@ type ErrorsTestEntityFields = {
22
22
 
23
23
  const foreignTableName = 'foreign_table';
24
24
 
25
- export default class ErrorsTestEntity extends Entity<
26
- ErrorsTestEntityFields,
27
- number,
28
- ViewerContext
29
- > {
25
+ export default class ErrorsTestEntity extends Entity<ErrorsTestEntityFields, 'id', ViewerContext> {
30
26
  static defineCompanionDefinition(): EntityCompanionDefinition<
31
27
  ErrorsTestEntityFields,
32
- number,
28
+ 'id',
33
29
  ViewerContext,
34
30
  ErrorsTestEntity,
35
31
  ErrorsTestEntityPrivacyPolicy
@@ -105,14 +101,14 @@ export default class ErrorsTestEntity extends Entity<
105
101
 
106
102
  class ErrorsTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
107
103
  ErrorsTestEntityFields,
108
- number,
104
+ 'id',
109
105
  ViewerContext,
110
106
  ErrorsTestEntity
111
107
  > {
112
108
  protected override readonly createRules = [
113
109
  new AlwaysAllowPrivacyPolicyRule<
114
110
  ErrorsTestEntityFields,
115
- number,
111
+ 'id',
116
112
  ViewerContext,
117
113
  ErrorsTestEntity
118
114
  >(),
@@ -120,7 +116,7 @@ class ErrorsTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
120
116
  protected override readonly readRules = [
121
117
  new AlwaysAllowPrivacyPolicyRule<
122
118
  ErrorsTestEntityFields,
123
- number,
119
+ 'id',
124
120
  ViewerContext,
125
121
  ErrorsTestEntity
126
122
  >(),
@@ -128,7 +124,7 @@ class ErrorsTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
128
124
  protected override readonly updateRules = [
129
125
  new AlwaysAllowPrivacyPolicyRule<
130
126
  ErrorsTestEntityFields,
131
- number,
127
+ 'id',
132
128
  ViewerContext,
133
129
  ErrorsTestEntity
134
130
  >(),
@@ -136,19 +132,20 @@ class ErrorsTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
136
132
  protected override readonly deleteRules = [
137
133
  new AlwaysAllowPrivacyPolicyRule<
138
134
  ErrorsTestEntityFields,
139
- number,
135
+ 'id',
140
136
  ViewerContext,
141
137
  ErrorsTestEntity
142
138
  >(),
143
139
  ];
144
140
  }
145
141
 
146
- export const ErrorsTestEntityConfiguration = new EntityConfiguration<ErrorsTestEntityFields>({
142
+ export const ErrorsTestEntityConfiguration = new EntityConfiguration<ErrorsTestEntityFields, 'id'>({
147
143
  idField: 'id',
148
144
  tableName: 'postgres_test_entities',
149
145
  schema: {
150
146
  id: new IntField({
151
147
  columnName: 'id',
148
+ cache: false,
152
149
  }),
153
150
  fieldNonNull: new StringField({
154
151
  columnName: 'field_non_null',
@@ -17,12 +17,12 @@ type InvalidTestEntityFields = {
17
17
 
18
18
  export default class InvalidTestEntity extends Entity<
19
19
  InvalidTestEntityFields,
20
- number,
20
+ 'id',
21
21
  ViewerContext
22
22
  > {
23
23
  static defineCompanionDefinition(): EntityCompanionDefinition<
24
24
  InvalidTestEntityFields,
25
- number,
25
+ 'id',
26
26
  ViewerContext,
27
27
  InvalidTestEntity,
28
28
  InvalidTestEntityPrivacyPolicy
@@ -57,14 +57,14 @@ export default class InvalidTestEntity extends Entity<
57
57
 
58
58
  class InvalidTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
59
59
  InvalidTestEntityFields,
60
- number,
60
+ 'id',
61
61
  ViewerContext,
62
62
  InvalidTestEntity
63
63
  > {
64
64
  protected override readonly createRules = [
65
65
  new AlwaysAllowPrivacyPolicyRule<
66
66
  InvalidTestEntityFields,
67
- number,
67
+ 'id',
68
68
  ViewerContext,
69
69
  InvalidTestEntity
70
70
  >(),
@@ -72,7 +72,7 @@ class InvalidTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
72
72
  protected override readonly readRules = [
73
73
  new AlwaysAllowPrivacyPolicyRule<
74
74
  InvalidTestEntityFields,
75
- number,
75
+ 'id',
76
76
  ViewerContext,
77
77
  InvalidTestEntity
78
78
  >(),
@@ -80,7 +80,7 @@ class InvalidTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
80
80
  protected override readonly updateRules = [
81
81
  new AlwaysAllowPrivacyPolicyRule<
82
82
  InvalidTestEntityFields,
83
- number,
83
+ 'id',
84
84
  ViewerContext,
85
85
  InvalidTestEntity
86
86
  >(),
@@ -88,19 +88,23 @@ class InvalidTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
88
88
  protected override readonly deleteRules = [
89
89
  new AlwaysAllowPrivacyPolicyRule<
90
90
  InvalidTestEntityFields,
91
- number,
91
+ 'id',
92
92
  ViewerContext,
93
93
  InvalidTestEntity
94
94
  >(),
95
95
  ];
96
96
  }
97
97
 
98
- export const invalidTestEntityConfiguration = new EntityConfiguration<InvalidTestEntityFields>({
98
+ export const invalidTestEntityConfiguration = new EntityConfiguration<
99
+ InvalidTestEntityFields,
100
+ 'id'
101
+ >({
99
102
  idField: 'id',
100
103
  tableName: 'postgres_test_entities',
101
104
  schema: {
102
105
  id: new IntField({
103
106
  columnName: 'id',
107
+ cache: false,
104
108
  }),
105
109
  name: new StringField({
106
110
  columnName: 'name',
@@ -2,7 +2,6 @@ import {
2
2
  AlwaysAllowPrivacyPolicyRule,
3
3
  EntityPrivacyPolicy,
4
4
  ViewerContext,
5
- UUIDField,
6
5
  StringField,
7
6
  BooleanField,
8
7
  StringArrayField,
@@ -11,6 +10,7 @@ import {
11
10
  EntityConfiguration,
12
11
  EntityCompanionDefinition,
13
12
  Entity,
13
+ UUIDField,
14
14
  } from '@expo/entity';
15
15
  import { Knex } from 'knex';
16
16
 
@@ -33,12 +33,12 @@ type PostgresTestEntityFields = {
33
33
 
34
34
  export default class PostgresTestEntity extends Entity<
35
35
  PostgresTestEntityFields,
36
- string,
36
+ 'id',
37
37
  ViewerContext
38
38
  > {
39
39
  static defineCompanionDefinition(): EntityCompanionDefinition<
40
40
  PostgresTestEntityFields,
41
- string,
41
+ 'id',
42
42
  ViewerContext,
43
43
  PostgresTestEntity,
44
44
  PostgresTestEntityPrivacyPolicy
@@ -81,14 +81,14 @@ export default class PostgresTestEntity extends Entity<
81
81
 
82
82
  class PostgresTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
83
83
  PostgresTestEntityFields,
84
- string,
84
+ 'id',
85
85
  ViewerContext,
86
86
  PostgresTestEntity
87
87
  > {
88
88
  protected override readonly createRules = [
89
89
  new AlwaysAllowPrivacyPolicyRule<
90
90
  PostgresTestEntityFields,
91
- string,
91
+ 'id',
92
92
  ViewerContext,
93
93
  PostgresTestEntity
94
94
  >(),
@@ -96,7 +96,7 @@ class PostgresTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
96
96
  protected override readonly readRules = [
97
97
  new AlwaysAllowPrivacyPolicyRule<
98
98
  PostgresTestEntityFields,
99
- string,
99
+ 'id',
100
100
  ViewerContext,
101
101
  PostgresTestEntity
102
102
  >(),
@@ -104,7 +104,7 @@ class PostgresTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
104
104
  protected override readonly updateRules = [
105
105
  new AlwaysAllowPrivacyPolicyRule<
106
106
  PostgresTestEntityFields,
107
- string,
107
+ 'id',
108
108
  ViewerContext,
109
109
  PostgresTestEntity
110
110
  >(),
@@ -112,14 +112,17 @@ class PostgresTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
112
112
  protected override readonly deleteRules = [
113
113
  new AlwaysAllowPrivacyPolicyRule<
114
114
  PostgresTestEntityFields,
115
- string,
115
+ 'id',
116
116
  ViewerContext,
117
117
  PostgresTestEntity
118
118
  >(),
119
119
  ];
120
120
  }
121
121
 
122
- export const postgresTestEntityConfiguration = new EntityConfiguration<PostgresTestEntityFields>({
122
+ export const postgresTestEntityConfiguration = new EntityConfiguration<
123
+ PostgresTestEntityFields,
124
+ 'id'
125
+ >({
123
126
  idField: 'id',
124
127
  tableName: 'postgres_test_entities',
125
128
  schema: {
@@ -157,4 +160,5 @@ export const postgresTestEntityConfiguration = new EntityConfiguration<PostgresT
157
160
  },
158
161
  databaseAdapterFlavor: 'postgres',
159
162
  cacheAdapterFlavor: 'redis',
163
+ compositeFieldDefinitions: [{ compositeField: ['hasACat', 'hasADog'], cache: false }],
160
164
  });