serverless-seoul / dynamorm

AWS DynamoDB ORM in Typescript
Apache License 2.0
55 stars 4 forks source link

Decorated attributes aren't invoking `setAttribute` #10

Closed mwildehahn closed 4 years ago

mwildehahn commented 4 years ago

I have the following tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "jsx": "preserve",
    "lib": ["dom", "es2017"],
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "preserveConstEnums": true,
    "removeComments": false,
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "target": "esnext",
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "paths": {
      "@app/*": ["src/*"]
    }
  },
  "exclude": ["node_modules"],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}

and the following .babelrc:

{
  "presets": ["next/babel"],
  "plugins": [
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }]
  ]
}

(I'm using next.js)

I have a user class:

import { v4 as uuid } from "uuid";
import { Decorator, Query, Table } from "dynamo-types";
import DynamoDBConnection from "@app/dynamo/DynamoDBConnection";

@Decorator.Table({
  name: process.env.USER_TABLE_NAME,
  connection: new DynamoDBConnection(),
})
export default class User extends Table {
  @Decorator.Attribute()
  public id!: string;

  @Decorator.Attribute()
  public name: string | null = null;

  @Decorator.Attribute()
  public email: string | null = null;

  @Decorator.Attribute()
  public emailVerified: string | null = null;

  @Decorator.Attribute()
  public image: string | null = null;

  @Decorator.Attribute()
  public createdAt!: string;

  @Decorator.Attribute()
  public updatedAt!: string;

  @Decorator.HashPrimaryKey("id")
  public static readonly primaryKey: Query.HashPrimaryKey<User, string>;

  @Decorator.HashGlobalSecondaryIndex("email")
  public static readonly emailIndex: Query.HashGlobalSecondaryIndex<
    User,
    string
  >;

  @Decorator.Writer()
  public static readonly writer: Query.Writer<User>;

  public static create(
    options: {
      name?: string;
      email?: string;
      image?: string;
      emailVerified?: boolean;
    } = {}
  ): User {
    const user = new this();
    user.id = uuid();

    const now = new Date().toISOString();
    user.createdAt = now;
    user.updatedAt = now;

    if (options.name) user.name = options.name;
    if (options.email) user.email = options.email;
    if (options.image) user.image = options.image;
    if (options.emailVerified) user.emailVerified = new Date().toISOString();

    return user;
  }
}

The issue I'm seeing is that setting user.id = for example doesn't invoke setAttribute to set the property in __attributes. If I call setAttribute directly, it works 🤔 .

I added some debug logging and see that the attribute decorator is getting picked up and it configures the getter/setter on the class... not sure why it isn't working.

Any ideas?

mwildehahn commented 4 years ago

I thought this might be related to @babel/plugin-proposal-class-properties and having loose: true but I removed that and it didn't make a difference

breath103 commented 4 years ago

I'm not sure, but I assume this must be babel + next.js build pipeline issue, since it's using standard decorator syntax. have you been able to check