{"id":30172871,"url":"https://github.com/stacksjs/bun-query-builder","last_synced_at":"2026-04-13T06:02:51.213Z","repository":{"id":309408610,"uuid":"1036162204","full_name":"stacksjs/bun-query-builder","owner":"stacksjs","description":"A safe, performant \u0026 fully-typed query builder for Bun.","archived":false,"fork":false,"pushed_at":"2026-04-11T08:19:26.000Z","size":33795,"stargazers_count":9,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-11T08:23:31.486Z","etag":null,"topics":["bun","javascript","mysql","postgres","query-builder","sqlite","typescript"],"latest_commit_sha":null,"homepage":"https://bun-query-builder.netlify.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stacksjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["stacksjs","chrisbbreuer"],"open_collective":"stacksjs"}},"created_at":"2025-08-11T16:42:46.000Z","updated_at":"2026-04-10T09:53:10.000Z","dependencies_parsed_at":"2025-08-11T19:34:31.026Z","dependency_job_id":"6e3922dc-2826-4624-8fbb-a18ceca982f0","html_url":"https://github.com/stacksjs/bun-query-builder","commit_stats":null,"previous_names":["stacksjs/bun-query-builder"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/stacksjs/bun-query-builder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fbun-query-builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fbun-query-builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fbun-query-builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fbun-query-builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stacksjs","download_url":"https://codeload.github.com/stacksjs/bun-query-builder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fbun-query-builder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31741541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T05:13:27.074Z","status":"ssl_error","status_checked_at":"2026-04-13T05:13:25.150Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","javascript","mysql","postgres","query-builder","sqlite","typescript"],"created_at":"2025-08-11T23:17:58.567Z","updated_at":"2026-04-13T06:02:51.201Z","avatar_url":"https://github.com/stacksjs.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\u003cimg src=\".github/art/cover.jpg\" alt=\"Social Card of this repo\"\u003e\u003c/p\u003e\n\n[![npm version][npm-version-src]][npm-version-href]\n[![GitHub Actions][github-actions-src]][github-actions-href]\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\u003c!-- [![npm downloads][npm-downloads-src]][npm-downloads-href] --\u003e\n\u003c!-- [![Codecov][codecov-src]][codecov-href] --\u003e\n\n# bun-query-builder\n\nFully-typed, model-driven Query Builder for Bun’s native `sql`.\n\nDefine your data model once and get a type-safe query experience _(a la Kysely/Laravel)_, powered by Bun’s tagged templates for safety and performance.\n\n## Features\n\n### Core Query Building\n\n- **Typed from Models**: Infer tables/columns/PKs from your model files; `selectFrom('users')` and `where({ active: true })` are typed.\n- **Fluent Builder**: `select/insert/update/delete`, `where/andWhere/orWhere`, `join/leftJoin/rightJoin/crossJoin`, `groupBy/having`, `union/unionAll`.\n- **Aggregations**: `count()`, `avg()`, `sum()`, `max()`, `min()` with full type safety.\n- **Batch Operations**: `insertMany()`, `updateMany()`, `deleteMany()` for efficient bulk operations.\n\n### Advanced Features\n\n- **Relations**: `with(...)`, `withCount(...)`, `whereHas(...)`, `has()`, `doesntHave()`, `selectAllRelations()` with configurable aliasing and constraint callbacks.\n- **Query Scopes**: Define reusable query constraints on models for cleaner, more maintainable code.\n- **Query Caching**: Built-in LRU cache with TTL support via `cache(ttlMs)`, `clearQueryCache()`, `setQueryCacheMaxSize()`.\n- **Model Hooks**: Lifecycle events - `beforeCreate`, `afterCreate`, `beforeUpdate`, `afterUpdate`, `beforeDelete`, `afterDelete`.\n\n### Utilities \u0026 Helpers\n\n- **Utilities**: `distinct/distinctOn`, `orderByDesc/latest/oldest/inRandomOrder`, `whereColumn/whereRaw/groupByRaw/havingRaw`, JSON/date helpers.\n- **Pagination**: `paginate`, `simplePaginate`, `cursorPaginate`, plus `chunk/chunkById/eachById`.\n- **Soft Deletes**: `withTrashed()`, `onlyTrashed()` for logical deletion support.\n\n### Database Operations\n\n- **Transactions**: `transaction` with retries/backoff/isolation/onRetry/afterCommit; `savepoint`; distributed tx helpers.\n- **Migrations**: Generate and execute migrations from models with full diff support.\n- **Seeders**: Database seeding with fake data generation via `ts-mocker` (faker alternative).\n- **Raw Queries**: Tagged templates and parameterized queries with `raw()` and `unsafe()`.\n\n### Configuration \u0026 Integration\n\n- **Configurable**: Dialect hints, timestamps, alias strategies, relation FK formats, JSON mode, random function, shared lock syntax.\n- **Bun API passthroughs**: `unsafe`, `file`, `simple`, pool `reserve/release`, `close`, `ping/waitForReady`.\n- **CLI**: Introspection, query printing, connectivity checks, file/unsafe execution, explain.\n\n\u003e Note: LISTEN/NOTIFY and COPY helpers are scaffolded and will be wired as Bun exposes native APIs.\n\n## Get Started\n\n### Installation\n\n```bash\nbun add bun-query-builder\n```\n\n### Usage\n\n```ts\nimport { buildDatabaseSchema, buildSchemaMeta, createQueryBuilder } from 'bun-query-builder'\n\n// Load or define your model files (see docs for model shape)\nconst models = {\n  User: { name: 'User', table: 'users', primaryKey: 'id', attributes: { id: { validation: { rule: {} } }, name: { validation: { rule: {} } }, active: { validation: { rule: {} } } } },\n} as const\n\nconst schema = buildDatabaseSchema(models as any)\nconst meta = buildSchemaMeta(models as any)\nconst db = createQueryBuilder\u003ctypeof schema\u003e({ schema, meta })\n\n// Fully-typed query\nconst q = db\n  .selectFrom('users')\n  .where({ active: true })\n  .orderBy('created_at', 'desc')\n  .limit(10)\n\nconst rows = await q.execute()\n```\n\n### Aggregations\n\n```ts\n// Get average age of active users\nconst avgAge = await db.selectFrom('users')\n  .where({ active: true })\n  .avg('age')\n\n// Count total posts\nconst totalPosts = await db.selectFrom('posts').count()\n\n// Get max and min scores\nconst maxScore = await db.selectFrom('users').max('score')\nconst minScore = await db.selectFrom('users').min('score')\n```\n\n### Batch Operations\n\n```ts\n// Insert multiple records at once\nawait db.insertMany('users', [\n  { name: 'Alice', email: 'alice@example.com' },\n  { name: 'Bob', email: 'bob@example.com' },\n  { name: 'Charlie', email: 'charlie@example.com' },\n])\n\n// Update multiple records matching conditions\nawait db.updateMany('users', { verified: false }, { status: 'pending' })\n\n// Delete multiple records by IDs\nawait db.deleteMany('users', [1, 2, 3, 4, 5])\n```\n\n### Query Caching\n\n```ts\n// Cache query results for 60 seconds (default)\nconst users = await db.selectFrom('users')\n  .where({ active: true })\n  .cache()\n  .get()\n\n// Custom cache TTL (5 seconds)\nconst posts = await db.selectFrom('posts')\n  .orderBy('created_at', 'desc')\n  .limit(10)\n  .cache(5000)\n  .get()\n\n// Clear all cached queries\nclearQueryCache()\n\n// Configure cache size\nsetQueryCacheMaxSize(500)\n```\n\n### Model Hooks\n\n```ts\nconst db = createQueryBuilder\u003ctypeof schema\u003e({\n  schema,\n  meta,\n  hooks: {\n    beforeCreate: async ({ table, data }) =\u003e {\n      console.log(`Creating ${table}:`, data)\n      // Modify data, validate, or throw to prevent creation\n    },\n    afterCreate: async ({ table, data, result }) =\u003e {\n      console.log(`Created ${table}:`, result)\n      // Trigger notifications, update caches, etc.\n    },\n    beforeUpdate: async ({ table, data, where }) =\u003e {\n      // Audit logging, validation, etc.\n    },\n    afterUpdate: async ({ table, data, where, result }) =\u003e {\n      // Clear related caches, send webhooks, etc.\n    },\n    beforeDelete: async ({ table, where }) =\u003e {\n      // Prevent deletion, check constraints, etc.\n    },\n    afterDelete: async ({ table, where, result }) =\u003e {\n      // Clean up related data, update aggregates, etc.\n    },\n  }\n})\n```\n\n### Query Scopes\n\n```ts\n// Define scopes on your models\nconst User = {\n  name: 'User',\n  table: 'users',\n  scopes: {\n    active: (qb) =\u003e qb.where({ status: 'active' }),\n    verified: (qb) =\u003e qb.where({ email_verified_at: ['IS NOT', null] }),\n    premium: (qb) =\u003e qb.where({ subscription: 'premium' }),\n  },\n  // ... other model properties\n}\n\n// Use scopes in queries\nconst activeUsers = await db.selectFrom('users')\n  .scope('active')\n  .scope('verified')\n  .get()\n```\n\n### Relations with Constraints\n\n```ts\n// Eager load with constraints\nconst users = await db.selectFrom('users')\n  .with({\n    posts: (qb) =\u003e qb.where('published', '=', true).orderBy('created_at', 'desc')\n  })\n  .get()\n\n// Check for related records\nconst usersWithPosts = await db.selectFrom('users')\n  .has('posts')\n  .get()\n\n// Query by relationship existence\nconst activeAuthors = await db.selectFrom('users')\n  .whereHas('posts', (qb) =\u003e qb.where('published', '=', true))\n  .get()\n```\n\n## Migrations\n\nGenerate and execute migrations from your models:\n\n```ts\nimport { generateMigration, executeMigration } from 'bun-query-builder'\n\n// Generate migration from models directory\nconst migration = await generateMigration('./models', {\n  dialect: 'postgres',\n  apply: true,\n  full: true\n})\n\n// Execute the migration\nawait executeMigration(migration)\n```\n\n## Database Seeding\n\nPopulate your database with test data using seeders powered by [ts-mocker](https://github.com/stacksjs/ts-mocker):\n\n### Creating a Seeder\n\n```bash\n# Generate a new seeder\nbun qb make:seeder User\n\n# This creates database/seeders/UserSeeder.ts\n```\n\n### Writing a Seeder\n\n```ts\nimport { Seeder } from 'bun-query-builder'\nimport { faker } from 'ts-mocker'\n\nexport default class UserSeeder extends Seeder {\n  async run(qb: any): Promise\u003cvoid\u003e {\n    // Generate 50 users with realistic fake data\n    const users = Array.from({ length: 50 }, () =\u003e ({\n      name: faker.person.fullName(),\n      email: faker.internet.email(),\n      age: faker.number.int(18, 80),\n      role: faker.helpers.arrayElement(['admin', 'user', 'moderator']),\n      created_at: new Date(),\n      updated_at: new Date(),\n    }))\n\n    await qb.table('users').insert(users).execute()\n  }\n\n  // Control execution order (lower runs first)\n  get order(): number {\n    return 10 // Default is 100\n  }\n}\n```\n\n### Running Seeders\n\n```bash\n# Run all seeders\nbun qb seed\nbun qb db:seed\n\n# Run a specific seeder\nbun qb seed --class UserSeeder\n\n# Drop all tables, re-run migrations and seed\nbun qb db:fresh\n```\n\n### Programmatic Usage\n\n```ts\nimport { runSeeders, runSeeder } from 'bun-query-builder'\n\n// Run all seeders\nawait runSeeders({\n  seedersDir: './database/seeders',\n  verbose: true\n})\n\n// Run specific seeder\nawait runSeeder('UserSeeder', { verbose: true })\n```\n\n### CLI\n\n```bash\n# Model Generation\nquery-builder make:model User\nquery-builder make:model Post --table=blog_posts\nquery-builder model:show User                   # Show detailed model info\n\n# Schema Introspection\nquery-builder introspect ./app/Models --verbose\nquery-builder sql ./app/Models users --limit 5\n\n# Migrations\nquery-builder migrate ./app/Models --dialect postgres\nquery-builder migrate:generate                  # Generate migration from drift\nquery-builder migrate:status                    # Show migration status\nquery-builder migrate:list                      # List all migrations\nquery-builder migrate:rollback --steps 2        # Rollback migrations\nquery-builder migrate:fresh ./app/Models\nquery-builder reset ./app/Models\n\n# Database Info\nquery-builder db:info                           # Show database statistics\nquery-builder db:stats                          # Alias for db:info\nquery-builder inspect users                     # Inspect table structure\nquery-builder table:info users                  # Alias for inspect\nquery-builder db:wipe --force                   # Drop all tables\nquery-builder db:optimize                       # Optimize database (VACUUM, ANALYZE)\nquery-builder db:optimize --aggressive          # Aggressive optimization\n\n# Interactive Console\nquery-builder console                           # Start REPL\nquery-builder tinker                            # Alias for console\n\n# Seeders\nquery-builder make:seeder User\nquery-builder seed\nquery-builder db:seed --class UserSeeder\nquery-builder db:fresh\n\n# Data Management\nquery-builder export users --format json\nquery-builder export users --format csv --output users.csv\nquery-builder import users users.json --truncate\nquery-builder dump --tables users,posts\n\n# Cache Management\nquery-builder cache:clear\nquery-builder cache:stats\nquery-builder cache:config --size 500\n\n# Performance\nquery-builder benchmark --iterations 1000\nquery-builder benchmark --operations select,insert\nquery-builder query:explain-all ./queries        # Batch EXPLAIN analysis\n\n# Schema Validation\nquery-builder validate:schema ./app/Models\nquery-builder check                             # Alias for validate:schema\n\n# Connectivity\nquery-builder ping\nquery-builder wait-ready --attempts 30 --delay 250\n\n# Execute SQL\nquery-builder file ./migrations/seed.sql\nquery-builder unsafe \"SELECT * FROM users WHERE id = $1\" --params \"[1]\"\nquery-builder explain \"SELECT * FROM users WHERE active = true\"\n\n# Diagrams \u0026 Visualization\nquery-builder relation:diagram                   # Generate Mermaid ER diagram\nquery-builder relation:diagram --format dot     # Generate Graphviz DOT\nquery-builder relation:diagram --output schema.mmd\n```\n\n## Performance\n\nBenchmarked on Apple M3 Pro, Bun 1.3.11, SQLite with 1,000 users and 5,000 posts. Kysely uses the official [`kysely-bun-sqlite`](https://github.com/nicksrandall/kysely-bun-sqlite) adapter.\n\n### Basic Queries\n\n| Benchmark | bun-query-builder | Kysely | Drizzle | Prisma |\n|-----------|------------------:|-------:|--------:|-------:|\n| SELECT: Find by ID | **8.3 µs** | 15.4 µs | 42.1 µs | 86.0 µs |\n| SELECT: Active users | **221 µs** | 233 µs | 466 µs | 3,040 µs |\n| SELECT: With LIMIT | **9.2 µs** | 19.3 µs | 41.2 µs | 106 µs |\n| SELECT: COUNT | **6.8 µs** | 30.0 µs | 32.6 µs | 81.4 µs |\n| INSERT: Single | **439 µs** | 558 µs | 472 µs | 657 µs |\n| UPDATE: Single | **8.3 µs** | 13.4 µs | 22.8 µs | 123 µs |\n| DELETE: Single | **7.5 µs** | 11.9 µs | 16.7 µs | 55 µs |\n\n### Advanced Queries\n\n| Benchmark | bun-query-builder | Kysely | Drizzle | Prisma |\n|-----------|------------------:|-------:|--------:|-------:|\n| JOIN: Users with posts | **28.1 µs** | 44.3 µs | 83.2 µs | 1,560 µs |\n| AGGREGATE: Average age | **29.3 µs** | 39.8 µs | 39.2 µs | 91.8 µs |\n| WHERE: Complex conditions | **98.7 µs** | 110 µs | 212 µs | 1,060 µs |\n| ORDER BY + LIMIT | **264 µs** | 313 µs | 337 µs | 511 µs |\n| GROUP BY + HAVING | **616 µs** | 625 µs | 779 µs | 1,740 µs |\n\n### Batch Operations\n\n| Benchmark | bun-query-builder | Kysely | Drizzle | Prisma |\n|-----------|------------------:|-------:|--------:|-------:|\n| INSERT MANY: 100 users | **704 µs** | 1,080 µs | 1,380 µs | 1,410 µs |\n| UPDATE MANY | **11.0 ms** | 10.8 ms | 10.7 ms | 11.9 ms |\n| DELETE MANY: By IDs | **15.5 µs** | 22.4 µs | 33.8 µs | 69.0 µs |\n| SELECT: 1000 rows | **248 µs** | 271 µs | 562 µs | 3,440 µs |\n\nLowest time per benchmark is **bolded**. bun-query-builder wins 16 of 16 benchmarks. [Full benchmark details →](./packages/benchmark/README.md)\n\n## Testing\n\n```bash\nbun test\n```\n\n## Changelog\n\nPlease see our [releases](https://github.com/stackjs/bun-query-builder/releases) page for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.\n\n## Community\n\nFor help, discussion about best practices, or any other conversation that would benefit from being searchable:\n\n[Discussions on GitHub](https://github.com/stacksjs/ts-starter/discussions)\n\nFor casual chit-chat with others using this package:\n\n[Join the Stacks Discord Server](https://discord.gg/stacksjs)\n\n## Postcardware\n\n“Software that is free, but hopes for a postcard.” We love receiving postcards from around the world showing where Stacks is being used! We showcase them on our website too.\n\nOur address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎\n\n## Sponsors\n\nWe would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.\n\n- [JetBrains](https://www.jetbrains.com/)\n- [The Solana Foundation](https://solana.com/)\n\n## License\n\nThe MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information.\n\nMade with 💙\n\n\u003c!-- Badges --\u003e\n[npm-version-src]: https://img.shields.io/npm/v/bun-query-builder?style=flat-square\n[npm-version-href]: https://npmjs.com/package/bun-query-builder\n[github-actions-src]: https://img.shields.io/github/actions/workflow/status/stacksjs/ts-starter/ci.yml?style=flat-square\u0026branch=main\n[github-actions-href]: https://github.com/stacksjs/ts-starter/actions?query=workflow%3Aci\n\n\u003c!-- [codecov-src]: https://img.shields.io/codecov/c/gh/stacksjs/ts-starter/main?style=flat-square\n[codecov-href]: https://codecov.io/gh/stacksjs/ts-starter --\u003e\n","funding_links":["https://github.com/sponsors/stacksjs","https://github.com/sponsors/chrisbbreuer","https://opencollective.com/stacksjs"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstacksjs%2Fbun-query-builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstacksjs%2Fbun-query-builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstacksjs%2Fbun-query-builder/lists"}