oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
71.1k stars 2.47k forks source link

Support TypeORM #4136

Open anurag-roy opened 9 months ago

anurag-roy commented 9 months ago

What version of Bun is running?

0.7.3

What platform is your computer?

Linux 5.15.0-78-generic x86_64 x86_64

What steps can reproduce the bug?

  1. Clone this repo:

    git clone https://github.com/anurag-roy/bun-typeorm-issue

    This was generated using typeorm cli and I updated some stuff in tsconfig and dependencies.

  2. Install dependencies

    bun install
  3. (Optional) Setup a local mysql server at port 3306. This step is optional because we can reproduce the error before even typeorm attempts to connect to a db.

  4. Run file

    bun run src/index.ts

What is the expected behavior?

The file should run successfully and print some logs of adding a user (If db successfully setup) or show that the connection was not found.

What do you see instead?

❯ bun run src/index.ts
4 | class TypeORMError extends Error {
5 |     get name() {
6 |         return this.constructor.name;
7 |     }
8 |     constructor(message) {
9 |         super(message);
            ^
error: Column type for User#firstName is not defined and cannot be guessed. Make sure you have turned on an "emitDecoratorMetadata": true option in tsconfig.json. Also make sure you have imported "reflect-metadata" on top of the main entry file in your application (before any entity imported).If you are using JavaScript instead of TypeScript you must explicitly provide a column type.
      at new TypeORMError (/home/anurag/Developer/Hobby/bun-typeorm/node_modules/typeorm/error/TypeORMError.js:9:8)
      at new ColumnTypeUndefinedError (/home/anurag/Developer/Hobby/bun-typeorm/node_modules/typeorm/error/ColumnTypeUndefinedError.js:11:8)
      at /home/anurag/Developer/Hobby/bun-typeorm/node_modules/typeorm/decorator/columns/Column.js:52:22
      at /home/anurag/Developer/Hobby/bun-typeorm/src/entity/User.ts:9:2

Additional information

This is what my tsconfig.json looks like:

{
  "compilerOptions": {
    "lib": ["ESNext"],
    "module": "CommonJS",
    "target": "ESNext",
    "moduleResolution": "bundler",
    "moduleDetection": "force",
    "outDir": "./build",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "sourceMap": true,
    "allowImportingTsExtensions": true,
    "strict": true,
    "downlevelIteration": true,
    "skipLibCheck": true,
    "jsx": "preserve",
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "allowJs": true,
    "noEmit": true,
    "types": [
      "bun-types" // add Bun global
    ]
  }
}

Looks like Bun is ignoring "emitDecoratorMetadata" present in my tsconfig. Or does it not support it?

Electroid commented 9 months ago

Thanks for reporting, what's the error you run into?

anurag-roy commented 9 months ago

Sorry @Electroid, I submitted the issue by mistake before completely filling it out. I have updated the comment now.

bnussman commented 9 months ago

I'm not sure how far Bun will support the TS decorators stuff. You may be able to "compile" your app with tsc and run the TSC's output with bun (bun run build/index.js).

I use Mikro-ORM and that's what I'm doing right now.

crishoj commented 8 months ago

I use Mikro-ORM and that's what I'm doing right now.

@bnussman, may I know how you init MikroORM with only .ts entities? It seems to expect both .ts and .js files:

const orm = await MikroORM.init<SqliteDriver>({
    entities: ['./entities/**/*.ts'], // path to our JS entities (dist), relative to `baseDir`
    entitiesTs: ['./entities/**/*.ts'], // path to our TS entities (source), relative to `baseDir`
});
bnussman commented 8 months ago

Use JS for the entities. Like I said: build with tsc and run the outputted JS with bun.

const config: Options = {
  entities: ['./build/entities/*.js'],
  entitiesTs: ['./src/entities/*.ts'],
};
Jarred-Sumner commented 8 months ago

I think @dylan-conway will have an exciting update for you today

bnussman commented 8 months ago

OMG! Nevermind, seems like @Jarred-Sumner is here to save the day ❤️🚀

ceopaludetto commented 8 months ago

I was able to use Mikro-ORM by creating a plugin:

import type { BunPlugin } from "bun";

import { readFile } from "fs/promises";

import strip from "strip-comments";
import { transpileModule, type TranspileOptions } from "typescript";

// fix this import based on your tsconfig location
import config from "../../tsconfig.json";

const theFinder = /((?<![(\s]\s*['"])@\w[.[\]\w\d]*\s*(?![;])[((?=\s)])/;
const findDecorators = (fileContent: string) => theFinder.test(strip(fileContent));

export const bunDecorators: BunPlugin = {
  name: "bun-decorators",
  setup: (build) => {
    build.onLoad({ filter: /\.ts$/ }, async ({ path }) => {
      const fileContent = await readFile(path, "utf-8");
      const hasDecorators = findDecorators(fileContent);

      if (!hasDecorators) return { contents: fileContent };
      return { contents: transpileModule(fileContent, config as unknown as TranspileOptions).outputText };
    });
  },
};

This plugin parses files that contains decorators using typescript transpileModule. Now instead of using entities and entitiesTs options on MikroORM you should import your entities. I usually do:

src/
  entities/
    some.entity.ts
    another.entity.ts
    index.ts // export every entity here
  index.ts // MikroORM.init here
import * as entities from "./entities"

MikroORM.init({
  entities: [...Object.values(entities)]
})
Zikoat commented 3 months ago

Current ts-node output with the above reproduction (after fixing some type errors):

$ ts-node ./src/index.ts
Error: connect ECONNREFUSED 127.0.0.1:3306
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16)
    --------------------
    at Protocol._enqueue (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at PoolConnection.connect (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/Connection.js:116:18)
    at Pool.getConnection (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/Pool.js:48:16)
    at /home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/typeorm/src/driver/mysql/MysqlDriver.ts:1268:18
    at new Promise (<anonymous>)
    at MysqlDriver.createPool (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/typeorm/src/driver/mysql/MysqlDriver.ts:1265:16)
    at MysqlDriver.connect (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/typeorm/src/driver/mysql/MysqlDriver.ts:400:36)
    at DataSource.initialize (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/src/data-source/DataSource.ts:252:47)
    at Object.<anonymous> (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/src/index.ts:4:15) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 3306,
  fatal: true
}

Output with bun:

bun run ./src/index.ts
105 |   if (!callSiteStack || typeof callSiteStack !== 'string') {
106 |     // No recorded call site
107 |     return;
108 |   }
109 | 
110 |   if (err.stack.indexOf(LONG_STACK_DELIMITER) !== -1) {
            ^
TypeError: undefined is not an object (evaluating 'err.stack.indexOf')
      at _addLongStackTrace (/home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/protocol/sequences/Sequence.js:110:7)
      at /home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/protocol/sequences/Sequence.js:65:5
      at /home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/protocol/Protocol.js:369:5
      at /home/zikoat/dev/typerom-repro/bun-typeorm-issue/node_modules/mysql/lib/Connection.js:418:3
      at node:net:375:35

However, when fixing the undefined reference, we get the error:

bun run ./src/index.ts
ECONNREFUSED: Failed to connect
 syscall: "connect"

Which doesnt include the yrl, but the error looks a bit nicer. I guess this can be closed, unless you guys want to fix the differing behavior regarding the error.

sfardiansyah-syky commented 1 month ago

I think it's because net.Socket hasn't fully implemented in Bun. As shown in issues that uses socket connection: #7325, #7851, #8789

sfardiansyah-syky commented 1 month ago

This net.Socket connection issue still not resolved in Bun v1.1.0