@nerdware/ddb-single-table
Version:
A schema-based DynamoDB modeling tool, high-level API, and type-generator built to supercharge single-table designs!⚡
300 lines • 17.7 kB
TypeScript
import { DdbClientWrapper } from "../DdbClientWrapper/index.js";
import type { ModelConstructorParameters, AttributesAliasesMap, KeyParameters, GetItemOpts, BatchGetItemsOpts, CreateItemOpts, UpsertItemOpts, UpdateItemOpts, DeleteItemOpts, BatchWriteItemsOpts, QueryOpts, ScanOpts } from "./types/index.js";
import type { IODirection, EnabledIOActions } from "../IOActions/types/index.js";
import type { ModelSchemaType, ModelSchemaOptions, ModelSchemaEntries } from "../Schema/types/index.js";
import type { TableKeysAndIndexes } from "../Table/types/index.js";
import type { BaseItem, UnknownItem, ItemTypeFromSchema, ItemCreationParameters } from "../types/index.js";
import type { PartialDeep } from "type-fest";
/**
* Each Model instance is provided with CRUD methods featuring parameter and return types which
* reflect the Model's schema. Model methods wrap `DynamoDBClient` command operations with sets
* of schema-aware middleware called {@link ioActions|"IO-Actions"} which provide rich functionality
* for database-IO like alias mapping, value validation, user-defined transforms, etc.
*
* IO-Actions are grouped into two sets based on the request-response cycle:
* - **`toDB`**: IO-Actions performed on _request arguments_.
* - **`fromDB`**: IO-Actions performed on _response values_.
*
* The IO-Actions undertaken for each set are listed below in order of execution. Note that some
* IO-Actions are skipped by certain methods, depending on the method's purpose. For example, item
* values provided to `Model.updateItem` are not subjected to `"required"` checks, since the method
* is intended to update individual properties of existing items.
* _See **{@link ioActions|IO-Actions}** for more info an any of the IO-Actions listed below._
*
* **`toDB`**:
* 1. **`Alias Mapping`** — Replaces "alias" keys with attribute names.
* 2. **`Set Defaults`** — Applies defaults defined in the schema.
* 3. **`Attribute toDB Modifiers`** — Runs your `transformValue.toDB` fns.
* 4. **`Item toDB Modifier`** — Runs your `transformItem.toDB` fn.
* 5. **`Type Checking`** — Checks properties for conformance with their `"type"`.
* 6. **`Attribute Validation`** — Validates individual item properties.
* 7. **`Item Validation`** — Validates an item in its entirety.
* 8. **`"Required" Checks`** — Checks for `"required"` and `"nullable"` attributes.
*
* **`fromDB`**:
* 1. **`Attribute fromDB Modifiers`** — Runs your `transformValue.fromDB` fns.
* 2. **`Item fromDB Modifier`** — Runs your `transformItem.fromDB` fn.
* 3. **`Alias Mapping`** — Replaces attribute names with "alias" keys.
*
* #### Ordering of Attributes
* IO-Actions which process individual attributes always process attributes in the same order:
* 1. The table hash key is always processed first.
* 2. The table sort key is always processed second.
* 3. Any index PKs are processed after the table SK.
* 4. All other attributes are then processed in the order they are defined in the schema.
*
* Aside from ensuring predictable execution, this consistency also opens up design opportunities
* for your schema. For example, if you have a schema which uses a function to dynamically generate
* a default value for an `id` attribute which is used as the table hash key, other non-key
* attributes may be defined using the item's generated `id` value.
*
* @template Schema - The Model's readonly schema.
* @template ItemType - A type which reflects a complete instance of a Model item.
* @template ItemCreationParams - The parameters used to create a new item instance.
*/
export declare class Model<const Schema extends ModelSchemaType, ItemType extends UnknownItem = ItemTypeFromSchema<Schema>, ItemCreationParams extends UnknownItem = ItemCreationParameters<Schema>> implements TableKeysAndIndexes {
readonly modelName: string;
readonly schema: Schema;
readonly schemaEntries: ModelSchemaEntries;
readonly schemaOptions: ModelSchemaOptions;
readonly attributesToAliasesMap: AttributesAliasesMap;
readonly aliasesToAttributesMap: AttributesAliasesMap;
readonly tableName: string;
readonly tableHashKey: TableKeysAndIndexes["tableHashKey"];
readonly tableRangeKey?: TableKeysAndIndexes["tableRangeKey"];
readonly indexes?: TableKeysAndIndexes["indexes"];
/** A wrapper-class around the DynamoDB client instance which greatly simplifies DDB operations. */
readonly ddb: DdbClientWrapper;
constructor(
/** The name of the Model. */
modelName: string,
/** The Model's {@link Schema}. */
modelSchema: Schema,
/** {@link ModelSchemaOptions} and table key/index properties. */
{ tableName, tableHashKey, tableRangeKey, indexes, ddb: ddbClientWrapper, autoAddTimestamps, allowUnknownAttributes, transformItem, validateItem, }: ModelConstructorParameters);
/**
* [`GetItem`][api-ref] operation wrapper.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html
*
* @param primaryKeys The primary keys of the item to get.
* @param getItemOpts Options for the underlying `GetItem` operation.
* @returns The item, if found.
*/
readonly getItem: (primaryKeys: KeyParameters<Schema>, getItemOpts?: GetItemOpts) => Promise<ItemType | undefined>;
/**
* [`BatchGetItem`][api-ref] operation wrapper.
*
* - **Max Chunk Size**: The provided `primaryKeys` are spliced into chunks of 100 (the maximum
* limit set by AWS for BatchGetItem requests).
*
* - **Automatic Retries**: Per AWS recommendations, BatchGetItem requests which either return
* `UnprocessedKeys` or result in a retryable error are automatically retried using an
* exponential backoff strategy which adheres to AWS best practices.
*
* - **Unprocessed Keys**: Any `UnprocessedKeys` returned by the batch request are re-submitted.
*
* - **Exponential Backoff**: All retries are implemented with an exponential backoff strategy:
* 1. First request: no delay
* 2. Second request: delay `initialDelay` milliseconds (default: 100)
* 3. All subsequent request delays are equal to the previous delay multiplied by the
* `timeMultiplier` (default: 2), until either:
* - The `maxRetries` limit is reached (default: 10), or
* - The `maxDelay` limit is reached (default: 3500, or 3.5 seconds)
*
* Ergo, the base `delay` calculation can be summarized as follows:
* > `initialDelay * timeMultiplier^attemptNumber milliseconds`
*
* If `useJitter` is true (default: false), the `delay` is randomized by applying the following
* to the base `delay`: `Math.round( Math.random() * delay )`. Note that the determination as
* to whether the delay exceeds the `maxDelay` is made BEFORE the jitter is applied.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html
*
* @param primaryKeys The primary keys of the items to get.
* @param batchGetItemsOpts Options for the underlying `BatchGetItem` operation.
* @returns The items, if found.
* @throws {ItemInputError} If `primaryKeys` is not an array.
*/
readonly batchGetItems: (primaryKeys: Array<KeyParameters<Schema>>, batchGetItemsOpts?: BatchGetItemsOpts) => Promise<Array<ItemType> | undefined>;
/**
* A [`PutItem`][api-ref] operation wrapper which guarantees existing items will not be
* overwritten by always including a [`ConditionExpression` which checks for the non-existence
* of the item's hash key][ddb-docs-conditional-put].
*
* If the Model's `schemaOptions` are configured to auto-add timestamps, this method will also add
* a `createdAt` attribute (or the `attrName` specified for the custom timestamp attribute) set to
* the current timestamp.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html
* [ddb-docs-conditional-put]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html#Expressions.ConditionExpressions.PreventingOverwrites
*
* @param item The item to create.
* @param createItemOpts Options for the underlying `PutItem` operation.
* @returns The provided `item` with any schema-defined defaults and transforms applied.
*/
readonly createItem: (item: ItemCreationParams, createItemOpts?: CreateItemOpts) => Promise<ItemType>;
/**
* A [`PutItem`][api-ref] operation wrapper which will either update an existing item or
* create a new one if an item with the specified keys does not yet exist.
*
* > This method will overwrite an existing item with the specified keys if one exists.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html
*
* @param item The item to upsert.
* @param upsertItemOpts Options for the underlying `PutItem` operation.
* @returns The provided `item` with any schema-defined defaults and transforms applied.
*/
readonly upsertItem: (item: ItemCreationParams, upsertItemOpts?: UpsertItemOpts) => Promise<ItemType>;
/**
* A [`BatchWriteItem`][api-ref] operation wrapper optimized for upserting items.
*
* > Note: `BatchWriteItem` does not support condition expressions.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html
*
* @param items The items to upsert.
* @param batchUpsertItemsOpts Options for the underlying `BatchWriteItem` operation.
* @throws {ItemInputError} If `items` is not an array.
* @returns The provided `items` with any schema-defined defaults and transformations applied.
*/
readonly batchUpsertItems: (items: Array<ItemCreationParams>, batchUpsertItemsOpts?: BatchWriteItemsOpts) => Promise<Array<ItemType>>;
/**
* [`UpdateItem`][api-ref] operation wrapper. This method uses the `update` param to generate the
* following `UpdateItem` arguments:
*
* - `UpdateExpression` (may include `"SET"` and/or `"REMOVE"` clauses)
* - `ExpressionAttributeNames`
* - `ExpressionAttributeValues`
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html
*
* @param primaryKeys The primary keys of the item to update.
* @param updateItemOpts The `update` object and options for the underlying `UpdateItem` operation.
* @returns The updated item with new/updated values.
*/
readonly updateItem: (primaryKeys: KeyParameters<Schema>, { update, updateOptions, ...updateItemOpts }: UpdateItemOpts<PartialDeep<ItemCreationParams, {
recurseIntoArrays: true;
}>>) => Promise<ItemType>;
/**
* [`DeleteItem`][api-ref] operation wrapper.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html
*
* @param primaryKeys The primary keys of the item to delete.
* @param deleteItemOpts Options for the underlying `DeleteItem` operation.
* @returns The deleted item.
*/
readonly deleteItem: (primaryKeys: KeyParameters<Schema>, deleteItemOpts?: DeleteItemOpts) => Promise<ItemType>;
/**
* A [`BatchWriteItem`][api-ref] operation wrapper optimized for deleting items.
*
* > Note: `BatchWriteItem` does not support condition expressions.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html
*
* @param primaryKeys The primary keys of the items to delete.
* @param batchDeleteItemsOpts Options for the underlying `BatchWriteItem` operation.
*/
readonly batchDeleteItems: (primaryKeys: Array<KeyParameters<Schema>>, batchDeleteItemsOpts?: BatchWriteItemsOpts) => Promise<Array<KeyParameters<Schema>>>;
/**
* A [`BatchWriteItem`][api-ref] operation wrapper which can be used for both
* upserting and deleting items. Note that while each individual underlying Put/Delete operation
* _is_ atomic, they're not atomic as a a whole, despite occurring within the same call (this is
* an AWS implementation limitation).
*
* > Note: `BatchWriteItem` does not support condition expressions.
*
* - **Max Chunk Size**: The provided put-requests are broken into chunks of 25 (the max limit for
* BatchWriteItem requests), and each chunk is submitted as a separate BatchWriteItem request.
*
* - **Automatic Retries**: Per AWS recommendations, batch requests which result in an error code
* that indicates the provisioned throughput has been exceeded, or that the on-demand request
* limit has been exceeded, are automatically retried. All other errors are re-thrown.
*
* - **Unprocessed Items**: Any `UnprocessedItems` returned by the batch request are re-submitted.
*
* - **Exponential Backoff**: All retries are implemented with an exponential backoff strategy:
* 1. First request: no delay
* 2. Second request: delay `initialDelay` milliseconds (default: 100)
* 3. All subsequent request delays are equal to the previous delay multiplied by the
* `timeMultiplier` (default: 2), until either:
* - The `maxRetries` limit is reached (default: 10), or
* - The `maxDelay` limit is reached (default: 3500, or 3.5 seconds)
*
* Ergo, the base `delay` calculation can be summarized as follows:
* > `initialDelay * timeMultiplier^attemptNumber milliseconds`
*
* If `useJitter` is true (default: false), the `delay` is randomized by applying the following
* to the base `delay`: `Math.round(Math.random() * delay)`. Note that the determination as to
* whether the delay exceeds the `maxDelay` is made BEFORE the jitter is applied.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html
*
* @param upsertItems An array of items to upsert.
* @param deleteItems An array of primary keys of items to delete.
* @param batchUpsertItemsOpts Options for the underlying `BatchWriteItem` operation.
* @throws {ItemInputError} If neither `upsertItems` nor `deleteItems` are arrays.
*/
readonly batchUpsertAndDeleteItems: ({ upsertItems, deleteItems, }: {
upsertItems?: Array<ItemCreationParams>;
deleteItems?: Array<KeyParameters<Schema>>;
}, batchWriteItemsOpts?: BatchWriteItemsOpts) => Promise<{
upsertItems?: Array<ItemType>;
deleteItems?: Array<KeyParameters<Schema>>;
}>;
/**
* [`Query`][api-ref] operation wrapper which applies defaults and/or transforms defined in
* this Model's schema to the returned items.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html
*
* // IDEA - Restrict QueryOpts.IndexName to only be a valid index name for the table.
*
* @param queryOpts Options for the underlying `Query` operation.
* @returns The items, if found.
*/
readonly query: ({ where, limit, KeyConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues, IndexName, ...queryOpts }: QueryOpts<ItemType>) => Promise<Array<ItemType>>;
/**
* [`Scan`][api-ref] operation wrapper which applies defaults and/or transforms defined in
* this Model's schema to the returned items.
*
* [api-ref]: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html
*
* // IDEA - Restrict ScanOpts.IndexName to only be a valid index name for the table.
*
* @param scanOpts Options for the underlying `Scan` operation.
* @returns The items, if found.
*/
readonly scan: (scanOpts?: ScanOpts) => Promise<Array<ItemType>>;
/**
* Value-transforming action sets grouped by data-flow directionality.
*
* | `Method` | Description |
* | :------- | :-----------------------------------------------------------------: |
* | `toDB` | Actions executed on values _before_ being passed to the SDK client. |
* | `fromDB` | Actions executed on values _returned_ from the SDK client. |
*/
readonly processItemAttributes: {
[K in IODirection]: <ProcessedItemAttributes extends UnknownItem = BaseItem>(itemAttrs: UnknownItem, enabledIOActions?: EnabledIOActions<K>) => ProcessedItemAttributes;
};
/**
* This method applies an array of IO-Actions to the provided `itemAttrs` object. It sets default
* IO-Actions context values which can be overridden via the {@link IOActionContext} parameter.
*
* @param itemAttrs The item attributes to apply IO-Actions to.
* @param ioActionsSet The array of IO-Actions to apply.
* @param ioActionsCtxOverrides Optional overrides for the IO-Actions context object.
* @returns The item after being processed by the IO-Actions.
*/
private readonly applyIOActionsToItemAttributes;
/**
* This private Model method takes primary key args from public methods like `Model.getItem`
* and applies key-specific IO-Actions accordingly. The IO-Actions context object provided to
* the `applyIOActionsToItemAttributes` private method only contains the key attributes, i.e.,
* the provided `schema` only contains the `tableHashKey` and `tableRangeKey` attributes.
*/
private readonly processKeyArgs;
}
//# sourceMappingURL=Model.d.ts.map