@infra-blocks/aws-dynamodb 0.1.0-alpha.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.
package/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # ts-aws-dynamodb
2
+ [![Build](https://github.com/infra-blocks/ts-aws-dynamodb/actions/workflows/build.yml/badge.svg)](https://github.com/infra-blocks/ts-aws-dynamodb/actions/workflows/build.yml)
3
+ [![Release](https://github.com/infra-blocks/ts-aws-dynamodb/actions/workflows/release.yml/badge.svg)](https://github.com/infra-blocks/ts-aws-dynamodb/actions/workflows/release.yml)
4
+ [![codecov](https://codecov.io/gh/infra-blocks/ts-aws-dynamodb/graph/badge.svg?token=4TB4Y7AINE)](https://codecov.io/gh/infra-blocks/ts-aws-dynamodb)
5
+
6
+ A convenience library wrapper around [`@aws-sdk/client-dynamodb`](https://www.npmjs.com/package/@aws-sdk/client-dynamodb) and
7
+ [`@aws-sdk/lib-dynamodb`](https://www.npmjs.com/package/@aws-sdk/lib-dynamodb). The wrapper offers:
8
+ - More type safe interfaces (trough the use of descriptive types, such as for condition expressions).
9
+ - More conventional field names. Input and output fields use the conventional `camelCase` JS/TS convention over the `PascalCase`
10
+ imposed by the AWS APIs.
11
+ - Every client error is wrapped into a error adding description about which operation triggered the error.
12
+ - Pagination is provided for APIs that support it and exposed as `AsyncIterators`.
@@ -0,0 +1,37 @@
1
+ import type { DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
2
+ import { DynamoDBClient as BaseClient } from "@aws-sdk/client-dynamodb";
3
+ import type { TranslateConfig } from "@aws-sdk/lib-dynamodb";
4
+ import { DynamoDBDocumentClient as Client } from "@aws-sdk/lib-dynamodb";
5
+ import type { Logger } from "@infra-blocks/logger-interface";
6
+ import { type Retry } from "@infra-blocks/retry";
7
+ import type { Attributes, GetItem, PutItem, Query, WriteTransaction } from "./types.js";
8
+ export declare class DynamoDbClientError extends Error {
9
+ constructor(message: string, options?: {
10
+ cause?: unknown;
11
+ });
12
+ }
13
+ export declare class DynamoDbClient {
14
+ private readonly client;
15
+ private readonly logger;
16
+ private constructor();
17
+ ready(): Retry<void>;
18
+ getItem<T>(params: GetItem): Promise<T | undefined>;
19
+ putItem(params: PutItem): Promise<void>;
20
+ transactWriteItems(params: WriteTransaction): Promise<void>;
21
+ query<T extends Attributes = Attributes>(query: Query): AsyncGenerator<T>;
22
+ queryOne<T extends Attributes = Attributes>(query: Query): Promise<T | undefined>;
23
+ static fromBase(params: {
24
+ client: BaseClient;
25
+ document?: TranslateConfig;
26
+ logger?: Logger;
27
+ }): DynamoDbClient;
28
+ static from(params: {
29
+ client: Client;
30
+ logger?: Logger;
31
+ }): DynamoDbClient;
32
+ static create(params?: {
33
+ base?: DynamoDBClientConfig;
34
+ document?: TranslateConfig;
35
+ logger?: Logger;
36
+ }): DynamoDbClient;
37
+ }
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DynamoDbClient = exports.DynamoDbClientError = void 0;
4
+ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
5
+ const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
6
+ const null_logger_1 = require("@infra-blocks/null-logger");
7
+ const retry_1 = require("@infra-blocks/retry");
8
+ class DynamoDbClientError extends Error {
9
+ constructor(message, options) {
10
+ super(message, options);
11
+ this.name = "DynamoDbClientError";
12
+ }
13
+ }
14
+ exports.DynamoDbClientError = DynamoDbClientError;
15
+ /*
16
+ The uniqueness constraint of an attribute, for example an email, can be enforced in DynamoDB using
17
+ this scheme: https://aws.amazon.com/blogs/database/simulating-amazon-dynamodb-unique-constraints-using-transactions/#:~:text=Primary%20keys%20are%20guaranteed%20to,are%20not%20the%20primary%20key.
18
+
19
+ This is to say, we can create items in a different table that only has a pk for this specific use case, or we could
20
+ also use the same table. It's just going to add some sheeet to the table.
21
+ */
22
+ class DynamoDbClient {
23
+ client;
24
+ logger;
25
+ constructor(params) {
26
+ const { client, logger } = params;
27
+ this.client = client;
28
+ this.logger = logger;
29
+ }
30
+ ready() {
31
+ return (0, retry_1.retry)(async () => {
32
+ await this.client.send(new client_dynamodb_1.ListTablesCommand({}));
33
+ }, {
34
+ isRetryableError: (err) => {
35
+ if ("code" in err) {
36
+ return err.code === "ECONNRESET";
37
+ }
38
+ return false;
39
+ },
40
+ });
41
+ }
42
+ async getItem(params) {
43
+ try {
44
+ const { table, parititionKey, sortKey } = params;
45
+ const key = {
46
+ [parititionKey.name]: parititionKey.value,
47
+ };
48
+ if (sortKey != null) {
49
+ key[sortKey.name] = sortKey.value;
50
+ }
51
+ const response = await this.client.send(new lib_dynamodb_1.GetCommand({
52
+ TableName: table,
53
+ Key: key,
54
+ }));
55
+ return response.Item;
56
+ }
57
+ catch (err) {
58
+ throw new DynamoDbClientError(`error while getting item from DynamoDB: ${JSON.stringify(params)}`, {
59
+ cause: err,
60
+ });
61
+ }
62
+ }
63
+ async putItem(params) {
64
+ try {
65
+ await this.client.send(toPutCommand(params));
66
+ }
67
+ catch (err) {
68
+ this.logger.error("error while putting item in DynamoDB caused by %s", err);
69
+ throw new DynamoDbClientError("error while putting item in DynamoDB", {
70
+ cause: err,
71
+ });
72
+ }
73
+ }
74
+ async transactWriteItems(params) {
75
+ try {
76
+ const commandInput = toTransactWriteItemsCommandInput(params);
77
+ if (this.logger.isDebugEnabled()) {
78
+ this.logger.debug("executing transaction write: %s", JSON.stringify(commandInput));
79
+ }
80
+ const command = new lib_dynamodb_1.TransactWriteCommand(commandInput);
81
+ await this.client.send(command);
82
+ }
83
+ catch (err) {
84
+ throw new DynamoDbClientError("error while transactionally writing items in DynamoDB", {
85
+ cause: err,
86
+ });
87
+ }
88
+ }
89
+ async *query(query) {
90
+ try {
91
+ const { expression, attributeValues } = query.condition.toJson();
92
+ let response = await this.client.send(new lib_dynamodb_1.QueryCommand({
93
+ TableName: query.table,
94
+ IndexName: query.index,
95
+ KeyConditionExpression: expression,
96
+ ExpressionAttributeValues: attributeValues,
97
+ }));
98
+ for (const item of response.Items || []) {
99
+ yield item;
100
+ }
101
+ while (response.LastEvaluatedKey != null) {
102
+ response = await this.client.send(new lib_dynamodb_1.QueryCommand({
103
+ TableName: query.table,
104
+ IndexName: query.index,
105
+ KeyConditionExpression: expression,
106
+ ExpressionAttributeValues: attributeValues,
107
+ ExclusiveStartKey: response.LastEvaluatedKey,
108
+ }));
109
+ for (const item of response.Items || []) {
110
+ yield item;
111
+ }
112
+ }
113
+ }
114
+ catch (err) {
115
+ throw new DynamoDbClientError("error while querying DynamoDB on the lookup index", {
116
+ cause: err,
117
+ });
118
+ }
119
+ }
120
+ async queryOne(query) {
121
+ try {
122
+ let item;
123
+ for await (const queryItem of this.query(query)) {
124
+ if (item != null) {
125
+ throw new DynamoDbClientError("expected one item in query but found at least 2");
126
+ }
127
+ item = queryItem;
128
+ }
129
+ return item;
130
+ }
131
+ catch (err) {
132
+ // TODO: careful here as email is PII.
133
+ throw new DynamoDbClientError(`error while querying one: ${JSON.stringify(query)}`, {
134
+ cause: err,
135
+ });
136
+ }
137
+ }
138
+ static fromBase(params) {
139
+ const { client, document: documentClientConfig, logger } = params;
140
+ const documentClient = lib_dynamodb_1.DynamoDBDocumentClient.from(client, documentClientConfig);
141
+ return DynamoDbClient.from({ client: documentClient, logger });
142
+ }
143
+ static from(params) {
144
+ const { client, logger = null_logger_1.NullLogger.create() } = params;
145
+ return new DynamoDbClient({ client, logger });
146
+ }
147
+ static create(params) {
148
+ const { base, document, logger } = params || {};
149
+ const baseClient = new client_dynamodb_1.DynamoDBClient(base || {});
150
+ return DynamoDbClient.fromBase({ client: baseClient, document, logger });
151
+ }
152
+ }
153
+ exports.DynamoDbClient = DynamoDbClient;
154
+ // Could be associated on the PutItem type if it was an opaque type rather
155
+ // than an interface.
156
+ function toPutCommand(params) {
157
+ return new lib_dynamodb_1.PutCommand(toToPutCommandInput(params));
158
+ }
159
+ function toToPutCommandInput(params) {
160
+ const { table, item, condition } = params;
161
+ const conditionPayload = condition != null ? condition.toAwsInput() : {};
162
+ return {
163
+ TableName: table,
164
+ Item: item,
165
+ ...conditionPayload,
166
+ };
167
+ }
168
+ function toTransactWriteItemsCommandInput(params) {
169
+ return {
170
+ TransactItems: params.items.map((item) => ({
171
+ Put: toToPutCommandInput(item),
172
+ })),
173
+ };
174
+ }
175
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { AttributePath, AttributeType, AttributeValue } from "./types.js";
2
+ type AttributeSubstitution = `#${string}`;
3
+ type ValueReference = `:${string}`;
4
+ export type ExpressionAwsInput = {
5
+ ConditionExpression: string;
6
+ ExpressionAttributeNames?: Record<AttributeSubstitution, AttributePath>;
7
+ ExpressionAttributeValues?: Record<ValueReference, AttributeValue>;
8
+ };
9
+ export declare class ConditionExpression {
10
+ private readonly expression;
11
+ private readonly substitutions?;
12
+ private readonly values?;
13
+ private constructor();
14
+ toAwsInput(): ExpressionAwsInput;
15
+ static attributeNotExists(attribute: AttributePath): ConditionExpression;
16
+ static attributeExists(attribute: AttributePath): ConditionExpression;
17
+ static attributeType(attribute: AttributePath, type: AttributeType): ConditionExpression;
18
+ }
19
+ export {};
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConditionExpression = void 0;
4
+ /**
5
+ * Represents a set of attribute names used in a condition expression.
6
+ *
7
+ * The uses cases for using attribute names are:
8
+ * - To access an attribute whose name conflicts with a DynamoDB reserved word.
9
+ * - To create a placeholder for repeating occurrences of an attribute name in an expression.
10
+ * - To prevent special characters in an attribute name from being misinterpreted in an expression.
11
+ */
12
+ class AttributeSubstitutions {
13
+ names;
14
+ constructor() {
15
+ this.names = new Map();
16
+ }
17
+ substitute(attribute) {
18
+ const existing = this.names.get(attribute);
19
+ if (existing != null) {
20
+ return existing;
21
+ }
22
+ const substitute = this.generateSubstitute(attribute);
23
+ this.names.set(attribute, substitute);
24
+ return substitute;
25
+ }
26
+ toAwsInput() {
27
+ const result = {};
28
+ for (const [attribute, substitute] of this.names.entries()) {
29
+ result[substitute] = attribute;
30
+ }
31
+ return result;
32
+ }
33
+ generateSubstitute(attribute) {
34
+ return `#${attribute}`;
35
+ }
36
+ }
37
+ class AttributeValues {
38
+ values;
39
+ counter;
40
+ constructor() {
41
+ this.values = new Map();
42
+ this.counter = 0;
43
+ }
44
+ referenceBy(value) {
45
+ const existing = this.values.get(value);
46
+ if (existing != null) {
47
+ return existing;
48
+ }
49
+ const reference = this.generateReference();
50
+ this.values.set(value, reference);
51
+ return reference;
52
+ }
53
+ toAwsInput() {
54
+ const result = {};
55
+ for (const [value, reference] of this.values.entries()) {
56
+ result[reference] = value;
57
+ }
58
+ return result;
59
+ }
60
+ generateReference() {
61
+ const reference = `:${this.counter}`;
62
+ this.counter += 1;
63
+ return reference;
64
+ }
65
+ }
66
+ class ConditionExpression {
67
+ expression;
68
+ substitutions;
69
+ values;
70
+ constructor(params) {
71
+ const { expression, substitutions, values } = params;
72
+ this.expression = expression;
73
+ this.substitutions = substitutions;
74
+ this.values = values;
75
+ }
76
+ toAwsInput() {
77
+ const result = {
78
+ ConditionExpression: this.expression,
79
+ };
80
+ if (this.substitutions != null) {
81
+ result.ExpressionAttributeNames = this.substitutions.toAwsInput();
82
+ }
83
+ if (this.values != null) {
84
+ result.ExpressionAttributeValues = this.values.toAwsInput();
85
+ }
86
+ return result;
87
+ }
88
+ static attributeNotExists(attribute) {
89
+ const substitutions = new AttributeSubstitutions();
90
+ const sub = substitutions.substitute(attribute);
91
+ return new ConditionExpression({
92
+ expression: `attribute_not_exists(${sub})`,
93
+ substitutions,
94
+ });
95
+ }
96
+ static attributeExists(attribute) {
97
+ const substitutions = new AttributeSubstitutions();
98
+ const sub = substitutions.substitute(attribute);
99
+ return new ConditionExpression({
100
+ expression: `attribute_exists(${sub})`,
101
+ substitutions,
102
+ });
103
+ }
104
+ static attributeType(attribute, type) {
105
+ const substitutions = new AttributeSubstitutions();
106
+ const sub = substitutions.substitute(attribute);
107
+ const values = new AttributeValues();
108
+ const valueRef = values.referenceBy(type);
109
+ return new ConditionExpression({
110
+ expression: `attribute_type(${sub}, ${valueRef})`,
111
+ substitutions,
112
+ values,
113
+ });
114
+ }
115
+ }
116
+ exports.ConditionExpression = ConditionExpression;
117
+ //# sourceMappingURL=condition-expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"condition-expression.js","sourceRoot":"","sources":["../../src/condition-expression.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from "./client.js";
2
+ export * from "./condition-expression.js";
3
+ export * from "./key-condition-expression.js";
4
+ export * from "./types.js";
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./client.js"), exports);
18
+ __exportStar(require("./condition-expression.js"), exports);
19
+ __exportStar(require("./key-condition-expression.js"), exports);
20
+ __exportStar(require("./types.js"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,4DAA0C;AAC1C,gEAA8C;AAC9C,6CAA2B"}
@@ -0,0 +1,20 @@
1
+ import type { Attributes } from "./types.js";
2
+ export declare class KeyConditionExpression {
3
+ private readonly expression;
4
+ private readonly attributeValues;
5
+ private constructor();
6
+ toJson(): {
7
+ expression: string;
8
+ attributeValues: Attributes;
9
+ };
10
+ static partitionKeyEquals(params: {
11
+ attributeName: string;
12
+ value: string;
13
+ token?: string;
14
+ }): KeyConditionExpression;
15
+ static equals(params: {
16
+ attributeName: string;
17
+ value: string;
18
+ token: string;
19
+ }): KeyConditionExpression;
20
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KeyConditionExpression = void 0;
4
+ class KeyConditionExpression {
5
+ expression;
6
+ attributeValues;
7
+ constructor(params) {
8
+ const { expression, attributeValues } = params;
9
+ this.expression = expression;
10
+ this.attributeValues = attributeValues;
11
+ }
12
+ toJson() {
13
+ return {
14
+ expression: this.expression,
15
+ attributeValues: this.attributeValues,
16
+ };
17
+ }
18
+ static partitionKeyEquals(params) {
19
+ const { attributeName, value, token = ":pk" } = params;
20
+ return KeyConditionExpression.equals({
21
+ attributeName,
22
+ value,
23
+ token,
24
+ });
25
+ }
26
+ static equals(params) {
27
+ const { attributeName, value, token } = params;
28
+ return new KeyConditionExpression({
29
+ expression: `${attributeName} = ${token}`,
30
+ attributeValues: { [token]: value },
31
+ });
32
+ }
33
+ }
34
+ exports.KeyConditionExpression = KeyConditionExpression;
35
+ //# sourceMappingURL=key-condition-expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-condition-expression.js","sourceRoot":"","sources":["../../src/key-condition-expression.ts"],"names":[],"mappings":";;;AAEA,MAAa,sBAAsB;IAChB,UAAU,CAAS;IACnB,eAAe,CAAa;IAE7C,YAAoB,MAGnB;QACC,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IACzC,CAAC;IAED,MAAM;QACJ,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,kBAAkB,CAAC,MAIzB;QACC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC;QACvD,OAAO,sBAAsB,CAAC,MAAM,CAAC;YACnC,aAAa;YACb,KAAK;YACL,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,MAIb;QACC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QAE/C,OAAO,IAAI,sBAAsB,CAAC;YAChC,UAAU,EAAE,GAAG,aAAa,MAAM,KAAK,EAAE;YACzC,eAAe,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;CACF;AA7CD,wDA6CC"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,30 @@
1
+ import type { NativeAttributeValue } from "@aws-sdk/lib-dynamodb";
2
+ import type { ConditionExpression } from "./condition-expression.js";
3
+ import type { KeyConditionExpression } from "./key-condition-expression.js";
4
+ export type AttributeName = string;
5
+ export type AttributeValue = NativeAttributeValue;
6
+ export type AttributePath = AttributeName;
7
+ export type AttributeType = "S" | "N" | "B" | "BOOL" | "NULL" | "M" | "L" | "SS" | "NS" | "BS";
8
+ export interface Attribute {
9
+ name: AttributeName;
10
+ value: AttributeValue;
11
+ }
12
+ export type Attributes = Record<AttributeName, NativeAttributeValue>;
13
+ export interface GetItem {
14
+ table: string;
15
+ parititionKey: Attribute;
16
+ sortKey?: Attribute;
17
+ }
18
+ export interface PutItem {
19
+ table: string;
20
+ item: Attributes;
21
+ condition?: ConditionExpression;
22
+ }
23
+ export interface WriteTransaction {
24
+ items: PutItem[];
25
+ }
26
+ export interface Query {
27
+ table: string;
28
+ index?: string;
29
+ condition: KeyConditionExpression;
30
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import type { DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
2
+ import { DynamoDBClient as BaseClient } from "@aws-sdk/client-dynamodb";
3
+ import type { TranslateConfig } from "@aws-sdk/lib-dynamodb";
4
+ import { DynamoDBDocumentClient as Client } from "@aws-sdk/lib-dynamodb";
5
+ import type { Logger } from "@infra-blocks/logger-interface";
6
+ import { type Retry } from "@infra-blocks/retry";
7
+ import type { Attributes, GetItem, PutItem, Query, WriteTransaction } from "./types.js";
8
+ export declare class DynamoDbClientError extends Error {
9
+ constructor(message: string, options?: {
10
+ cause?: unknown;
11
+ });
12
+ }
13
+ export declare class DynamoDbClient {
14
+ private readonly client;
15
+ private readonly logger;
16
+ private constructor();
17
+ ready(): Retry<void>;
18
+ getItem<T>(params: GetItem): Promise<T | undefined>;
19
+ putItem(params: PutItem): Promise<void>;
20
+ transactWriteItems(params: WriteTransaction): Promise<void>;
21
+ query<T extends Attributes = Attributes>(query: Query): AsyncGenerator<T>;
22
+ queryOne<T extends Attributes = Attributes>(query: Query): Promise<T | undefined>;
23
+ static fromBase(params: {
24
+ client: BaseClient;
25
+ document?: TranslateConfig;
26
+ logger?: Logger;
27
+ }): DynamoDbClient;
28
+ static from(params: {
29
+ client: Client;
30
+ logger?: Logger;
31
+ }): DynamoDbClient;
32
+ static create(params?: {
33
+ base?: DynamoDBClientConfig;
34
+ document?: TranslateConfig;
35
+ logger?: Logger;
36
+ }): DynamoDbClient;
37
+ }
@@ -0,0 +1,170 @@
1
+ import { DynamoDBClient as BaseClient, ListTablesCommand, } from "@aws-sdk/client-dynamodb";
2
+ import { DynamoDBDocumentClient as Client, GetCommand, PutCommand, QueryCommand, TransactWriteCommand, } from "@aws-sdk/lib-dynamodb";
3
+ import { NullLogger } from "@infra-blocks/null-logger";
4
+ import { retry } from "@infra-blocks/retry";
5
+ export class DynamoDbClientError extends Error {
6
+ constructor(message, options) {
7
+ super(message, options);
8
+ this.name = "DynamoDbClientError";
9
+ }
10
+ }
11
+ /*
12
+ The uniqueness constraint of an attribute, for example an email, can be enforced in DynamoDB using
13
+ this scheme: https://aws.amazon.com/blogs/database/simulating-amazon-dynamodb-unique-constraints-using-transactions/#:~:text=Primary%20keys%20are%20guaranteed%20to,are%20not%20the%20primary%20key.
14
+
15
+ This is to say, we can create items in a different table that only has a pk for this specific use case, or we could
16
+ also use the same table. It's just going to add some sheeet to the table.
17
+ */
18
+ export class DynamoDbClient {
19
+ client;
20
+ logger;
21
+ constructor(params) {
22
+ const { client, logger } = params;
23
+ this.client = client;
24
+ this.logger = logger;
25
+ }
26
+ ready() {
27
+ return retry(async () => {
28
+ await this.client.send(new ListTablesCommand({}));
29
+ }, {
30
+ isRetryableError: (err) => {
31
+ if ("code" in err) {
32
+ return err.code === "ECONNRESET";
33
+ }
34
+ return false;
35
+ },
36
+ });
37
+ }
38
+ async getItem(params) {
39
+ try {
40
+ const { table, parititionKey, sortKey } = params;
41
+ const key = {
42
+ [parititionKey.name]: parititionKey.value,
43
+ };
44
+ if (sortKey != null) {
45
+ key[sortKey.name] = sortKey.value;
46
+ }
47
+ const response = await this.client.send(new GetCommand({
48
+ TableName: table,
49
+ Key: key,
50
+ }));
51
+ return response.Item;
52
+ }
53
+ catch (err) {
54
+ throw new DynamoDbClientError(`error while getting item from DynamoDB: ${JSON.stringify(params)}`, {
55
+ cause: err,
56
+ });
57
+ }
58
+ }
59
+ async putItem(params) {
60
+ try {
61
+ await this.client.send(toPutCommand(params));
62
+ }
63
+ catch (err) {
64
+ this.logger.error("error while putting item in DynamoDB caused by %s", err);
65
+ throw new DynamoDbClientError("error while putting item in DynamoDB", {
66
+ cause: err,
67
+ });
68
+ }
69
+ }
70
+ async transactWriteItems(params) {
71
+ try {
72
+ const commandInput = toTransactWriteItemsCommandInput(params);
73
+ if (this.logger.isDebugEnabled()) {
74
+ this.logger.debug("executing transaction write: %s", JSON.stringify(commandInput));
75
+ }
76
+ const command = new TransactWriteCommand(commandInput);
77
+ await this.client.send(command);
78
+ }
79
+ catch (err) {
80
+ throw new DynamoDbClientError("error while transactionally writing items in DynamoDB", {
81
+ cause: err,
82
+ });
83
+ }
84
+ }
85
+ async *query(query) {
86
+ try {
87
+ const { expression, attributeValues } = query.condition.toJson();
88
+ let response = await this.client.send(new QueryCommand({
89
+ TableName: query.table,
90
+ IndexName: query.index,
91
+ KeyConditionExpression: expression,
92
+ ExpressionAttributeValues: attributeValues,
93
+ }));
94
+ for (const item of response.Items || []) {
95
+ yield item;
96
+ }
97
+ while (response.LastEvaluatedKey != null) {
98
+ response = await this.client.send(new QueryCommand({
99
+ TableName: query.table,
100
+ IndexName: query.index,
101
+ KeyConditionExpression: expression,
102
+ ExpressionAttributeValues: attributeValues,
103
+ ExclusiveStartKey: response.LastEvaluatedKey,
104
+ }));
105
+ for (const item of response.Items || []) {
106
+ yield item;
107
+ }
108
+ }
109
+ }
110
+ catch (err) {
111
+ throw new DynamoDbClientError("error while querying DynamoDB on the lookup index", {
112
+ cause: err,
113
+ });
114
+ }
115
+ }
116
+ async queryOne(query) {
117
+ try {
118
+ let item;
119
+ for await (const queryItem of this.query(query)) {
120
+ if (item != null) {
121
+ throw new DynamoDbClientError("expected one item in query but found at least 2");
122
+ }
123
+ item = queryItem;
124
+ }
125
+ return item;
126
+ }
127
+ catch (err) {
128
+ // TODO: careful here as email is PII.
129
+ throw new DynamoDbClientError(`error while querying one: ${JSON.stringify(query)}`, {
130
+ cause: err,
131
+ });
132
+ }
133
+ }
134
+ static fromBase(params) {
135
+ const { client, document: documentClientConfig, logger } = params;
136
+ const documentClient = Client.from(client, documentClientConfig);
137
+ return DynamoDbClient.from({ client: documentClient, logger });
138
+ }
139
+ static from(params) {
140
+ const { client, logger = NullLogger.create() } = params;
141
+ return new DynamoDbClient({ client, logger });
142
+ }
143
+ static create(params) {
144
+ const { base, document, logger } = params || {};
145
+ const baseClient = new BaseClient(base || {});
146
+ return DynamoDbClient.fromBase({ client: baseClient, document, logger });
147
+ }
148
+ }
149
+ // Could be associated on the PutItem type if it was an opaque type rather
150
+ // than an interface.
151
+ function toPutCommand(params) {
152
+ return new PutCommand(toToPutCommandInput(params));
153
+ }
154
+ function toToPutCommandInput(params) {
155
+ const { table, item, condition } = params;
156
+ const conditionPayload = condition != null ? condition.toAwsInput() : {};
157
+ return {
158
+ TableName: table,
159
+ Item: item,
160
+ ...conditionPayload,
161
+ };
162
+ }
163
+ function toTransactWriteItemsCommandInput(params) {
164
+ return {
165
+ TransactItems: params.items.map((item) => ({
166
+ Put: toToPutCommandInput(item),
167
+ })),
168
+ };
169
+ }
170
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { AttributePath, AttributeType, AttributeValue } from "./types.js";
2
+ type AttributeSubstitution = `#${string}`;
3
+ type ValueReference = `:${string}`;
4
+ export type ExpressionAwsInput = {
5
+ ConditionExpression: string;
6
+ ExpressionAttributeNames?: Record<AttributeSubstitution, AttributePath>;
7
+ ExpressionAttributeValues?: Record<ValueReference, AttributeValue>;
8
+ };
9
+ export declare class ConditionExpression {
10
+ private readonly expression;
11
+ private readonly substitutions?;
12
+ private readonly values?;
13
+ private constructor();
14
+ toAwsInput(): ExpressionAwsInput;
15
+ static attributeNotExists(attribute: AttributePath): ConditionExpression;
16
+ static attributeExists(attribute: AttributePath): ConditionExpression;
17
+ static attributeType(attribute: AttributePath, type: AttributeType): ConditionExpression;
18
+ }
19
+ export {};
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Represents a set of attribute names used in a condition expression.
3
+ *
4
+ * The uses cases for using attribute names are:
5
+ * - To access an attribute whose name conflicts with a DynamoDB reserved word.
6
+ * - To create a placeholder for repeating occurrences of an attribute name in an expression.
7
+ * - To prevent special characters in an attribute name from being misinterpreted in an expression.
8
+ */
9
+ class AttributeSubstitutions {
10
+ names;
11
+ constructor() {
12
+ this.names = new Map();
13
+ }
14
+ substitute(attribute) {
15
+ const existing = this.names.get(attribute);
16
+ if (existing != null) {
17
+ return existing;
18
+ }
19
+ const substitute = this.generateSubstitute(attribute);
20
+ this.names.set(attribute, substitute);
21
+ return substitute;
22
+ }
23
+ toAwsInput() {
24
+ const result = {};
25
+ for (const [attribute, substitute] of this.names.entries()) {
26
+ result[substitute] = attribute;
27
+ }
28
+ return result;
29
+ }
30
+ generateSubstitute(attribute) {
31
+ return `#${attribute}`;
32
+ }
33
+ }
34
+ class AttributeValues {
35
+ values;
36
+ counter;
37
+ constructor() {
38
+ this.values = new Map();
39
+ this.counter = 0;
40
+ }
41
+ referenceBy(value) {
42
+ const existing = this.values.get(value);
43
+ if (existing != null) {
44
+ return existing;
45
+ }
46
+ const reference = this.generateReference();
47
+ this.values.set(value, reference);
48
+ return reference;
49
+ }
50
+ toAwsInput() {
51
+ const result = {};
52
+ for (const [value, reference] of this.values.entries()) {
53
+ result[reference] = value;
54
+ }
55
+ return result;
56
+ }
57
+ generateReference() {
58
+ const reference = `:${this.counter}`;
59
+ this.counter += 1;
60
+ return reference;
61
+ }
62
+ }
63
+ export class ConditionExpression {
64
+ expression;
65
+ substitutions;
66
+ values;
67
+ constructor(params) {
68
+ const { expression, substitutions, values } = params;
69
+ this.expression = expression;
70
+ this.substitutions = substitutions;
71
+ this.values = values;
72
+ }
73
+ toAwsInput() {
74
+ const result = {
75
+ ConditionExpression: this.expression,
76
+ };
77
+ if (this.substitutions != null) {
78
+ result.ExpressionAttributeNames = this.substitutions.toAwsInput();
79
+ }
80
+ if (this.values != null) {
81
+ result.ExpressionAttributeValues = this.values.toAwsInput();
82
+ }
83
+ return result;
84
+ }
85
+ static attributeNotExists(attribute) {
86
+ const substitutions = new AttributeSubstitutions();
87
+ const sub = substitutions.substitute(attribute);
88
+ return new ConditionExpression({
89
+ expression: `attribute_not_exists(${sub})`,
90
+ substitutions,
91
+ });
92
+ }
93
+ static attributeExists(attribute) {
94
+ const substitutions = new AttributeSubstitutions();
95
+ const sub = substitutions.substitute(attribute);
96
+ return new ConditionExpression({
97
+ expression: `attribute_exists(${sub})`,
98
+ substitutions,
99
+ });
100
+ }
101
+ static attributeType(attribute, type) {
102
+ const substitutions = new AttributeSubstitutions();
103
+ const sub = substitutions.substitute(attribute);
104
+ const values = new AttributeValues();
105
+ const valueRef = values.referenceBy(type);
106
+ return new ConditionExpression({
107
+ expression: `attribute_type(${sub}, ${valueRef})`,
108
+ substitutions,
109
+ values,
110
+ });
111
+ }
112
+ }
113
+ //# sourceMappingURL=condition-expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"condition-expression.js","sourceRoot":"","sources":["../../src/condition-expression.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from "./client.js";
2
+ export * from "./condition-expression.js";
3
+ export * from "./key-condition-expression.js";
4
+ export * from "./types.js";
@@ -0,0 +1,5 @@
1
+ export * from "./client.js";
2
+ export * from "./condition-expression.js";
3
+ export * from "./key-condition-expression.js";
4
+ export * from "./types.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,YAAY,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Attributes } from "./types.js";
2
+ export declare class KeyConditionExpression {
3
+ private readonly expression;
4
+ private readonly attributeValues;
5
+ private constructor();
6
+ toJson(): {
7
+ expression: string;
8
+ attributeValues: Attributes;
9
+ };
10
+ static partitionKeyEquals(params: {
11
+ attributeName: string;
12
+ value: string;
13
+ token?: string;
14
+ }): KeyConditionExpression;
15
+ static equals(params: {
16
+ attributeName: string;
17
+ value: string;
18
+ token: string;
19
+ }): KeyConditionExpression;
20
+ }
@@ -0,0 +1,31 @@
1
+ export class KeyConditionExpression {
2
+ expression;
3
+ attributeValues;
4
+ constructor(params) {
5
+ const { expression, attributeValues } = params;
6
+ this.expression = expression;
7
+ this.attributeValues = attributeValues;
8
+ }
9
+ toJson() {
10
+ return {
11
+ expression: this.expression,
12
+ attributeValues: this.attributeValues,
13
+ };
14
+ }
15
+ static partitionKeyEquals(params) {
16
+ const { attributeName, value, token = ":pk" } = params;
17
+ return KeyConditionExpression.equals({
18
+ attributeName,
19
+ value,
20
+ token,
21
+ });
22
+ }
23
+ static equals(params) {
24
+ const { attributeName, value, token } = params;
25
+ return new KeyConditionExpression({
26
+ expression: `${attributeName} = ${token}`,
27
+ attributeValues: { [token]: value },
28
+ });
29
+ }
30
+ }
31
+ //# sourceMappingURL=key-condition-expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-condition-expression.js","sourceRoot":"","sources":["../../src/key-condition-expression.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,sBAAsB;IAChB,UAAU,CAAS;IACnB,eAAe,CAAa;IAE7C,YAAoB,MAGnB;QACC,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IACzC,CAAC;IAED,MAAM;QACJ,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,kBAAkB,CAAC,MAIzB;QACC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC;QACvD,OAAO,sBAAsB,CAAC,MAAM,CAAC;YACnC,aAAa;YACb,KAAK;YACL,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,MAIb;QACC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QAE/C,OAAO,IAAI,sBAAsB,CAAC;YAChC,UAAU,EAAE,GAAG,aAAa,MAAM,KAAK,EAAE;YACzC,eAAe,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,30 @@
1
+ import type { NativeAttributeValue } from "@aws-sdk/lib-dynamodb";
2
+ import type { ConditionExpression } from "./condition-expression.js";
3
+ import type { KeyConditionExpression } from "./key-condition-expression.js";
4
+ export type AttributeName = string;
5
+ export type AttributeValue = NativeAttributeValue;
6
+ export type AttributePath = AttributeName;
7
+ export type AttributeType = "S" | "N" | "B" | "BOOL" | "NULL" | "M" | "L" | "SS" | "NS" | "BS";
8
+ export interface Attribute {
9
+ name: AttributeName;
10
+ value: AttributeValue;
11
+ }
12
+ export type Attributes = Record<AttributeName, NativeAttributeValue>;
13
+ export interface GetItem {
14
+ table: string;
15
+ parititionKey: Attribute;
16
+ sortKey?: Attribute;
17
+ }
18
+ export interface PutItem {
19
+ table: string;
20
+ item: Attributes;
21
+ condition?: ConditionExpression;
22
+ }
23
+ export interface WriteTransaction {
24
+ items: PutItem[];
25
+ }
26
+ export interface Query {
27
+ table: string;
28
+ index?: string;
29
+ condition: KeyConditionExpression;
30
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@infra-blocks/aws-dynamodb",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "A convenience wrapper over @aws-sdk/client-dynamodb and @aws-sdk/lib-dynamodb.",
5
+ "keywords": [
6
+ "aws",
7
+ "dynamodb",
8
+ "expression"
9
+ ],
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/infra-blocks/ts-aws-dynamodb.git"
13
+ },
14
+ "license": "ISC",
15
+ "author": "",
16
+ "type": "module",
17
+ "exports": {
18
+ "import": "./lib/esm/index.js",
19
+ "require": "./lib/cjs/index.js",
20
+ "default": "./lib/esm/index.js"
21
+ },
22
+ "files": [
23
+ "lib/**/*.{js,cjs,mjs,json,d.ts,map}"
24
+ ],
25
+ "scripts": {
26
+ "prebuild": "npm run clean",
27
+ "build": "tsc -b tsconfig.build.esm.json tsconfig.build.cjs.json",
28
+ "postbuild": "scripts/post-build.sh",
29
+ "clean": "rm -rf lib && rm -f infra-blocks-*.tgz",
30
+ "compile": "tsc",
31
+ "fix": "biome check --write",
32
+ "lint": "biome ci",
33
+ "prepack": "npm run build",
34
+ "test": "npm run test:unit && npm run test:integration",
35
+ "test:coverage": "c8 npm run test",
36
+ "test:coverage:lcov": "c8 --reporter=lcov npm run test",
37
+ "test:integration": "mocha --config test/integration/.mocharc.cjs 'test/integration/**/*.spec.ts'",
38
+ "test:unit": "mocha --config test/unit/.mocharc.cjs 'test/unit/**/*.spec.ts'"
39
+ },
40
+ "devDependencies": {
41
+ "@biomejs/biome": "^2.0.6",
42
+ "@infra-blocks/test": "^0.4.0",
43
+ "@types/mocha": "^10.0.10",
44
+ "@types/node": "^24.0.10",
45
+ "c8": "^10.1.3",
46
+ "lefthook": "^1.11.16",
47
+ "mocha": "^11.7.1",
48
+ "tsx": "^4.20.3",
49
+ "typescript": "^5.8.3"
50
+ },
51
+ "engines": {
52
+ "node": ">=24.0.0"
53
+ },
54
+ "dependencies": {
55
+ "@aws-sdk/client-dynamodb": "^3.840.0",
56
+ "@aws-sdk/lib-dynamodb": "^3.840.0",
57
+ "@infra-blocks/logger-interface": "^0.3.1",
58
+ "@infra-blocks/null-logger": "^0.1.1",
59
+ "@infra-blocks/retry": "^0.1.1"
60
+ }
61
+ }