@lafken/dynamo 0.12.12 → 0.12.13

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.
@@ -19,6 +19,9 @@ class QueryBuilderBase {
19
19
  sort && this.validateGlobalKey(Object.keys(sort), isGlobalIndex);
20
20
  const partitionFilters = [];
21
21
  for (const key in partition) {
22
+ if (partition[key] === undefined) {
23
+ continue;
24
+ }
22
25
  partitionFilters.push(this.resolveFilter({
23
26
  expressionName: key,
24
27
  value: partition[key],
@@ -50,6 +53,9 @@ class QueryBuilderBase {
50
53
  }
51
54
  }
52
55
  for (const key in sortValues) {
56
+ if (sortValues[key] === undefined) {
57
+ continue;
58
+ }
53
59
  let filterExpressionKey = 'equal';
54
60
  let sortValue = sort[key];
55
61
  if (typeof sortValue === 'object') {
@@ -41,12 +41,14 @@ class DynamoIndexes {
41
41
  }
42
42
  return index;
43
43
  }
44
- const partitionKeys = Object.keys(partition);
45
- const sortKeys = Object.keys(sort || {});
44
+ const partitionKeys = Object.keys(partition).filter((key) => partition[key] !== undefined);
45
+ const sortKeys = Object.keys(sort || {}).filter((key) => sort?.[key] !== undefined);
46
46
  if (partitionKeys.length > 1 || sortKeys.length > 1) {
47
47
  return this.getGlobalIndex(new Set(partitionKeys), new Set(sortKeys));
48
48
  }
49
- if (this.partitionKey === partitionKeys[0] && this.sortKey !== sortKeys[0]) {
49
+ if (this.partitionKey === partitionKeys[0] &&
50
+ this.sortKey !== sortKeys[0] &&
51
+ sortKeys[0] !== undefined) {
50
52
  const index = this.getLocalIndex(sortKeys[0]);
51
53
  if (index) {
52
54
  return index;
@@ -42,12 +42,6 @@ class FindBuilder extends base_1.QueryBuilderBase {
42
42
  const command = new client_dynamodb_1.QueryCommand(input);
43
43
  const { Items = [], LastEvaluatedKey } = await this.queryOptions.client.send(command);
44
44
  const resultData = Items.map((item) => (0, util_dynamodb_1.unmarshall)(item));
45
- if (input.Limit === 1) {
46
- return {
47
- data: [resultData[0]],
48
- cursor: LastEvaluatedKey ? (0, util_dynamodb_1.unmarshall)(LastEvaluatedKey) : undefined,
49
- };
50
- }
51
45
  const items = data.concat(resultData);
52
46
  if (LastEvaluatedKey && (!input.Limit || items.length < input.Limit)) {
53
47
  return this.runQuery({
@@ -7,7 +7,6 @@ class FindAllBuilder extends find_1.FindBuilder {
7
7
  constructor(queryOptions) {
8
8
  super(queryOptions);
9
9
  this.queryOptions = queryOptions;
10
- this.find();
11
10
  }
12
11
  then(resolve, reject) {
13
12
  return this.exec().then(resolve, reject);
@@ -7,7 +7,6 @@ class FindOneBuilder extends find_1.FindBuilder {
7
7
  constructor(queryOptions) {
8
8
  super(queryOptions);
9
9
  this.queryOptions = queryOptions;
10
- this.find();
11
10
  }
12
11
  then(resolve, reject) {
13
12
  return this.exec().then(resolve, reject);
@@ -16,19 +16,156 @@ import type { ScanBuilder } from '../query-builder/scan/scan';
16
16
  import type { UpdateBuilder } from '../query-builder/update/update';
17
17
  import type { UpsertBuilder } from '../query-builder/upsert/upsert';
18
18
  export type RepositoryReturn<E extends ClassResource> = {
19
+ /**
20
+ * Queries a single item using `QueryCommand`.
21
+ *
22
+ * Builds a `KeyConditionExpression` from `keyCondition` and automatically resolves the
23
+ * secondary index (GSI/LSI) to use when applicable. Optionally applies a `FilterExpression`
24
+ * on the results and enforces `Limit: 1`. If `cacheTtl` is provided, the result is stored
25
+ * in the in-memory cache keyed by table name and `inputProps`.
26
+ *
27
+ * @param inputProps - Query conditions: `keyCondition`, `filter`, `projection`, `cursor`, `limit`, `sortDirection`.
28
+ * @param cacheTtl - In-memory cache TTL in seconds. If omitted, no caching is applied.
29
+ * @returns Thenable builder that resolves with the first matching item or `undefined`.
30
+ */
19
31
  findOne(inputProps: QueryOneProps<E>, cacheTtl?: number): FindOneBuilder<E>;
32
+ /**
33
+ * Queries multiple items using `QueryCommand`.
34
+ *
35
+ * Builds a `KeyConditionExpression` from `keyCondition` and automatically resolves the
36
+ * secondary index (GSI/LSI) to use when applicable. Optionally applies a `FilterExpression`,
37
+ * pagination via `ExclusiveStartKey` (cursor), `Limit`, `ProjectionExpression`, and sort
38
+ * direction. Automatically paginates until all results are retrieved. If `cacheTtl` is
39
+ * provided, the result is stored in the in-memory cache.
40
+ *
41
+ * @param inputProps - Query conditions: `keyCondition`, `filter`, `projection`, `cursor`, `limit`, `sortDirection`.
42
+ * @param cacheTtl - In-memory cache TTL in seconds. If omitted, no caching is applied.
43
+ * @returns Thenable builder that resolves with `{ data, cursor }`.
44
+ */
20
45
  findAll(inputProps: QueryProps<E>, cacheTtl?: number): FindAllBuilder<E>;
46
+ /**
47
+ * Scans the entire table using `ScanCommand`.
48
+ *
49
+ * Unlike `findAll`, does not require a `keyCondition` and reads every item in the table.
50
+ * Optionally applies a `FilterExpression`, pagination via `ExclusiveStartKey` (cursor),
51
+ * `Limit`, and `ProjectionExpression`. Automatically paginates until the requested limit is
52
+ * reached. **Avoid on large tables due to high read capacity consumption.**
53
+ *
54
+ * @param inputProps - Optional parameters: `filter`, `projection`, `cursor`, `limit`.
55
+ * @returns Thenable builder that resolves with `{ data, cursor }`.
56
+ */
21
57
  scan(inputProps?: FindProps<E>): ScanBuilder<E>;
58
+ /**
59
+ * Creates or replaces an item using `PutItemCommand`.
60
+ *
61
+ * If an item with the same primary key already exists, it is fully overwritten.
62
+ * Optionally accepts a `ConditionExpression` via `inputProps.condition` to guard the write
63
+ * (e.g. verify an attribute has a specific value before writing).
64
+ *
65
+ * @param item - The full item to write to the table.
66
+ * @param inputProps - Optional parameters: `condition` for `ConditionExpression`.
67
+ * @returns Thenable builder that resolves with the written item.
68
+ */
22
69
  upsert(item: Item<E>, inputProps?: UpsertProps<E>): UpsertBuilder<E>;
70
+ /**
71
+ * Creates a new item using `PutItemCommand`, ensuring it does not already exist.
72
+ *
73
+ * Internally adds an automatic `ConditionExpression` using `attribute_not_exists` on the
74
+ * partition key (and sort key if present), causing the operation to fail if the item already
75
+ * exists. Does not accept additional conditions.
76
+ *
77
+ * @param item - The item to create. Throws a DynamoDB error if the item already exists.
78
+ * @returns Thenable builder that resolves with the created item.
79
+ */
23
80
  create(item: Item<E>): CreateBuilder<E>;
81
+ /**
82
+ * Updates attributes of an existing item using `UpdateItemCommand`.
83
+ *
84
+ * Builds an `UpdateExpression` with `SET` clauses (for `setValues` and `replaceValues`) and
85
+ * `REMOVE` clauses (for `removeValues`). The difference between `setValues` and `replaceValues`
86
+ * is that `setValues` performs a deep merge on nested objects, while `replaceValues` overwrites
87
+ * the attribute entirely. Optionally applies a `ConditionExpression` via `condition` and returns
88
+ * previous or new attributes when `returnValue` is specified.
89
+ *
90
+ * @param inputProps - `keyCondition` (primary key of the item to update), `setValues`,
91
+ * `replaceValues`, `removeValues`, `condition` for `ConditionExpression`, and `returnValue`
92
+ * (`'all_old'` | `'all_new'` | `'updated_old'` | `'updated_new'`).
93
+ * @returns Thenable builder that resolves with the updated item if `returnValue` was specified, or `undefined`.
94
+ */
24
95
  update<R extends ReturnValueOption | undefined = undefined>(inputProps: Omit<UpdateProps<E>, 'returnValue'> & {
25
96
  returnValue?: R;
26
97
  }): UpdateBuilder<E, R>;
98
+ /**
99
+ * Fetches a single item by its exact primary key using `GetItemCommand`.
100
+ *
101
+ * Unlike `findOne`, uses `GetItemCommand` instead of `QueryCommand`, making it more efficient
102
+ * for exact-key lookups. Supports `ConsistentRead` for strongly consistent reads and
103
+ * `ProjectionExpression` to return only specific attributes. If `cacheTtl` is provided,
104
+ * the result is stored in the in-memory cache.
105
+ *
106
+ * @param key - Primary key of the item (partition key and sort key if applicable).
107
+ * @param options - Options: `consistentRead`, `projection`, `cacheTtl` for in-memory caching.
108
+ * @returns Thenable builder that resolves with the found item or `undefined`.
109
+ */
27
110
  getItem(key: TablePartition<Item<E>>, options?: GetItemOptions<E>): GetItemBuilder<E>;
111
+ /**
112
+ * Deletes an item by its primary key using `DeleteItemCommand`.
113
+ *
114
+ * Does not apply any `ConditionExpression`. If the item does not exist, the operation
115
+ * completes without error.
116
+ *
117
+ * @param key - Primary key of the item to delete (partition key and sort key if applicable).
118
+ * @returns Thenable builder that resolves with `true` on completion.
119
+ */
28
120
  delete(key: TablePartition<Item<E>>): DeleteBuilder<E>;
121
+ /**
122
+ * Fetches multiple items by their primary keys using `BatchGetItemCommand`.
123
+ *
124
+ * Automatically splits keys into batches of up to 100 items (DynamoDB limit) and executes
125
+ * all batches in parallel. Automatically retries `UnprocessedKeys` up to `maxAttempt` times
126
+ * (default 5). Supports `ConsistentRead` and `ProjectionExpression`.
127
+ *
128
+ * @param keys - List of primary keys to retrieve.
129
+ * @param options - Options: `consistentRead`, `projection`, `maxAttempt` (default: 5).
130
+ * @returns Thenable builder that resolves with the array of found items.
131
+ */
29
132
  batchGet(keys: TablePartition<Item<E>>[], options?: BatchGetOptions<E>): BatchGetBuilder<E>;
133
+ /**
134
+ * Creates multiple items using `BatchWriteItemCommand` with `PutRequest`.
135
+ *
136
+ * Automatically splits items into batches of up to 25 (DynamoDB limit) and sends them in
137
+ * parallel. Automatically retries `UnprocessedItems` up to `maxAttempt` times (default 5).
138
+ * Does not apply a `ConditionExpression`; if an item already exists, it is overwritten.
139
+ *
140
+ * @param items - List of items to write to the table.
141
+ * @returns Thenable builder that resolves when all writes are complete.
142
+ */
30
143
  bulkCreate(items: Item<E>[]): BulkCreateBuilder<E>;
144
+ /**
145
+ * Deletes multiple items using `BatchWriteItemCommand` with `DeleteRequest`.
146
+ *
147
+ * Automatically splits keys into batches of up to 25 (DynamoDB limit) and sends them in
148
+ * parallel. Automatically retries `UnprocessedItems` up to `maxAttempt` times (default 5).
149
+ * If a key does not exist, the operation completes without error.
150
+ *
151
+ * @param keys - List of primary keys of the items to delete.
152
+ * @returns Thenable builder that resolves when all deletions are complete.
153
+ */
31
154
  bulkDelete(keys: TablePartition<Item<E>>[]): BulkDeleteBuilder<E>;
155
+ /**
156
+ * Sends an arbitrary command directly to the DynamoDB client.
157
+ *
158
+ * Allows executing SDK commands not covered by the repository methods.
159
+ *
160
+ * @param command - Any DynamoDB SDK command (`@aws-sdk/client-dynamodb`).
161
+ * @returns Promise that resolves with the typed command response.
162
+ */
32
163
  sendRawCommand<T = unknown>(command: Parameters<DynamoDBClient['send']>[0]): Promise<T>;
164
+ /**
165
+ * Clears the in-memory cache shared by `findOne`, `findAll`, and `getItem`.
166
+ *
167
+ * All cached results are invalidated immediately. Useful after write operations that may
168
+ * leave stale data in the cache.
169
+ */
33
170
  clearCache(): void;
34
171
  };
@@ -1,4 +1,30 @@
1
1
  import { type TransactWriteItem } from '@aws-sdk/client-dynamodb';
2
2
  import type { QueryTransactions } from './transaction.types';
3
+ /**
4
+ * Resolves the `TransactWriteItem` operation type for a given query builder.
5
+ *
6
+ * Maps builder instances to their corresponding DynamoDB transactional operation key:
7
+ * - `CreateBuilder` / `UpsertBuilder` → `'Put'`
8
+ * - `UpdateBuilder` → `'Update'`
9
+ * - `DeleteBuilder` → `'Delete'`
10
+ *
11
+ * @param builder - A query builder instance representing one transactional operation.
12
+ * @throws If the builder type is not supported within a transaction.
13
+ * @returns The `TransactWriteItem` key (`'Put'` | `'Update'` | `'Delete'`).
14
+ */
3
15
  export declare const getTransactionType: (builder: QueryTransactions) => keyof TransactWriteItem;
16
+ /**
17
+ * Executes multiple write operations atomically using `TransactWriteItemsCommand`.
18
+ *
19
+ * Accepts an array of query builders (`CreateBuilder`, `UpsertBuilder`, `UpdateBuilder`, or
20
+ * `DeleteBuilder`) and groups them into a single transactional request. DynamoDB guarantees
21
+ * all operations either succeed or fail together. Supports up to 100 items per transaction
22
+ * (DynamoDB limit). Does not apply any `ConditionExpression` beyond what each builder already
23
+ * carries; each builder's command is extracted via `getCommand()` and mapped to the appropriate
24
+ * `TransactWriteItem` operation type.
25
+ *
26
+ * @param queryBuilders - Array of write builders to include in the transaction.
27
+ * @throws If any builder type is unsupported or if the transaction is rejected by DynamoDB
28
+ * (e.g. a condition check fails in one of the items).
29
+ */
4
30
  export declare const transaction: (queryBuilders: QueryTransactions[]) => Promise<void>;
@@ -7,6 +7,18 @@ const create_1 = require("../query-builder/create/create");
7
7
  const delete_1 = require("../query-builder/delete/delete");
8
8
  const update_1 = require("../query-builder/update/update");
9
9
  const upsert_1 = require("../query-builder/upsert/upsert");
10
+ /**
11
+ * Resolves the `TransactWriteItem` operation type for a given query builder.
12
+ *
13
+ * Maps builder instances to their corresponding DynamoDB transactional operation key:
14
+ * - `CreateBuilder` / `UpsertBuilder` → `'Put'`
15
+ * - `UpdateBuilder` → `'Update'`
16
+ * - `DeleteBuilder` → `'Delete'`
17
+ *
18
+ * @param builder - A query builder instance representing one transactional operation.
19
+ * @throws If the builder type is not supported within a transaction.
20
+ * @returns The `TransactWriteItem` key (`'Put'` | `'Update'` | `'Delete'`).
21
+ */
10
22
  const getTransactionType = (builder) => {
11
23
  let type;
12
24
  if (builder instanceof create_1.CreateBuilder || builder instanceof upsert_1.UpsertBuilder) {
@@ -24,6 +36,20 @@ const getTransactionType = (builder) => {
24
36
  return type;
25
37
  };
26
38
  exports.getTransactionType = getTransactionType;
39
+ /**
40
+ * Executes multiple write operations atomically using `TransactWriteItemsCommand`.
41
+ *
42
+ * Accepts an array of query builders (`CreateBuilder`, `UpsertBuilder`, `UpdateBuilder`, or
43
+ * `DeleteBuilder`) and groups them into a single transactional request. DynamoDB guarantees
44
+ * all operations either succeed or fail together. Supports up to 100 items per transaction
45
+ * (DynamoDB limit). Does not apply any `ConditionExpression` beyond what each builder already
46
+ * carries; each builder's command is extracted via `getCommand()` and mapped to the appropriate
47
+ * `TransactWriteItem` operation type.
48
+ *
49
+ * @param queryBuilders - Array of write builders to include in the transaction.
50
+ * @throws If any builder type is unsupported or if the transaction is rejected by DynamoDB
51
+ * (e.g. a condition check fails in one of the items).
52
+ */
27
53
  const transaction = async (queryBuilders) => {
28
54
  const transactionCommands = queryBuilders.map((builder) => {
29
55
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lafken/dynamo",
3
- "version": "0.12.12",
3
+ "version": "0.12.13",
4
4
  "private": false,
5
5
  "description": "Define DynamoDB tables using TypeScript decorators - type-safe, declarative infrastructure with Lafken",
6
6
  "keywords": [
@@ -56,31 +56,31 @@
56
56
  "lib"
57
57
  ],
58
58
  "dependencies": {
59
- "@aws-sdk/client-dynamodb": "^3.1056.0",
59
+ "@aws-sdk/client-dynamodb": "^3.1062.0",
60
60
  "@aws-sdk/util-dynamodb": "^3.996.2",
61
61
  "aws-xray-sdk": "^3.12.0",
62
62
  "reflect-metadata": "^0.2.2",
63
- "@lafken/resolver": "0.12.12"
63
+ "@lafken/resolver": "0.12.13"
64
64
  },
65
65
  "devDependencies": {
66
- "@cdktn/provider-aws": "^24.3.0",
66
+ "@cdktn/provider-aws": "^24.4.0",
67
67
  "@swc/core": "^1.15.40",
68
68
  "@swc/helpers": "^0.5.23",
69
- "@vitest/runner": "^4.1.7",
69
+ "@vitest/runner": "^4.1.8",
70
70
  "aws-sdk-client-mock": "^4.1.0",
71
71
  "cdktn": "^0.23.2",
72
72
  "cdktn-vitest": "^1.0.0",
73
73
  "constructs": "^10.6.0",
74
74
  "typescript": "6.0.3",
75
75
  "unplugin-swc": "^1.5.9",
76
- "vitest": "^4.1.7",
77
- "@lafken/common": "0.12.12"
76
+ "vitest": "^4.1.8",
77
+ "@lafken/common": "0.12.13"
78
78
  },
79
79
  "peerDependencies": {
80
80
  "@cdktn/provider-aws": ">=23.0.0",
81
81
  "cdktn": ">=0.22.0",
82
82
  "constructs": "^10.4.5",
83
- "@lafken/common": "0.12.12"
83
+ "@lafken/common": "0.12.13"
84
84
  },
85
85
  "engines": {
86
86
  "node": ">=20.19"