drizzle-multitenant 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +94 -339
- package/dist/cli/index.js +686 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/{context-DBerWr50.d.ts → context-DoHx79MS.d.ts} +1 -1
- package/dist/cross-schema/index.d.ts +152 -1
- package/dist/cross-schema/index.js +208 -1
- package/dist/cross-schema/index.js.map +1 -1
- package/dist/index.d.ts +62 -5
- package/dist/index.js +1181 -50
- package/dist/index.js.map +1 -1
- package/dist/integrations/express.d.ts +3 -3
- package/dist/integrations/fastify.d.ts +3 -3
- package/dist/integrations/nestjs/index.d.ts +1 -1
- package/dist/integrations/nestjs/index.js +484 -3
- package/dist/integrations/nestjs/index.js.map +1 -1
- package/dist/migrator/index.d.ts +116 -1
- package/dist/migrator/index.js +418 -0
- package/dist/migrator/index.js.map +1 -1
- package/dist/types-B5eSRLFW.d.ts +235 -0
- package/package.json +9 -3
- package/dist/types-DKVaTaIb.d.ts +0 -130
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/banner.svg" alt="drizzle-multitenant" width="500" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Multi-tenancy toolkit for Drizzle ORM</strong>
|
|
7
|
+
</p>
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
Schema isolation, tenant context propagation, and parallel migrations for PostgreSQL
|
|
11
|
+
</p>
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
└─────────────────────────────────────────────────────────────────────┘
|
|
18
|
-
```
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://www.npmjs.com/package/drizzle-multitenant"><img src="https://img.shields.io/npm/v/drizzle-multitenant.svg?style=flat-square&color=4A9A98" alt="npm version"></a>
|
|
15
|
+
<a href="https://www.npmjs.com/package/drizzle-multitenant"><img src="https://img.shields.io/npm/dm/drizzle-multitenant.svg?style=flat-square&color=3D5A80" alt="npm downloads"></a>
|
|
16
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-6AADAB.svg?style=flat-square" alt="License"></a>
|
|
17
|
+
<a href="https://mateusflorez.github.io/drizzle-multitenant/"><img src="https://img.shields.io/badge/docs-online-2B3E5C.svg?style=flat-square" alt="Documentation"></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<br />
|
|
19
21
|
|
|
20
22
|
## Features
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
| Feature | Description |
|
|
25
|
+
|---------|-------------|
|
|
26
|
+
| **Schema Isolation** | PostgreSQL schema-per-tenant with automatic LRU pool management |
|
|
27
|
+
| **Context Propagation** | AsyncLocalStorage-based tenant context across your entire stack |
|
|
28
|
+
| **Parallel Migrations** | Apply migrations to all tenants concurrently with progress tracking |
|
|
29
|
+
| **Cross-Schema Queries** | Type-safe joins between tenant and shared tables |
|
|
30
|
+
| **Connection Retry** | Automatic retry with exponential backoff for transient failures |
|
|
31
|
+
| **Framework Support** | First-class Express, Fastify, and NestJS integrations |
|
|
32
|
+
|
|
33
|
+
<br />
|
|
28
34
|
|
|
29
35
|
## Installation
|
|
30
36
|
|
|
@@ -32,6 +38,8 @@ Multi-tenancy toolkit for Drizzle ORM with schema isolation, tenant context, and
|
|
|
32
38
|
npm install drizzle-multitenant drizzle-orm pg
|
|
33
39
|
```
|
|
34
40
|
|
|
41
|
+
<br />
|
|
42
|
+
|
|
35
43
|
## Quick Start
|
|
36
44
|
|
|
37
45
|
### 1. Define your configuration
|
|
@@ -40,94 +48,89 @@ npm install drizzle-multitenant drizzle-orm pg
|
|
|
40
48
|
// tenant.config.ts
|
|
41
49
|
import { defineConfig } from 'drizzle-multitenant';
|
|
42
50
|
import * as tenantSchema from './schemas/tenant';
|
|
43
|
-
import * as sharedSchema from './schemas/shared';
|
|
44
51
|
|
|
45
52
|
export default defineConfig({
|
|
46
|
-
connection: {
|
|
47
|
-
url: process.env.DATABASE_URL!,
|
|
48
|
-
},
|
|
53
|
+
connection: { url: process.env.DATABASE_URL! },
|
|
49
54
|
isolation: {
|
|
50
55
|
strategy: 'schema',
|
|
51
|
-
schemaNameTemplate: (
|
|
52
|
-
maxPools: 50,
|
|
53
|
-
poolTtlMs: 60 * 60 * 1000,
|
|
54
|
-
},
|
|
55
|
-
schemas: {
|
|
56
|
-
tenant: tenantSchema,
|
|
57
|
-
shared: sharedSchema,
|
|
58
|
-
},
|
|
59
|
-
// Optional: CLI migrations config
|
|
60
|
-
migrations: {
|
|
61
|
-
tenantFolder: './drizzle/tenant',
|
|
62
|
-
migrationsTable: '__drizzle_migrations', // Custom table name
|
|
63
|
-
tenantDiscovery: async () => {
|
|
64
|
-
// Return list of tenant IDs for migrations
|
|
65
|
-
return ['tenant-1', 'tenant-2'];
|
|
66
|
-
},
|
|
56
|
+
schemaNameTemplate: (id) => `tenant_${id}`,
|
|
67
57
|
},
|
|
58
|
+
schemas: { tenant: tenantSchema },
|
|
68
59
|
});
|
|
69
60
|
```
|
|
70
61
|
|
|
71
62
|
### 2. Create the tenant manager
|
|
72
63
|
|
|
73
64
|
```typescript
|
|
65
|
+
// app.ts
|
|
74
66
|
import { createTenantManager } from 'drizzle-multitenant';
|
|
75
67
|
import config from './tenant.config';
|
|
76
68
|
|
|
77
69
|
const tenants = createTenantManager(config);
|
|
78
70
|
|
|
79
|
-
//
|
|
80
|
-
const db = tenants.getDb('
|
|
71
|
+
// Type-safe database for each tenant
|
|
72
|
+
const db = tenants.getDb('acme');
|
|
81
73
|
const users = await db.select().from(schema.users);
|
|
82
|
-
|
|
83
|
-
// Get shared DB (public schema)
|
|
84
|
-
const shared = tenants.getSharedDb();
|
|
85
|
-
const plans = await shared.select().from(sharedSchema.plans);
|
|
86
74
|
```
|
|
87
75
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
import { createTenantContext } from 'drizzle-multitenant';
|
|
76
|
+
<br />
|
|
92
77
|
|
|
93
|
-
|
|
78
|
+
## CLI Commands
|
|
94
79
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
80
|
+
```bash
|
|
81
|
+
npx drizzle-multitenant init # Interactive setup wizard
|
|
82
|
+
npx drizzle-multitenant generate --name=users # Generate migration
|
|
83
|
+
npx drizzle-multitenant migrate --all # Apply to all tenants
|
|
84
|
+
npx drizzle-multitenant status # Check migration status
|
|
85
|
+
npx drizzle-multitenant tenant:create --id=acme # Create new tenant
|
|
101
86
|
```
|
|
102
87
|
|
|
88
|
+
<br />
|
|
89
|
+
|
|
103
90
|
## Framework Integrations
|
|
104
91
|
|
|
105
|
-
|
|
92
|
+
<details>
|
|
93
|
+
<summary><strong>Express</strong></summary>
|
|
106
94
|
|
|
107
95
|
```typescript
|
|
108
96
|
import { createExpressMiddleware } from 'drizzle-multitenant/express';
|
|
109
97
|
|
|
110
|
-
|
|
98
|
+
app.use(createExpressMiddleware({
|
|
111
99
|
manager: tenants,
|
|
112
100
|
extractTenantId: (req) => req.headers['x-tenant-id'] as string,
|
|
113
|
-
|
|
114
|
-
});
|
|
101
|
+
}));
|
|
115
102
|
|
|
116
|
-
app.
|
|
103
|
+
app.get('/users', async (req, res) => {
|
|
104
|
+
const db = req.tenantContext.db;
|
|
105
|
+
const users = await db.select().from(schema.users);
|
|
106
|
+
res.json(users);
|
|
107
|
+
});
|
|
117
108
|
```
|
|
118
109
|
|
|
119
|
-
|
|
110
|
+
</details>
|
|
111
|
+
|
|
112
|
+
<details>
|
|
113
|
+
<summary><strong>Fastify</strong></summary>
|
|
120
114
|
|
|
121
115
|
```typescript
|
|
122
116
|
import { fastifyTenantPlugin } from 'drizzle-multitenant/fastify';
|
|
123
117
|
|
|
124
|
-
|
|
118
|
+
fastify.register(fastifyTenantPlugin, {
|
|
125
119
|
manager: tenants,
|
|
126
120
|
extractTenantId: (req) => req.headers['x-tenant-id'] as string,
|
|
127
121
|
});
|
|
122
|
+
|
|
123
|
+
fastify.get('/users', async (req, reply) => {
|
|
124
|
+
const db = req.tenantContext.db;
|
|
125
|
+
const users = await db.select().from(schema.users);
|
|
126
|
+
return users;
|
|
127
|
+
});
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
</details>
|
|
131
|
+
|
|
132
|
+
<details>
|
|
133
|
+
<summary><strong>NestJS</strong></summary>
|
|
131
134
|
|
|
132
135
|
```typescript
|
|
133
136
|
import { TenantModule, InjectTenantDb } from 'drizzle-multitenant/nestjs';
|
|
@@ -135,9 +138,8 @@ import { TenantModule, InjectTenantDb } from 'drizzle-multitenant/nestjs';
|
|
|
135
138
|
@Module({
|
|
136
139
|
imports: [
|
|
137
140
|
TenantModule.forRoot({
|
|
138
|
-
config
|
|
141
|
+
config,
|
|
139
142
|
extractTenantId: (req) => req.headers['x-tenant-id'],
|
|
140
|
-
isGlobal: true,
|
|
141
143
|
}),
|
|
142
144
|
],
|
|
143
145
|
})
|
|
@@ -145,264 +147,39 @@ export class AppModule {}
|
|
|
145
147
|
|
|
146
148
|
@Injectable({ scope: Scope.REQUEST })
|
|
147
149
|
export class UserService {
|
|
148
|
-
constructor(@InjectTenantDb() private
|
|
150
|
+
constructor(@InjectTenantDb() private db: TenantDb) {}
|
|
149
151
|
|
|
150
|
-
|
|
152
|
+
findAll() {
|
|
151
153
|
return this.db.select().from(users);
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
```
|
|
155
157
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Use `TenantDbFactory` when you need to access tenant databases from singleton services:
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
import { TenantDbFactory, InjectTenantDbFactory } from 'drizzle-multitenant/nestjs';
|
|
162
|
-
|
|
163
|
-
@Injectable() // Singleton - no scope needed
|
|
164
|
-
export class ReportService {
|
|
165
|
-
constructor(@InjectTenantDbFactory() private dbFactory: TenantDbFactory) {}
|
|
166
|
-
|
|
167
|
-
async generateReport(tenantId: string) {
|
|
168
|
-
const db = this.dbFactory.getDb(tenantId);
|
|
169
|
-
return db.select().from(reports);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Cron job example
|
|
174
|
-
@Injectable()
|
|
175
|
-
export class DailyReportCron {
|
|
176
|
-
constructor(@InjectTenantDbFactory() private dbFactory: TenantDbFactory) {}
|
|
177
|
-
|
|
178
|
-
@Cron('0 8 * * *')
|
|
179
|
-
async run() {
|
|
180
|
-
const tenants = await this.getTenantIds();
|
|
181
|
-
for (const tenantId of tenants) {
|
|
182
|
-
const db = this.dbFactory.getDb(tenantId);
|
|
183
|
-
await this.processReports(db);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
#### Debugging
|
|
190
|
-
|
|
191
|
-
The injected `TenantDb` provides debug utilities:
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
// Console output shows useful info
|
|
195
|
-
console.log(tenantDb);
|
|
196
|
-
// [TenantDb] tenant=123 schema=empresa_123
|
|
197
|
-
|
|
198
|
-
// Access debug information
|
|
199
|
-
console.log(tenantDb.__debug);
|
|
200
|
-
// { tenantId: '123', schemaName: 'empresa_123', isProxy: true, poolCount: 5 }
|
|
201
|
-
|
|
202
|
-
// Quick access
|
|
203
|
-
console.log(tenantDb.__tenantId); // '123'
|
|
204
|
-
|
|
205
|
-
// In tests
|
|
206
|
-
expect(tenantDb.__tenantId).toBe('expected-tenant');
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
## CLI Commands
|
|
210
|
-
|
|
211
|
-
```bash
|
|
212
|
-
# Initialize configuration (interactive wizard)
|
|
213
|
-
npx drizzle-multitenant init
|
|
214
|
-
|
|
215
|
-
# Generate a new migration
|
|
216
|
-
npx drizzle-multitenant generate --name=add-users-table
|
|
217
|
-
|
|
218
|
-
# Apply migrations to all tenants (with progress bar)
|
|
219
|
-
npx drizzle-multitenant migrate --all --concurrency=10
|
|
220
|
-
|
|
221
|
-
# Interactive tenant selection
|
|
222
|
-
npx drizzle-multitenant migrate # Shows checkbox to select tenants
|
|
158
|
+
</details>
|
|
223
159
|
|
|
224
|
-
|
|
225
|
-
npx drizzle-multitenant status
|
|
160
|
+
<br />
|
|
226
161
|
|
|
227
|
-
|
|
228
|
-
npx drizzle-multitenant tenant:create --id=new-tenant
|
|
162
|
+
## Documentation
|
|
229
163
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
--no-color # Disable colored output
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### JSON Output
|
|
251
|
-
|
|
252
|
-
```bash
|
|
253
|
-
# Get status as JSON for scripting
|
|
254
|
-
npx drizzle-multitenant status --json | jq '.tenants[] | select(.pending > 0)'
|
|
255
|
-
|
|
256
|
-
# Parse migration results
|
|
257
|
-
npx drizzle-multitenant migrate --all --json | jq '.summary'
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Status Output
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
┌──────────────────┬──────────────┬────────────┬─────────┬─────────┬──────────┐
|
|
264
|
-
│ Tenant │ Schema │ Format │ Applied │ Pending │ Status │
|
|
265
|
-
├──────────────────┼──────────────┼────────────┼─────────┼─────────┼──────────┤
|
|
266
|
-
│ abc-123 │ tenant_abc │ drizzle-kit│ 45 │ 3 │ Behind │
|
|
267
|
-
│ def-456 │ tenant_def │ name │ 48 │ 0 │ OK │
|
|
268
|
-
│ ghi-789 │ tenant_ghi │ (new) │ 0 │ 48 │ Behind │
|
|
269
|
-
└──────────────────┴──────────────┴────────────┴─────────┴─────────┴──────────┘
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## Migration Table Formats
|
|
273
|
-
|
|
274
|
-
`drizzle-multitenant` supports multiple migration table formats for compatibility with existing databases:
|
|
275
|
-
|
|
276
|
-
### Supported Formats
|
|
277
|
-
|
|
278
|
-
| Format | Identifier | Timestamp | Compatible With |
|
|
279
|
-
|--------|------------|-----------|-----------------|
|
|
280
|
-
| `name` | Filename | `applied_at` (timestamp) | drizzle-multitenant native |
|
|
281
|
-
| `hash` | SHA-256 | `created_at` (timestamp) | Custom scripts |
|
|
282
|
-
| `drizzle-kit` | SHA-256 | `created_at` (bigint) | drizzle-kit migrate |
|
|
283
|
-
|
|
284
|
-
### Configuration
|
|
285
|
-
|
|
286
|
-
```typescript
|
|
287
|
-
// tenant.config.ts
|
|
288
|
-
export default defineConfig({
|
|
289
|
-
// ...
|
|
290
|
-
migrations: {
|
|
291
|
-
tenantFolder: './drizzle/tenant',
|
|
292
|
-
tenantDiscovery: async () => getTenantIds(),
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Table format for tracking migrations
|
|
296
|
-
* - "auto": Auto-detect existing format (default)
|
|
297
|
-
* - "name": Filename-based (drizzle-multitenant native)
|
|
298
|
-
* - "hash": SHA-256 hash
|
|
299
|
-
* - "drizzle-kit": Exact drizzle-kit format
|
|
300
|
-
*/
|
|
301
|
-
tableFormat: 'auto',
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Format to use when creating new tables (only for "auto" mode)
|
|
305
|
-
* @default "name"
|
|
306
|
-
*/
|
|
307
|
-
defaultFormat: 'name',
|
|
308
|
-
},
|
|
309
|
-
});
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### Migrating from drizzle-kit
|
|
313
|
-
|
|
314
|
-
If you have existing databases with migrations applied via `drizzle-kit migrate`, the CLI will automatically detect the format:
|
|
315
|
-
|
|
316
|
-
```bash
|
|
317
|
-
# Check current format for all tenants
|
|
318
|
-
npx drizzle-multitenant status
|
|
319
|
-
|
|
320
|
-
# Apply new migrations (works with any format)
|
|
321
|
-
npx drizzle-multitenant migrate --all
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Converting Between Formats
|
|
325
|
-
|
|
326
|
-
Use the `convert-format` command to standardize all tenants to a single format:
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
# Preview conversion (dry-run)
|
|
330
|
-
npx drizzle-multitenant convert-format --to=name --dry-run
|
|
331
|
-
|
|
332
|
-
# Convert all tenants to name format
|
|
333
|
-
npx drizzle-multitenant convert-format --to=name
|
|
334
|
-
|
|
335
|
-
# Convert specific tenant
|
|
336
|
-
npx drizzle-multitenant convert-format --to=name --tenant=abc-123
|
|
337
|
-
|
|
338
|
-
# Convert to drizzle-kit format (for compatibility)
|
|
339
|
-
npx drizzle-multitenant convert-format --to=drizzle-kit
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
## Cross-Schema Queries
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
import { createCrossSchemaQuery } from 'drizzle-multitenant/cross-schema';
|
|
346
|
-
|
|
347
|
-
const query = createCrossSchemaQuery({
|
|
348
|
-
tenantDb: tenants.getDb('tenant-123'),
|
|
349
|
-
sharedDb: tenants.getSharedDb(),
|
|
350
|
-
tenantSchema: 'tenant_123',
|
|
351
|
-
sharedSchema: 'public',
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
// Type-safe join between tenant and shared tables
|
|
355
|
-
const result = await query
|
|
356
|
-
.select({
|
|
357
|
-
orderId: orders.id,
|
|
358
|
-
planName: subscriptionPlans.name,
|
|
359
|
-
})
|
|
360
|
-
.from(orders)
|
|
361
|
-
.leftJoin(subscriptionPlans, eq(orders.planId, subscriptionPlans.id));
|
|
362
|
-
```
|
|
164
|
+
<table>
|
|
165
|
+
<tr>
|
|
166
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/getting-started">Getting Started</a></td>
|
|
167
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/configuration">Configuration</a></td>
|
|
168
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/cli">CLI Commands</a></td>
|
|
169
|
+
</tr>
|
|
170
|
+
<tr>
|
|
171
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/frameworks/express">Express</a></td>
|
|
172
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/frameworks/fastify">Fastify</a></td>
|
|
173
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/frameworks/nestjs">NestJS</a></td>
|
|
174
|
+
</tr>
|
|
175
|
+
<tr>
|
|
176
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/cross-schema">Cross-Schema Queries</a></td>
|
|
177
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/guide/advanced">Advanced Features</a></td>
|
|
178
|
+
<td><a href="https://mateusflorez.github.io/drizzle-multitenant/api/reference">API Reference</a></td>
|
|
179
|
+
</tr>
|
|
180
|
+
</table>
|
|
363
181
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
### Core
|
|
367
|
-
|
|
368
|
-
| Export | Description |
|
|
369
|
-
|--------|-------------|
|
|
370
|
-
| `defineConfig()` | Create typed configuration |
|
|
371
|
-
| `createTenantManager()` | Create pool manager instance |
|
|
372
|
-
| `createTenantContext()` | Create AsyncLocalStorage context |
|
|
373
|
-
|
|
374
|
-
### Manager Methods
|
|
375
|
-
|
|
376
|
-
| Method | Description |
|
|
377
|
-
|--------|-------------|
|
|
378
|
-
| `getDb(tenantId)` | Get Drizzle instance for tenant |
|
|
379
|
-
| `getSharedDb()` | Get Drizzle instance for shared schema |
|
|
380
|
-
| `getSchemaName(tenantId)` | Get schema name for tenant |
|
|
381
|
-
| `hasPool(tenantId)` | Check if pool exists |
|
|
382
|
-
| `evictPool(tenantId)` | Force evict a pool |
|
|
383
|
-
| `dispose()` | Cleanup all pools |
|
|
384
|
-
|
|
385
|
-
### NestJS Decorators
|
|
386
|
-
|
|
387
|
-
| Decorator | Description |
|
|
388
|
-
|-----------|-------------|
|
|
389
|
-
| `@InjectTenantDb()` | Inject tenant database (request-scoped) |
|
|
390
|
-
| `@InjectTenantDbFactory()` | Inject factory for singleton services |
|
|
391
|
-
| `@InjectSharedDb()` | Inject shared database |
|
|
392
|
-
| `@InjectTenantContext()` | Inject tenant context |
|
|
393
|
-
| `@InjectTenantManager()` | Inject tenant manager |
|
|
394
|
-
| `@RequiresTenant()` | Mark route as requiring tenant |
|
|
395
|
-
| `@PublicRoute()` | Mark route as public |
|
|
396
|
-
|
|
397
|
-
### TenantDbFactory Methods
|
|
398
|
-
|
|
399
|
-
| Method | Description |
|
|
400
|
-
|--------|-------------|
|
|
401
|
-
| `getDb(tenantId)` | Get Drizzle instance for tenant |
|
|
402
|
-
| `getSharedDb()` | Get shared database instance |
|
|
403
|
-
| `getSchemaName(tenantId)` | Get schema name for tenant |
|
|
404
|
-
| `getDebugInfo(tenantId)` | Get debug info (tenantId, schema, pool stats) |
|
|
405
|
-
| `getManager()` | Get underlying TenantManager |
|
|
182
|
+
<br />
|
|
406
183
|
|
|
407
184
|
## Requirements
|
|
408
185
|
|
|
@@ -410,29 +187,7 @@ const result = await query
|
|
|
410
187
|
- PostgreSQL 12+
|
|
411
188
|
- Drizzle ORM 0.29+
|
|
412
189
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
| Package | Purpose |
|
|
416
|
-
|---------|---------|
|
|
417
|
-
| `drizzle-orm` | Type-safe ORM |
|
|
418
|
-
| `pg` | PostgreSQL driver |
|
|
419
|
-
| `lru-cache` | Pool management |
|
|
420
|
-
| `commander` | CLI framework |
|
|
421
|
-
| `chalk` | Terminal styling |
|
|
422
|
-
| `ora` | Loading spinners |
|
|
423
|
-
| `cli-table3` | Table formatting |
|
|
424
|
-
| `cli-progress` | Progress bars |
|
|
425
|
-
| `@inquirer/prompts` | Interactive prompts |
|
|
426
|
-
|
|
427
|
-
## Comparison
|
|
428
|
-
|
|
429
|
-
| Feature | drizzle-multitenant | Manual Implementation |
|
|
430
|
-
|---------|---------------------|----------------------|
|
|
431
|
-
| Pool management | Automatic LRU | Manual |
|
|
432
|
-
| Context propagation | AsyncLocalStorage | Pass through params |
|
|
433
|
-
| Parallel migrations | Built-in CLI | Custom scripts |
|
|
434
|
-
| Cross-schema queries | Type-safe builder | Raw SQL |
|
|
435
|
-
| Framework support | Express/Fastify/NestJS/Hono | DIY |
|
|
190
|
+
<br />
|
|
436
191
|
|
|
437
192
|
## License
|
|
438
193
|
|