npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@moznion/ts-dynamodb-attributes-transformer

v0.2.0

Published

Code transformer plugin for Amazon DynamoDB attributes powered by TypeScript Compiler API

Downloads

19

Readme

ts-dynamodb-attributes-transformer .github/workflows/check.yml npm version

Code transformer plugin powered by TypeScript Compiler API that transforms TypeScript object from/to Amazon DynamoDB attributes.

Description

This plugin replaces the TypeScript function invocation with the generated object code. In short, this plugin generates the code for every property of type T.

dynamodbRecord<T>(obj: T): Record<keyof T, AttributeValue>

This plugin replaces dynamodbRecord<T>(obj: T) invocation with Record<keyof T, AttributeValue> value that is defined in aws-sdk-js-v3 according to the type T and the contents of the object.

This plugin powers the users can do drop-in replacements for the existing Record<keyof T, AttributeValue> value and/or the generator with dynamodbRecord<T>(obj: T) function.

fromDynamodbRecord<T>(attrs: Record<string, AttributeValue>): T

This replaces fromDynamodbRecord<T>(attrs: Record<string, AttributeValue>) invocation with the object which has type T. This method is responsible to translate the DynamoDB attributes to the actual TypeScript object, i.e. unmarshalling.

Motivations

  • To do automatic generation of the DynamoDB attribute data type code that is recognizable by aws-sdk-js-v3, with type safety.
    • Manual making the translation layer between the object and DynamoDB's Record is no longer needed!
  • 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.

Benchmark

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

marshalling:

node version: v16.17.0
dynamodb-data-types marshalling x 3,845,247 ops/sec ±0.63% (90 runs sampled)
ts-dynamodb-attributes-transformer marshalling x 13,614,974 ops/sec ±0.24% (100 runs sampled)
Fastest is ts-dynamodb-attributes-transformer marshalling

unmarshalling:

node version: v16.17.0
dynamodb-data-types unmarshalling x 1,800,718 ops/sec ±0.30% (96 runs sampled)
ts-dynamodb-attributes-transformer unmarshalling x 3,493,272 ops/sec ±0.50% (98 runs sampled)
Fastest is ts-dynamodb-attributes-transformer unmarshalling

Please see also benchmark project.

Synopsis

Marshalling into DynamoDB record from the Typescript Object

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'],
  ]),
});

/*
 * Then you can use this record value on the aws-sdk-js-v3's DynamoDB client; for example,
 *
 *   const dyn = new DynamoDBClient(...);
 *   await dyn.send(new PutItemCommand({
 *     TableName: "...",
 *     Item: record, // <= HERE!
 *   }));
 */

Then this plugin transforms the above TypeScript code like the following JavaScript code:

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'],
  ]),
});
/*
 * This record is equal to the following object:
 *
 *   {
 *     id: { N: "12345" },
 *     name: { S: "John Doe" },
 *     tags: {
 *       M: {
 *         foo: { S: "bar" },
 *         buz: { S: "qux" }
 *       }
 *     }
 *   }
 */

Unmarshalling into TypeScript object from DynamoDB record

import { fromDynamodbRecord } from '@moznion/ts-dynamodb-attributes-transformer';

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

const user: User = fromDynamodbRecord<User>({
  id: {
    N: '12345',
  },
  name: {
    S: 'John Doe',
  },
  tags: {
    M: {
      foo: {
        S: 'bar',
      },
      buz: {
        S: 'qux',
      },
    },
  },
});

Then this plugin transforms the above TypeScript code like the following JavaScript code:

const record = (function (arg) {
  return {
    id: (function () {
      const numStr = arg.id.N;
      return numStr === undefined ? undefined : Number(numStr);
    })(),
    name: arg.name.S,
    tags: (function () {
      var m, r;
      m = new Map();
      r = arg['tags']?.M;
      for (const k in r) {
        m.set(k, r[k]?.S);
      }
      return m;
    })(),
  };
})({
  id: {
    N: '12345',
  },
  name: {
    S: 'John Doe',
  },
  tags: {
    M: {
      foo: {
        S: 'bar',
      },
      buz: {
        S: 'qux',
      },
    },
  },
});

/*
 * This object is equal to the following:
 *
 *   {
 *     id: 12345,
 *     name: "John Doe",
 *     tags: {
 *       foo: { S: "bar" },
 *       buz: { S: "qux" },
 *     }
 *   }
 */

How to use this transformer

This plugin exports the functions that have the signature function dynamodbRecord<T extends object>(item: T, shouldLenientTypeCheck?: boolean): Record<keyof T, AttributeValue> and function fromDynamodbRecord<T extends object>(attrs: Record<string, AttributeValue>, shouldLenientTypeCheck?: boolean): T.

These functions are the markers to indicate to the transformer to replace the function invocation with the generated code. Therefore, there are some restrictions:

  • 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.
  • Type T must be class or interface. If it needs to do unmarshalling, this type T must be a derived type of the interface.

Examples

ttypescript

ttypescript is a custom TypeScript compiler that triggers the specified transformers in the tsconfig.json.

Please refer to the examples/ttypescript project directory and ttypescript official README for more details.

Anyway, the important thing is specifying compilerOptions.plugins in tsconfig.json like the following:

{
  "compilerOptions": {
    // ...
    "plugins": [
      { "transform": "@moznion/ts-dynamodb-attributes-transformer/transformer" }
    ]
  },
  // ...
}

ts-jest

If you use ts-jest with this transformer, one of the easiest ways is using that with ttypescript toghether.

It needs ttypescript configuration and additionally the jest configuration in jest.config.js like the below:

module.exports = {
  // ...
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      {
        compiler: 'ttypescript',
      },
    ],
  },
  // ...
};

TypeScript types to DynamoDB types

Please see also Supported data types and naming rules in Amazon DynamoDB for more details about the DynamoDB types.

Scalar Types

| TypeScript | DynamoDB | |----------------|------------| | number, BigInt | N | | string | S | | Uint8Array | B | | boolean | BOOL | | unknown | NULL |

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 }.

Document Types

| TypeScript | DynamoDB | |----------------------------------------------------------------|----------| | Set<string> | SS | | Set<number>, Set<BigInt> | NS | | Set<Uint8Array> | BS | | List<$SCALAR_TYPE> | L | | Map<string, $SCALAR_TYPE>, { [key: string]: $SCALAR_TYPE } | M |

Options

Lenient type checking (default: false)

By default, if this plugin encounters unsupported types, it raises the error and halts the transformation.

But if true value is given through the second argument of the function, it proceeds the transformation with ignoring the unsupported typed property even if it gets the unsupported types.

Note

This transformer plugin referred to the various things from kimamula/ts-transformer-keys

Authors

moznion ([email protected])