From 0c84a39b7732e530bf0b2ffbc9273badbd695922 Mon Sep 17 00:00:00 2001 From: Nathan Duthoit Date: Tue, 16 Apr 2024 15:47:46 -0500 Subject: [PATCH] feat(aws-sdk-v3): remove v2 types --- src/aws-sdk-v2.types.ts | 21 ------------------- .../impl/index/gsi-partition-key.decorator.ts | 4 ++-- .../impl/index/gsi-sort-key.decorator.ts | 4 ++-- .../impl/index/lsi-sort-key.decorator.ts | 4 ++-- src/decorator/impl/index/util.ts | 6 +++--- .../impl/key/partition-key.decorator.ts | 4 ++-- src/decorator/impl/key/sort-key.decorator.ts | 4 ++-- src/decorator/impl/model/model.decorator.ts | 4 ++-- .../metadata/property-metadata.model.ts | 6 +++--- .../batchget/batch-get-full.response.ts | 3 +-- src/dynamo/batchget/batch-get-utils.ts | 3 +-- src/dynamo/batchwrite/batch-write-utils.ts | 3 +-- src/dynamo/expression/param-util.ts | 5 ++--- src/dynamo/operation-params.type.ts | 5 ++--- .../batch-get-single-table.response.ts | 3 +-- src/dynamo/request/query/query.response.ts | 3 +-- src/dynamo/request/read-many.request.ts | 3 +-- src/dynamo/request/scan/scan.response.ts | 3 +-- src/helper/fetch-all.function.ts | 4 ++-- src/mapper/mapper.spec.ts | 6 +++--- 20 files changed, 34 insertions(+), 64 deletions(-) delete mode 100644 src/aws-sdk-v2.types.ts diff --git a/src/aws-sdk-v2.types.ts b/src/aws-sdk-v2.types.ts deleted file mode 100644 index f4437bba5..000000000 --- a/src/aws-sdk-v2.types.ts +++ /dev/null @@ -1,21 +0,0 @@ -// tslint:disable:interface-over-type-literal -/* - * holds different types which are no longer available in aws-sdk v3, might be inlined at some point. Open to discuss. - * TODO v3: discuss how to proceed - */ -import { AttributeValue, KeysAndAttributes, WriteRequest } from '@aws-sdk/client-dynamodb' -export type BatchGetRequestMap = { [key: string]: KeysAndAttributes } -export type BatchWriteItemRequestMap = { [key: string]: WriteRequest[] } - -export type ExpressionAttributeNameMap = { [key: string]: string /* was: AttributeName */ } -export type ExpressionAttributeValueMap = { [key: string]: AttributeValue /* was: AttributeValue */ } - -export type AttributeMap = { [key: string]: AttributeValue } - -export type Key = { [key: string]: AttributeValue } - -// TODO v3: somehow the import of KeyType from @aws-sdk/client-dynamodb does not work at runtime -export enum KeyType { - HASH = 'HASH', - RANGE = 'RANGE', -} diff --git a/src/decorator/impl/index/gsi-partition-key.decorator.ts b/src/decorator/impl/index/gsi-partition-key.decorator.ts index e401c199c..cceea9929 100644 --- a/src/decorator/impl/index/gsi-partition-key.decorator.ts +++ b/src/decorator/impl/index/gsi-partition-key.decorator.ts @@ -1,7 +1,7 @@ /** * @module decorators */ -import { KeyType } from '../../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { IndexType } from './index-type.enum' import { initOrUpdateIndex } from './util' @@ -11,7 +11,7 @@ import { initOrUpdateIndex } from './util' export function GSIPartitionKey(indexName: string): PropertyDecorator { return (target: any, propertyKey: string | symbol) => { if (typeof propertyKey === 'string') { - initOrUpdateIndex(IndexType.GSI, { name: indexName, keyType: KeyType.HASH }, target, propertyKey) + initOrUpdateIndex(IndexType.GSI, { name: indexName, keyType: DynamoDB.KeyType.HASH }, target, propertyKey) } } } diff --git a/src/decorator/impl/index/gsi-sort-key.decorator.ts b/src/decorator/impl/index/gsi-sort-key.decorator.ts index 89e5c2ae7..201ecd40c 100644 --- a/src/decorator/impl/index/gsi-sort-key.decorator.ts +++ b/src/decorator/impl/index/gsi-sort-key.decorator.ts @@ -1,7 +1,7 @@ /** * @module decorators */ -import { KeyType } from '../../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { IndexType } from './index-type.enum' import { initOrUpdateIndex } from './util' @@ -11,7 +11,7 @@ import { initOrUpdateIndex } from './util' export function GSISortKey(indexName: string): PropertyDecorator { return (target: any, propertyKey: string | symbol) => { if (typeof propertyKey === 'string') { - initOrUpdateIndex(IndexType.GSI, { name: indexName, keyType: KeyType.RANGE }, target, propertyKey) + initOrUpdateIndex(IndexType.GSI, { name: indexName, keyType: DynamoDB.KeyType.RANGE }, target, propertyKey) } } } diff --git a/src/decorator/impl/index/lsi-sort-key.decorator.ts b/src/decorator/impl/index/lsi-sort-key.decorator.ts index a0295b006..cb9e02301 100644 --- a/src/decorator/impl/index/lsi-sort-key.decorator.ts +++ b/src/decorator/impl/index/lsi-sort-key.decorator.ts @@ -1,7 +1,7 @@ /** * @module decorators */ -import { KeyType } from '../../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { IndexType } from './index-type.enum' import { initOrUpdateIndex } from './util' @@ -11,7 +11,7 @@ import { initOrUpdateIndex } from './util' export function LSISortKey(indexName: string): PropertyDecorator { return (target: any, propertyKey: string | symbol) => { if (typeof propertyKey === 'string') { - initOrUpdateIndex(IndexType.LSI, { name: indexName, keyType: KeyType.RANGE }, target, propertyKey) + initOrUpdateIndex(IndexType.LSI, { name: indexName, keyType: DynamoDB.KeyType.RANGE }, target, propertyKey) } } } diff --git a/src/decorator/impl/index/util.ts b/src/decorator/impl/index/util.ts index b212f57a6..6dfd12362 100644 --- a/src/decorator/impl/index/util.ts +++ b/src/decorator/impl/index/util.ts @@ -1,7 +1,7 @@ /** * @module decorators */ -import { KeyType } from '../../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { PropertyMetadata } from '../../metadata/property-metadata.model' import { initOrUpdateProperty } from '../property/init-or-update-property.function' import { KEY_PROPERTY } from '../property/key-property.const' @@ -12,7 +12,7 @@ import { IndexType } from './index-type.enum' */ export interface IndexData { name: string - keyType: KeyType + keyType: DynamoDB.KeyType } /** @@ -47,7 +47,7 @@ export function initOrUpdateIndex(indexType: IndexType, indexData: IndexData, ta /** * @hidden */ -function initOrUpdateGSI(indexes: Record, indexData: IndexData): Partial> { +function initOrUpdateGSI(indexes: Record, indexData: IndexData): Partial> { if (indexes[indexData.name]) { // TODO INVESTIGATE when we throw an error we have a problem where multiple different classes extend one base class, this will be executed multiple times // throw new Error( diff --git a/src/decorator/impl/key/partition-key.decorator.ts b/src/decorator/impl/key/partition-key.decorator.ts index 528830feb..8b250f37e 100644 --- a/src/decorator/impl/key/partition-key.decorator.ts +++ b/src/decorator/impl/key/partition-key.decorator.ts @@ -1,7 +1,7 @@ /** * @module decorators */ -import { KeyType } from '../../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { createOptModelLogger } from '../../../logger/logger' import { PropertyMetadata } from '../../metadata/property-metadata.model' import { initOrUpdateProperty } from '../property/init-or-update-property.function' @@ -32,7 +32,7 @@ export function PartitionKey(): PropertyDecorator { } } - initOrUpdateProperty({ key: { type: KeyType.HASH } }, target, propertyKey) + initOrUpdateProperty({ key: { type: DynamoDB.KeyType.HASH } }, target, propertyKey) } } } diff --git a/src/decorator/impl/key/sort-key.decorator.ts b/src/decorator/impl/key/sort-key.decorator.ts index 2ca6e35f5..a460d23f7 100644 --- a/src/decorator/impl/key/sort-key.decorator.ts +++ b/src/decorator/impl/key/sort-key.decorator.ts @@ -1,13 +1,13 @@ /** * @module decorators */ -import { KeyType } from '../../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { initOrUpdateProperty } from '../property/init-or-update-property.function' export function SortKey(): PropertyDecorator { return (target: any, propertyKey: string | symbol) => { if (typeof propertyKey === 'string') { - initOrUpdateProperty({ key: { type: KeyType.RANGE } }, target, propertyKey) + initOrUpdateProperty({ key: { type: DynamoDB.KeyType.RANGE } }, target, propertyKey) } } } diff --git a/src/decorator/impl/model/model.decorator.ts b/src/decorator/impl/model/model.decorator.ts index a809cd70c..20f25da79 100644 --- a/src/decorator/impl/model/model.decorator.ts +++ b/src/decorator/impl/model/model.decorator.ts @@ -1,7 +1,7 @@ /** * @module decorators */ -import { KeyType } from '../../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { kebabCase } from '../../../helper/kebab-case.function' import { ModelMetadata } from '../../metadata/model-metadata.model' import { PropertyMetadata } from '../../metadata/property-metadata.model' @@ -63,7 +63,7 @@ export function Model(opts: ModelData = {}): ClassDecorator { */ function testForGSI( property: PropertyMetadata, -): property is PropertyMetadata & { keyForGSI: Record } { +): property is PropertyMetadata & { keyForGSI: Record } { return !!(property.keyForGSI && Object.keys(property.keyForGSI).length) } diff --git a/src/decorator/metadata/property-metadata.model.ts b/src/decorator/metadata/property-metadata.model.ts index ab7e5de6d..105a8af75 100644 --- a/src/decorator/metadata/property-metadata.model.ts +++ b/src/decorator/metadata/property-metadata.model.ts @@ -1,7 +1,7 @@ /** * @module metadata */ -import { KeyType } from '../../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { MapperForType } from '../../mapper/for-type/base.mapper' import { Attribute } from '../../mapper/type/attribute.type' import { ModelConstructor } from '../../model/model-constructor' @@ -12,7 +12,7 @@ export interface TypeInfo { } export interface Key { - type: KeyType + type: DynamoDB.KeyType } export interface PropertyMetadata { @@ -41,7 +41,7 @@ export interface PropertyMetadata { mapperForSingleItem?: () => MapperForType // maps the index name to the key type to describe for which GSI this property describes a key attribute - keyForGSI?: Record + keyForGSI?: Record // holds all the the index names for which this property describes the sort key attribute sortKeyForLSI?: string[] diff --git a/src/dynamo/batchget/batch-get-full.response.ts b/src/dynamo/batchget/batch-get-full.response.ts index a4cc56841..c6eef1bc6 100644 --- a/src/dynamo/batchget/batch-get-full.response.ts +++ b/src/dynamo/batchget/batch-get-full.response.ts @@ -2,7 +2,6 @@ * @module multi-model-requests/batch-get */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../aws-sdk-v2.types' import { BatchGetResponse } from './batch-get.response' /** @@ -16,7 +15,7 @@ export interface BatchGetFullResponse { /** * A map of tables and their respective keys that were not processed with the current response. The UnprocessedKeys value is in the same form as RequestItems, so the value can be provided directly to a subsequent BatchGetItem operation. For more information, see RequestItems in the Request Parameters section. Each element consists of: Keys - An array of primary key attribute values that define specific items in the table. ProjectionExpression - One or more attributes to be retrieved from the table or index. By default, all attributes are returned. If a requested attribute is not found, it does not appear in the result. ConsistentRead - The consistency of a read operation. If set to true, then a strongly consistent read is used; otherwise, an eventually consistent read is used. If there are no unprocessed keys remaining, the response contains an empty UnprocessedKeys map. */ - UnprocessedKeys?: DynamoDBv2.BatchGetRequestMap + UnprocessedKeys?: Record /** * The read capacity units consumed by the entire BatchGetItem operation. Each element consists of: TableName - The table that consumed the provisioned throughput. CapacityUnits - The total number of capacity units consumed. */ diff --git a/src/dynamo/batchget/batch-get-utils.ts b/src/dynamo/batchget/batch-get-utils.ts index 4b42d9c6f..3dabe29ed 100644 --- a/src/dynamo/batchget/batch-get-utils.ts +++ b/src/dynamo/batchget/batch-get-utils.ts @@ -2,7 +2,6 @@ * @module multi-model-requests/batch-get */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../aws-sdk-v2.types' import { promiseDelay } from '../../helper/promise-delay.function' import { DynamoDbWrapper } from '../dynamo-db-wrapper' @@ -45,7 +44,7 @@ export function batchGetItemsFetchAll( * @hidden */ export type BatchGetItemOutputWithUnprocessedKeys = DynamoDB.BatchGetItemOutput & { - UnprocessedKeys: DynamoDBv2.BatchGetRequestMap + UnprocessedKeys: Record } /** diff --git a/src/dynamo/batchwrite/batch-write-utils.ts b/src/dynamo/batchwrite/batch-write-utils.ts index 920f60ece..f0edcef30 100644 --- a/src/dynamo/batchwrite/batch-write-utils.ts +++ b/src/dynamo/batchwrite/batch-write-utils.ts @@ -2,7 +2,6 @@ * @module multi-model-requests/batch-write */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../aws-sdk-v2.types' import { promiseDelay } from '../../helper/promise-delay.function' import { DynamoDbWrapper } from '../dynamo-db-wrapper' @@ -45,7 +44,7 @@ export function batchWriteItemsWriteAll( * @hidden */ export type BatchWriteItemOutputWithUnprocessedItems = DynamoDB.BatchWriteItemOutput & { - UnprocessedItems: DynamoDBv2.BatchWriteItemRequestMap + UnprocessedItems: Record } /** diff --git a/src/dynamo/expression/param-util.ts b/src/dynamo/expression/param-util.ts index 70ebb7516..25b51ddee 100644 --- a/src/dynamo/expression/param-util.ts +++ b/src/dynamo/expression/param-util.ts @@ -2,7 +2,6 @@ * @module expression */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../aws-sdk-v2.types' import { isEmpty } from '../../helper/is-empty.function' import { isString } from '../../helper/is-string.function' import { ConditionalParams } from '../operation-params.type' @@ -27,12 +26,12 @@ export function addExpression( ) { const nameSafeCondition = resolveAttributeValueNameConflicts(condition, params) - const expressionAttributeNames = { + const expressionAttributeNames = >{ ...params.ExpressionAttributeNames, ...nameSafeCondition.attributeNames, } - const expressionAttributeValues = { + const expressionAttributeValues = >{ ...params.ExpressionAttributeValues, ...nameSafeCondition.attributeValues, } diff --git a/src/dynamo/operation-params.type.ts b/src/dynamo/operation-params.type.ts index b02aa064c..99eb21fe7 100644 --- a/src/dynamo/operation-params.type.ts +++ b/src/dynamo/operation-params.type.ts @@ -2,7 +2,6 @@ * @module dynamo-easy */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../aws-sdk-v2.types' /** * @hidden @@ -15,8 +14,8 @@ export interface ConditionalParamsHost { * @hidden */ export interface ConditionalParams { - expressionAttributeNames?: DynamoDBv2.ExpressionAttributeNameMap - expressionAttributeValues?: DynamoDBv2.ExpressionAttributeValueMap + expressionAttributeNames?: Record + expressionAttributeValues?: Record [key: string]: any } diff --git a/src/dynamo/request/batchgetsingletable/batch-get-single-table.response.ts b/src/dynamo/request/batchgetsingletable/batch-get-single-table.response.ts index fbbcbf743..d0b3d8ec9 100644 --- a/src/dynamo/request/batchgetsingletable/batch-get-single-table.response.ts +++ b/src/dynamo/request/batchgetsingletable/batch-get-single-table.response.ts @@ -2,7 +2,6 @@ * @module store-requests */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../../aws-sdk-v2.types' /** * Response from {@link BatchGetSingleTableRequest}::exec @@ -15,7 +14,7 @@ export interface BatchGetSingleTableResponse { /** * A map of tables and their respective keys that were not processed with the current response. The UnprocessedKeys value is in the same form as RequestItems, so the value can be provided directly to a subsequent BatchGetItem operation. For more information, see RequestItems in the Request Parameters section. Each element consists of: Keys - An array of primary key attribute values that define specific items in the table. ProjectionExpression - One or more attributes to be retrieved from the table or index. By default, all attributes are returned. If a requested attribute is not found, it does not appear in the result. ConsistentRead - The consistency of a read operation. If set to true, then a strongly consistent read is used; otherwise, an eventually consistent read is used. If there are no unprocessed keys remaining, the response contains an empty UnprocessedKeys map. */ - UnprocessedKeys?: DynamoDBv2.BatchGetRequestMap + UnprocessedKeys?: Record /** * The read capacity units consumed by the entire BatchGetItem operation. Each element consists of: TableName - The table that consumed the provisioned throughput. CapacityUnits - The total number of capacity units consumed. */ diff --git a/src/dynamo/request/query/query.response.ts b/src/dynamo/request/query/query.response.ts index 9b30f3813..c787acd5a 100644 --- a/src/dynamo/request/query/query.response.ts +++ b/src/dynamo/request/query/query.response.ts @@ -2,7 +2,6 @@ * @module store-requests */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../../aws-sdk-v2.types' /** * copied from aws-sdk/clients/dynamoDb QueryOutput but added generics, because we process the items and map them @@ -24,7 +23,7 @@ export interface QueryResponse { /** * The primary key of the item where the operation stopped, inclusive of the previous result set. Use this value to start a new operation, excluding this value in the new request. If LastEvaluatedKey is empty, then the "last page" of results has been processed and there is no more data to be retrieved. If LastEvaluatedKey is not empty, it does not necessarily mean that there is more data in the result set. The only way to know when you have reached the end of the result set is when LastEvaluatedKey is empty. */ - LastEvaluatedKey?: DynamoDBv2.Key + LastEvaluatedKey?: Record /** * The capacity units consumed by the Query operation. The data returned includes the total provisioned throughput consumed, along with statistics for the table and any indexes involved in the operation. ConsumedCapacity is only returned if the ReturnConsumedCapacity parameter was specified For more information, see Provisioned Throughput in the Amazon DynamoDB Developer Guide. */ diff --git a/src/dynamo/request/read-many.request.ts b/src/dynamo/request/read-many.request.ts index 08b7d42b5..2309a5b94 100644 --- a/src/dynamo/request/read-many.request.ts +++ b/src/dynamo/request/read-many.request.ts @@ -2,7 +2,6 @@ * @module store-requests */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../aws-sdk-v2.types' import { SecondaryIndex } from '../../decorator/impl/index/secondary-index' import { fetchAll } from '../../helper/fetch-all.function' import { promiseTap } from '../../helper/promise-tap.function' @@ -59,7 +58,7 @@ export abstract class ReadManyRequest< * @param key A map representing the start id which is included in next call, if null is delivered * startKey will be removed from params */ - exclusiveStartKey(key: DynamoDBv2.Key | null): this { + exclusiveStartKey(key: Record | null): this { // TODO ENHANCEMENT exclusiveStartKey(item: Partial) if (key) { this.params.ExclusiveStartKey = key diff --git a/src/dynamo/request/scan/scan.response.ts b/src/dynamo/request/scan/scan.response.ts index a789ea09c..aa48f47ac 100644 --- a/src/dynamo/request/scan/scan.response.ts +++ b/src/dynamo/request/scan/scan.response.ts @@ -2,7 +2,6 @@ * @module store-requests */ import * as DynamoDB from '@aws-sdk/client-dynamodb' -import * as DynamoDBv2 from '../../../aws-sdk-v2.types' export interface ScanResponse { /** @@ -20,7 +19,7 @@ export interface ScanResponse { /** * The primary key of the item where the operation stopped, inclusive of the previous result set. Use this value to start a new operation, excluding this value in the new request. If LastEvaluatedKey is empty, then the "last page" of results has been processed and there is no more data to be retrieved. If LastEvaluatedKey is not empty, it does not necessarily mean that there is more data in the result set. The only way to know when you have reached the end of the result set is when LastEvaluatedKey is empty. */ - LastEvaluatedKey?: DynamoDBv2.Key + LastEvaluatedKey?: Record /** * The capacity units consumed by the Scan operation. The data returned includes the total provisioned throughput consumed, along with statistics for the table and any indexes involved in the operation. ConsumedCapacity is only returned if the ReturnConsumedCapacity parameter was specified. For more information, see Provisioned Throughput in the Amazon DynamoDB Developer Guide. */ diff --git a/src/helper/fetch-all.function.ts b/src/helper/fetch-all.function.ts index 5bbaf97b8..d952af1a0 100644 --- a/src/helper/fetch-all.function.ts +++ b/src/helper/fetch-all.function.ts @@ -1,7 +1,7 @@ /** * @module helper */ -import * as DynamoDBv2 from '../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { QueryRequest } from '../dynamo/request/query/query.request' import { ReadManyRequest } from '../dynamo/request/read-many.request' import { ScanRequest } from '../dynamo/request/scan/scan.request' @@ -11,7 +11,7 @@ import { ScanRequest } from '../dynamo/request/scan/scan.request' * available. This can be used with scan and query requests. */ -export function fetchAll(request: ScanRequest | QueryRequest, startKey?: DynamoDBv2.Key): Promise { +export function fetchAll(request: ScanRequest | QueryRequest, startKey?: Record): Promise { request.limit(ReadManyRequest.INFINITE_LIMIT) if (startKey) { request.exclusiveStartKey(startKey) diff --git a/src/mapper/mapper.spec.ts b/src/mapper/mapper.spec.ts index 2ea2e98c6..1dfe6ed1b 100644 --- a/src/mapper/mapper.spec.ts +++ b/src/mapper/mapper.spec.ts @@ -41,7 +41,7 @@ import { NestedModelWithCustomMapper, } from '../../test/models/model-with-nested-model-with-custom-mapper.model' import { NestedComplexModel } from '../../test/models/nested-complex.model' -import * as DynamoDBv2 from '../aws-sdk-v2.types' +import * as DynamoDB from '@aws-sdk/client-dynamodb' import { metadataForModel } from '../decorator/metadata/metadata-for-model.function' import { PropertyMetadata } from '../decorator/metadata/property-metadata.model' import { createKeyAttributes, createToKeyFn, fromDb, fromDbOne, toDb, toDbOne, toKey } from './mapper' @@ -713,13 +713,13 @@ describe('Mapper', () => { describe('model with non string/number/binary keys', () => { it('should accept date as HASH or RANGE key', () => { const now = new Date() - const toDbVal: DynamoDBv2.AttributeMap = toDb(new ModelWithDateAsHashKey(now), ModelWithDateAsHashKey) + const toDbVal: Record = toDb(new ModelWithDateAsHashKey(now), ModelWithDateAsHashKey) expect(toDbVal.startDate.S).toBeDefined() expect(toDbVal.startDate.S).toEqual(now.toISOString()) }) it('should accept date as HASH or RANGE key on GSI', () => { const now = new Date() - const toDbVal: DynamoDBv2.AttributeMap = toDb( + const toDbVal: Record = toDb( new ModelWithDateAsIndexHashKey(0, now), ModelWithDateAsIndexHashKey, )