drizzle-team / drizzle-orm

Headless TypeScript ORM with a head. Runs on Node, Bun and Deno. Lives on the Edge and yes, it's a JavaScript ORM too 😅
https://orm.drizzle.team
Apache License 2.0
24.87k stars 664 forks source link

[BUG]: FindFirst method doesn't work in Bun v1.0.30 #1971

Closed sum117 closed 3 months ago

sum117 commented 9 months ago

What version of drizzle-orm are you using?

0.29.4

What version of drizzle-kit are you using?

0.20.14

Describe the Bug

When using the .query api, it's possible to use the findMany() method, but when I attempt to use the findFirst() one, an object with undefined fields is returned, and inside the drizzle studio, trying the same results in this:

Example inside drizzle studio

image

Example inside IDE

⚠️ When hovering over the method findFirst(), I get this message: TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context.

image

Expected behavior

We should be able to get the result back without this weird typeError. I'm having to use this query to make it work:

const foundUser = (
    await db.select().from(users).where(eq(users.id, userId))
).at(0);

Environment & setup

I'm using bun v1.0.30:

Package.json

{
  "name": "bun-drizzle-test-bot",
  "module": "index.ts",
  "type": "module",
  "scripts": {
    "generate": "drizzle-kit generate:sqlite",
    "studio": "drizzle-kit studio",
    "dev": "bun src/index.ts --watch"
  },
  "devDependencies": {
    "@types/bun": "latest",
    "@types/luxon": "^3.4.2",
    "better-sqlite3": "^9.4.3",
    "drizzle-kit": "^0.20.14"
  },
  "peerDependencies": {
    "typescript": "^5.0.0"
  },
  "dependencies": {
    "discord.js": "^14.14.1",
    "drizzle-orm": "^0.29.4",
    "i18next": "^23.10.0",
    "luxon": "^3.4.4"
  }
}

My schema

import { relations } from "drizzle-orm";
import {
  integer,
  primaryKey,
  sqliteTable,
  text,
} from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: text("id").primaryKey(),
  joinedBotAt: integer("joinedBotAt", { mode: "timestamp_ms" }),
  level: integer("level").notNull().default(1),
  preferredLanguage: text("preferredLanguage", { enum: ["en-US", "pt-BR"] })
    .notNull()
    .default("en-US"),
  exp: integer("exp").notNull().default(0),
});

export const usersRelations = relations(users, ({ many }) => ({
  characters: many(characters),
  posts: many(posts),
}));

export const characters = sqliteTable("characters", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  authorId: text("authorId").notNull(),
  name: text("name").notNull(),
  level: integer("level").notNull().default(1),
  exp: integer("exp").notNull().default(0),
  age: integer("age").notNull().default(18),
  imageUrl: text("imageUrl").notNull(),

  birthday: integer("birthday", { mode: "timestamp_ms" }),
  backstory: text("backstory"),
  personality: text("personality"),
  appearance: text("appearance"),
  race: text("race"),
  gender: text("gender"),
  pronouns: text("pronouns"),
  title: text("title"),
  embedColor: text("embedColor"),
});

export const charactersRelations = relations(characters, ({ one, many }) => ({
  author: one(users, {
    fields: [characters.authorId],
    references: [users.id],
  }),
  categories: many(categoriesToCharacters),
  posts: many(postsToCharacters),
  items: many(itemsCharacters),
}));

export const categories = sqliteTable("categories", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  authorId: text("authorId").notNull(),
  name: text("name").notNull(),
});

export const categoriesRelations = relations(categories, ({ one, many }) => ({
  author: one(users, {
    fields: [categories.authorId],
    references: [users.id],
  }),
  characters: many(categoriesToCharacters),
}));

export const categoriesToCharacters = sqliteTable(
  "categoriesToCharacters",
  {
    categoryId: text("categoryId")
      .notNull()
      .references(() => categories.id),
    characterId: text("characterId")
      .notNull()
      .references(() => characters.id),
  },
  (table) => ({
    primaryKey: primaryKey({ columns: [table.categoryId, table.characterId] }),
  })
);

export const categoriesToCharactersRelations = relations(
  categoriesToCharacters,
  ({ one }) => ({
    category: one(categories, {
      fields: [categoriesToCharacters.categoryId],
      references: [categories.id],
    }),
    character: one(characters, {
      fields: [categoriesToCharacters.characterId],
      references: [characters.id],
    }),
  })
);

export const postsToCharacters = sqliteTable(
  "postsToCharacters",
  {
    postId: text("postId")
      .notNull()
      .references(() => posts.messageId),
    characterId: text("characterId")
      .notNull()
      .references(() => characters.id),
  },
  (table) => ({
    primaryKey: primaryKey({ columns: [table.postId, table.characterId] }),
  })
);

export const postsToCharactersRelations = relations(
  postsToCharacters,
  ({ one }) => ({
    post: one(posts, {
      fields: [postsToCharacters.postId],
      references: [posts.messageId],
    }),
    character: one(characters, {
      fields: [postsToCharacters.characterId],
      references: [characters.id],
    }),
  })
);

export const items = sqliteTable("items", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  authorId: text("authorId").notNull(),
  name: text("name").notNull(),
  description: text("description"),
  imageUrl: text("imageUrl"),
});

export const itemsRelations = relations(items, ({ one, many }) => ({
  author: one(users, {
    fields: [items.authorId],
    references: [users.id],
  }),
}));

export const itemsCharacters = sqliteTable("itemsCharacters", {
  itemId: text("itemId").primaryKey(),
  characterId: text("characterId").notNull(),
  quantity: integer("quantity").notNull().default(0),
  isEquipped: integer("isEquipped", { mode: "boolean" })
    .notNull()
    .default(false),
});

export const itemsCharactersRelations = relations(
  itemsCharacters,
  ({ one }) => ({
    item: one(items, {
      fields: [itemsCharacters.itemId],
      references: [items.id],
    }),
    character: one(characters, {
      fields: [itemsCharacters.characterId],
      references: [characters.id],
    }),
  })
);

export const posts = sqliteTable("posts", {
  messageId: text("messageId").primaryKey(),
  channelId: text("channelId").notNull(),
  guildId: text("guildId").notNull(),
  content: text("content").notNull(),
  authorId: text("authorId").notNull(),
});

export const postsRelations = relations(posts, ({ one, many }) => ({
  characters: many(postsToCharacters),
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
pedro199288 commented 8 months ago

I was having a similar issue and I it has been fixed (at least for my case) in drizzle-orm@0.30.2

shaileshaanand commented 8 months ago

This bug was fixed in drizzle-orm@0.30.2 in PR #1885

kevinmarrec commented 5 months ago

@shaileshaanand This issue probably should be closed if fixed.

Still, I have a concern with your implementation in #1885 regarding performance and usage of Bun underlying API.

Shouldn't we be using get instead of values, and then make it an array for the mapping if it is required ?

It's just hat get should be using get, somehow, don't you agree ?

I also found https://github.com/drizzle-team/drizzle-orm/pull/1276 which seemed to have another approach, but it doesn't seem perfect either.

There's probably some improvements to do.