Repository: typedorm/typedorm (ts)

Issue:
Strongly Consistent Reads
I searched docs and some of the source for options to pass in the ability to read w/ strong consistency but couldn't find anything. Is this automatically applied, or currently not available?

Pull request:
[#198] strong consistent read support
closes #198 

Patch:
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6eaa21a..73f1813 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -14,5 +14,6 @@
     "unmarshall"
   ],
   "editor.formatOnSave": true,
-  "typescript.tsdk": "node_modules/typescript/lib"
+  "typescript.tsdk": "node_modules/typescript/lib",
+  "jest.autoRun": "off"
 }
diff --git a/docs/api.md b/docs/api.md
index b1cbfca..4b2ae6e 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -243,6 +243,11 @@ findOne(
     // Specify attributes to get, only selected attributes are fetched
     // @default `ALL`
     select
+
+    // @optional
+    // Perform a consistent read on the table, consumes twice as much RCUs then normal
+    // @default false
+    consistentRead
   },
 
   // @optional
@@ -272,6 +277,14 @@ exists(
   // Primary key attributes or unique attributes referenced in schemas
   attributes,
 
+  // @optional
+  options: {
+    // @optional
+    // Perform a consistent read on the table, consumes twice as much RCUs then normal
+    // @default false
+    consistentRead
+  }
+
   // @optional
   // extra non-functional options
   metadataOptions: {
@@ -428,6 +441,11 @@ find(
     // Specify attributes to get, only selected attributes are fetched
     // @default `ALL`
     select
+
+    // @optional
+    // Perform a consistent read on the table, consumes twice as much RCUs then normal
+    // @default false
+    consistentRead
   },
 
   // @optional
@@ -477,6 +495,11 @@ count(
     // therefore this should be avoided wherever possible, but can be helpful in some cases
     // see this https://www.alexdebrie.com/posts/dynamodb-filter-expressions/ for more details
     where
+
+    // @optional
+    // Perform a consistent read on the table, consumes twice as much RCUs then normal
+    // @default false
+    consistentRead
   },
 
   // @optional
diff --git a/packages/core/src/classes/manager/entity-manager.ts b/packages/core/src/classes/manager/entity-manager.ts
index 90c347a..c838e3d 100644
--- a/packages/core/src/classes/manager/entity-manager.ts
+++ b/packages/core/src/classes/manager/entity-manager.ts
@@ -1,4 +1,5 @@
 import {
+  CONSUMED_CAPACITY_TYPE,
   EntityAttributes,
   EntityTarget,
   MANAGER_NAME,
@@ -95,6 +96,16 @@ export interface EntityManagerFindOptions<Entity, PartitionKey> {
    * @default all attributes are fetched
    */
   select?: ProjectionKeys<Entity>;
+
+  /**
+   * Perform a consistent read on the table, consumes twice as much RCUs then normal
+   *
+   * @description Strongly consistent reads are not supported on global secondary indexes.
+   * If you query a global secondary index with ConsistentRead set to true,
+   * you will receive a ValidationException.
+   * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-ConsistentRead
+   */
+  consistentRead?: boolean;
 }
 
 export interface EntityManagerCountOptions<Entity, PartitionKey> {
@@ -115,6 +126,16 @@ export interface EntityManagerCountOptions<Entity, PartitionKey> {
    * are read
    */
   where?: FilterOptions<Entity, PartitionKey>;
+
+  /**
+   * Perform a consistent read on the table, consumes twice as much RCUs then normal
+   *
+   * @description Strongly consistent reads are not supported on global secondary indexes.
+   * If you query a global secondary index with ConsistentRead set to true,
+   * you will receive a ValidationException.
+   * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-ConsistentRead
+   */
+  consistentRead?: boolean;
 }
 
 export interface EntityManagerFindOneOptions<Entity> {
@@ -123,6 +144,35 @@ export interface EntityManagerFindOneOptions<Entity> {
    * @default all attributes are fetched
    */
   select?: ProjectionKeys<Entity>;
+
+  /**
+   * Perform a consistent read on the table, consumes twice as much RCUs then normal
+   */
+  consistentRead?: boolean;
+}
+
+export interface EntityManagerExistsOptions {
+  /**
+   * Perform a consistent read on the table, consumes twice as much RCUs then normal
+   *
+   * @description Strongly consistent reads are not supported on global secondary indexes.
+   * If you query a global secondary index with ConsistentRead set to true,
+   * you will receive a ValidationException.
+   * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-ConsistentRead
+   */
+  consistentRead?: boolean;
+
+  /**
+   * @deprecated - Provide the "requestId" in the next parameter instead
+   * Only available here for backwards compatibility
+   */
+  requestId?: string;
+
+  /**
+   * @deprecated - Provide the "returnConsumedCapacity" in the next parameter instead
+   * Only available here for backwards compatibility
+   */
+  returnConsumedCapacity?: CONSUMED_CAPACITY_TYPE;
 }
 
 export class EntityManager {
@@ -262,6 +312,7 @@ export class EntityManager {
   async exists<Entity, KeyAttributes = Partial<Entity>>(
     entityClass: EntityTarget<Entity>,
     attributes: KeyAttributes,
+    options?: EntityManagerExistsOptions,
     metadataOptions?: MetadataOptions
   ) {
     if (isEmptyObject(attributes)) {
@@ -314,14 +365,21 @@ export class EntityManager {
       return !!(await this.findOne(
         entityClass,
         attributes,
-        undefined,
-        metadataOptions
+        {consistentRead: options?.consistentRead},
+        {
+          requestId: options?.requestId ?? metadataOptions?.requestId,
+          returnConsumedCapacity:
+            options?.returnConsumedCapacity ??
+            metadataOptions?.returnConsumedCapacity,
+        }
       ));
     }
 
     // try finding entity by unique attribute
     if (!isEmptyObject(uniqueAttributes)) {
-      const requestId = getUniqueRequestId(metadataOptions?.requestId);
+      const requestId = getUniqueRequestId(
+        options?.requestId ?? metadataOptions?.requestId
+      );
       if (Object.keys(uniqueAttributes).length > 1) {
         throw new Error('Can only query one unique attribute at a time.');
       }
@@ -345,7 +403,9 @@ export class EntityManager {
       const response = await this.connection.documentClient.get({
         Key: {...parsedPrimaryKey},
         TableName: metadata.table.name,
-        ReturnConsumedCapacity: metadataOptions?.returnConsumedCapacity,
+        ConsistentRead: options?.consistentRead,
+        ReturnConsumedCapacity:
+          options?.requestId ?? metadataOptions?.returnConsumedCapacity,
       });
       // stats
       if (response?.ConsumedCapacity) {
diff --git a/packages/core/src/classes/transformer/document-client-request-transformer.ts b/packages/core/src/classes/transformer/document-client-request-transformer.ts
index 3e0e7fb..804d215 100644
--- a/packages/core/src/classes/transformer/document-client-request-transformer.ts
+++ b/packages/core/src/classes/transformer/document-client-request-transformer.ts
@@ -82,10 +82,13 @@ export interface ManagerToDynamoQueryItemsOptions {
   select?: any[];
 
   onlyCount?: boolean;
+
+  consistentRead?: boolean;
 }
 
 export interface ManagerToDynamoGetItemOptions {
   select?: any[];
+  consistentRead?: boolean;
 }
 
 export class DocumentClientRequestTransformer extends BaseTransformer {
@@ -300,23 +303,12 @@ export class DocumentClientRequestTransformer extends BaseTransformer {
       Key: {
         ...parsedPrimaryKey,
       },
+      ConsistentRead: options?.consistentRead,
       ReturnConsumedCapacity: metadataOptions?.returnConsumedCapacity,
     } as DocumentClientTypes.GetItemInput;
 
-    // early return if no options were provided
-    if (!options || isEmptyObject(options)) {
-      this.connection.logger.logTransform({
-        requestId: metadataOptions?.requestId,
-        operation: TRANSFORM_TYPE.GET,
-        prefix: 'After',
-        entityName: metadata.name,
-        primaryKey: null,
-        body: transformBody,
-      });
-      return transformBody;
-    }
-
-    if (options.select?.length) {
+    // if restricted item projection was requested
+    if (options?.select?.length) {
       const projection = this.expressionInputParser.parseToProjection(
         options.select
       );
@@ -846,27 +838,6 @@ export class DocumentClientRequestTransformer extends BaseTransformer {
       partitionKeyCondition
     );
 
-    // if no query options are present, resolve key condition expression
-    if (!queryOptions || isEmptyObject(queryOptions)) {
-      const transformedQueryItem = {
-        TableName: table.name,
-        IndexName: queryIndexName,
-        ReturnConsumedCapacity: metadataOptions?.returnConsumedCapacity,
-        ...partitionKeyConditionExpression,
-      };
-
-      this.connection.logger.logTransform({
-        requestId: metadataOptions?.requestId,
-        operation: TRANSFORM_TYPE.QUERY,
-        prefix: 'After',
-        entityName: name,
-        primaryKey: partitionKeyAttributes,
-        body: transformedQueryItem,
-      });
-
-      return transformedQueryItem;
-    }
-
     const parsedSortKey = {} as {name: string};
     // if no we are not querying against index, validate if table is using composite key
     if (!indexToQuery) {
@@ -882,115 +853,126 @@ export class DocumentClientRequestTransformer extends BaseTransformer {
     }
 
     // at this point we have resolved partition key and table to query
-    const {
-      keyCondition,
-      limit,
-      orderBy: order,
-      where,
-      select,
-      onlyCount,
-    } = queryOptions;
-
     let queryInputParams = {
       TableName: table.name,
       IndexName: queryIndexName,
       ReturnConsumedCapacity: metadataOptions?.returnConsumedCapacity,
-      Limit: limit,
-      ScanIndexForward: !order || order === QUERY_ORDER.ASC,
       ...partitionKeyConditionExpression,
     } as DocumentClientTypes.QueryInput;
 
-    // if key condition was provided
-    if (keyCondition && !isEmptyObject(keyCondition)) {
-      // build sort key condition
-      const sortKeyCondition = this.expressionInputParser.parseToKeyCondition(
-        parsedSortKey.name,
-        keyCondition
-      );
-
-      // if condition resolution was successful, we can merge both partition and sort key conditions now
+    if (queryOptions && !isEmptyObject(queryOptions)) {
       const {
-        KeyConditionExpression,
-        ExpressionAttributeNames,
-        ExpressionAttributeValues,
-      } = this.expressionBuilder.buildKeyConditionExpression(
-        partitionKeyCondition.merge(sortKeyCondition)
-      );
+        orderBy: order,
+        limit,
+        keyCondition,
+        where,
+        select,
+        onlyCount,
+        consistentRead,
+      } = queryOptions;
 
       queryInputParams = {
         ...queryInputParams,
-        KeyConditionExpression,
-        ExpressionAttributeNames: {
-          ...queryInputParams.ExpressionAttributeNames,
-          ...ExpressionAttributeNames,
-        },
-        ExpressionAttributeValues: {
-          ...queryInputParams.ExpressionAttributeValues,
-          ...ExpressionAttributeValues,
-        },
+        Limit: limit,
+        ConsistentRead: consistentRead,
       };
-    }
-
-    // when filter conditions are given generate filter expression
-    if (where && !isEmptyObject(where)) {
-      const filter = this.expressionInputParser.parseToFilter(where);
 
-      if (!filter) {
-        throw new InvalidFilterInputError(where);
+      if (order) {
+        queryInputParams.ScanIndexForward = order === QUERY_ORDER.ASC;
       }
 
-      const {
-        FilterExpression,
-        ExpressionAttributeNames,
-        ExpressionAttributeValues,
-      } = this.expressionBuilder.buildFilterExpression(filter);
-
-      queryInputParams = {
-        ...queryInputParams,
-        FilterExpression,
-        ExpressionAttributeNames: {
-          ...queryInputParams.ExpressionAttributeNames,
-          ...ExpressionAttributeNames,
-        },
-        ExpressionAttributeValues: {
-          ...queryInputParams.ExpressionAttributeValues,
-          ...ExpressionAttributeValues,
-        },
-      };
-    }
+      // if key condition was provided
+      if (keyCondition && !isEmptyObject(keyCondition)) {
+        // build sort key condition
+        const sortKeyCondition = this.expressionInputParser.parseToKeyCondition(
+          parsedSortKey.name,
+          keyCondition
+        );
 
-    // check if only the count was requested
-    if (onlyCount) {
-      if (select?.length) {
-        throw new Error(
-          'Attributes projection and count can not be used together'
+        // if condition resolution was successful, we can merge both partition and sort key conditions now
+        const {
+          KeyConditionExpression,
+          ExpressionAttributeNames,
+          ExpressionAttributeValues,
+        } = this.expressionBuilder.buildKeyConditionExpression(
+          partitionKeyCondition.merge(sortKeyCondition)
         );
+
+        queryInputParams = {
+          ...queryInputParams,
+          KeyConditionExpression,
+          ExpressionAttributeNames: {
+            ...queryInputParams.ExpressionAttributeNames,
+            ...ExpressionAttributeNames,
+          },
+          ExpressionAttributeValues: {
+            ...queryInputParams.ExpressionAttributeValues,
+            ...ExpressionAttributeValues,
+          },
+        };
       }
-      // count and projection selection can not be used together
-      queryInputParams.Select = QUERY_SELECT_TYPE.COUNT;
-    }
 
-    // when projection keys are provided
-    if (select && select.length) {
-      const projection = this.expressionInputParser.parseToProjection(select);
+      // when filter conditions are given generate filter expression
+      if (where && !isEmptyObject(where)) {
+        const filter = this.expressionInputParser.parseToFilter(where);
 
-      if (!projection) {
-        throw new InvalidSelectInputError(select);
+        if (!filter) {
+          throw new InvalidFilterInputError(where);
+        }
+
+        const {
+          FilterExpression,
+          ExpressionAttributeNames,
+          ExpressionAttributeValues,
+        } = this.expressionBuilder.buildFilterExpression(filter);
+
+        queryInputParams = {
+          ...queryInputParams,
+          FilterExpression,
+          ExpressionAttributeNames: {
+            ...queryInputParams.ExpressionAttributeNames,
+            ...ExpressionAttributeNames,
+          },
+          ExpressionAttributeValues: {
+            ...queryInputParams.ExpressionAttributeValues,
+            ...ExpressionAttributeValues,
+          },
+        };
       }
 
-      const {
-        ProjectionExpression,
-        ExpressionAttributeNames,
-      } = this.expressionBuilder.buildProjectionExpression(projection);
+      // check if only the count was requested
+      if (onlyCount) {
+        if (select?.length) {
+          throw new Error(
+            'Attributes projection and count can not be used together'
+          );
+        }
+        // count and projection selection can not be used together
+        queryInputParams.Select = QUERY_SELECT_TYPE.COUNT;
+      }
 
-      queryInputParams = {
-        ...queryInputParams,
-        ProjectionExpression,
-        ExpressionAttributeNames: {
-          ...queryInputParams.ExpressionAttributeNames,
-          ...ExpressionAttributeNames,
-        },
-      };
+      // when projection keys are provided
+      if (select && select.length) {
+        const projection = this.expressionInputParser.parseToProjection(select);
+
+        if (!projection) {
+          throw new InvalidSelectInputError(select);
+        }
+
+        const {
+          ProjectionExpression,
+          ExpressionAttributeNames,
+        } = this.expressionBuilder.buildProjectionExpression(projection);
+
+        queryInputParams = {
+          ...queryInputParams,
+          ProjectionExpression,
+          ExpressionAttributeNames: {
+            ...queryInputParams.ExpressionAttributeNames,
+            ...ExpressionAttributeNames,
+          },
+        };
+      }
     }
 
     this.connection.logger.logTransform({


Test patch:
diff --git a/__test__/github-issues/157/issue-157.spec.ts b/__test__/github-issues/157/issue-157.spec.ts
index 78ea2a1..034dc28 100644
--- a/__test__/github-issues/157/issue-157.spec.ts
+++ b/__test__/github-issues/157/issue-157.spec.ts
@@ -62,7 +62,6 @@ test('correctly queries matching items when values for set type is not a native
     IndexName: 'email-index-v2',
     KeyConditionExpression: '#KY_CE_email = :KY_CE_email',
     Limit: 1,
-    ScanIndexForward: true,
     TableName: 'user-v2',
   });
 
diff --git a/packages/core/src/classes/manager/__test__/entity-manager.spec.ts b/packages/core/src/classes/manager/__test__/entity-manager.spec.ts
index d3829fe..e3a8790 100644
--- a/packages/core/src/classes/manager/__test__/entity-manager.spec.ts
+++ b/packages/core/src/classes/manager/__test__/entity-manager.spec.ts
@@ -230,15 +230,22 @@ test('finds one entity by given primary key', async () => {
     }),
   });
 
-  const userEntity = await manager.findOne<User, UserPrimaryKey>(User, {
-    id: '1',
-  });
+  const userEntity = await manager.findOne<User, UserPrimaryKey>(
+    User,
+    {
+      id: '1',
+    },
+    {
+      consistentRead: true,
+    }
+  );
   expect(dcMock.get).toHaveBeenCalledTimes(1);
   expect(dcMock.get).toHaveBeenCalledWith({
     Key: {
       PK: 'USER#1',
       SK: 'USER#1',
     },
+    ConsistentRead: true,
     TableName: 'test-table',
   });
   expect(userEntity).toEqual({
@@ -304,6 +311,7 @@ test('checks if given item exists', async () => {
       id: '1',
     },
     {
+      consistentRead: true,
       returnConsumedCapacity: CONSUMED_CAPACITY_TYPE.INDEXES,
     }
   );
@@ -314,6 +322,7 @@ test('checks if given item exists', async () => {
       SK: 'USER#1',
     },
     TableName: 'test-table',
+    ConsistentRead: true,
     ReturnConsumedCapacity: 'INDEXES',
   });
   expect(userEntity).toEqual(true);
@@ -1060,7 +1069,6 @@ test('finds items matching given query params', async () => {
     KeyConditionExpression:
       '(#KY_CE_PK = :KY_CE_PK) AND (begins_with(#KY_CE_SK, :KY_CE_SK))',
     Limit: 10,
-    ScanIndexForward: true,
     TableName: 'test-table',
   });
   expect(users).toEqual({
@@ -1110,6 +1118,7 @@ test('finds items matching given query params and options', async () => {
       keyCondition: {
         BEGINS_WITH: 'USER#',
       },
+      consistentRead: true,
       where: {
         AND: {
           age: {
@@ -1141,12 +1150,12 @@ test('finds items matching given query params and options', async () => {
       ':FE_age_start': 1,
       ':FE_name': 'Me',
     },
+    ConsistentRead: true,
     KeyConditionExpression:
       '(#KY_CE_PK = :KY_CE_PK) AND (begins_with(#KY_CE_SK, :KY_CE_SK))',
     FilterExpression:
       '(#FE_age BETWEEN :FE_age_start AND :FE_age_end) AND (#FE_name = :FE_name) AND (attribute_exists(#FE_status))',
     Limit: 10,
-    ScanIndexForward: true,
     TableName: 'test-table',
   });
   expect(users).toEqual({
@@ -1199,7 +1208,6 @@ test('finds items with alternate syntax', async () => {
     KeyConditionExpression:
       '(#KY_CE_PK = :KY_CE_PK) AND (begins_with(#KY_CE_SK, :KY_CE_SK))',
     Limit: 10,
-    ScanIndexForward: true,
     TableName: 'test-table',
   });
   expect(users).toEqual({
@@ -1272,7 +1280,6 @@ test('finds item from given cursor position', async () => {
     KeyConditionExpression:
       '(#KY_CE_PK = :KY_CE_PK) AND (begins_with(#KY_CE_SK, :KY_CE_SK))',
     Limit: 10,
-    ScanIndexForward: true,
     TableName: 'test-table',
   });
 });
@@ -1333,7 +1340,6 @@ test('queries items until limit is met', async () => {
         KeyConditionExpression:
           '(#KY_CE_PK = :KY_CE_PK) AND (begins_with(#KY_CE_SK, :KY_CE_SK))',
         Limit: 2000,
-        ScanIndexForward: true,
         TableName: 'test-table',
       },
     ],
@@ -1351,7 +1357,6 @@ test('queries items until limit is met', async () => {
         KeyConditionExpression:
           '(#KY_CE_PK = :KY_CE_PK) AND (begins_with(#KY_CE_SK, :KY_CE_SK))',
         Limit: 2000,
-        ScanIndexForward: true,
         TableName: 'test-table',
       },
     ],
@@ -1378,6 +1383,7 @@ test('counts items matching given query params', async () => {
       keyCondition: {
         BEGINS_WITH: 'USER#',
       },
+      consistentRead: true,
     }
   );
 
@@ -1394,7 +1400,7 @@ test('counts items matching given query params', async () => {
     KeyConditionExpression:
       '(#KY_CE_PK = :KY_CE_PK) AND (begins_with(#KY_CE_SK, :KY_CE_SK))',
     Select: 'COUNT',
-    ScanIndexForward: true,
+    ConsistentRead: true,
     TableName: 'test-table',
   });
   expect(usersCount).toEqual(132);
@@ -1466,7 +1472,6 @@ test('counts items with multiple requests', async () => {
         FilterExpression:
           '(#FE_age BETWEEN :FE_age_start AND :FE_age_end) AND (#FE_name = :FE_name) AND (attribute_exists(#FE_status))',
         Select: 'COUNT',
-        ScanIndexForward: true,
         TableName: 'test-table',
       },
     ],
@@ -1492,7 +1497,6 @@ test('counts items with multiple requests', async () => {
         FilterExpression:
           '(#FE_age BETWEEN :FE_age_start AND :FE_age_end) AND (#FE_name = :FE_name) AND (attribute_exists(#FE_status))',
         Select: 'COUNT',
-        ScanIndexForward: true,
         TableName: 'test-table',
       },
     ],
@@ -1518,7 +1522,6 @@ test('counts items with multiple requests', async () => {
         FilterExpression:
           '(#FE_age BETWEEN :FE_age_start AND :FE_age_end) AND (#FE_name = :FE_name) AND (attribute_exists(#FE_status))',
         Select: 'COUNT',
-        ScanIndexForward: true,
         TableName: 'test-table',
       },
     ],
diff --git a/packages/core/src/classes/transformer/__test__/dc-request-transformer.spec.ts b/packages/core/src/classes/transformer/__test__/dc-request-transformer.spec.ts
index 3cb8b5f..2a8dee3 100644
--- a/packages/core/src/classes/transformer/__test__/dc-request-transformer.spec.ts
+++ b/packages/core/src/classes/transformer/__test__/dc-request-transformer.spec.ts
@@ -85,6 +85,27 @@ test('transforms get item requests for inherited class', () => {
   });
 });
 
+test('transforms get item requests with consistent read options', () => {
+  const getItem = transformer.toDynamoGetItem(
+    Customer,
+    {
+      id: '1',
+      email: 'user@example.com',
+    },
+    {
+      consistentRead: true,
+    }
+  );
+  expect(getItem).toEqual({
+    Key: {
+      PK: 'CUS#1',
+      SK: 'CUS#user@example.com',
+    },
+    TableName: 'test-table',
+    ConsistentRead: true,
+  });
+});
+
 /**
  * @group toDynamoPutItem
  */
@@ -1222,6 +1243,29 @@ test('transforms simple query item request', () => {
   });
 });
 
+test('transforms simple query item request with consistent read option', () => {
+  const queryItem = transformer.toDynamoQueryItem<User, UserPrimaryKey>(
+    User,
+    {
+      id: '1',
+    },
+    {
+      consistentRead: true,
+    }
+  );
+  expect(queryItem).toEqual({
+    ExpressionAttributeNames: {
+      '#KY_CE_PK': 'PK',
+    },
+    ExpressionAttributeValues: {
+      ':KY_CE_PK': 'USER#1',
+    },
+    KeyConditionExpression: '#KY_CE_PK = :KY_CE_PK',
+    TableName: 'test-table',
+    ConsistentRead: true,
+  });
+});
+
 test('transforms simple query item request with projection expression', () => {
   const queryItem = transformer.toDynamoQueryItem<User, UserPrimaryKey>(
     User,
@@ -1241,7 +1285,6 @@ test('transforms simple query item request with projection expression', () => {
     ExpressionAttributeValues: {
       ':KY_CE_PK': 'USER#1',
     },
-    ScanIndexForward: true,
     KeyConditionExpression: '#KY_CE_PK = :KY_CE_PK',
     TableName: 'test-table',
     ProjectionExpression: '#PE_status, #PE_name',
@@ -1265,7 +1308,6 @@ test('transforms simple count query item request', () => {
     ExpressionAttributeValues: {
       ':KY_CE_PK': 'USER#1',
     },
-    ScanIndexForward: true,
     KeyConditionExpression: '#KY_CE_PK = :KY_CE_PK',
     TableName: 'test-table',
     Select: 'COUNT',
@@ -1295,7 +1337,6 @@ test('transforms query item request with filter input', () => {
       ':KY_CE_PK': 'USER#1',
       ':FE_name': 'suzan',
     },
-    ScanIndexForward: true,
     KeyConditionExpression: '#KY_CE_PK = :KY_CE_PK',
     FilterExpression: '#FE_name = :FE_name',
     TableName: 'test-table',