Skip to content

Commit 656f735

Browse files
committed
📝 doc
Signed-off-by: moznion <moznion@mail.moznion.net>
1 parent 288e1f7 commit 656f735

File tree

5 files changed

+206
-8
lines changed

5 files changed

+206
-8
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
node_modules/
2+
lib/*.js
3+
lib/*.d.ts
4+
transformer.d.ts
5+
transformer.js

README.md

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,191 @@
11
# ts-dynamodb-attributes-transformer
22

3-
TypeScript Compiler API Transformer for Amazon DynamoDB attributes.
3+
Code transformer plugin for Amazon DynamoDB attributes powered by [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API).
44

5+
## How it works
6+
7+
This plugin replaces the TypeScript function invocation of `dynamodbRecord<T>(obj: T)` with `Record<string, AttributeValue>` value that is defined in aws-sdk-js-v3 according to the type `T` and the contents of the object. In short, this plugin generates the DynamoDB attribute code for every property of type `T`.
8+
9+
This plugin powers the users can do drop-in replacements for the existing `Record<string, AttributeValue>` value and/or the generator with `dynamodbRecord<T>(obj: T)` function.
10+
11+
Manual making the translation layer between the object and DynamoDB's Record is no longer needed!
12+
13+
## Motivations
14+
15+
- To do automatic generation of the [DynamoDB attribute data type](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) code that is recognizable by [aws-sdk-js-v3](https://github.com/aws/aws-sdk-js-v3), with type safety.
16+
- Performance. This uses TypeScript Compiler API, so it generates/determine the DynamoDB attribute code at the compiling timing. This means the logic doesn't have to do a reflection on the fly so this contributes to a good performance.
17+
18+
## Synopsis
19+
20+
```ts
21+
import { AttributeValue } from '@aws-sdk/client-dynamodb';
22+
import { dynamodbRecord } from '@moznion/ts-dynamodb-attributes-transformer';
23+
24+
interface User {
25+
readonly id: number;
26+
readonly name: string;
27+
readonly tags: Map<string, string>;
28+
}
29+
30+
const record: Record<string, AttributeValue> = dynamodbRecord<User>({
31+
id: 12345,
32+
name: 'John Doe',
33+
tags: new Map<string, string>([
34+
['foo', 'bar'],
35+
['buz', 'qux'],
36+
]),
37+
});
38+
39+
/*
40+
* Then you can use this record value on the aws-sdk-js-v3's DynamoDB client; for example,
41+
*
42+
* const dyn = new DynamoDBClient(...);
43+
* await dyn.send(new PutItemCommand({
44+
* TableName: "...",
45+
* Item: record, // <= HERE!
46+
* }));
47+
*/
48+
```
49+
50+
Then this plugin transforms the above TypeScript code like the following JavaScript code:
51+
52+
```js
53+
const record = function () {
54+
var arg;
55+
arg = {
56+
id: 12345,
57+
name: 'John Doe',
58+
tags: new Map([
59+
['foo', 'bar'],
60+
['buz', 'qux'],
61+
]),
62+
}
63+
return {
64+
id: {
65+
N: arg.id.toString()
66+
},
67+
name: {
68+
S: arg.name
69+
},
70+
tags: {
71+
M: function () {
72+
var m;
73+
m = {}
74+
for (const kv of arg.tags) {
75+
m[kv[0]] = { S: kv[1] }
76+
}
77+
return m;
78+
}()
79+
}
80+
};
81+
}();
82+
/*
83+
* This record is equal to the following object:
84+
*
85+
* {
86+
* id: { N: "12345" },
87+
* name: { S: "John Doe" },
88+
* tags: {
89+
* M: {
90+
* foo: { S: "bar" },
91+
* buz: { S: "qux" }
92+
* }
93+
* }
94+
* }
95+
*/
96+
```
97+
98+
## How to use this transformer
99+
100+
This plugin exports a function that has the signature `dynamodbRecord<T extends object>(item: T): Record<string, AttributeValue>`.
101+
102+
This function is a marker to indicate to the transformer to replace this function invocation with the generated DynamoDB record code. Therefore, there are some restrictions:
103+
104+
- Type parameter `T` is mandatory parameter (i.e. this mustn't be omitted). A transformer analyzes the type of the given `T` to collect the property information.
105+
- Type `T` must be class or interface.
106+
107+
### Examples
108+
109+
#### ttypescript
110+
111+
[ttypescript](https://github.com/cevek/ttypescript) is a custom TypeScript compiler that triggers the specified transformers in the tsconfig.json.
112+
113+
Please refer to the [examples/ttypescript](./examples/ttypescript) project directory and [ttypescript official README](https://github.com/cevek/ttypescript) for more details.
114+
115+
Anyway, the important thing is specifying `compilerOptions.plugins` in tsconfig.json like the following:
116+
117+
```json
118+
{
119+
"compilerOptions": {
120+
// ...
121+
"plugins": [
122+
{ "transform": "@moznion/ts-dynamodb-attributes-transformer/transformer" }
123+
]
124+
},
125+
// ...
126+
}
127+
```
128+
129+
#### ts-jest
130+
131+
If you use [ts-jest](https://github.com/kulshekhar/ts-jest) with this transformer, one of the easiest ways is using that with ttypescript toghether.
132+
133+
It needs ttypescript configuration and additionally the jest configuration in `jest.config.js` like the below:
134+
135+
```js
136+
module.exports = {
137+
// ...
138+
transform: {
139+
'^.+\\.tsx?$': [
140+
'ts-jest',
141+
{
142+
compiler: 'ttypescript',
143+
},
144+
],
145+
},
146+
// ...
147+
};
148+
149+
```
150+
151+
## TypeScript types to DynamoDB types
152+
153+
Please see also [Supported data types and naming rules in Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) for more details about the DynamoDB types.
154+
155+
### Scalar Types
156+
157+
| TypeScript | DynamoDB |
158+
|----------------|------------|
159+
| number, BigInt | N |
160+
| string | S |
161+
| Uint8Array | B |
162+
| boolean | BOOL |
163+
| unknown | NULL |
164+
165+
NOTE: if the TypeScript property has `unknown` type and the value is `null` then DynamoDB attribute becomes `{ NULL: true }`. Else, that attribute value is `{ NULL: false }`.
166+
167+
### Document Types
168+
169+
| TypeScript | DynamoDB |
170+
|----------------------------------------------------------------|----------|
171+
| `Set<string>` | SS |
172+
| `Set<number>`, `Set<BigInt>` | NS |
173+
| `Set<Uint8Array>` | BS |
174+
| `List<$SCALAR_TYPE>` | L |
175+
| `Map<string, $SCALAR_TYPE>`, `{ [key: string]: $SCALAR_TYPE }` | M |
176+
177+
## Options
178+
179+
### `TS_DYNAMODB_ATTR_TRANSFORMER_LENIENT_TYPE_CHECK` env var (default: `<empty>`)
180+
181+
By default, if this plugin encounters unsupported types, it raises the error and halts the transformation.
182+
183+
But if `TS_DYNAMODB_ATTR_TRANSFORMER_LENIENT_TYPE_CHECK` environment variable is not empty, it proceeds the transformation with ignoring the unsupported typed property even if it gets the unsupported types.
184+
185+
## Note
186+
187+
This transformer plugin referred to the various things from [kimamula/ts-transformer-keys](https://github.com/kimamula/ts-transformer-keys)
188+
189+
## Authors
190+
191+
moznion (<moznion@mail.moznion.net>)

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
2-
"name": "ts-dynamodb-attributes-transformer",
2+
"name": "@moznion/ts-dynamodb-attributes-transformer",
33
"version": "0.0.1",
4-
"description": "TypeScript Compiler API Transformer for Amazon DynamoDB attributes",
4+
"description": "Code transformer plugin for Amazon DynamoDB attributes powered by TypeScript Compiler API",
55
"main": "index.js",
66
"types": "index.d.ts",
77
"scripts": {
8+
"build": "tsc",
89
"test": "TS_DYNAMODB_ATTR_TRANSFORMER_LENIENT_TYPE_CHECK=true jest",
910
"fmt": "find -name '*.ts' -not -path './node_modules/*' | xargs prettier --write",
1011
"lint": "eslint ."
@@ -39,5 +40,12 @@
3940
},
4041
"dependencies": {
4142
"@aws-sdk/client-dynamodb": "^3.186.0"
42-
}
43+
},
44+
"files": [
45+
"index.js",
46+
"index.d.ts",
47+
"transformer.js",
48+
"transformer.ts",
49+
"lib"
50+
]
4351
}

tsconfig.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
}
2727
]
2828
},
29-
"include": [
30-
],
3129
"exclude": [
30+
"tests",
3231
"node_modules"
3332
]
3433
}

0 commit comments

Comments
 (0)