DEV Community

moznion
moznion

Posted on

ts-dynamodb-attributes-transformer: A code transformer of TypeScript object to DynamoDB attributes

I published "ts-dynamodb-attributes-transformer" that transforms the TypsScript object to Amazon DynamoDB attributes (precisely, this attributes type is Record<string, AttributeValue> that is defined at aws-sdk-js-v3):

https://github.com/moznion/ts-dynamodb-attributes-transformer

And this is also available on npm:

https://www.npmjs.com/package/@moznion/ts-dynamodb-attributes-transformer

ts-dynamodb-attributes-transformer is a code transformer plugin that uses TypeScript Compiler API.

Let's see how this transformer works.
When it gives the following TypeScript code to this transformer,

import { AttributeValue } from '@aws-sdk/client-dynamodb';
import { dynamodbRecord } from '@moznion/ts-dynamodb-attributes-transformer';

interface User {
  readonly id: number;
  readonly name: string;
  readonly tags: Map<string, string>;
}

const record: Record<keyof User, AttributeValue> = dynamodbRecord<User>({
  id: 12345,
  name: 'John Doe',
  tags: new Map<string, string>([
    ['foo', 'bar'],
    ['buz', 'qux'],
  ]),
});
Enter fullscreen mode Exit fullscreen mode

This transformer detects dynamodbRecord<T>(obj: T) (in this case that is dynamodbRecord<User>(...)) function invocation and analyzes the fields definition of the type parameter T (in this case User), and it generates the JavaScript code like the following according to the T-typed object given as a parameter.

const record = function (arg) {
    return {
        id: {
            N: arg.id.toString()
        },
        name: {
            S: arg.name
        },
        tags: {
            M: function () {
                var m;
                m = {}
                for (const kv of arg.tags) {
                    m[kv[0]] = { S: kv[1] }
                }
                return m;
            }()
        }
    };
}({
    id: 12345,
    name: 'John Doe',
    tags: new Map([
        ['foo', 'bar'],
        ['buz', 'qux'],
    ]),
});
Enter fullscreen mode Exit fullscreen mode

This behavior is like it replaces dynamodbRecord<T>(obj: T) invocation with a generator function for DynamoDB attributes entirely.

As I noted above, this is a TypeScript transformer plugin so it needs to hook this plugin on TypeScript compilation phase. I suppose one of the easiest ways is using ttypescript which is a custom TypeScript compiler that can hook the transformer plugin on a compilation. Please refer also to the "How to use this transformer" section in README.

Naturally, this plugin can transform a target object to the DynamoDB attributes according to the type definition of that object. And this uses TypeScript Compiler API to transform the code thus it can determine the code to generate on compilation statically so it doesn't have to do reflection or something on the fly to construct the DynamoDB attributes object. This contributes to good performance.

The benchmark result between this project and kayomarz/dynamodb-data-types is the following:

node version: v16.17.0
dynamodb-data-types marshalling x 3,475,450 ops/sec ±0.45% (96 runs sampled)
ts-dynamodb-attributes-transformer marshalling x 13,405,409 ops/sec ±0.43% (91 runs sampled)
Fastest is ts-dynamodb-attributes-transformer marshalling
Enter fullscreen mode Exit fullscreen mode

This shows this transformer is about 3.85 times faster than the dynamodb-data-types.

At this moment, this plugin satisfies my use case but I would appreciate your suggestions if you have some enhancement ideas or find any issues!

Top comments (0)