Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] transaction completes but errors: Table "undefined" not found #1662

Open
6 tasks done
qantrepreneur opened this issue Feb 9, 2024 · 1 comment
Open
6 tasks done

Comments

@qantrepreneur
Copy link

Summary:

While using transactions it complains that the table name is undefined and should be registered first. Even when it errors it still writes to the database successfully.

Code sample:

Schema

import { Schema, Table, model } from "dynamoose";
import { Item } from "dynamoose/dist/Item";

import { getTarget } from "@/lib/env";

export interface ILinkedAccount {
  accountId: string;
  globalAccountId?: string;
  linkingCode: string;
  linkingCodeExpiresAt: number;
  linked: boolean;
}

export interface ILinkedAccountItem extends Item, ILinkedAccount {}

export const LinkedAccountSchema = new Schema(
  {
    accountId: {
      hashKey: true,
      type: String,
    },
    globalAccountId: {
      type: String,
      index: {
        name: "globalAccountId-accountId-index",
        type: "global",
      },
    },
    linkingCode: {
      type: String,
      required: true,
      index: {
        name: "linkingCode-accountId-index",
        type: "global",
      },
    },
    linkingCodeExpiresAt: {
      type: Number,
      required: true,
    },
    linked: {
      type: Boolean,
      required: true,
      default: false,
    },
  },
  {
    saveUnknown: false,
    timestamps: true,
  },
);

const tableName = `nft-linked-accounts-${getTarget()}`;

const LinkedAccount = model<ILinkedAccountItem>(tableName, LinkedAccountSchema);

export const LinkedAccountTable = new Table(tableName, [LinkedAccount], {
  create: false,
  update: false,
  waitForActive: false,
});

export default LinkedAccount;
import { Schema, Table, model } from "dynamoose";
import { Item } from "dynamoose/dist/Item";

import { getTarget } from "@/lib/env";

export interface IAccount {
  id: string;
  email: string;
  hashedPassword?: string;
}

export interface IAccountItem extends Item, IAccount {}

export const AccountSchema = new Schema(
  {
    id: {
      hashKey: true,
      type: String,
    },
    email: {
      type: String,
      required: true,
      index: {
        name: "email-id-index",
        type: "global",
      },
    },
    hashedPassword: {
      type: String,
      required: true,
    },
  },
  {
    saveUnknown: false,
    timestamps: true,
  },
);

const tableName = `nft-global-accounts-${getTarget()}`;

const Account = model<IAccountItem>(tableName, AccountSchema);

export const AccountTable = new Table(tableName, [Account], {
  create: false,
  update: false,
  waitForActive: false,
});

export default Account;

Model

export async function link(
  linkingCode: ILinkedAccount["linkingCode"],
  globalAccountId: ILinkedAccount["globalAccountId"],
  asTransaction: boolean = false,
) {
  const parseResult = linkedAccountLinkingSchema.safeParse({
    linkingCode,
    globalAccountId,
  });

  if (!parseResult.success) {
    throw new CustomZodParseError(parseResult.error);
  }

  const { data: safeData } = parseResult;

  const existingLinkedAccount = await withLinkingCode(safeData.linkingCode);

  if (!existingLinkedAccount) {
    throw new LinkingCodeNotFoundError(safeData.linkingCode);
  }

  if (existingLinkedAccount.linked) {
    throw new LinkedAccountLinkedFoundError(existingLinkedAccount.accountId);
  }

  if (existingLinkedAccount.linkingCodeExpiresAt < Date.now()) {
    throw new LinkingCodeExpiredError(safeData.linkingCode);
  }

  const updateData: LinkUpdateData = {
    globalAccountId: safeData.globalAccountId,
    linked: true,
  };

  if (asTransaction) {
    return {
      data: updateData,
      transaction: () => {
        return LinkedAccount.transaction.update(
          { accountId: existingLinkedAccount.accountId },
          updateData,
          { return: "item" },
        );
      },
    };
  }

  return LinkedAccount.update(
    { accountId: existingLinkedAccount.accountId },
    updateData,
    {
      return: "item",
    },
  );
}
export async function create(
  email: IAccount["email"],
  password: string,
  asTransaction: boolean = false,
) {
  const parseResult = accountCreationSchema.safeParse({ email, password });

  if (!parseResult.success) {
    throw new CustomZodParseError(parseResult.error);
  }

  const { data: safeData } = parseResult;

  const existingAccounts = await Account.query({
    email: safeData.email.toLowerCase(),
  })
    .all()
    .exec();

  if (existingAccounts.length > 0) {
    throw new AccountExistsError(safeData.email);
  }

  const creationData: IAccount = {
    id: generateId(),
    email: safeData.email.toLowerCase(),
    hashedPassword: await argon2.hash(safeData.password),
  };

  if (asTransaction) {
    return {
      data: creationData,
      transaction: () => {
        return Account.transaction.create(creationData, { return: "item" });
      },
    };
  }

  return Account.create(creationData, { return: "item" });
}

General

const { data: accountCreationData, transaction: accountTransaction } =
  await create(safeData.email, safeData.password, true);

const { transaction: linkAccountTransaction } = await link(
  safeData.linkingCode,
  accountCreationData.id,
  true,
);

const items = await transaction([
  accountTransaction(),
  linkAccountTransaction(),
]);

Current output and behavior (including stack trace):

InvalidParameter: Table "undefined" not found. Please register the table with dynamoose before using it in transactions.
    at /Users/work/Documents/nfts/nft-global-accounts/node_modules/dynamoose/dist/Transaction.js:64:23
    at Array.forEach (<anonymous>)
    at /Users/work/Documents/nfts/nft-global-accounts/node_modules/dynamoose/dist/Transaction.js:62:16
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async post (webpack-internal:///(api)/./pages/api/auth/signup.ts:52:23)
    at async eval (webpack-internal:///(api)/./middlewares/api.ts:12:13)
    at async K (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/compiled/next-server/pages-api.runtime.dev.js:21:2946)
    at async U.render (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/compiled/next-server/pages-api.runtime.dev.js:21:3827)
    at async DevServer.runApi (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/server/next-server.js:556:9)
    at async NextNodeServer.handleCatchallRenderRequest (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/server/next-server.js:268:37)
    at async DevServer.handleRequestImpl (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/server/base-server.js:807:17)
    at async /Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/server/dev/next-dev-server.js:331:20
    at async Span.traceAsyncFn (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/trace/trace.js:151:20)
    at async DevServer.handleRequest (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/server/dev/next-dev-server.js:328:24)
    at async invokeRender (/Users/work/Documents/nfts/nft-global-accounts/node_modules/next/dist/server/lib/router-server.js:163:21)

It does write to the database.

Expected output and behavior:

Writes to the database without any errors.

Environment:

Operating System: macOS
Operating System Version: 14.1.1
Node.js version (node -v): v18.17.0
NPM version: (npm -v): 9.6.7
Dynamoose version: 4.0.0

Other information (if applicable):

Other:

  • I have read through the Dynamoose documentation before posting this issue
  • I have searched through the GitHub issues (including closed issues) and pull requests to ensure this issue has not already been raised before
  • I have searched the internet and Stack Overflow to ensure this issue hasn't been raised or answered before
  • I have tested the code provided and am confident it doesn't work as intended
  • I have filled out all fields above
  • I am running the latest version of Dynamoose
@qantrepreneur
Copy link
Author

If I remove the the { return: "item" }, it doesn't error. Not very optimal, but will do for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant