{"_id":"@apinecka/drizzle","_rev":"2-54d7c454f95488f954a33f1128a119e1","name":"@apinecka/drizzle","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@apinecka/drizzle","version":"1.0.0","keywords":["nestjs","drizzle","drizzle-orm","postgres","postgresql"],"author":{"name":"Tomáš Cupák","email":"tomcupak@gmail.com"},"license":"MIT","_id":"@apinecka/drizzle@1.0.0","maintainers":[{"name":"tomcupak","email":"tomcupak@gmail.com"}],"homepage":"https://github.com/tomcupak/apinecka-libs/tree/master/libs/drizzle#readme","bugs":{"url":"https://github.com/tomcupak/apinecka-libs/issues"},"dist":{"shasum":"289ef2d6a8bc939b7361c92c2bc67f5e9cea4c6c","tarball":"https://registry.npmjs.org/@apinecka/drizzle/-/drizzle-1.0.0.tgz","fileCount":25,"integrity":"sha512-HLXzHkhpPfkfI9UD1cVK0iluODqcXYtCaTGPA0/PNDHwz/rm6hv3rdG65qAWKmpu3BYaaBNLJiP1gjd1V9HGrw==","signatures":[{"sig":"MEYCIQCmqh3gEyBRv8N9gTyMofM4Qocvtzp+xGTlsAoJIISsSwIhAMMtw9zqSjX2AVB37Y1j2R/5O3BqNcCM6XUDEv9v4AnJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":237168},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","default":"./dist/testing/index.js"}},"gitHead":"98edf21044238a08e2ae6047c72930dead79a240","scripts":{"build":"tsc","clean":"del-cli dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"tomcupak","email":"tomcupak@gmail.com"},"repository":{"url":"git+https://github.com/tomcupak/apinecka-libs.git","type":"git","directory":"libs/drizzle"},"_npmVersion":"11.6.1","description":"NestJS module for Drizzle ORM over Postgres: a DI-friendly connection wrapper, a lock-coordinated migration runner, and test-database helpers. Bring your own schema.","directories":{},"_nodeVersion":"24.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.16.2","del-cli":"^7.0.0","@types/pg":"^8.11.10","typescript":"^5.8.3","@types/node":"^22.15.33","drizzle-orm":"^0.45.2","@nestjs/core":"^11.1.7","@nestjs/common":"^11.1.7","@nestjs/testing":"^11.1.7","reflect-metadata":"^0.2.2"},"peerDependencies":{"pg":"^8.16","drizzle-orm":"^0.45","@nestjs/common":"^11.0.0"},"_npmOperationalInternal":{"tmp":"tmp/drizzle_1.0.0_1786382345052_0.25621311358188725","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@apinecka/drizzle","version":"1.1.0","description":"NestJS module for Drizzle ORM over Postgres: a DI-friendly connection wrapper, a lock-coordinated migration runner, and test-database helpers. Bring your own schema.","keywords":["nestjs","drizzle","drizzle-orm","postgres","postgresql"],"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","default":"./dist/testing/index.js"}},"scripts":{"build":"tsc","clean":"del-cli dist","prepublishOnly":"npm run clean && npm run build"},"author":{"name":"Tomáš Cupák","email":"tomcupak@gmail.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/tomcupak/apinecka-libs.git","directory":"libs/drizzle"},"homepage":"https://github.com/tomcupak/apinecka-libs/tree/master/libs/drizzle#readme","bugs":{"url":"https://github.com/tomcupak/apinecka-libs/issues"},"publishConfig":{"access":"public"},"peerDependencies":{"@nestjs/common":"^11.0.0","drizzle-orm":"^0.45","pg":"^8.16"},"devDependencies":{"@nestjs/common":"^11.1.7","@nestjs/core":"^11.1.7","@nestjs/testing":"^11.1.7","@types/node":"^22.15.33","@types/pg":"^8.11.10","del-cli":"^7.0.0","drizzle-orm":"^0.45.2","pg":"^8.16.2","reflect-metadata":"^0.2.2","typescript":"^5.8.3"},"gitHead":"cc8e721adb3bf2e60c2ae046afdb902f7b7519e0","_id":"@apinecka/drizzle@1.1.0","_nodeVersion":"24.10.0","_npmVersion":"11.6.1","dist":{"integrity":"sha512-lRKI4x8pWhCBYgEC0ZYAydjvObL6nXDKRoB2XO59AhmnSMY+D1jEpZed+aTFr+HNevFLIY36elsiDPrxDXkbig==","shasum":"7a1df839080f9c8a72ab5b4a17f3f2a3d0ce975d","tarball":"https://registry.npmjs.org/@apinecka/drizzle/-/drizzle-1.1.0.tgz","fileCount":25,"unpackedSize":239694,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCVobtIh+3Qw8DM+I9s+Ektdxawdn1wAiy7hgLJrx8EtgIhAJjj3UGSYpcSJCkkLbXxnwFYxlHvOyC7+7abjhV1PYZ1"}]},"_npmUser":{"name":"tomcupak","email":"tomcupak@gmail.com"},"directories":{},"maintainers":[{"name":"tomcupak","email":"tomcupak@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/drizzle_1.1.0_1788503098874_0.6428271207142844"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-10T17:19:04.862Z","modified":"2026-09-04T06:24:59.190Z","1.0.0":"2026-08-10T17:19:05.204Z","1.1.0":"2026-09-04T06:24:59.018Z"},"bugs":{"url":"https://github.com/tomcupak/apinecka-libs/issues"},"author":{"name":"Tomáš Cupák","email":"tomcupak@gmail.com"},"license":"MIT","homepage":"https://github.com/tomcupak/apinecka-libs/tree/master/libs/drizzle#readme","keywords":["nestjs","drizzle","drizzle-orm","postgres","postgresql"],"repository":{"type":"git","url":"git+https://github.com/tomcupak/apinecka-libs.git","directory":"libs/drizzle"},"description":"NestJS module for Drizzle ORM over Postgres: a DI-friendly connection wrapper, a lock-coordinated migration runner, and test-database helpers. Bring your own schema.","maintainers":[{"name":"tomcupak","email":"tomcupak@gmail.com"}],"readme":"# @apinecka/drizzle\n\nNestJS module for [`drizzle-orm`](https://www.npmjs.com/package/drizzle-orm) over Postgres\n(via [`pg`](https://www.npmjs.com/package/pg)): a DI-friendly connection wrapper\n(`DrizzleModule`), a lock-coordinated migration runner (`migrateDb`), and test-database helpers.\n\nThis package ships **no schema**. You write your Drizzle schema and migrations the normal way\n(`drizzle-kit`) and register them with `DrizzleModule` yourself - see\n[Schema registration](#schema-registration) below.\n\n## Install\n\n```bash\nnpm install @apinecka/drizzle drizzle-orm pg @nestjs/common\n```\n\n## Usage\n\n```ts\nimport { DrizzleModule } from '@apinecka/drizzle'\nimport * as schema from './schema'\n\n@Module({\n\timports: [\n\t\tDrizzleModule.forRoot({\n\t\t\tcredentials: { host: 'localhost', port: 5432, user: 'postgres', password: 'postgres', database: 'app' },\n\t\t\tschema,\n\t\t}),\n\t],\n})\nexport class AppModule {}\n```\n\n```ts\nimport { DrizzleProvider } from '@apinecka/drizzle'\nimport * as schema from './schema'\n\n@Injectable()\nexport class UsersService {\n\tconstructor(private db: DrizzleProvider<typeof schema>) {}\n\n\tfindAll() {\n\t\treturn this.db.main.select().from(schema.users)\n\t}\n}\n```\n\n`DrizzleProvider` is injectable by type - no `@Inject()` decorator or DI token needed. It exposes\na single connection under `main`, populated once Nest calls `onApplicationBootstrap()` during\nstartup - so don't read it from your own services' constructors or `onModuleInit()`, which run\nearlier.\n\nIt also ends its connection pool for you on `onModuleDestroy()`, which Nest calls automatically\nwhen the app (or a `TestingModule`) is closed - `app.close()` in production (paired with\n`app.enableShutdownHooks()` to run it on `SIGTERM`/`SIGINT` too), `moduleRef.close()` in tests. No\nmanual cleanup needed; call `provider.close()` directly only if you need to end the pool without\ntearing down the whole module.\n\n## Schema registration\n\n`DrizzleProvider` deliberately stays a single, small class: one connection named `main`. You're\nnot meant to configure it further - copy it instead. It's a handful of lines, and copying keeps\nevery app's DB wiring equally easy to read instead of hiding behind options.\n\n**Want the connection under a different name than `main`?** Write your own provider (matching\n`DrizzleProvider`'s constructor) and pass it to `forRoot()`:\n\n```ts\n// db.provider.ts\nimport { closeDb, DrizzleCredentials, getDb } from '@apinecka/drizzle'\nimport { Injectable, OnModuleDestroy } from '@nestjs/common'\nimport { NodePgDatabase } from 'drizzle-orm/node-postgres'\n\nimport * as schema from './schema'\n\n@Injectable()\nexport class DbProvider implements OnModuleDestroy {\n\tprimary!: NodePgDatabase<typeof schema>\n\n\tconstructor(private config: { credentials: DrizzleCredentials; schema: typeof schema }) {}\n\n\tasync onApplicationBootstrap() {\n\t\tthis.primary = await getDb(this.config)\n\t}\n\n\tasync onModuleDestroy() {\n\t\tawait closeDb(this.primary)\n\t}\n}\n```\n\n```ts\n// app.module.ts\nimport { DrizzleModule } from '@apinecka/drizzle'\n\nimport { DbProvider } from './db.provider'\nimport * as schema from './schema'\n\n@Module({\n\timports: [DrizzleModule.forRoot({ credentials, schema, provider: DbProvider })],\n})\nexport class AppModule {}\n```\n\nYour own provider is responsible for its own cleanup, same as `DrizzleProvider` - `getDb()`'s\nresult carries its underlying `pg` `Pool` as `$client`, and `closeDb()` is just `db.$client.end()`.\n\n**Need more than one database** (a second, unrelated database, or a read-only replica)? Copy\n`DrizzleProvider` and add one property + one `getDb()` call per connection in\n`onApplicationBootstrap()` - `DrizzleModule.forRoot()` won't fit anymore since it only wires up a\nsingle `{ credentials, schema }`, so pair it with your own tiny module too (copied from\n`DrizzleModule`):\n\n```ts\n// db.provider.ts\nimport { DrizzleCredentials, getDb } from '@apinecka/drizzle'\nimport { Injectable } from '@nestjs/common'\nimport { NodePgDatabase } from 'drizzle-orm/node-postgres'\n\nimport * as schema from './schema'\n\nexport interface DbProviderConfig {\n\tmain: DrizzleCredentials\n\tmainReadOnly: DrizzleCredentials\n\tlogs: DrizzleCredentials\n}\n\n@Injectable()\nexport class DbProvider {\n\tmain!: NodePgDatabase<typeof schema>\n\tmainReadOnly!: NodePgDatabase<typeof schema>\n\tlogs!: NodePgDatabase<typeof schema>\n\n\tconstructor(private config: DbProviderConfig) {}\n\n\tasync onApplicationBootstrap() {\n\t\tthis.main = await getDb({ credentials: this.config.main, schema })\n\t\tthis.mainReadOnly = await getDb({ credentials: this.config.mainReadOnly, schema })\n\t\tthis.logs = await getDb({ credentials: this.config.logs, schema })\n\t}\n}\n```\n\n```ts\n// db.module.ts\nimport { DynamicModule, Module } from '@nestjs/common'\n\nimport { DbProvider, DbProviderConfig } from './db.provider'\n\n@Module({})\nexport class DbModule {\n\tstatic forRoot(config: DbProviderConfig): DynamicModule {\n\t\treturn {\n\t\t\tmodule: DbModule,\n\t\t\tproviders: [{ provide: DbProvider, useFactory: () => new DbProvider(config) }],\n\t\t\texports: [DbProvider],\n\t\t\tglobal: true,\n\t\t}\n\t}\n}\n```\n\n```ts\n@Injectable()\nexport class UsersService {\n\tconstructor(private db: DbProvider) {}\n\n\tfindAll() {\n\t\treturn this.db.main.select().from(schema.users)\n\t}\n}\n```\n\n## Migrations\n\n### Generating a migration\n\nMigrations are generated by the `drizzle-kit` CLI from your schema - install it as a dev\ndependency (`npm install -D drizzle-kit`) and give it its own config, separate from anything in\nthis package (`drizzle-kit` doesn't know about NestJS or `DrizzleModule` at all - it just diffs\nyour schema against the last generated migration):\n\n```ts\n// drizzle.config.ts - [development ONLY], next to your schema.ts\nimport type { Config } from 'drizzle-kit'\n\nexport default {\n\tschema: './schema.ts',\n\tout: './migrations',\n\tdialect: 'postgresql',\n\tbreakpoints: true,\n\tdbCredentials: {\n\t\thost: 'localhost',\n\t\tport: 5432,\n\t\tuser: 'postgres',\n\t\tpassword: 'postgres',\n\t\tdatabase: 'app',\n\t\tssl: false,\n\t},\n} satisfies Config\n```\n\n```bash\nnpx drizzle-kit generate --config=./drizzle.config.ts --name=descriptive_name\n```\n\nThis writes a new `.sql` file (plus its `meta/*_snapshot.json`) into `out`. Treat everything\nunder `out` as a generated artifact: never hand-edit a migration file. If a migration hasn't\nbeen applied anywhere yet (e.g. you're still iterating on a schema change locally), delete it,\nadjust the schema, and regenerate instead of patching the SQL directly - once it *has* shipped\nanywhere, change the schema further and generate a new migration on top of it instead.\n\n### Running migrations\n\n`migrateDb()` runs those `drizzle-kit`-generated migrations and is safe to call from every\ninstance on startup, even when several instances boot against the same database concurrently: it\ncoordinates via a Postgres advisory lock, so only one instance migrates while the rest block\nuntil it's done, and retries with backoff on infrastructure failures.\n\n```ts\nimport { migrateDb } from '@apinecka/drizzle'\nimport { Logger } from '@nestjs/common'\n\nawait migrateDb({\n\tlogger: new Logger('Migration'),\n\tcredentials: { host: 'localhost', database: 'app' },\n\tmigrationsPath: path.resolve(__dirname, './migrations'),\n\tmigrationLockKey: 483_921, // any stable number you pick - see below\n})\n```\n\n`migrationLockKey` is required, not defaulted - it's the advisory-lock key that decides who\ncoordinates with whom, so silently sharing one across every consumer of this package (as an\ninternal default would) risks unrelated migration sets blocking on each other for no reason. Use\nthe *same* key across every instance migrating the *same* migration set against the *same*\ndatabase (that's the coordination you want - only one of them should actually run the SQL at a\ntime), and a *different* key for any other, unrelated migration set that might run against that\ndatabase.\n\n## Error handling\n\n`PostgresErrorCode` names the raw Postgres `error.code` values worth branching on (e.g. from a\n`catch` block around an insert):\n\n```ts\nimport { PostgresErrorCode } from '@apinecka/drizzle'\n\ntry {\n\tawait db.insert(schema.users).values(user)\n} catch (err) {\n\tif ((err as { code?: string }).code === PostgresErrorCode.UniqueViolation) {\n\t\tthrow new ConflictException('User already exists')\n\t}\n\tthrow err\n}\n```\n\n## Testing helpers\n\n`@apinecka/drizzle/testing` is a separate entry point for test-only helpers (they use a raw `pg`\nclient for admin actions like dropping a database, which you don't want anywhere near production\ncode).\n\nMigrating is comparatively slow and every test file reuses the same schema, so run\n`dropAndCreateTestDb()`/`migrateTestDb()` **exactly once for the whole test run**, via Jest's\n`globalSetup` - never per test file, and never per test. Individual tests then just\n`truncateTestDb()` to guarantee empty tables:\n\n```ts\n// jest.global-setup.ts - runs once, before any test file, in its own process\nimport { dropAndCreateTestDb, migrateTestDb } from '@apinecka/drizzle/testing'\n\nexport default async function () {\n\t// credentials default to getTestDbCredentials() - pass them explicitly only for a second database\n\tawait dropAndCreateTestDb()\n\tawait migrateTestDb({ migrationsPath: path.resolve(__dirname, './migrations'), migrationLockKey: 483_921 })\n}\n```\n\n```js\n// jest.config.js\n/** @type {import('jest').Config} */\nmodule.exports = {\n\t// ...\n\tglobalSetup: '<rootDir>/jest.global-setup.ts',\n}\n```\n\n```ts\n// some.spec.ts\nimport { truncateTestDb } from '@apinecka/drizzle/testing'\n\nafterEach(async () => {\n\tawait truncateTestDb(db, ['public'])\n})\n```\n\n`getTestDbCredentials()` reads `TEST_DB_HOST` / `TEST_DB_PORT` / `TEST_DB_USER` /\n`TEST_DB_PASSWORD` / `TEST_DB_NAME`, falling back to a local Postgres on the default port.\n\n### Setting `TEST_DB_*` for Jest\n\nPoint Jest at a setup file via `setupFiles` and set the vars there. Using `??=` means CI can still\noverride any of them by exporting real env vars before running Jest, while local runs get sane\ndefaults for free:\n\n```js\n// jest.config.js\n/** @type {import('jest').Config} */\nmodule.exports = {\n\t// ...\n\tsetupFiles: ['<rootDir>/jest.env.js'],\n}\n```\n\n```js\n// jest.env.js\nprocess.env.TEST_DB_HOST ??= 'localhost'\nprocess.env.TEST_DB_PORT ??= '5432'\nprocess.env.TEST_DB_USER ??= 'postgres'\nprocess.env.TEST_DB_PASSWORD ??= 'postgres'\nprocess.env.TEST_DB_NAME ??= 'test'\n```\n\n## Peer dependencies\n\n- `@nestjs/common` — the module is NestJS-specific.\n- `drizzle-orm` / `pg` — the underlying ORM and Postgres driver.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}