├── .github └── workflows │ ├── bench.yml │ └── dev.yml ├── .gitignore ├── LICENSE ├── README.md ├── bun.lockb ├── config.json ├── loader.mjs ├── mysql.bench.ts ├── package.json ├── postgres.bench.ts ├── prisma ├── schema.mysql.prisma └── schema.postgres.prisma ├── results ├── .gitkeep ├── bun-mysql-cpu-count.txt ├── bun-mysql-default.txt ├── bun-mysql-max.txt ├── bun-mysql-single.txt ├── bun-postgres-cpu-count.txt ├── bun-postgres-default.txt ├── bun-postgres-max.txt ├── bun-postgres-single.txt ├── node-mysql-cpu-count.txt ├── node-mysql-default.txt ├── node-mysql-max.txt ├── node-mysql-single.txt ├── node-postgres-cpu-count.txt ├── node-postgres-default.txt ├── node-postgres-max.txt └── node-postgres-single.txt ├── src ├── config.ts ├── helpers.ts ├── mysql │ ├── all.test.ts │ ├── drizzle.ts │ ├── index.ts │ ├── knex.ts │ ├── kysely.ts │ ├── mariadb.ts │ ├── mikro.ts │ ├── mysql2.ts │ ├── prisma.ts │ ├── sequelize.ts │ └── typeorm.ts ├── postgres │ ├── all.test.ts │ ├── drizzle.ts │ ├── index.ts │ ├── knex.ts │ ├── kysely.ts │ ├── mikro.ts │ ├── pg-typed.ts │ ├── pg.ts │ ├── postgres.ts │ ├── prisma.ts │ ├── queries.queries.ts │ ├── queries.sql │ ├── sequelize.ts │ └── typeorm.ts ├── setup │ ├── index.ts │ ├── init-mysql.ts │ ├── init-postgres.ts │ └── users.ts └── utils.ts └── tsconfig.json /.github/workflows/bench.yml: -------------------------------------------------------------------------------- 1 | name: ORM Benchmark 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | schedule: 8 | - cron: '0 0 * * 1' 9 | workflow_dispatch: 10 | 11 | permissions: write-all 12 | 13 | jobs: 14 | bench: 15 | name: Bench 16 | strategy: 17 | fail-fast: true 18 | runs-on: ubuntu-latest 19 | services: 20 | mysql: 21 | image: mysql:8 22 | env: 23 | MYSQL_ALLOW_EMPTY_PASSWORD: yes 24 | MYSQL_DATABASE: mysqltest 25 | MYSQL_USER: mysqltest 26 | MYSQL_PASSWORD: mysqltest 27 | ports: 28 | - 3306:3306 29 | options: >- 30 | --health-cmd="mysqladmin ping" 31 | --health-interval=10s 32 | --health-timeout=5s 33 | --health-retries=5 34 | postgres: 35 | image: postgres:16 36 | env: 37 | POSTGRES_PASSWORD: postgres 38 | ports: 39 | - 5432:5432 40 | options: >- 41 | --health-cmd pg_isready 42 | --health-interval 10s 43 | --health-timeout 5s 44 | --health-retries 5 45 | steps: 46 | - name: MySQL - Verify mysqltest DB exists 47 | run: mysql --host 0.0.0.0 --port 3306 -umysqltest -pmysqltest -e "SHOW DATABASES LIKE 'mysqltest'" 48 | - uses: actions/checkout@v4 49 | with: 50 | persist-credentials: true 51 | ref: ${{ github.head_ref }} 52 | - name: Setup Node.js environment 53 | uses: actions/setup-node@v4.0.0 54 | with: 55 | node-version: 22 56 | - name: Install required global packages 57 | run: npm i -g bun npm-check-updates 58 | - name: Update & install packages 59 | run: | 60 | ncu -u 61 | bun i 62 | - name: Setup Databases 63 | run: bun --bun run src/setup 64 | env: 65 | PG_HOST: 0.0.0.0 66 | MYSQL_HOST: 0.0.0.0 67 | - name: Test 68 | run: | 69 | bun prisma generate --schema=./prisma/schema.postgres.prisma > /dev/null 70 | bun --bun test 71 | env: 72 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 73 | MAX_CONNECTION: DEFAULT 74 | PG_HOST: 0.0.0.0 75 | MYSQL_HOST: 0.0.0.0 76 | - name: Bun Prisma Generate MySQL Schema 77 | run: bun prisma generate --schema=./prisma/schema.mysql.prisma > /dev/null 78 | env: 79 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 80 | MAX_CONNECTION: DEFAULT 81 | MYSQL_HOST: 0.0.0.0 82 | - name: Bun MySQL ORMs benchmark using DEFAULT connections 83 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-default.txt 84 | env: 85 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 86 | MAX_CONNECTION: DEFAULT 87 | MYSQL_HOST: 0.0.0.0 88 | - name: Bun MySQL ORMs benchmark using MAX connections 89 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-max.txt 90 | env: 91 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 92 | MAX_CONNECTION: MAX 93 | MYSQL_HOST: 0.0.0.0 94 | - name: Bun MySQL ORMs benchmark using CPU_COUNT as max connections 95 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-cpu-count.txt 96 | env: 97 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 98 | MAX_CONNECTION: CPU_COUNT 99 | MYSQL_HOST: 0.0.0.0 100 | - name: Bun MySQL ORMs benchmark using only a single connection 101 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-single.txt 102 | env: 103 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 104 | MAX_CONNECTION: 1 105 | MYSQL_HOST: 0.0.0.0 106 | - name: Bun Prisma Generate Postgres Schema 107 | run: bun prisma generate --schema=./prisma/schema.postgres.prisma > /dev/null 108 | env: 109 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 110 | MAX_CONNECTION: DEFAULT 111 | PG_HOST: 0.0.0.0 112 | - name: Bun Postgres ORMs benchmark using DEFAULT connections 113 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-default.txt 114 | env: 115 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 116 | MAX_CONNECTION: DEFAULT 117 | PG_HOST: 0.0.0.0 118 | - name: Bun Postgres ORMs benchmark using MAX connections 119 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-max.txt 120 | env: 121 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 122 | MAX_CONNECTION: MAX 123 | PG_HOST: 0.0.0.0 124 | - name: Bun Postgres ORMs benchmark using CPU_COUNT as max connections 125 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-cpu-count.txt 126 | env: 127 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 128 | MAX_CONNECTION: CPU_COUNT 129 | PG_HOST: 0.0.0.0 130 | - name: Bun Postgres ORMs benchmark using only a single connection 131 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-single.txt 132 | env: 133 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 134 | MAX_CONNECTION: 1 135 | PG_HOST: 0.0.0.0 136 | - name: Node Prisma Generate MySQL Schema 137 | run: npx prisma generate --schema=./prisma/schema.mysql.prisma > /dev/null 138 | env: 139 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 140 | MAX_CONNECTION: DEFAULT 141 | MYSQL_HOST: 0.0.0.0 142 | - name: Node MySQL ORMs benchmark using DEFAULT connections 143 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-default.txt 144 | env: 145 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 146 | MAX_CONNECTION: DEFAULT 147 | MYSQL_HOST: 0.0.0.0 148 | - name: Node MySQL ORMs benchmark using MAX connections 149 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-max.txt 150 | env: 151 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 152 | MAX_CONNECTION: MAX 153 | MYSQL_HOST: 0.0.0.0 154 | - name: Node MySQL ORMs benchmark using CPU_COUNT as max connections 155 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-cpu-count.txt 156 | env: 157 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 158 | MAX_CONNECTION: CPU_COUNT 159 | MYSQL_HOST: 0.0.0.0 160 | - name: Node MySQL ORMs benchmark using only a single connection 161 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-single.txt 162 | env: 163 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 164 | MAX_CONNECTION: 1 165 | MYSQL_HOST: 0.0.0.0 166 | - name: Node Prisma Generate Postgres Schema 167 | run: npx prisma generate --schema=./prisma/schema.postgres.prisma > /dev/null 168 | env: 169 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 170 | MAX_CONNECTION: DEFAULT 171 | PG_HOST: 0.0.0.0 172 | - name: Node Postgres ORMs benchmark using DEFAULT connections 173 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-default.txt 174 | env: 175 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 176 | MAX_CONNECTION: DEFAULT 177 | PG_HOST: 0.0.0.0 178 | - name: Node Postgres ORMs benchmark using MAX connections 179 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-max.txt 180 | env: 181 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 182 | MAX_CONNECTION: MAX 183 | PG_HOST: 0.0.0.0 184 | - name: Node Postgres ORMs benchmark using CPU_COUNT as max connections 185 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-cpu-count.txt 186 | env: 187 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 188 | MAX_CONNECTION: CPU_COUNT 189 | PG_HOST: 0.0.0.0 190 | - name: Node Postgres ORMs benchmark using only a single connection 191 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-single.txt 192 | env: 193 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 194 | MAX_CONNECTION: 1 195 | PG_HOST: 0.0.0.0 196 | - name: Commit changes 197 | uses: EndBug/add-and-commit@v9 198 | with: 199 | default_author: github_actions 200 | -------------------------------------------------------------------------------- /.github/workflows/dev.yml: -------------------------------------------------------------------------------- 1 | name: Test benchmark on dev 2 | 3 | on: 4 | push: 5 | branches: 6 | - dev 7 | workflow_dispatch: 8 | 9 | permissions: write-all 10 | 11 | jobs: 12 | bench: 13 | name: Test Benchmark on dev 14 | strategy: 15 | fail-fast: true 16 | runs-on: ubuntu-latest 17 | services: 18 | mysql: 19 | image: mysql:8 20 | env: 21 | MYSQL_ALLOW_EMPTY_PASSWORD: yes 22 | MYSQL_DATABASE: mysqltest 23 | MYSQL_USER: mysqltest 24 | MYSQL_PASSWORD: mysqltest 25 | ports: 26 | - 3306:3306 27 | options: >- 28 | --health-cmd="mysqladmin ping" 29 | --health-interval=10s 30 | --health-timeout=5s 31 | --health-retries=5 32 | postgres: 33 | image: postgres:16 34 | env: 35 | POSTGRES_PASSWORD: postgres 36 | ports: 37 | - 5432:5432 38 | options: >- 39 | --health-cmd pg_isready 40 | --health-interval 10s 41 | --health-timeout 5s 42 | --health-retries 5 43 | steps: 44 | - name: MySQL - Verify mysqltest DB exists 45 | run: mysql --host 0.0.0.0 --port 3306 -umysqltest -pmysqltest -e "SHOW DATABASES LIKE 'mysqltest'" 46 | - uses: actions/checkout@v4 47 | with: 48 | persist-credentials: true 49 | ref: ${{ github.head_ref }} 50 | - name: Setup Node.js environment 51 | uses: actions/setup-node@v4.0.0 52 | with: 53 | node-version: 20 54 | - name: Install required global packages 55 | run: npm i -g bun npm-check-updates 56 | - name: Update & install packages 57 | run: | 58 | ncu -u 59 | bun i 60 | - name: Setup Databases 61 | run: bun --bun run src/setup 62 | env: 63 | PG_HOST: 0.0.0.0 64 | MYSQL_HOST: 0.0.0.0 65 | - name: Test 66 | run: | 67 | bun prisma generate --schema=./prisma/schema.postgres.prisma > /dev/null 68 | bun --bun test 69 | env: 70 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 71 | MAX_CONNECTION: DEFAULT 72 | PG_HOST: 0.0.0.0 73 | MYSQL_HOST: 0.0.0.0 74 | - name: Bun Prisma Generate MySQL Schema 75 | run: bun prisma generate --schema=./prisma/schema.mysql.prisma > /dev/null 76 | env: 77 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 78 | MAX_CONNECTION: DEFAULT 79 | MYSQL_HOST: 0.0.0.0 80 | - name: Bun MySQL ORMs benchmark using DEFAULT connections 81 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-default.txt 82 | env: 83 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 84 | MAX_CONNECTION: DEFAULT 85 | MYSQL_HOST: 0.0.0.0 86 | - name: Bun MySQL ORMs benchmark using MAX connections 87 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-max.txt 88 | env: 89 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 90 | MAX_CONNECTION: MAX 91 | MYSQL_HOST: 0.0.0.0 92 | - name: Bun MySQL ORMs benchmark using CPU_COUNT as max connections 93 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-cpu-count.txt 94 | env: 95 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 96 | MAX_CONNECTION: CPU_COUNT 97 | MYSQL_HOST: 0.0.0.0 98 | - name: Bun MySQL ORMs benchmark using only a single connection 99 | run: bun --bun run mysql.bench.ts > ./results/bun-mysql-single.txt 100 | env: 101 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 102 | MAX_CONNECTION: 1 103 | MYSQL_HOST: 0.0.0.0 104 | - name: Bun Prisma Generate Postgres Schema 105 | run: bun prisma generate --schema=./prisma/schema.postgres.prisma > /dev/null 106 | env: 107 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 108 | MAX_CONNECTION: DEFAULT 109 | PG_HOST: 0.0.0.0 110 | - name: Bun Postgres ORMs benchmark using DEFAULT connections 111 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-default.txt 112 | env: 113 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 114 | MAX_CONNECTION: DEFAULT 115 | PG_HOST: 0.0.0.0 116 | - name: Bun Postgres ORMs benchmark using MAX connections 117 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-max.txt 118 | env: 119 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 120 | MAX_CONNECTION: MAX 121 | PG_HOST: 0.0.0.0 122 | - name: Bun Postgres ORMs benchmark using CPU_COUNT as max connections 123 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-cpu-count.txt 124 | env: 125 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 126 | MAX_CONNECTION: CPU_COUNT 127 | PG_HOST: 0.0.0.0 128 | - name: Bun Postgres ORMs benchmark using only a single connection 129 | run: bun --bun run postgres.bench.ts > ./results/bun-postgres-single.txt 130 | env: 131 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 132 | MAX_CONNECTION: 1 133 | PG_HOST: 0.0.0.0 134 | - name: Node Prisma Generate MySQL Schema 135 | run: npx prisma generate --schema=./prisma/schema.mysql.prisma > /dev/null 136 | env: 137 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 138 | MAX_CONNECTION: DEFAULT 139 | MYSQL_HOST: 0.0.0.0 140 | - name: Node MySQL ORMs benchmark using DEFAULT connections 141 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-default.txt 142 | env: 143 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 144 | MAX_CONNECTION: DEFAULT 145 | MYSQL_HOST: 0.0.0.0 146 | - name: Node MySQL ORMs benchmark using MAX connections 147 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-max.txt 148 | env: 149 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 150 | MAX_CONNECTION: MAX 151 | MYSQL_HOST: 0.0.0.0 152 | - name: Node MySQL ORMs benchmark using CPU_COUNT as max connections 153 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-cpu-count.txt 154 | env: 155 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 156 | MAX_CONNECTION: CPU_COUNT 157 | MYSQL_HOST: 0.0.0.0 158 | - name: Node MySQL ORMs benchmark using only a single connection 159 | run: node --no-deprecation --import ./loader.mjs mysql.bench.ts > ./results/node-mysql-single.txt 160 | env: 161 | DATABASE_URL: mysql://mysqltest:mysqltest@0.0.0.0:3306/mysqltest 162 | MAX_CONNECTION: 1 163 | MYSQL_HOST: 0.0.0.0 164 | - name: Node Prisma Generate Postgres Schema 165 | run: npx prisma generate --schema=./prisma/schema.postgres.prisma > /dev/null 166 | env: 167 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 168 | MAX_CONNECTION: DEFAULT 169 | PG_HOST: 0.0.0.0 170 | - name: Node Postgres ORMs benchmark using DEFAULT connections 171 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-default.txt 172 | env: 173 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 174 | MAX_CONNECTION: DEFAULT 175 | PG_HOST: 0.0.0.0 176 | - name: Node Postgres ORMs benchmark using MAX connections 177 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-max.txt 178 | env: 179 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 180 | MAX_CONNECTION: MAX 181 | PG_HOST: 0.0.0.0 182 | - name: Node Postgres ORMs benchmark using CPU_COUNT as max connections 183 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-cpu-count.txt 184 | env: 185 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 186 | MAX_CONNECTION: CPU_COUNT 187 | PG_HOST: 0.0.0.0 188 | - name: Node Postgres ORMs benchmark using only a single connection 189 | run: node --no-deprecation --import ./loader.mjs postgres.bench.ts > ./results/node-postgres-single.txt 190 | env: 191 | DATABASE_URL: postgres://postgres:postgres@0.0.0.0:5432/postgres 192 | MAX_CONNECTION: 1 193 | PG_HOST: 0.0.0.0 194 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | 15 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 16 | 17 | # Runtime data 18 | 19 | pids 20 | _.pid 21 | _.seed 22 | \*.pid.lock 23 | 24 | # Directory for instrumented libs generated by jscoverage/JSCover 25 | 26 | lib-cov 27 | 28 | # Coverage directory used by tools like istanbul 29 | 30 | coverage 31 | \*.lcov 32 | 33 | # nyc test coverage 34 | 35 | .nyc_output 36 | 37 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 38 | 39 | .grunt 40 | 41 | # Bower dependency directory (https://bower.io/) 42 | 43 | bower_components 44 | 45 | # node-waf configuration 46 | 47 | .lock-wscript 48 | 49 | # Compiled binary addons (https://nodejs.org/api/addons.html) 50 | 51 | build/Release 52 | 53 | # Dependency directories 54 | 55 | node_modules/ 56 | jspm_packages/ 57 | 58 | # Snowpack dependency directory (https://snowpack.dev/) 59 | 60 | web_modules/ 61 | 62 | # TypeScript cache 63 | 64 | \*.tsbuildinfo 65 | 66 | # Optional npm cache directory 67 | 68 | .npm 69 | 70 | # Optional eslint cache 71 | 72 | .eslintcache 73 | 74 | # Optional stylelint cache 75 | 76 | .stylelintcache 77 | 78 | # Microbundle cache 79 | 80 | .rpt2_cache/ 81 | .rts2_cache_cjs/ 82 | .rts2_cache_es/ 83 | .rts2_cache_umd/ 84 | 85 | # Optional REPL history 86 | 87 | .node_repl_history 88 | 89 | # Output of 'npm pack' 90 | 91 | \*.tgz 92 | 93 | # Yarn Integrity file 94 | 95 | .yarn-integrity 96 | 97 | # dotenv environment variable files 98 | 99 | .env 100 | .env.development.local 101 | .env.test.local 102 | .env.production.local 103 | .env.local 104 | 105 | # parcel-bundler cache (https://parceljs.org/) 106 | 107 | .cache 108 | .parcel-cache 109 | 110 | # Next.js build output 111 | 112 | .next 113 | out 114 | 115 | # Nuxt.js build / generate output 116 | 117 | .nuxt 118 | dist 119 | 120 | # Gatsby files 121 | 122 | .cache/ 123 | 124 | # Comment in the public line in if your project uses Gatsby and not Next.js 125 | 126 | # https://nextjs.org/blog/next-9-1#public-directory-support 127 | 128 | # public 129 | 130 | # vuepress build output 131 | 132 | .vuepress/dist 133 | 134 | # vuepress v2.x temp and cache directory 135 | 136 | .temp 137 | .cache 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.\* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | 177 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Imam Fahrur Rofi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeScript (and JavaScript) ORMs Benchmark 2 | 3 | Object-Relational Mapping (ORM) is a powerful technique that allows you to interact with databases using the same language you’re using for your application. This project aims to provide an objective assessment of the performance of popular Node.js ORMs. 4 | 5 | ## Results 6 | 7 | Check [results](./results) 8 | 9 | ## List of ORM 10 | 11 | ### MySQL 12 | 13 | - [DrizzleORM](./src/mysql/drizzle.ts) 14 | - [KnexJS](./src/mysql/knex.ts) 15 | - [Kysely](./src/mysql/kysely.ts) 16 | - [Mariadb](./src/mysql/mariadb.ts) 17 | - [MikroORM](./src/mysql/mikro.ts) 18 | - [MySQL2](./src/mysql/mysql2.ts) 19 | - [Prisma](./src/mysql/prisma.ts) 20 | - [Sequelize](./src/mysql/sequelize.ts) 21 | - [TypeORM](./src/mysql/typeorm.ts) 22 | 23 | ### PostgreSQL 24 | 25 | - [DrizzleORM](./src/postgres/drizzle.ts) 26 | - [KnexJS](./src/postgres/knex.ts) 27 | - [Kysely](./src/postgres/kysely.ts) 28 | - [MikroORM](./src/postgres/mikro.ts) 29 | - [PgTyped](./src/postgres/pg-typed.ts) 30 | - [Pg](./src/postgres/pg.ts) 31 | - [Postgres.js](./src/postgres/postgres.ts) 32 | - [Prisma](./src/postgres/prisma.ts) 33 | - [Sequelize](./src/postgres/sequelize.ts) 34 | - [TypeORM](./src/postgres/typeorm.ts) 35 | 36 | 37 | ## License 38 | This project is licensed under the MIT License. Feel free to explore, contribute, and share your insights! 39 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masfahru/typescript-orm-benchmark/311eeee8dd414b0301a3530ae1181a0f2e137755/bun.lockb -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "transforms": [ 3 | { 4 | "mode": "sql", 5 | "include": "**/*.sql", 6 | "emitTemplate": "{{dir}}/{{name}}.queries.ts" 7 | } 8 | ], 9 | "srcDir": "./src/", 10 | "failOnError": false, 11 | "camelCaseColumnNames": false, 12 | "db": { 13 | "host": "0.0.0.0", 14 | "user": "postgres", 15 | "dbName": "postgres", 16 | "password": "postgres" 17 | } 18 | } -------------------------------------------------------------------------------- /loader.mjs: -------------------------------------------------------------------------------- 1 | import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./")); -------------------------------------------------------------------------------- /mysql.bench.ts: -------------------------------------------------------------------------------- 1 | import { run, bench, group } from 'mitata'; 2 | import { getUser } from './src/helpers'; 3 | import { 4 | drizzleMySqlGetUser, 5 | knexMySqlGetUser, 6 | kyselyMySqlGetUser, 7 | mariadbGetUser, 8 | mikroMySqlGetUser, 9 | mySql2GetUser, 10 | prismaMySqlGetUser, 11 | sequelizeMySqlGetUser, 12 | typeormMySqlGetUser, 13 | } from './src/mysql'; 14 | 15 | group('MySQL', async () => { 16 | bench('DrizzleORM', async () => await getUser(drizzleMySqlGetUser)); 17 | bench('KnexJS', async () => await getUser(knexMySqlGetUser)); 18 | bench('Kysely', async () => await getUser(kyselyMySqlGetUser)); 19 | bench('Mariadb', async () => await getUser(mariadbGetUser)); 20 | bench('MikroORM', async () => await getUser(mikroMySqlGetUser)); 21 | bench('MySQL2', async () => await getUser(mySql2GetUser)); 22 | bench('Prisma', async () => await getUser(prismaMySqlGetUser)); 23 | bench('Sequelize', async () => await getUser(sequelizeMySqlGetUser)); 24 | bench('TypeORM', async () => await getUser(typeormMySqlGetUser)); 25 | }); 26 | 27 | await run({ 28 | colors: false, 29 | }); 30 | 31 | process.exit(0); 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-orm-benchmark", 3 | "module": "index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@pgtyped/cli": "^2.4.3", 7 | "@types/pg": "^8.15.4", 8 | "@types/pg-pool": "^2.0.6", 9 | "bun-types": "latest" 10 | }, 11 | "peerDependencies": { 12 | "typescript": "^5.0.0" 13 | }, 14 | "dependencies": { 15 | "@faker-js/faker": "^9.8.0", 16 | "@mikro-orm/core": "^6.4.16", 17 | "@mikro-orm/mysql": "^6.4.16", 18 | "@mikro-orm/postgresql": "^6.4.16", 19 | "@pgtyped/runtime": "^2.4.2", 20 | "@prisma/client": "^6.8.2", 21 | "drizzle-orm": "^0.44.1", 22 | "knex": "^3.1.0", 23 | "kysely": "^0.28.2", 24 | "mariadb": "^3.4.2", 25 | "mitata": "^1.0.34", 26 | "mysql2": "^3.14.1", 27 | "pg": "^8.16.0", 28 | "pg-pool": "^3.10.0", 29 | "postgres": "~3.4.7", 30 | "prisma": "^6.8.2", 31 | "reflect-metadata": "^0.2.2", 32 | "sequelize": "^6.37.7", 33 | "ts-node": "^10.9.2", 34 | "typeorm": "^0.3.24" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /postgres.bench.ts: -------------------------------------------------------------------------------- 1 | import { run, bench, group } from 'mitata'; 2 | import { getUser } from './src/helpers'; 3 | import { 4 | drizzlePostgreGetUser, 5 | knexPostgresGetUser, 6 | kyselyPostgresGetUser, 7 | mikroPostgresGetUser, 8 | pgGetUser, 9 | postgresGetUser, 10 | prismaPostgresGetUser, 11 | sequelizePostgresGetUser, 12 | typeormPostgresGetUser, 13 | pgTypedGetUser, 14 | } from './src/postgres'; 15 | 16 | group('PostgreSQL', () => { 17 | bench('DrizzleORM', async () => await getUser(drizzlePostgreGetUser)); 18 | bench('KnexJS', async () => await getUser(knexPostgresGetUser)); 19 | bench('Kysely', async () => await getUser(kyselyPostgresGetUser)); 20 | bench('MikroORM', async () => await getUser(mikroPostgresGetUser)); 21 | bench('Pg', async () => await getUser(pgGetUser)); 22 | bench('PgTyped', async () => await getUser(pgTypedGetUser)); 23 | bench('Postgres.js', async () => await getUser(postgresGetUser)); 24 | bench('Prisma', async () => await getUser(prismaPostgresGetUser)); 25 | bench('Sequelize', async () => await getUser(sequelizePostgresGetUser)); 26 | bench('TypeORM', async () => await getUser(typeormPostgresGetUser)); 27 | }); 28 | 29 | await run({ 30 | colors: false, 31 | }); 32 | 33 | process.exit(0); 34 | -------------------------------------------------------------------------------- /prisma/schema.mysql.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | binaryTargets = ["native", "debian-openssl-3.0.x"] 4 | } 5 | 6 | datasource db { 7 | provider = "mysql" 8 | url = env("DATABASE_URL") 9 | } 10 | 11 | model users { 12 | id Int @id @default(autoincrement()) @db.UnsignedInt 13 | username String @db.VarChar(255) 14 | email String @db.VarChar(255) 15 | password String @db.VarChar(255) 16 | name String @db.VarChar(255) 17 | created_at DateTime @default(now()) @db.DateTime(0) 18 | updated_at DateTime @default(now()) @db.DateTime(0) 19 | deleted_at DateTime? @db.DateTime(0) 20 | 21 | @@index([email], map: "users_email_index") 22 | @@index([username], map: "users_username_index") 23 | } 24 | -------------------------------------------------------------------------------- /prisma/schema.postgres.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | binaryTargets = ["native", "debian-openssl-3.0.x"] 4 | } 5 | 6 | datasource db { 7 | provider = "postgres" 8 | url = env("DATABASE_URL") 9 | } 10 | 11 | model users { 12 | id Int @id @default(autoincrement()) 13 | username String @db.VarChar(255) 14 | email String @db.VarChar(255) 15 | password String @db.VarChar(255) 16 | name String @db.VarChar(255) 17 | created_at DateTime @default(now()) @db.Timestamptz(6) 18 | updated_at DateTime @default(now()) @db.Timestamptz(6) 19 | deleted_at DateTime? @db.Timestamptz(6) 20 | 21 | @@index([email], map: "users_email_index") 22 | @@index([username], map: "users_username_index") 23 | } 24 | -------------------------------------------------------------------------------- /results/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masfahru/typescript-orm-benchmark/311eeee8dd414b0301a3530ae1181a0f2e137755/results/.gitkeep -------------------------------------------------------------------------------- /results/bun-mysql-cpu-count.txt: -------------------------------------------------------------------------------- 1 | clk: ~3.08 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 542.62 µs/iter 535.50 µs █ 10 | (359.88 µs … 4.09 ms) 1.94 ms █▇ 11 | ( 0.00 b … 5.25 mb) 30.37 kb ▇██▆▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 355.65 µs/iter 351.46 µs █ 14 | (261.06 µs … 2.13 ms) 1.45 ms ██ 15 | ( 0.00 b … 256.00 kb) 2.58 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 311.70 µs/iter 304.13 µs █ 18 | (243.28 µs … 1.63 ms) 1.31 ms ██ 19 | ( 0.00 b … 384.00 kb) 3.56 kb ██▆▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | Mariadb 246.97 µs/iter 245.56 µs █ 22 | (180.65 µs … 1.82 ms) 1.19 ms ▄█ 23 | ( 0.00 b … 256.00 kb) 1.22 kb ██▆▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | MikroORM 521.55 µs/iter 617.84 µs █ 26 | (34.04 µs … 3.38 ms) 2.34 ms █ █▆ 27 | ( 0.00 b … 768.00 kb) 14.58 kb █▂▁▁██▇▃▂▂▁▁▁▁▁▁▁▁▁▁▁ 28 | 29 | MySQL2 263.68 µs/iter 258.95 µs █ 30 | (202.25 µs … 1.72 ms) 1.21 ms ▇█ 31 | ( 0.00 b … 384.00 kb) 1.93 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Prisma 549.84 µs/iter 534.13 µs █ 34 | (449.56 µs … 1.94 ms) 1.59 ms █ 35 | ( 0.00 b … 896.00 kb) 3.77 kb ██▆▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Sequelize 507.84 µs/iter 489.18 µs █ 38 | (347.13 µs … 3.31 ms) 1.97 ms █▂ 39 | ( 0.00 b … 5.75 mb) 20.29 kb ▇██▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | TypeORM 437.41 µs/iter 433.46 µs █ 42 | (320.15 µs … 2.11 ms) 1.71 ms ▂█ 43 | ( 0.00 b … 384.00 kb) 4.32 kb ███▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/bun-mysql-default.txt: -------------------------------------------------------------------------------- 1 | clk: ~3.08 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 543.98 µs/iter 541.27 µs █ 10 | (359.89 µs … 3.39 ms) 2.12 ms █▄ 11 | ( 0.00 b … 1.50 mb) 30.08 kb ▇██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 350.28 µs/iter 342.73 µs █ 14 | (264.94 µs … 1.97 ms) 1.32 ms ▄█ 15 | ( 0.00 b … 256.00 kb) 2.27 kb ██▇▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 313.50 µs/iter 307.82 µs █ 18 | (244.42 µs … 1.80 ms) 1.25 ms ▅█ 19 | ( 0.00 b … 384.00 kb) 3.50 kb ██▆▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | Mariadb 249.72 µs/iter 245.04 µs █ 22 | (184.73 µs … 1.70 ms) 1.24 ms ▆█ 23 | ( 0.00 b … 256.00 kb) 1.78 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | MikroORM 524.89 µs/iter 622.50 µs ▃ █▅ 26 | (34.70 µs … 3.14 ms) 2.36 ms █ ██ 27 | ( 0.00 b … 768.00 kb) 13.16 kb █▂▁▁██▇▃▂▁▁▁▁▁▁▁▁▁▂▁▁ 28 | 29 | MySQL2 265.00 µs/iter 264.62 µs ▂█ 30 | (204.41 µs … 1.41 ms) 1.20 ms ██ 31 | ( 0.00 b … 128.00 kb) 1.00 kb ██▇▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Prisma 549.63 µs/iter 534.86 µs █ 34 | (454.35 µs … 1.79 ms) 1.49 ms █ 35 | ( 0.00 b … 820.00 kb) 3.50 kb ██▇▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Sequelize 503.33 µs/iter 491.87 µs █ 38 | (349.41 µs … 2.97 ms) 1.90 ms █▃ 39 | ( 0.00 b … 4.25 mb) 18.67 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | TypeORM 446.36 µs/iter 436.85 µs █ 42 | (317.83 µs … 2.63 ms) 1.73 ms █ 43 | ( 0.00 b … 512.00 kb) 3.99 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/bun-mysql-max.txt: -------------------------------------------------------------------------------- 1 | clk: ~1.56 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 585.88 µs/iter 573.79 µs █ 10 | (369.87 µs … 4.40 ms) 2.36 ms █ 11 | ( 0.00 b … 5.00 mb) 31.60 kb ▇██▄▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 353.63 µs/iter 344.46 µs ▂█ 14 | (263.49 µs … 2.52 ms) 1.43 ms ██ 15 | ( 0.00 b … 256.00 kb) 2.08 kb ███▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 318.03 µs/iter 313.92 µs █ 18 | (244.33 µs … 1.64 ms) 1.30 ms ▄█ 19 | ( 0.00 b … 384.00 kb) 3.30 kb ██▇▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | Mariadb 309.79 µs/iter 271.21 µs █ 22 | (203.58 µs … 2.65 ms) 1.40 ms ▇█ 23 | ( 0.00 b … 256.00 kb) 4.42 kb ██▃▁▁▁▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | MikroORM 526.61 µs/iter 624.27 µs █ 26 | (36.63 µs … 3.17 ms) 2.36 ms █ █▆ 27 | ( 0.00 b … 640.00 kb) 12.19 kb █▂▁▁██▆▃▂▁▁▁▁▁▁▁▁▁▁▁▁ 28 | 29 | MySQL2 266.14 µs/iter 263.77 µs █ 30 | (205.45 µs … 1.49 ms) 1.24 ms ██ 31 | ( 0.00 b … 256.00 kb) 1.26 kb ██▅▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Prisma 554.12 µs/iter 540.13 µs █ 34 | (452.36 µs … 1.74 ms) 1.53 ms █ 35 | ( 0.00 b … 808.00 kb) 3.41 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Sequelize 509.06 µs/iter 498.84 µs █ 38 | (356.98 µs … 3.19 ms) 1.98 ms █ 39 | ( 0.00 b … 1.00 mb) 19.41 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | TypeORM 441.71 µs/iter 428.66 µs █ 42 | (317.18 µs … 2.32 ms) 1.71 ms █ 43 | ( 0.00 b … 384.00 kb) 5.56 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/bun-mysql-single.txt: -------------------------------------------------------------------------------- 1 | clk: ~3.06 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 525.48 µs/iter 506.71 µs █ 10 | (358.37 µs … 3.03 ms) 1.95 ms █ 11 | ( 0.00 b … 2.50 mb) 26.35 kb ▅██▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 346.20 µs/iter 342.52 µs ▃█ 14 | (261.61 µs … 1.85 ms) 1.29 ms ██ 15 | ( 0.00 b … 384.00 kb) 2.52 kb ███▄▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 315.15 µs/iter 308.40 µs ▂█ 18 | (245.21 µs … 1.79 ms) 1.27 ms ██ 19 | ( 0.00 b … 384.00 kb) 3.03 kb ██▇▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | Mariadb 237.59 µs/iter 238.95 µs ▅█ 22 | (179.73 µs … 1.51 ms) 1.14 ms ██ 23 | ( 0.00 b … 256.00 kb) 1.22 kb ███▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | MikroORM 507.33 µs/iter 595.48 µs ▅ ██ 26 | (34.15 µs … 3.48 ms) 2.25 ms █ ██ 27 | ( 0.00 b … 640.00 kb) 14.29 kb █▃▁▁██▇▄▂▁▂▁▁▁▁▁▁▁▁▁▁ 28 | 29 | MySQL2 265.53 µs/iter 265.11 µs ▃█ 30 | (206.42 µs … 1.60 ms) 1.23 ms ██ 31 | ( 0.00 b … 256.00 kb) 968.51 b ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Prisma 547.00 µs/iter 528.37 µs █ 34 | (454.46 µs … 1.73 ms) 1.48 ms █ 35 | ( 0.00 b … 896.00 kb) 3.54 kb ▇█▆▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Sequelize 497.79 µs/iter 482.44 µs █ 38 | (351.24 µs … 2.63 ms) 1.89 ms █ 39 | ( 0.00 b … 896.00 kb) 18.96 kb ▇██▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | TypeORM 434.70 µs/iter 421.28 µs █ 42 | (315.48 µs … 2.25 ms) 1.72 ms █ 43 | ( 0.00 b … 384.00 kb) 5.05 kb ▇█▇▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/bun-postgres-cpu-count.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.43 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 434.66 µs/iter 426.83 µs █ 10 | (304.62 µs … 2.50 ms) 1.66 ms ▅█▄ 11 | ( 0.00 b … 896.00 kb) 15.05 kb ███▅▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 346.89 µs/iter 343.23 µs █ 14 | (259.16 µs … 1.93 ms) 1.40 ms ▅█ 15 | ( 0.00 b … 384.00 kb) 2.98 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 318.50 µs/iter 312.38 µs █ 18 | (245.79 µs … 1.65 ms) 1.32 ms ▄█ 19 | ( 0.00 b … 384.00 kb) 2.75 kb ██▆▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | MikroORM 483.64 µs/iter 589.53 µs ▄ █ 22 | (35.12 µs … 3.38 ms) 2.28 ms █ ██ 23 | ( 0.00 b … 896.00 kb) 13.36 kb █▂▁▁██▆▂▂▁▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | Pg 278.73 µs/iter 271.64 µs █ 26 | (220.54 µs … 1.46 ms) 1.27 ms ▇█ 27 | ( 0.00 b … 512.00 kb) 3.90 kb ██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 28 | 29 | PgTyped 305.15 µs/iter 298.16 µs █ 30 | (230.52 µs … 2.10 ms) 1.33 ms ▄█ 31 | ( 0.00 b … 256.00 kb) 2.34 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Postgres.js 213.48 µs/iter 212.46 µs █ 34 | (151.56 µs … 1.62 ms) 1.14 ms █ 35 | ( 0.00 b … 256.00 kb) 1.83 kb ██▅▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Prisma 544.36 µs/iter 526.12 µs █ 38 | (440.92 µs … 1.77 ms) 1.51 ms █ 39 | ( 0.00 b … 256.00 kb) 2.69 kb ▃█▆▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | Sequelize 464.37 µs/iter 439.98 µs █ 42 | (316.16 µs … 3.85 ms) 1.85 ms █ 43 | ( 0.00 b … 4.38 mb) 20.97 kb ▆█▇▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | 45 | TypeORM 461.83 µs/iter 454.59 µs █ 46 | (327.82 µs … 2.46 ms) 1.79 ms █▂ 47 | ( 0.00 b … 256.00 kb) 5.19 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /results/bun-postgres-default.txt: -------------------------------------------------------------------------------- 1 | clk: ~1.57 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 438.69 µs/iter 430.16 µs █ 10 | (301.94 µs … 2.43 ms) 1.71 ms █ 11 | ( 0.00 b … 896.00 kb) 13.35 kb ███▄▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 348.23 µs/iter 344.04 µs █ 14 | (262.20 µs … 1.71 ms) 1.36 ms ██ 15 | ( 0.00 b … 256.00 kb) 2.38 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 319.18 µs/iter 313.66 µs █ 18 | (248.93 µs … 1.80 ms) 1.33 ms ▆█ 19 | ( 0.00 b … 384.00 kb) 3.50 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | MikroORM 499.59 µs/iter 601.96 µs █ 22 | (36.20 µs … 3.01 ms) 2.34 ms █ █▇ 23 | ( 0.00 b … 896.00 kb) 11.85 kb █▂▁▁██▅▃▂▁▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | Pg 281.24 µs/iter 272.39 µs ▆█ 26 | (226.38 µs … 1.45 ms) 1.25 ms ██ 27 | ( 0.00 b … 512.00 kb) 3.55 kb ██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 28 | 29 | PgTyped 301.82 µs/iter 293.58 µs ▃█ 30 | (237.64 µs … 1.70 ms) 1.32 ms ██ 31 | ( 0.00 b … 384.00 kb) 2.90 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Postgres.js 212.68 µs/iter 208.75 µs ▂█ 34 | (158.50 µs … 1.53 ms) 1.17 ms ██ 35 | ( 0.00 b … 256.00 kb) 1.78 kb ██▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Prisma 551.49 µs/iter 528.69 µs █ 38 | (451.12 µs … 1.77 ms) 1.57 ms █ 39 | ( 0.00 b … 896.00 kb) 3.57 kb ▆█▅▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | Sequelize 471.06 µs/iter 457.10 µs █ 42 | (322.03 µs … 3.01 ms) 1.89 ms ▂█▃ 43 | ( 0.00 b … 1.25 mb) 19.98 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | 45 | TypeORM 452.13 µs/iter 442.88 µs █ 46 | (323.30 µs … 2.11 ms) 1.75 ms █ 47 | ( 0.00 b … 512.00 kb) 5.52 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /results/bun-postgres-max.txt: -------------------------------------------------------------------------------- 1 | clk: ~1.58 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 443.49 µs/iter 446.21 µs █ 10 | (301.99 µs … 2.18 ms) 1.72 ms █▃ 11 | ( 0.00 b … 768.00 kb) 15.39 kb ███▅▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 353.03 µs/iter 348.51 µs █ 14 | (264.12 µs … 2.00 ms) 1.44 ms ▆█ 15 | ( 0.00 b … 256.00 kb) 2.21 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 318.77 µs/iter 311.64 µs █ 18 | (246.71 µs … 1.88 ms) 1.31 ms ▄█ 19 | ( 0.00 b … 512.00 kb) 3.75 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | MikroORM 497.22 µs/iter 612.57 µs █ 22 | (35.43 µs … 3.18 ms) 2.36 ms █ █▄ 23 | ( 0.00 b … 640.00 kb) 11.73 kb █▂▁▂██▆▃▁▁▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | Pg 279.42 µs/iter 273.13 µs █ 26 | (220.56 µs … 1.46 ms) 1.28 ms ▇█ 27 | ( 0.00 b … 3.25 mb) 3.55 kb ██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 28 | 29 | PgTyped 301.33 µs/iter 293.15 µs █ 30 | (228.62 µs … 1.78 ms) 1.32 ms █ 31 | ( 0.00 b … 256.00 kb) 1.90 kb ▇█▅▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Postgres.js 214.48 µs/iter 212.96 µs ▅█ 34 | (160.07 µs … 1.55 ms) 1.18 ms ██ 35 | ( 0.00 b … 256.00 kb) 1.89 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Prisma 543.27 µs/iter 523.79 µs █ 38 | (447.90 µs … 2.00 ms) 1.50 ms █ 39 | ( 0.00 b … 768.00 kb) 3.53 kb ██▆▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | Sequelize 465.53 µs/iter 449.77 µs █ 42 | (318.61 µs … 3.15 ms) 2.01 ms █ 43 | ( 0.00 b … 896.00 kb) 20.09 kb ▇██▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | 45 | TypeORM 458.17 µs/iter 448.40 µs █ 46 | (327.28 µs … 2.48 ms) 1.77 ms █ 47 | ( 0.00 b … 384.00 kb) 5.59 kb ▇██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /results/bun-postgres-single.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.22 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: bun 1.2.15 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 436.41 µs/iter 429.30 µs █ 10 | (303.70 µs … 2.35 ms) 1.70 ms ▂█ 11 | ( 0.00 b … 896.00 kb) 15.41 kb ███▅▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 12 | 13 | KnexJS 346.26 µs/iter 344.62 µs █ 14 | (257.87 µs … 1.87 ms) 1.40 ms ██ 15 | ( 0.00 b … 384.00 kb) 2.10 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 321.21 µs/iter 313.20 µs █ 18 | (242.45 µs … 1.76 ms) 1.35 ms █ 19 | ( 0.00 b … 384.00 kb) 2.57 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 20 | 21 | MikroORM 475.93 µs/iter 581.24 µs ▂ █ 22 | (35.22 µs … 2.79 ms) 2.36 ms █ █▃ 23 | ( 0.00 b … 896.00 kb) 12.12 kb █▂▁▂██▅▂▂▁▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | Pg 279.81 µs/iter 271.42 µs █ 26 | (223.22 µs … 1.55 ms) 1.26 ms ██ 27 | ( 0.00 b … 384.00 kb) 3.47 kb ██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 28 | 29 | PgTyped 294.18 µs/iter 285.48 µs ▄█ 30 | (233.11 µs … 1.54 ms) 1.28 ms ██ 31 | ( 0.00 b … 256.00 kb) 2.31 kb ██▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Postgres.js 214.19 µs/iter 210.77 µs █ 34 | (157.22 µs … 1.57 ms) 1.17 ms ▅█ 35 | ( 0.00 b … 256.00 kb) 1.71 kb ██▄▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 36 | 37 | Prisma 542.93 µs/iter 523.32 µs █ 38 | (452.06 µs … 1.65 ms) 1.51 ms █ 39 | ( 0.00 b … 740.00 kb) 3.50 kb ▇█▅▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 40 | 41 | Sequelize 464.74 µs/iter 442.77 µs █ 42 | (316.80 µs … 4.91 ms) 1.89 ms █ 43 | ( 0.00 b … 5.38 mb) 20.73 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | 45 | TypeORM 455.21 µs/iter 454.42 µs █ 46 | (320.51 µs … 2.37 ms) 1.74 ms █▃ 47 | ( 0.00 b … 384.00 kb) 5.45 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /results/node-mysql-cpu-count.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.46 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 487.35 µs/iter 509.27 µs █ 10 | (405.08 µs … 1.61 ms) 849.25 µs ██▅▃ 11 | ( 1.27 kb … 1.59 mb) 102.93 kb ██████▇▄▂▂▂▂▁▁▂▁▁▁▁▁▁ 12 | 13 | KnexJS 384.46 µs/iter 395.82 µs ▂▅█▃ 14 | (311.22 µs … 2.11 ms) 599.61 µs ████▄ 15 | ( 8.37 kb … 882.43 kb) 56.69 kb ▃▅█████▇▅▃▃▄▂▂▂▂▂▁▁▁▁ 16 | 17 | Kysely 321.30 µs/iter 331.98 µs █▄ 18 | (277.40 µs … 2.40 ms) 459.43 µs ██▇▅▅▇ 19 | ( 3.83 kb … 1.18 mb) 31.74 kb ▅███████▇▃▂▃▂▂▂▂▂▁▁▁▁ 20 | 21 | Mariadb 259.81 µs/iter 267.88 µs █ 22 | (210.50 µs … 2.93 ms) 453.51 µs ▄█▆▆▅ 23 | ( 2.02 kb … 482.69 kb) 15.66 kb ▂█████▇▃▃▂▁▁▁▁▁▁▁▁▁▁▁ 24 | 25 | MikroORM 511.33 µs/iter 638.38 µs █▇ 26 | (49.34 µs … 4.28 ms) 1.37 ms ▃▂ ██ 27 | ( 4.53 kb … 972.01 kb) 91.65 kb ██▁▁▁▁▁▁██▅▄▃▁▁▁▁▁▁▁▁ 28 | 29 | MySQL2 297.94 µs/iter 305.19 µs █ 30 | (241.24 µs … 4.47 ms) 428.66 µs ▅ ██▄ 31 | ( 7.77 kb … 623.02 kb) 27.99 kb ▂▂█▇████▇▄▃▃▂▂▂▁▁▁▁▁▁ 32 | 33 | Prisma 548.99 µs/iter 554.29 µs ██▃ 34 | (495.39 µs … 2.85 ms) 668.36 µs ████▅ 35 | ( 2.34 kb … 423.09 kb) 21.45 kb ▂███████▆▆▇▅▄▃▂▂▂▂▁▁▁ 36 | 37 | Sequelize 495.41 µs/iter 510.41 µs █▃▆ 38 | (412.87 µs … 3.83 ms) 785.12 µs ████▆ 39 | ( 5.66 kb … 831.79 kb) 83.82 kb ███████▆▃▃▃▃▂▂▂▂▁▂▁▁▁ 40 | 41 | TypeORM 412.95 µs/iter 423.19 µs █ 42 | (356.43 µs … 3.28 ms) 620.12 µs ██▆▄▄ 43 | ( 5.91 kb … 895.55 kb) 68.21 kb ▆██████▄▃▃▂▂▁▂▁▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/node-mysql-default.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.42 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 502.86 µs/iter 521.67 µs █ 10 | (404.15 µs … 4.58 ms) 930.12 µs ██▄▃ 11 | ( 6.21 kb … 1.34 mb) 101.87 kb ▆█████▅▃▃▂▂▂▂▂▂▂▁▁▁▁▁ 12 | 13 | KnexJS 388.44 µs/iter 402.15 µs ██▄ 14 | (313.65 µs … 1.40 ms) 654.79 µs ███▇ 15 | ( 11.38 kb … 919.52 kb) 56.98 kb ▄▅█████▅▄▃▃▂▂▂▁▁▁▁▁▁▁ 16 | 17 | Kysely 315.86 µs/iter 322.06 µs █▂ 18 | (277.26 µs … 2.54 ms) 461.27 µs ████▂ 19 | ( 1.18 kb … 775.76 kb) 31.95 kb ▃█████▇▅▃▂▂▂▁▂▂▁▁▁▁▁▁ 20 | 21 | Mariadb 257.77 µs/iter 268.22 µs ▅▇█ ▂ 22 | (207.99 µs … 5.19 ms) 364.48 µs ▄██████▅▃▂ 23 | ( 1.01 kb … 645.70 kb) 16.48 kb ▄██████████▆▅▃▂▂▂▁▂▁▁ 24 | 25 | MikroORM 512.95 µs/iter 646.80 µs █ 26 | (50.83 µs … 3.78 ms) 1.26 ms ▃ ██ 27 | ( 3.11 kb … 1.10 mb) 90.05 kb ██▁▁▁▁▁▁▁██▅▃▂▂▂▁▁▁▁▁ 28 | 29 | MySQL2 277.95 µs/iter 286.68 µs █ 30 | (241.06 µs … 2.65 ms) 391.05 µs ▂██▇▃ 31 | ( 3.00 kb … 623.02 kb) 27.65 kb ▁███████▆▄▄▂▂▂▁▁▁▁▁▁▁ 32 | 33 | Prisma 542.28 µs/iter 544.07 µs ▂▇█▅ 34 | (491.56 µs … 2.94 ms) 679.46 µs ████▅ 35 | ( 18.75 kb … 425.30 kb) 21.27 kb ▂██████▇▄▃▂▃▂▂▂▂▁▁▁▁▁ 36 | 37 | Sequelize 493.96 µs/iter 522.13 µs █▅ 38 | (409.44 µs … 2.53 ms) 782.35 µs ███▅ ▃ 39 | ( 5.66 kb … 1.01 mb) 83.60 kb ████████▇▄▄▃▂▁▂▁▁▁▁▁▁ 40 | 41 | TypeORM 415.65 µs/iter 421.83 µs ▇██▄ 42 | (360.17 µs … 4.00 ms) 623.19 µs ████▆ 43 | ( 37.10 kb … 1.32 mb) 68.34 kb ▆██████▅▃▃▃▂▁▁▂▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/node-mysql-max.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.46 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 544.24 µs/iter 576.61 µs ██▄ 10 | (415.74 µs … 3.21 ms) 1.11 ms ███▅▂ 11 | ( 5.69 kb … 1.32 mb) 110.01 kb ▆██████▅▃▂▂▂▂▁▂▁▁▁▁▁▁ 12 | 13 | KnexJS 399.99 µs/iter 409.60 µs █▅▄ 14 | (325.13 µs … 3.36 ms) 652.76 µs ▄███▇ 15 | (296.00 b … 1.85 mb) 55.62 kb ▅██████▇▄▃▃▂▂▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 318.50 µs/iter 324.16 µs ▆█ 18 | (273.88 µs … 3.25 ms) 543.23 µs ███▆ 19 | ( 12.16 kb … 778.89 kb) 32.53 kb ▂█████▃▂▂▁▁▂▁▁▁▁▁▁▁▁▁ 20 | 21 | Mariadb 306.38 µs/iter 291.09 µs █ 22 | (236.48 µs … 3.92 ms) 782.48 µs █▅ 23 | ( 1.88 kb … 676.16 kb) 17.54 kb ███▄▂▂▁▁▁▁▁▁▁▁▁▁▂▂▁▁▁ 24 | 25 | MikroORM 500.18 µs/iter 631.89 µs █ 26 | (43.25 µs … 5.96 ms) 1.26 ms ▃ █▄ 27 | ( 2.91 kb … 907.63 kb) 88.62 kb ▇█▁▁▁▁▁▁▂██▃▃▂▁▁▁▁▁▁▁ 28 | 29 | MySQL2 291.93 µs/iter 301.19 µs █ 30 | (247.84 µs … 3.95 ms) 490.55 µs ██▃▆ 31 | (912.00 b … 620.34 kb) 27.90 kb ▂█████▆▃▃▂▂▁▁▁▁▁▁▁▁▁▁ 32 | 33 | Prisma 549.71 µs/iter 547.08 µs █▇ 34 | (492.77 µs … 3.77 ms) 710.62 µs ▇███ 35 | ( 18.75 kb … 331.94 kb) 21.45 kb ▂▅████▇▄▃▃▂▂▂▂▂▁▁▁▁▁▁ 36 | 37 | Sequelize 500.79 µs/iter 520.17 µs █▇▂ 38 | (418.97 µs … 2.59 ms) 778.67 µs █████▄ 39 | (176.00 b … 1.00 mb) 85.80 kb ▇███████▄▃▄▂▂▂▂▂▂▁▁▁▁ 40 | 41 | TypeORM 427.90 µs/iter 430.85 µs █ 42 | (367.61 µs … 3.50 ms) 830.43 µs ██▂ 43 | ( 7.04 kb … 1.14 mb) 68.95 kb ▆███▄▃▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/node-mysql-single.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.45 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • MySQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 494.62 µs/iter 513.85 µs █▅ 10 | (406.19 µs … 1.98 ms) 843.36 µs ██▇▅▂ 11 | ( 6.16 kb … 1.48 mb) 101.44 kb ███████▅▃▃▂▁▂▁▂▂▂▂▁▁▁ 12 | 13 | KnexJS 393.89 µs/iter 410.97 µs ▃▇█ 14 | (321.65 µs … 3.11 ms) 593.08 µs ▃███▇▄▃ 15 | ( 8.23 kb … 863.96 kb) 55.89 kb ▂████████▄▄▃▃▂▂▂▂▁▁▁▁ 16 | 17 | Kysely 317.38 µs/iter 326.26 µs █▇ 18 | (276.40 µs … 1.59 ms) 493.44 µs ██▆▆▃ 19 | (952.00 b … 1.18 mb) 31.58 kb ▄█████▇▄▂▂▂▂▂▂▁▁▁▁▁▁▁ 20 | 21 | Mariadb 260.44 µs/iter 275.92 µs ▂█▇ ▂ 22 | (211.43 µs … 3.63 ms) 388.35 µs ███▅▄█▅▅ 23 | ( 1.91 kb … 666.05 kb) 17.06 kb ▃█████████▆▄▃▂▂▂▁▂▁▁▁ 24 | 25 | MikroORM 506.30 µs/iter 638.15 µs ██ 26 | (43.77 µs … 4.61 ms) 1.23 ms ▇ ██ 27 | ( 24.00 b … 1.52 mb) 94.73 kb ▇█▂▁▁▁▁▁▁██▆▄▃▂▂▁▁▁▁▁ 28 | 29 | MySQL2 287.21 µs/iter 298.48 µs ▆ ▂█ 30 | (248.17 µs … 1.07 ms) 397.76 µs █████▇▆▂ 31 | ( 2.99 kb … 555.89 kb) 27.75 kb ▃████████▅▅▃▂▂▂▂▁▁▁▁▁ 32 | 33 | Prisma 545.93 µs/iter 549.58 µs █▇ 34 | (498.78 µs … 2.85 ms) 683.24 µs ▂████▄ 35 | ( 18.72 kb … 425.30 kb) 21.40 kb ▂██████▆▄▄▂▃▂▂▁▁▂▁▁▁▁ 36 | 37 | Sequelize 502.21 µs/iter 510.22 µs █▅▅ 38 | (411.94 µs … 3.37 ms) 864.00 µs ███▇ 39 | ( 20.64 kb … 927.93 kb) 85.32 kb ██████▄▄▄▃▃▃▂▂▂▁▂▁▁▁▁ 40 | 41 | TypeORM 414.09 µs/iter 421.26 µs █▄▆ 42 | (357.94 µs … 2.37 ms) 628.34 µs ▂████▅ 43 | ( 5.91 kb … 1.14 mb) 68.73 kb ███████▄▃▄▃▂▂▂▁▁▁▁▁▁▁ 44 | -------------------------------------------------------------------------------- /results/node-postgres-cpu-count.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.46 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 434.55 µs/iter 460.05 µs ▅▇▅█▅ 10 | (345.15 µs … 1.65 ms) 682.47 µs ██████▆▃ 11 | (464.00 b … 0.98 mb) 80.40 kb ▆████████▇▅▄▄▄▃▂▂▂▂▂▁ 12 | 13 | KnexJS 376.33 µs/iter 391.48 µs ▆█▃ 14 | (297.94 µs … 2.93 ms) 632.45 µs ███▄ 15 | (752.00 b … 920.15 kb) 45.47 kb ▄██████▇▅▃▃▃▂▂▁▂▁▁▁▁▁ 16 | 17 | Kysely 311.34 µs/iter 317.61 µs ▃█▃ 18 | (268.21 µs … 2.45 ms) 413.63 µs ████▇▅ 19 | ( 11.68 kb … 514.78 kb) 22.33 kb ▂████████▅▅▄▃▂▂▂▂▂▂▁▁ 20 | 21 | MikroORM 501.81 µs/iter 631.01 µs █ 22 | (49.08 µs … 4.73 ms) 1.29 ms ▂ █ 23 | ( 2.00 kb … 1.54 mb) 82.72 kb ▇█▂▁▁▁▁▁▇█▇▃▃▂▁▁▁▁▁▁▁ 24 | 25 | Pg 263.70 µs/iter 268.77 µs ▆█▇ ▃ 26 | (219.65 µs … 5.65 ms) 370.50 µs █████▅ 27 | ( 8.09 kb … 597.06 kb) 13.50 kb ▂▇███████▆▄▃▃▂▂▁▁▁▁▁▁ 28 | 29 | PgTyped 285.63 µs/iter 291.36 µs ▃▄█▇ 30 | (245.72 µs … 2.28 ms) 391.50 µs ▂████▇▅ 31 | ( 4.76 kb … 1.20 mb) 19.06 kb ▁███████▇▄▃▃▂▂▂▂▂▁▁▁▁ 32 | 33 | Postgres.js 227.68 µs/iter 232.91 µs ▃█▂ 34 | (189.41 µs … 3.12 ms) 336.56 µs ▃███▃▃ 35 | ( 6.53 kb … 563.30 kb) 13.73 kb ▃██████▇▅▃▃▃▂▂▂▂▁▁▁▁▁ 36 | 37 | Prisma 542.99 µs/iter 545.59 µs █▆ 38 | (497.36 µs … 2.76 ms) 665.93 µs ▃▇███▄ 39 | ( 18.73 kb … 295.84 kb) 21.15 kb ▂██████▆▄▄▃▃▃▂▂▂▁▁▁▁▁ 40 | 41 | Sequelize 454.37 µs/iter 460.21 µs ▄█▂ 42 | (367.62 µs … 3.37 ms) 811.54 µs ███▇ 43 | (504.00 b … 0.99 mb) 68.92 kb ▄█████▅▃▃▃▂▂▁▁▁▁▁▁▁▁▁ 44 | 45 | TypeORM 427.61 µs/iter 437.56 µs █▆ 46 | (353.79 µs … 3.30 ms) 682.86 µs ▇██▅▆ 47 | ( 1.00 kb … 0.99 mb) 67.02 kb ▄██████▆▃▃▃▂▂▁▁▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /results/node-postgres-default.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.46 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 431.74 µs/iter 462.04 µs █▆ 10 | (344.87 µs … 5.59 ms) 680.15 µs ██▅▄▃ 11 | ( 4.95 kb … 1.21 mb) 79.91 kb ▆████████▅▅▃▃▃▃▂▃▂▂▁▁ 12 | 13 | KnexJS 366.40 µs/iter 367.41 µs ▇█ 14 | (299.64 µs … 3.22 ms) 632.21 µs ▂██▆ 15 | ( 6.96 kb … 2.02 mb) 43.18 kb ▆████▇▄▃▃▂▂▂▁▁▁▁▁▁▁▁▁ 16 | 17 | Kysely 311.77 µs/iter 314.63 µs ▇█ 18 | (271.48 µs … 3.29 ms) 432.46 µs ▇████ 19 | ( 11.36 kb … 727.02 kb) 22.50 kb ▄██████▆▄▃▃▂▂▁▂▂▁▁▁▁▁ 20 | 21 | MikroORM 506.03 µs/iter 625.26 µs █ 22 | (42.03 µs … 3.64 ms) 1.38 ms ▄ █▄ 23 | ( 1.63 kb … 1.94 mb) 84.68 kb ▆█▁▁▁▁▁▁██▄▄▂▁▁▁▁▁▁▁▁ 24 | 25 | Pg 259.17 µs/iter 261.91 µs █▆ 26 | (222.37 µs … 4.90 ms) 370.81 µs ██▇▃ 27 | ( 11.20 kb … 651.16 kb) 13.60 kb ▁██████▇▃▃▃▂▂▂▁▁▁▁▁▁▁ 28 | 29 | PgTyped 279.05 µs/iter 283.86 µs █▂ 30 | (242.16 µs … 2.70 ms) 392.13 µs ▆███▂▂ 31 | ( 3.39 kb … 1.94 mb) 19.01 kb ▃███████▄▃▂▂▂▂▁▁▁▁▁▁▁ 32 | 33 | Postgres.js 232.30 µs/iter 244.61 µs ▆█ 34 | (188.78 µs … 3.01 ms) 334.82 µs ▂██▇▄▂▃▅ 35 | ( 5.45 kb … 553.80 kb) 12.70 kb ▆█████████▅▅▃▂▂▂▁▁▁▁▁ 36 | 37 | Prisma 537.14 µs/iter 539.30 µs ██▇ 38 | (493.39 µs … 2.65 ms) 657.53 µs ▇███▅ 39 | ( 18.73 kb … 395.71 kb) 21.11 kb ▂▇█████▆▅▃▃▂▂▂▁▂▁▂▁▁▁ 40 | 41 | Sequelize 448.81 µs/iter 461.97 µs ▅█▃ 42 | (360.13 µs … 3.41 ms) 782.27 µs ████▄ 43 | (800.00 b … 899.77 kb) 71.78 kb ▅█████▇▄▃▃▃▂▂▂▂▂▁▁▁▁▁ 44 | 45 | TypeORM 421.65 µs/iter 433.50 µs █ 46 | (354.38 µs … 2.43 ms) 694.74 µs ▇█▇▆▃ 47 | (776.00 b … 1.10 mb) 65.87 kb ▃█████▆▄▂▂▂▂▁▁▁▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /results/node-postgres-max.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.44 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 437.07 µs/iter 453.62 µs ▅█▄ 10 | (345.04 µs … 3.21 ms) 735.70 µs ▆███▆▃ 11 | (496.00 b … 1.31 mb) 80.45 kb ▅██████▆▅▄▃▃▃▂▂▂▁▁▁▁▁ 12 | 13 | KnexJS 369.03 µs/iter 375.71 µs █▆▅ 14 | (305.38 µs … 2.06 ms) 537.30 µs ▂▄███▆ 15 | ( 12.58 kb … 924.11 kb) 44.91 kb ▃███████▆▄▄▃▃▂▁▂▁▂▂▁▁ 16 | 17 | Kysely 309.36 µs/iter 312.94 µs █▆▂ 18 | (268.09 µs … 2.86 ms) 449.19 µs ▆███▇ 19 | ( 18.58 kb … 869.43 kb) 23.35 kb ▄██████▆▄▃▂▂▂▂▂▁▁▁▁▁▁ 20 | 21 | MikroORM 498.31 µs/iter 629.86 µs █▄ 22 | (46.50 µs … 2.23 ms) 1.02 ms ▇ ██ 23 | ( 3.53 kb … 0.98 mb) 86.51 kb ▅█▃▁▁▁▁▁▁▁▂██▆▃▄▂▁▁▁▁ 24 | 25 | Pg 259.80 µs/iter 265.00 µs █▄ 26 | (224.04 µs … 2.80 ms) 383.98 µs ██▇▃▂ 27 | ( 11.19 kb … 808.97 kb) 13.43 kb ▁▇█████▄▃▃▂▂▁▁▁▁▁▁▁▁▁ 28 | 29 | PgTyped 285.97 µs/iter 290.98 µs ██▆ 30 | (242.02 µs … 2.95 ms) 400.74 µs ███▄▄ 31 | ( 3.38 kb … 1.37 mb) 18.79 kb ▂██████▇▆▄▄▃▃▂▂▂▂▁▁▁▁ 32 | 33 | Postgres.js 230.97 µs/iter 242.63 µs ▄█▄ █ ▆ 34 | (185.94 µs … 3.23 ms) 335.22 µs ████▇█▄█ 35 | ( 2.41 kb … 389.78 kb) 12.64 kb ▂█████████▇▄▃▃▁▂▁▁▁▁▁ 36 | 37 | Prisma 538.87 µs/iter 541.23 µs █▄ 38 | (484.47 µs … 2.69 ms) 710.04 µs ▅██▅ 39 | ( 18.75 kb … 331.73 kb) 21.43 kb ▂▅████▇▄▃▂▂▂▁▂▁▁▁▁▁▁▁ 40 | 41 | Sequelize 447.08 µs/iter 458.84 µs █▄ 42 | (364.51 µs … 3.68 ms) 795.80 µs ██▄▂ 43 | (536.00 b … 1.30 mb) 70.71 kb ▃█████▄▄▃▂▂▂▁▁▁▁▁▁▁▁▁ 44 | 45 | TypeORM 422.88 µs/iter 432.63 µs █▄ 46 | (346.80 µs … 2.08 ms) 636.26 µs ▆███▄ 47 | (880.00 b … 1.09 mb) 64.45 kb ▂██████▇▆▃▄▃▂▂▂▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /results/node-postgres-single.txt: -------------------------------------------------------------------------------- 1 | clk: ~2.41 GHz 2 | cpu: AMD EPYC 7763 64-Core Processor 3 | runtime: node 22.15.0 (x64-linux) 4 | 5 | benchmark avg (min … max) p75 / p99 (min … top 1%) 6 | ------------------------------------------- ------------------------------- 7 | • PostgreSQL 8 | ------------------------------------------- ------------------------------- 9 | DrizzleORM 437.28 µs/iter 463.25 µs █▃ ▃ 10 | (343.71 µs … 3.28 ms) 707.99 µs ██▂▃█▆▂ 11 | ( 5.16 kb … 993.05 kb) 78.00 kb ▄███████▇▄▄▃▃▃▂▂▂▁▁▁▁ 12 | 13 | KnexJS 363.80 µs/iter 375.05 µs █▆▃▃ 14 | (296.24 µs … 3.50 ms) 543.00 µs ▅████▃ 15 | ( 9.13 kb … 750.88 kb) 44.61 kb ▃███████▇▄▄▃▃▂▂▁▁▁▁▁▁ 16 | 17 | Kysely 314.15 µs/iter 318.77 µs ▃▇█▆▂ 18 | (269.04 µs … 2.39 ms) 457.57 µs █████▃ 19 | ( 2.63 kb … 684.66 kb) 23.20 kb ▅██████▇▄▃▂▃▃▂▂▂▂▂▂▁▁ 20 | 21 | MikroORM 489.04 µs/iter 627.20 µs █ 22 | (49.87 µs … 2.53 ms) 1.23 ms ▃ █▂ 23 | ( 1.89 kb … 1.41 mb) 85.37 kb ▇█▂▁▁▁▁▁▂██▄▅▂▂▁▁▁▁▁▁ 24 | 25 | Pg 252.75 µs/iter 257.23 µs █▆ 26 | (216.31 µs … 2.54 ms) 361.15 µs ▆██▆▃ 27 | ( 11.20 kb … 540.91 kb) 13.54 kb ▁▃█████▆▄▂▂▂▂▂▂▂▁▁▁▁▁ 28 | 29 | PgTyped 280.65 µs/iter 288.67 µs █▂ 30 | (240.70 µs … 2.47 ms) 368.48 µs ▆████▃ 31 | ( 3.36 kb … 847.53 kb) 18.77 kb ▂▆████████▇▄▄▃▂▂▁▁▁▁▁ 32 | 33 | Postgres.js 235.25 µs/iter 242.14 µs ▆▇ █▃ 34 | (190.27 µs … 3.05 ms) 363.47 µs ▃█████▂ 35 | ( 3.13 kb … 626.83 kb) 12.87 kb ▃███████▇▄▃▂▂▂▂▁▁▁▁▁▁ 36 | 37 | Prisma 534.53 µs/iter 537.47 µs █▆ 38 | (488.88 µs … 2.78 ms) 672.42 µs ████▂ 39 | ( 18.76 kb … 478.88 kb) 21.41 kb ▂▇█████▆▃▂▂▂▁▁▁▁▁▁▁▁▁ 40 | 41 | Sequelize 446.90 µs/iter 459.77 µs █▂ 42 | (364.38 µs … 3.16 ms) 757.75 µs ███▅ 43 | ( 5.51 kb … 963.50 kb) 73.35 kb ▃█████▇▄▃▃▂▂▂▂▂▁▁▁▁▁▁ 44 | 45 | TypeORM 418.10 µs/iter 420.65 µs █▄ 46 | (351.58 µs … 3.42 ms) 650.57 µs ████▄ 47 | (912.00 b … 931.19 kb) 64.73 kb ▃█████▅▄▃▃▂▂▂▁▁▁▁▁▁▁▁ 48 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import { createPool } from 'mariadb'; 2 | import postgres from 'postgres'; 3 | import os from 'node:os'; 4 | 5 | const maxConnection = String(process.env.MAX_CONNECTION).toUpperCase(); 6 | 7 | const mySqlConfig = { 8 | host: process.env.MYSQL_HOST ?? 'localhost', 9 | port: Number(process.env.MYSQL_PORT) || 3306, 10 | user: process.env.MYSQL_USER ?? 'mysqltest', 11 | password: process.env.MYSQL_PASSWORD ?? 'mysqltest', 12 | database: process.env.MYSQL_DATABASE ?? 'mysqltest', 13 | connectionLimit: Number(maxConnection) || 1, 14 | }; 15 | 16 | const postgresConfig = { 17 | host: process.env.PG_HOST ?? 'localhost', 18 | port: Number(process.env.PG_PORT) || 5432, 19 | user: process.env.PG_USER ?? 'postgres', 20 | password: process.env.PG_PASSWORD ?? 'postgres', 21 | database: process.env.PG_DATABASE ?? 'postgres', 22 | max: Number(maxConnection) || 1, 23 | }; 24 | 25 | if (maxConnection !== 'DEFAULT') { 26 | if (maxConnection === 'MAX') { 27 | const mysql = createPool(mySqlConfig); 28 | const sql = postgres({ 29 | ...postgresConfig, 30 | max: 1, 31 | }); 32 | 33 | mySqlConfig.connectionLimit = await mysql 34 | .execute('SHOW VARIABLES LIKE "max_connections"') 35 | .then((res) => Math.floor(Number(res[0].Value) * 0.9)); 36 | postgresConfig.max = await sql`SHOW max_connections`.then((res) => 37 | Number(res[0].max_connections) 38 | ); 39 | } else if (maxConnection === 'CPU_COUNT') { 40 | // @ts-ignore 41 | mySqlConfig.connectionLimit = os.availableParallelism(); 42 | postgresConfig.max = mySqlConfig.connectionLimit; 43 | } 44 | } else { 45 | mySqlConfig.connectionLimit = 0; 46 | postgresConfig.max = 0; 47 | } 48 | 49 | export { mySqlConfig, postgresConfig }; 50 | -------------------------------------------------------------------------------- /src/helpers.ts: -------------------------------------------------------------------------------- 1 | type GetUser = (id: number) => Promise; 2 | 3 | export const getUser = async (fun: GetUser) => 4 | await fun(Math.ceil(Math.random() * 2000)); -------------------------------------------------------------------------------- /src/mysql/all.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, afterAll } from 'bun:test'; 2 | import { drizzleClose, drizzleMySqlGetUser } from './drizzle'; 3 | import { knexClose, knexMySqlGetUser } from './knex'; 4 | import { kyselyClose, kyselyMySqlGetUser } from './kysely'; 5 | import { mariadbClose, mariadbGetUser } from './mariadb'; 6 | import { mySql2Close, mySql2GetUser } from './mysql2'; 7 | import { prismaClose, prismaMySqlGetUser } from './prisma'; 8 | import { sequelizeClose, sequelizeMySqlGetUser } from './sequelize'; 9 | import { mikroClose, mikroMySqlGetUser } from './mikro'; 10 | import { typeormClose, typeormMySqlGetUser } from './typeorm'; 11 | 12 | describe('[MySQL] unit tests', () => { 13 | const checkUnit = async (fun: (id: number) => Promise) => { 14 | const user = await fun(1); 15 | expect(user?.id).toBe(1); 16 | }; 17 | 18 | it('DrizzleORM', async () => { 19 | await checkUnit(drizzleMySqlGetUser); 20 | await drizzleClose(); 21 | }); 22 | 23 | it('KnexJS', async () => { 24 | await checkUnit(knexMySqlGetUser); 25 | await knexClose(); 26 | }); 27 | 28 | it('Kysely', async () => { 29 | await checkUnit(kyselyMySqlGetUser); 30 | await kyselyClose(); 31 | }); 32 | 33 | it('Mariadb', async () => { 34 | await checkUnit(mariadbGetUser); 35 | await mariadbClose(); 36 | }); 37 | 38 | it('MikroORM', async () => { 39 | await checkUnit(mikroMySqlGetUser); 40 | await mikroClose(); 41 | }); 42 | 43 | it('MySQL2', async () => { 44 | await checkUnit(mySql2GetUser); 45 | await mySql2Close(); 46 | }); 47 | 48 | it('Prisma', async () => { 49 | await checkUnit(prismaMySqlGetUser); 50 | await prismaClose(); 51 | }); 52 | 53 | it('Sequelize', async () => { 54 | await checkUnit(sequelizeMySqlGetUser); 55 | await sequelizeClose(); 56 | }); 57 | 58 | it('TypeORM', async () => { 59 | await checkUnit(typeormMySqlGetUser); 60 | await typeormClose(); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /src/mysql/drizzle.ts: -------------------------------------------------------------------------------- 1 | import { drizzle } from 'drizzle-orm/mysql2'; 2 | import { createPool } from 'mysql2/promise'; 3 | import { mySqlConfig } from '../config'; 4 | import { mysqlTable, bigint, varchar, time } from 'drizzle-orm/mysql-core'; 5 | import { eq } from 'drizzle-orm'; 6 | 7 | const users = mysqlTable('users', { 8 | id: bigint('id', { mode: 'number' }).primaryKey().autoincrement(), 9 | username: varchar('username', { length: 256 }).notNull(), 10 | email: varchar('email', { length: 256 }).notNull(), 11 | password: varchar('password', { length: 256 }).notNull(), 12 | name: varchar('name', { length: 256 }).notNull(), 13 | createdAt: time('created_at').notNull(), 14 | updatedAt: time('updated_at').notNull(), 15 | deletedAt: time('deleted_at'), 16 | }); 17 | 18 | const { connectionLimit, ...config } = mySqlConfig; 19 | 20 | if (connectionLimit) { 21 | Object.assign(config, { connectionLimit }); 22 | } 23 | 24 | const poolConnection = createPool(config); 25 | 26 | const db = drizzle(poolConnection, { schema: { users }, mode: 'default' }); 27 | 28 | export const drizzleMySqlGetUser = async (id: number) => 29 | await db.query.users.findFirst({ 30 | where: eq(users.id, id), 31 | }); 32 | 33 | export const drizzleClose = () => poolConnection.end(); 34 | -------------------------------------------------------------------------------- /src/mysql/index.ts: -------------------------------------------------------------------------------- 1 | export * from './drizzle'; 2 | export * from './knex'; 3 | export * from './kysely'; 4 | export * from './mariadb'; 5 | export * from './mysql2'; 6 | export * from './prisma'; 7 | export * from './sequelize'; 8 | export * from './mikro'; 9 | export * from './typeorm'; 10 | -------------------------------------------------------------------------------- /src/mysql/knex.ts: -------------------------------------------------------------------------------- 1 | import knex from 'knex'; 2 | import { mySqlConfig } from '../config'; 3 | 4 | const { connectionLimit, ...config } = mySqlConfig; 5 | 6 | const knexConfig: knex.Knex.Config = { 7 | client: 'mysql2', 8 | connection: config, 9 | pool: { min: 0, max: connectionLimit }, 10 | }; 11 | 12 | if (!connectionLimit) { 13 | delete knexConfig.pool; 14 | } 15 | 16 | const db = knex(knexConfig); 17 | 18 | export const knexMySqlGetUser = async (id: number) => 19 | await db.select().from('users').where('id', id).first(); 20 | 21 | export const knexClose = async () => await db.destroy(); 22 | -------------------------------------------------------------------------------- /src/mysql/kysely.ts: -------------------------------------------------------------------------------- 1 | import { ColumnType, Generated, Selectable } from 'kysely'; 2 | import { createPool } from 'mysql2'; 3 | import { Kysely, MysqlDialect } from 'kysely'; 4 | import { mySqlConfig } from '../config'; 5 | 6 | interface Database { 7 | users: UserTable; 8 | } 9 | 10 | interface UserTable { 11 | id: Generated; 12 | username: string; 13 | email: string; 14 | password: string; 15 | name: string; 16 | created_at: ColumnType; 17 | updated_at: ColumnType; 18 | deleted_at: ColumnType | null; 19 | } 20 | 21 | type User = Selectable; 22 | 23 | const { connectionLimit, ...config } = mySqlConfig; 24 | 25 | if (connectionLimit) { 26 | Object.assign(config, { connectionLimit }); 27 | } 28 | 29 | const dialect = new MysqlDialect({ 30 | pool: createPool(config), 31 | }); 32 | 33 | const db = new Kysely({ 34 | dialect, 35 | }); 36 | 37 | export const kyselyMySqlGetUser = async (id: number) => 38 | await db 39 | .selectFrom('users') 40 | .selectAll() 41 | .where('id', '=', id) 42 | .executeTakeFirst(); 43 | 44 | export const kyselyClose = () => db.destroy(); 45 | -------------------------------------------------------------------------------- /src/mysql/mariadb.ts: -------------------------------------------------------------------------------- 1 | import { createPool } from 'mariadb'; 2 | import { mySqlConfig } from '../config'; 3 | 4 | const { connectionLimit, ...config } = mySqlConfig; 5 | 6 | if (connectionLimit) { 7 | Object.assign(config, { connectionLimit }); 8 | } 9 | 10 | const pool = createPool(config); 11 | 12 | export const mariadbGetUser = async (id: number) => 13 | await pool 14 | .execute('SELECT * FROM `users` WHERE id = ?', [id]) 15 | .then((arr) => arr[0]); 16 | 17 | export const mariadbClose = () => pool.end(); 18 | -------------------------------------------------------------------------------- /src/mysql/mikro.ts: -------------------------------------------------------------------------------- 1 | import { MySqlDriver, Options, MikroORM, Entity, PrimaryKey, Property } from '@mikro-orm/mysql'; 2 | import { mySqlConfig } from '../config'; 3 | 4 | @Entity({ 5 | tableName: 'users', 6 | }) 7 | class User { 8 | @PrimaryKey() 9 | id!: number; 10 | 11 | @Property() 12 | username: string; 13 | 14 | @Property() 15 | email: string; 16 | 17 | @Property() 18 | password: string; 19 | 20 | @Property() 21 | name: string; 22 | 23 | @Property() 24 | createdAt: Date = new Date(); 25 | 26 | @Property({ onUpdate: () => new Date() }) 27 | updatedAt: Date = new Date(); 28 | 29 | @Property({ nullable: true }) 30 | deletedAt?: Date; 31 | 32 | constructor(username: string, email: string, password: string, name: string) { 33 | this.username = username; 34 | this.email = email; 35 | this.password = password; 36 | this.name = name; 37 | } 38 | } 39 | 40 | const options: Options = { 41 | entities: [User], 42 | dbName: mySqlConfig.database, 43 | port: mySqlConfig.port, 44 | host: mySqlConfig.host, 45 | user: mySqlConfig.user, 46 | password: mySqlConfig.password, 47 | pool: { 48 | min: 0, 49 | max: mySqlConfig.connectionLimit, 50 | }, 51 | allowGlobalContext: true, 52 | }; 53 | 54 | if (!mySqlConfig.connectionLimit) { 55 | delete options.pool; 56 | } 57 | 58 | const orm = await MikroORM.init(options); 59 | 60 | export const mikroMySqlGetUser = async (id: number) => 61 | await orm.em.findOne(User, { id }); 62 | 63 | export const mikroClose = () => orm.close(); 64 | -------------------------------------------------------------------------------- /src/mysql/mysql2.ts: -------------------------------------------------------------------------------- 1 | import { createPool } from 'mysql2/promise'; 2 | import { mySqlConfig } from '../config'; 3 | 4 | const { connectionLimit, ...config } = mySqlConfig; 5 | 6 | if (connectionLimit) { 7 | Object.assign(config, { connectionLimit }); 8 | } 9 | 10 | const pool = createPool(config); 11 | 12 | export const mySql2GetUser = async (id: number) => 13 | await pool 14 | .execute('SELECT * FROM `users` WHERE id = ?', [id]) 15 | .then(([rows]) => (rows as unknown[])[0]); 16 | 17 | export const mySql2Close = () => pool.end(); 18 | -------------------------------------------------------------------------------- /src/mysql/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client'; 2 | import { mySqlConfig } from '../config'; 3 | 4 | const prismaClientOptions = { 5 | datasourceUrl: mySqlConfig.connectionLimit 6 | ? `${process.env.DATABASE_URL}?connection_limit=${mySqlConfig.connectionLimit}` 7 | : process.env.DATABASE_URL, 8 | }; 9 | 10 | const prisma = new PrismaClient(prismaClientOptions); 11 | 12 | export const prismaMySqlGetUser = async (id: number) => 13 | await prisma.users.findFirst({ 14 | where: { 15 | id, 16 | }, 17 | }); 18 | 19 | export const prismaClose = () => prisma.$disconnect(); 20 | -------------------------------------------------------------------------------- /src/mysql/sequelize.ts: -------------------------------------------------------------------------------- 1 | import { Options, Sequelize, DataTypes, Model } from 'sequelize'; 2 | import { mySqlConfig } from '../config'; 3 | 4 | const { connectionLimit, ...config } = mySqlConfig; 5 | 6 | const options: Options = { 7 | dialect: 'mysql', 8 | host: config.host, 9 | username: config.user, 10 | password: config.password, 11 | port: config.port, 12 | database: config.database, 13 | pool: { 14 | min: 0, 15 | max: connectionLimit, 16 | }, 17 | logging: false, 18 | }; 19 | 20 | if (!connectionLimit) { 21 | delete options.pool; 22 | } 23 | 24 | const sequelize = new Sequelize(options); 25 | 26 | class User extends Model {} 27 | 28 | User.init( 29 | { 30 | id: { 31 | type: DataTypes.INTEGER, 32 | autoIncrement: true, 33 | primaryKey: true, 34 | }, 35 | username: { 36 | type: DataTypes.STRING, 37 | }, 38 | email: { 39 | type: DataTypes.STRING, 40 | }, 41 | password: { 42 | type: DataTypes.STRING, 43 | }, 44 | name: { 45 | type: DataTypes.STRING, 46 | }, 47 | createdAt: { 48 | type: DataTypes.DATE, 49 | }, 50 | updatedAt: { 51 | type: DataTypes.DATE, 52 | }, 53 | deletedAt: { 54 | type: DataTypes.DATE, 55 | allowNull: true, 56 | }, 57 | }, 58 | { sequelize, underscored: true, tableName: 'users' } 59 | ); 60 | 61 | export const sequelizeMySqlGetUser = (id: number) => 62 | User.findOne({ 63 | where: { 64 | id, 65 | }, 66 | }); 67 | 68 | export const sequelizeClose = () => sequelize.close(); 69 | -------------------------------------------------------------------------------- /src/mysql/typeorm.ts: -------------------------------------------------------------------------------- 1 | import { DataSource, Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; 2 | import { mySqlConfig } from '../config'; 3 | import { DataSourceOptions } from 'typeorm/browser'; 4 | 5 | @Entity({ 6 | name: 'users', 7 | }) 8 | class User { 9 | @PrimaryGeneratedColumn() 10 | id!: number; 11 | 12 | @Column() 13 | username!: string; 14 | 15 | @Column() 16 | email!: string; 17 | 18 | @Column() 19 | password!: string; 20 | 21 | @Column() 22 | name!: number; 23 | 24 | @Column({ 25 | name: 'created_at', 26 | }) 27 | createdAt!: Date; 28 | 29 | @Column({ 30 | name: 'updated_at', 31 | }) 32 | updatedAt!: Date; 33 | 34 | @Column({ 35 | name: 'deleted_at', 36 | }) 37 | deletedAt?: Date; 38 | } 39 | 40 | const options: DataSourceOptions = { 41 | type: 'mysql', 42 | host: mySqlConfig.host, 43 | port: mySqlConfig.port, 44 | username: mySqlConfig.user, 45 | password: mySqlConfig.password, 46 | database: mySqlConfig.database, 47 | poolSize: mySqlConfig.connectionLimit, 48 | synchronize: false, 49 | logging: false, 50 | entities: [User], 51 | }; 52 | 53 | if (!options.poolSize) { 54 | // @ts-ignore 55 | delete options.poolSize; 56 | } 57 | 58 | const dataSource = new DataSource(options); 59 | 60 | await dataSource.initialize(); 61 | 62 | export const typeormMySqlGetUser = (id: number) => 63 | dataSource.getRepository(User).findOne({ 64 | where: { 65 | id, 66 | }, 67 | }); 68 | 69 | export const typeormClose = () => dataSource.destroy(); 70 | -------------------------------------------------------------------------------- /src/postgres/all.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'bun:test'; 2 | import { drizzleClose, drizzlePostgreGetUser } from './drizzle'; 3 | import { knexPostgresGetUser, knexClose } from './knex'; 4 | import { kyselyClose, kyselyPostgresGetUser } from './kysely'; 5 | import { mikroClose, mikroPostgresGetUser } from './mikro'; 6 | import { prismaClose, prismaPostgresGetUser } from './prisma'; 7 | import { sequelizeClose, sequelizePostgresGetUser } from './sequelize'; 8 | import { pgClose, pgGetUser } from './pg'; 9 | import { postgresClose, postgresGetUser } from './postgres'; 10 | import { typeormClose, typeormPostgresGetUser } from './typeorm'; 11 | import { pgTypedClose, pgTypedGetUser } from './pg-typed'; 12 | 13 | describe('[PostgreSQL] unit tests', () => { 14 | const checkUnit = async (fun: (id: number) => Promise) => { 15 | const user = await fun(1); 16 | expect(user?.id).toBe(1); 17 | }; 18 | 19 | it('DrizzleORM', async () => { 20 | await checkUnit(drizzlePostgreGetUser); 21 | await drizzleClose(); 22 | }); 23 | 24 | it('KnexJS', async () => { 25 | await checkUnit(knexPostgresGetUser); 26 | await knexClose(); 27 | }); 28 | 29 | it('Kysely', async () => { 30 | await checkUnit(kyselyPostgresGetUser); 31 | await kyselyClose(); 32 | }); 33 | 34 | it('MikroORM', async () => { 35 | await checkUnit(mikroPostgresGetUser); 36 | await mikroClose(); 37 | }); 38 | 39 | it('Pg', async () => { 40 | await checkUnit(pgGetUser); 41 | await pgClose(); 42 | }); 43 | 44 | it('PgTyped', async () => { 45 | await checkUnit(pgTypedGetUser); 46 | await pgTypedClose(); 47 | }); 48 | 49 | it('Postgres.js', async () => { 50 | await checkUnit(postgresGetUser); 51 | await postgresClose(); 52 | }); 53 | 54 | it('Prisma', async () => { 55 | await checkUnit(prismaPostgresGetUser); 56 | await prismaClose(); 57 | }); 58 | 59 | it('Sequelize', async () => { 60 | await checkUnit(sequelizePostgresGetUser); 61 | await sequelizeClose(); 62 | }); 63 | 64 | it('TypeORM', async () => { 65 | await checkUnit(typeormPostgresGetUser); 66 | await typeormClose(); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /src/postgres/drizzle.ts: -------------------------------------------------------------------------------- 1 | import { drizzle } from 'drizzle-orm/node-postgres'; 2 | import pg from 'pg'; 3 | import { postgresConfig } from '../config'; 4 | import { eq } from 'drizzle-orm'; 5 | import { serial, text, pgTable, timestamp } from 'drizzle-orm/pg-core'; 6 | 7 | const users = pgTable('users', { 8 | id: serial('id').primaryKey(), 9 | username: text('username').notNull(), 10 | email: text('email').notNull(), 11 | password: text('password').notNull(), 12 | name: text('name').notNull(), 13 | createdAt: timestamp('created_at').notNull(), 14 | updatedAt: timestamp('updated_at').notNull(), 15 | deletedAt: timestamp('deleted_at'), 16 | }); 17 | 18 | const { max, ...config } = postgresConfig; 19 | 20 | if (max) { 21 | Object.assign(config, { max }); 22 | } 23 | 24 | const pool = new pg.Pool(config); 25 | 26 | const db = drizzle(pool); 27 | 28 | export const drizzlePostgreGetUser = async (id: number) => 29 | await db 30 | .select() 31 | .from(users) 32 | .where(eq(users.id, id)) 33 | .then((arr) => arr[0]); 34 | 35 | export const drizzleClose = () => pool.end(); 36 | -------------------------------------------------------------------------------- /src/postgres/index.ts: -------------------------------------------------------------------------------- 1 | export * from './drizzle'; 2 | export * from './knex'; 3 | export * from './kysely'; 4 | export * from './mikro'; 5 | export * from './pg'; 6 | export * from './pg-typed'; 7 | export * from './postgres'; 8 | export * from './prisma'; 9 | export * from './sequelize'; 10 | export * from './typeorm'; 11 | -------------------------------------------------------------------------------- /src/postgres/knex.ts: -------------------------------------------------------------------------------- 1 | import knex from 'knex'; 2 | import { postgresConfig } from '../config'; 3 | 4 | const { max, ...config } = postgresConfig; 5 | 6 | const knexConfig: knex.Knex.Config = { 7 | client: 'postgres', 8 | connection: config, 9 | pool: { min: 0, max: max }, 10 | }; 11 | 12 | if (!max) { 13 | delete knexConfig.pool; 14 | } 15 | 16 | const db = knex(knexConfig); 17 | 18 | export const knexPostgresGetUser = async (id: number) => 19 | await db.select().from('users').where('id', id).first(); 20 | 21 | export const knexClose = async () => await db.destroy(); 22 | -------------------------------------------------------------------------------- /src/postgres/kysely.ts: -------------------------------------------------------------------------------- 1 | import { ColumnType, Generated, Selectable } from 'kysely'; 2 | import Pool from 'pg-pool'; 3 | import { Kysely, PostgresDialect } from 'kysely'; 4 | import { postgresConfig } from '../config'; 5 | 6 | interface Database { 7 | users: UserTable; 8 | } 9 | 10 | interface UserTable { 11 | id: Generated; 12 | username: string; 13 | email: string; 14 | password: string; 15 | name: string; 16 | created_at: ColumnType; 17 | updated_at: ColumnType; 18 | deleted_at: ColumnType | null; 19 | } 20 | 21 | type User = Selectable; 22 | 23 | const { max, ...config } = postgresConfig; 24 | 25 | if (max) { 26 | Object.assign(config, { max }); 27 | } 28 | 29 | const dialect = new PostgresDialect({ 30 | pool: new Pool(config), 31 | }); 32 | 33 | const db = new Kysely({ 34 | dialect, 35 | }); 36 | 37 | export const kyselyPostgresGetUser = async (id: number) => 38 | await db 39 | .selectFrom('users') 40 | .selectAll() 41 | .where('id', '=', id) 42 | .executeTakeFirst(); 43 | 44 | export const kyselyClose = () => db.destroy(); 45 | -------------------------------------------------------------------------------- /src/postgres/mikro.ts: -------------------------------------------------------------------------------- 1 | import { PostgreSqlDriver, Options, MikroORM, Entity, PrimaryKey, Property } from '@mikro-orm/postgresql'; 2 | import { postgresConfig } from '../config'; 3 | 4 | @Entity({ 5 | tableName: 'users', 6 | }) 7 | class User { 8 | @PrimaryKey() 9 | id!: number; 10 | 11 | @Property() 12 | username: string; 13 | 14 | @Property() 15 | email: string; 16 | 17 | @Property() 18 | password: string; 19 | 20 | @Property() 21 | name: string; 22 | 23 | @Property() 24 | createdAt: Date = new Date(); 25 | 26 | @Property({ onUpdate: () => new Date() }) 27 | updatedAt: Date = new Date(); 28 | 29 | @Property({ nullable: true }) 30 | deletedAt?: Date; 31 | 32 | constructor(username: string, email: string, password: string, name: string) { 33 | this.username = username; 34 | this.email = email; 35 | this.password = password; 36 | this.name = name; 37 | } 38 | } 39 | 40 | const options: Options = { 41 | entities: [User], 42 | dbName: postgresConfig.database, 43 | port: postgresConfig.port, 44 | host: postgresConfig.host, 45 | user: postgresConfig.user, 46 | password: postgresConfig.password, 47 | pool: { 48 | min: 0, 49 | max: postgresConfig.max, 50 | }, 51 | allowGlobalContext: true, 52 | }; 53 | 54 | if (!postgresConfig.max) { 55 | delete options.pool; 56 | } 57 | 58 | const orm = await MikroORM.init(options); 59 | 60 | export const mikroPostgresGetUser = async (id: number) => 61 | await orm.em.findOne(User, { id }); 62 | 63 | export const mikroClose = () => orm.close(); 64 | -------------------------------------------------------------------------------- /src/postgres/pg-typed.ts: -------------------------------------------------------------------------------- 1 | import Pool from 'pg-pool'; 2 | import { postgresConfig } from '../config'; 3 | import { PoolConfig } from 'pg'; 4 | import { findUserById } from './queries.queries'; 5 | 6 | const poolConfig: PoolConfig = postgresConfig; 7 | 8 | if (!poolConfig.max) { 9 | delete poolConfig.max; 10 | } 11 | 12 | const pool = new Pool(poolConfig); 13 | 14 | export const pgTypedGetUser = async (id: number) => { 15 | const client = await pool.connect(); 16 | 17 | return findUserById 18 | .run( 19 | { 20 | id, 21 | }, 22 | client 23 | ) 24 | .then((rows) => rows[0]) 25 | .finally(() => client.release()); 26 | }; 27 | 28 | export const pgTypedClose = async () => await pool.end(); 29 | -------------------------------------------------------------------------------- /src/postgres/pg.ts: -------------------------------------------------------------------------------- 1 | import Pool from 'pg-pool'; 2 | import { postgresConfig } from '../config'; 3 | import { PoolConfig } from 'pg'; 4 | 5 | const poolConfig: PoolConfig = postgresConfig; 6 | 7 | if (!poolConfig.max) { 8 | delete poolConfig.max; 9 | } 10 | 11 | const pool = new Pool(poolConfig); 12 | 13 | export const pgGetUser = async (id: number) => 14 | await pool 15 | .query('SELECT * FROM users WHERE id = $1', [id]) 16 | .then((res) => res.rows[0]); 17 | 18 | export const pgClose = async () => await pool.end(); 19 | -------------------------------------------------------------------------------- /src/postgres/postgres.ts: -------------------------------------------------------------------------------- 1 | import postgres, { Options } from 'postgres'; 2 | import { postgresConfig } from '../config'; 3 | 4 | const options: Options = postgresConfig; 5 | 6 | if (!options.max) { 7 | delete options.max; 8 | } 9 | 10 | const sql = postgres(Object.assign({ transform: postgres.camel }, options)); 11 | 12 | export const postgresGetUser = async (id: number) => 13 | await sql`SELECT * FROM users WHERE id = ${id}`.then((rows) => rows[0]); 14 | 15 | export const postgresClose = async () => await sql.end({ timeout: 1 }); 16 | -------------------------------------------------------------------------------- /src/postgres/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client'; 2 | import { postgresConfig } from '../config'; 3 | 4 | const prismaClientOptions = { 5 | datasourceUrl: postgresConfig.max 6 | ? `${process.env.DATABASE_URL}?connection_limit=${postgresConfig.max}` 7 | : process.env.DATABASE_URL, 8 | }; 9 | 10 | const prisma = new PrismaClient(prismaClientOptions); 11 | 12 | export const prismaPostgresGetUser = async (id: number) => 13 | await prisma.users.findFirst({ 14 | where: { 15 | id, 16 | }, 17 | }); 18 | 19 | export const prismaClose = () => prisma.$disconnect(); 20 | -------------------------------------------------------------------------------- /src/postgres/queries.queries.ts: -------------------------------------------------------------------------------- 1 | /** Types generated for queries found in "src/postgres/queries.sql" */ 2 | import { PreparedQuery } from '@pgtyped/runtime'; 3 | 4 | /** 'FindUserById' parameters type */ 5 | export interface IFindUserByIdParams { 6 | id?: number | null | void; 7 | } 8 | 9 | /** 'FindUserById' return type */ 10 | export interface IFindUserByIdResult { 11 | created_at: Date; 12 | deleted_at: Date | null; 13 | email: string; 14 | id: number; 15 | name: string; 16 | password: string; 17 | updated_at: Date; 18 | username: string; 19 | } 20 | 21 | /** 'FindUserById' query type */ 22 | export interface IFindUserByIdQuery { 23 | params: IFindUserByIdParams; 24 | result: IFindUserByIdResult; 25 | } 26 | 27 | const findUserByIdIR: any = { 28 | usedParamSet: { id: true }, 29 | params: [ 30 | { 31 | name: 'id', 32 | required: false, 33 | transform: { type: 'scalar' }, 34 | locs: [{ a: 31, b: 33 }], 35 | }, 36 | ], 37 | statement: 'SELECT * FROM users WHERE id = :id', 38 | }; 39 | 40 | /** 41 | * Query generated from SQL: 42 | * ``` 43 | * SELECT * FROM users WHERE id = :id 44 | * ``` 45 | */ 46 | export const findUserById = new PreparedQuery< 47 | IFindUserByIdParams, 48 | IFindUserByIdResult 49 | >(findUserByIdIR); 50 | -------------------------------------------------------------------------------- /src/postgres/queries.sql: -------------------------------------------------------------------------------- 1 | /* @name FindUserById */ 2 | SELECT * FROM users WHERE id = :id; -------------------------------------------------------------------------------- /src/postgres/sequelize.ts: -------------------------------------------------------------------------------- 1 | import { Options, Sequelize, DataTypes, Model } from 'sequelize'; 2 | import { postgresConfig } from '../config'; 3 | 4 | const { max, ...config } = postgresConfig; 5 | 6 | const options: Options = { 7 | dialect: 'postgres', 8 | host: config.host, 9 | username: config.user, 10 | password: config.password, 11 | port: config.port, 12 | database: config.database, 13 | pool: { 14 | min: 0, 15 | max, 16 | }, 17 | logging: false, 18 | }; 19 | 20 | if (!max) { 21 | delete options.pool; 22 | } 23 | 24 | const sequelize = new Sequelize(options); 25 | 26 | class User extends Model {} 27 | 28 | User.init( 29 | { 30 | id: { 31 | type: DataTypes.INTEGER, 32 | autoIncrement: true, 33 | primaryKey: true, 34 | }, 35 | username: { 36 | type: DataTypes.STRING, 37 | }, 38 | email: { 39 | type: DataTypes.STRING, 40 | }, 41 | password: { 42 | type: DataTypes.STRING, 43 | }, 44 | name: { 45 | type: DataTypes.STRING, 46 | }, 47 | createdAt: { 48 | type: DataTypes.DATE, 49 | }, 50 | updatedAt: { 51 | type: DataTypes.DATE, 52 | }, 53 | deletedAt: { 54 | type: DataTypes.DATE, 55 | allowNull: true, 56 | }, 57 | }, 58 | { sequelize, underscored: true, tableName: 'users' } 59 | ); 60 | 61 | export const sequelizePostgresGetUser = (id: number) => 62 | User.findOne({ 63 | where: { 64 | id, 65 | }, 66 | }); 67 | 68 | export const sequelizeClose = () => sequelize.close(); 69 | -------------------------------------------------------------------------------- /src/postgres/typeorm.ts: -------------------------------------------------------------------------------- 1 | import { DataSource, Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; 2 | import { postgresConfig } from '../config'; 3 | import { DataSourceOptions } from 'typeorm/browser'; 4 | 5 | @Entity({ 6 | name: 'users', 7 | }) 8 | class User { 9 | @PrimaryGeneratedColumn() 10 | id!: number; 11 | 12 | @Column() 13 | username!: string; 14 | 15 | @Column() 16 | email!: string; 17 | 18 | @Column() 19 | password!: string; 20 | 21 | @Column() 22 | name!: number; 23 | 24 | @Column({ 25 | name: 'created_at', 26 | }) 27 | createdAt!: Date; 28 | 29 | @Column({ 30 | name: 'updated_at', 31 | }) 32 | updatedAt!: Date; 33 | 34 | @Column({ 35 | name: 'deleted_at', 36 | }) 37 | deletedAt?: Date; 38 | } 39 | 40 | const options: DataSourceOptions = { 41 | type: 'postgres', 42 | host: postgresConfig.host, 43 | port: postgresConfig.port, 44 | username: postgresConfig.user, 45 | password: postgresConfig.password, 46 | database: postgresConfig.database, 47 | poolSize: postgresConfig.max, 48 | synchronize: false, 49 | logging: false, 50 | entities: [User], 51 | }; 52 | 53 | if (!options.poolSize) { 54 | // @ts-ignore 55 | delete options.poolSize; 56 | } 57 | 58 | const dataSource = new DataSource(options); 59 | 60 | await dataSource.initialize(); 61 | 62 | export const typeormPostgresGetUser = (id: number) => 63 | dataSource.getRepository(User).findOne({ 64 | where: { 65 | id, 66 | }, 67 | }); 68 | 69 | export const typeormClose = () => dataSource.destroy(); 70 | -------------------------------------------------------------------------------- /src/setup/index.ts: -------------------------------------------------------------------------------- 1 | import * as initMysql from './init-mysql'; 2 | import * as initPostgres from './init-postgres'; 3 | 4 | initMysql; 5 | initPostgres; 6 | -------------------------------------------------------------------------------- /src/setup/init-mysql.ts: -------------------------------------------------------------------------------- 1 | import { createPool } from 'mariadb'; 2 | import { mySqlConfig } from '../config'; 3 | import { users } from './users'; 4 | 5 | const pool = createPool(mySqlConfig); 6 | 7 | await pool.execute('drop table if exists `users`'); 8 | 9 | await pool.execute(` 10 | create table 11 | if not exists \`users\` ( 12 | id int unsigned not null auto_increment primary key, 13 | username varchar(255) not null, 14 | email varchar(255) not null, 15 | password varchar(255) not null, 16 | name varchar(255) not null, 17 | created_at datetime not null default CURRENT_TIMESTAMP, 18 | updated_at datetime not null default CURRENT_TIMESTAMP, 19 | deleted_at datetime null 20 | )`); 21 | 22 | await pool.execute( 23 | 'alter table `users` add index users_username_index (username)' 24 | ); 25 | 26 | await pool.execute('alter table `users` add index users_email_index (email)'); 27 | 28 | const usersLen = users.length; 29 | console.time(`[MySQL] time elapsed for inserting ${usersLen} users`); 30 | await pool.batch( 31 | 'insert into `users`(username, email, password, name) values (?, ?, ?, ?)', 32 | users.map((user) => [user.username, user.email, user.password, user.name]) 33 | ); 34 | console.timeEnd(`[MySQL] time elapsed for inserting ${usersLen} users`); 35 | 36 | await pool 37 | .execute('select count(id) as total from `users`') 38 | .then((res) => console.log(`[MySQL] total users: ${res[0].total}`)); 39 | 40 | await pool.end(); 41 | -------------------------------------------------------------------------------- /src/setup/init-postgres.ts: -------------------------------------------------------------------------------- 1 | import postgres from 'postgres'; 2 | import { postgresConfig } from '../config'; 3 | import { users } from './users'; 4 | 5 | const sql = postgres({ 6 | ...postgresConfig, 7 | max: 1, 8 | onnotice: () => {}, 9 | }); 10 | 11 | await sql`drop table if exists ${sql('users')}`; 12 | 13 | await sql` 14 | create table if not exists 15 | ${sql('users')} ( 16 | "id" serial primary key, 17 | "username" varchar(255) not null, 18 | "email" varchar(255) not null, 19 | "password" varchar(255) not null, 20 | "name" varchar(255) not null, 21 | "created_at" timestamptz not null default CURRENT_TIMESTAMP, 22 | "updated_at" timestamptz not null default CURRENT_TIMESTAMP, 23 | "deleted_at" timestamptz null default null 24 | )`; 25 | 26 | await sql`create index "users_username_index" on ${sql('users')} ("username")`; 27 | 28 | await sql`create index "users_email_index" on ${sql('users')} ("email")`; 29 | 30 | const usersLen = users.length; 31 | console.time(`[PostgreSQL] time elapsed for inserting ${usersLen} users`); 32 | await sql`insert into ${sql.unsafe('users')} ${sql(users)}`; 33 | console.timeEnd(`[PostgreSQL] time elapsed for inserting ${usersLen} users`); 34 | 35 | await sql`select count(id) as total from ${sql('users')}`.then((res) => 36 | console.log(`[PostgreSQL] total users: ${res[0].total}`) 37 | ); 38 | 39 | await sql.end({ timeout: 1 }); 40 | -------------------------------------------------------------------------------- /src/setup/users.ts: -------------------------------------------------------------------------------- 1 | import { generateUsers } from '../utils'; 2 | 3 | console.time('Generate 2000 users'); 4 | export const users = await generateUsers(2000); 5 | console.timeEnd('Generate 2000 users'); -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { faker } from '@faker-js/faker'; 2 | import Bun from 'bun'; 3 | 4 | export const createRandomUser = async () => ({ 5 | username: faker.internet.username(), 6 | email: faker.internet.email(), 7 | password: await Bun.password.hash(faker.internet.password()), 8 | name: faker.person.fullName(), 9 | }); 10 | 11 | export const generateUsers = async (n = 5000) => { 12 | const arr = new Array(n); 13 | for (let i = 0; i < n; i++) { 14 | arr[i] = createRandomUser(); 15 | } 16 | return Promise.all(arr); 17 | }; 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ESNext"], 4 | "module": "esnext", 5 | "target": "esnext", 6 | "moduleResolution": "bundler", 7 | "moduleDetection": "force", 8 | "allowImportingTsExtensions": true, 9 | "noEmit": true, 10 | "composite": true, 11 | "strict": true, 12 | "downlevelIteration": true, 13 | "skipLibCheck": true, 14 | "jsx": "react-jsx", 15 | "allowSyntheticDefaultImports": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "allowJs": true, 18 | "types": [ 19 | "bun-types" // add Bun global 20 | ], 21 | "experimentalDecorators": true, 22 | "emitDecoratorMetadata": true, 23 | "esModuleInterop": true 24 | }, 25 | "include": ["**/*"], 26 | "exclude": ["node_modules/*"], 27 | "extends": "./node_modules/@tsconfig/node16/tsconfig.json", 28 | "ts-node": { 29 | "esm": true, 30 | "transpileOnly": true, 31 | "experimentalSpecifierResolution": "node" 32 | } 33 | } 34 | --------------------------------------------------------------------------------