@bunnykit/orm 0.1.24 → 0.1.26

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/README.md CHANGED
@@ -23,7 +23,8 @@ An **Eloquent-inspired ORM** built specifically for [Bun](https://bun.sh)'s nati
23
23
  - 🧬 **Eloquent-style Models** — Property attributes, defaults, casts, dirty tracking, soft deletes, scopes, find-or-fail, first-or-create
24
24
  - 🔗 **Relations** — Standard, many-to-many, polymorphic, through, one-of-many, and relation queries
25
25
  - 👁️ **Observers** — Lifecycle hooks (`creating`, `created`, `updating`, `updated`, etc.)
26
- - 🚀 **Migrations & CLI** — Create, run, and rollback migrations from the command line
26
+ - 🚀 **Migrations & CLI** — Create, run, reset, refresh, and inspect migrations from the command line
27
+ - 🌱 **Seeders & Factories** — Run all seeders or target one seeder by name/file, plus lightweight model factories
27
28
  - 💬 **REPL** — Inspect models and run queries interactively with `bunny repl`
28
29
  - ⚡ **Streaming** — `chunk`, `cursor`, `each`, and `lazy` for memory-efficient large dataset processing
29
30
 
@@ -71,6 +72,7 @@ export default {
71
72
  // }),
72
73
  // listTenants: async () => await getAllTenantIds(),
73
74
  // },
75
+ seedersPath: "./database/seeders",
74
76
  modelsPath: ["./src/models", "./src/admin/models"],
75
77
  // Optional legacy type output directory
76
78
  // typesOutDir: "./src/generated/model-types",
@@ -87,6 +89,7 @@ Or use environment variables:
87
89
  ```bash
88
90
  export DATABASE_URL="sqlite://app.db"
89
91
  export MIGRATIONS_PATH="./database/migrations,./database/tenant-migrations"
92
+ export SEEDERS_PATH="./database/seeders"
90
93
  export MODELS_PATH="./src/models,./src/admin/models"
91
94
  export TYPES_OUT_DIR="./src/generated/model-types"
92
95
  ```
@@ -1108,6 +1111,84 @@ ObserverRegistry.register(User, {
1108
1111
 
1109
1112
  ---
1110
1113
 
1114
+ ## Seeders and Factories
1115
+
1116
+ Set `seedersPath` in `bunny.config.ts` to define the default directory used by `db:seed`:
1117
+
1118
+ ```ts
1119
+ export default {
1120
+ connection: { url: "sqlite://app.db" },
1121
+ seedersPath: "./database/seeders",
1122
+ };
1123
+ ```
1124
+
1125
+ `seedersPath` can also be an array:
1126
+
1127
+ ```ts
1128
+ export default {
1129
+ connection: { url: "sqlite://app.db" },
1130
+ seedersPath: ["./database/seeders", "./modules/demo/seeders"],
1131
+ };
1132
+ ```
1133
+
1134
+ Create a seeder by extending `Seeder`:
1135
+
1136
+ ```ts
1137
+ import { Seeder } from "@bunnykit/orm";
1138
+ import { User } from "../models/User";
1139
+
1140
+ export default class UserSeeder extends Seeder {
1141
+ async run(): Promise<void> {
1142
+ await User.create({ name: "Ada Lovelace", email: "ada@example.test" });
1143
+ }
1144
+ }
1145
+ ```
1146
+
1147
+ Run every seeder in `seedersPath`:
1148
+
1149
+ ```bash
1150
+ bun run bunny db:seed
1151
+ ```
1152
+
1153
+ Run one seeder by class/file name from `seedersPath`:
1154
+
1155
+ ```bash
1156
+ bun run bunny db:seed UserSeeder
1157
+ ```
1158
+
1159
+ Run one seeder by direct file path:
1160
+
1161
+ ```bash
1162
+ bun run bunny db:seed ./database/seeders/UserSeeder.ts
1163
+ ```
1164
+
1165
+ Programmatic seeding is available through `SeederRunner`:
1166
+
1167
+ ```ts
1168
+ import { SeederRunner } from "@bunnykit/orm";
1169
+
1170
+ await new SeederRunner(connection).runTarget("UserSeeder", "./database/seeders");
1171
+ await new SeederRunner(connection).runFile("./database/seeders/UserSeeder.ts");
1172
+ ```
1173
+
1174
+ Factories can create raw attributes, unsaved models, or persisted records:
1175
+
1176
+ ```ts
1177
+ import { factory } from "@bunnykit/orm";
1178
+ import { User } from "../models/User";
1179
+
1180
+ const users = factory(User, (sequence) => ({
1181
+ name: `User ${sequence}`,
1182
+ email: `user${sequence}@example.test`,
1183
+ }));
1184
+
1185
+ const attributes = users.raw();
1186
+ const model = users.make();
1187
+ const created = await users.count(3).state({ role: "admin" }).create();
1188
+ ```
1189
+
1190
+ ---
1191
+
1111
1192
  ## Migrations
1112
1193
 
1113
1194
  ### CLI Commands
@@ -1125,9 +1206,27 @@ bun run bunny migrate
1125
1206
  # Rollback the last batch
1126
1207
  bun run bunny migrate:rollback
1127
1208
 
1209
+ # Rollback all migrations
1210
+ bun run bunny migrate:reset
1211
+
1212
+ # Reset and rerun migrations
1213
+ bun run bunny migrate:refresh
1214
+
1215
+ # Drop all tables and rerun migrations
1216
+ bun run bunny migrate:fresh
1217
+
1128
1218
  # Show migration status
1129
1219
  bun run bunny migrate:status
1130
1220
 
1221
+ # Run all seeders in seedersPath
1222
+ bun run bunny db:seed
1223
+
1224
+ # Run one seeder by name from seedersPath
1225
+ bun run bunny db:seed UserSeeder
1226
+
1227
+ # Run one seeder by direct file path
1228
+ bun run bunny db:seed ./database/seeders/UserSeeder.ts
1229
+
1131
1230
  # Dump the current database schema
1132
1231
  bun run bunny schema:dump ./database/schema.sql
1133
1232
 
package/dist/bin/bunny.js CHANGED
@@ -5,6 +5,7 @@ import { TenantContext } from "../src/connection/TenantContext.js";
5
5
  import { configureBunny } from "../src/config/BunnyConfig.js";
6
6
  import { Migrator } from "../src/migration/Migrator.js";
7
7
  import { MigrationCreator } from "../src/migration/MigrationCreator.js";
8
+ import { SeederRunner } from "../src/seeding/Seeder.js";
8
9
  import { TypeGenerator } from "../src/typegen/TypeGenerator.js";
9
10
  import { existsSync } from "fs";
10
11
  import { mkdir, rm, writeFile } from "fs/promises";
@@ -64,6 +65,18 @@ async function runMigratorCommand(command, migrator, statusLabel) {
64
65
  await migrator.rollback();
65
66
  return;
66
67
  }
68
+ if (command === "migrate:reset") {
69
+ await migrator.reset();
70
+ return;
71
+ }
72
+ if (command === "migrate:refresh") {
73
+ await migrator.refresh();
74
+ return;
75
+ }
76
+ if (command === "migrate:fresh") {
77
+ await migrator.fresh();
78
+ return;
79
+ }
67
80
  const status = await migrator.status();
68
81
  if (statusLabel) {
69
82
  console.log(statusLabel);
@@ -338,6 +351,7 @@ async function loadConfig(allowFallback = false) {
338
351
  return {
339
352
  connection: { url },
340
353
  migrationsPath: parseEnvPathSetting(process.env.MIGRATIONS_PATH) || "./database/migrations",
354
+ seedersPath: parseEnvPathSetting(process.env.SEEDERS_PATH),
341
355
  modelsPath: parseEnvPathSetting(process.env.MODELS_PATH),
342
356
  };
343
357
  }
@@ -354,6 +368,7 @@ async function loadConfig(allowFallback = false) {
354
368
  filename: process.env.DB_DATABASE,
355
369
  },
356
370
  migrationsPath: parseEnvPathSetting(process.env.MIGRATIONS_PATH) || "./database/migrations",
371
+ seedersPath: parseEnvPathSetting(process.env.SEEDERS_PATH),
357
372
  modelsPath: parseEnvPathSetting(process.env.MODELS_PATH),
358
373
  };
359
374
  }
@@ -361,6 +376,7 @@ async function loadConfig(allowFallback = false) {
361
376
  return {
362
377
  connection: { url: "sqlite://:memory:" },
363
378
  migrationsPath: parseEnvPathSetting(process.env.MIGRATIONS_PATH) || "./database/migrations",
379
+ seedersPath: parseEnvPathSetting(process.env.SEEDERS_PATH),
364
380
  modelsPath: parseEnvPathSetting(process.env.MODELS_PATH),
365
381
  };
366
382
  }
@@ -432,9 +448,29 @@ async function main() {
432
448
  else if (command === "migrate:rollback") {
433
449
  await runConfiguredMigrationCommand(command, config, connection, parseMigrationTarget(args.slice(1)));
434
450
  }
451
+ else if (command === "migrate:reset") {
452
+ await runConfiguredMigrationCommand(command, config, connection, parseMigrationTarget(args.slice(1)));
453
+ }
454
+ else if (command === "migrate:refresh") {
455
+ await runConfiguredMigrationCommand(command, config, connection, parseMigrationTarget(args.slice(1)));
456
+ }
457
+ else if (command === "migrate:fresh") {
458
+ await runConfiguredMigrationCommand(command, config, connection, parseMigrationTarget(args.slice(1)));
459
+ }
435
460
  else if (command === "migrate:status") {
436
461
  await runConfiguredMigrationCommand(command, config, connection, parseMigrationTarget(args.slice(1)));
437
462
  }
463
+ else if (command === "db:seed") {
464
+ const target = args[1];
465
+ const seederPath = config.seedersPath || "./database/seeders";
466
+ const runner = new SeederRunner(connection);
467
+ if (target) {
468
+ await runner.runTarget(target, seederPath);
469
+ }
470
+ else {
471
+ await runner.runPaths(seederPath);
472
+ }
473
+ }
438
474
  else {
439
475
  console.log("Usage:");
440
476
  console.log(" bun run bunny migrate Run landlord migrations, then all tenant migrations when configured");
@@ -443,7 +479,12 @@ async function main() {
443
479
  console.log(" bun run bunny migrate --tenant <id> Run one tenant's migrations only");
444
480
  console.log(" bun run bunny migrate:make <name> [dir] Create a new migration");
445
481
  console.log(" bun run bunny migrate:rollback Rollback the last batch");
482
+ console.log(" bun run bunny migrate:reset Rollback all migrations");
483
+ console.log(" bun run bunny migrate:refresh Reset and rerun migrations");
484
+ console.log(" bun run bunny migrate:fresh Drop all tables and rerun migrations");
446
485
  console.log(" bun run bunny migrate:status Show migration status");
486
+ console.log(" bun run bunny db:seed Run seeders from seedersPath");
487
+ console.log(" bun run bunny db:seed <seeder> Run one seeder by file path or name");
447
488
  console.log(" bun run bunny schema:dump [path] Dump the current database schema");
448
489
  console.log(" bun run bunny schema:squash [path] Dump schema and mark configured migrations as ran");
449
490
  console.log(" bun run bunny types:generate [dir] Generate model type declarations from DB schema");
@@ -5,6 +5,7 @@ import type { ConnectionConfig } from "../types/index.js";
5
5
  export interface BunnyConfig {
6
6
  connection: ConnectionConfig;
7
7
  migrationsPath?: string | string[];
8
+ seedersPath?: string | string[];
8
9
  migrations?: {
9
10
  landlord?: string | string[];
10
11
  tenant?: string | string[];
@@ -18,10 +18,13 @@ export declare class Connection {
18
18
  getDriverName(): "sqlite" | "mysql" | "postgres";
19
19
  getGrammar(): Grammar;
20
20
  getSchema(): string | undefined;
21
+ static isSafeIdentifier(value: string): boolean;
22
+ static assertSafeIdentifier(value: string, label?: string): void;
23
+ static assertSafeQualifiedIdentifier(value: string, label?: string): void;
21
24
  withSchema(schema: string): Connection;
22
25
  withoutSchema(): Connection;
23
26
  qualifyTable(table: string): string;
24
- private quoteIdentifier;
27
+ quoteIdentifier(value: string): string;
25
28
  query(sqlString: string, bindings?: any[]): Promise<any[]>;
26
29
  run(sqlString: string, bindings?: any[]): Promise<any>;
27
30
  beginTransaction(): Promise<void>;
@@ -59,7 +59,22 @@ export class Connection {
59
59
  getSchema() {
60
60
  return this.schema;
61
61
  }
62
+ static isSafeIdentifier(value) {
63
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);
64
+ }
65
+ static assertSafeIdentifier(value, label = "identifier") {
66
+ if (!this.isSafeIdentifier(value)) {
67
+ throw new Error(`Invalid ${label}: ${value}`);
68
+ }
69
+ }
70
+ static assertSafeQualifiedIdentifier(value, label = "identifier") {
71
+ const parts = value.split(".");
72
+ if (parts.length === 0 || parts.some((part) => !this.isSafeIdentifier(part))) {
73
+ throw new Error(`Invalid ${label}: ${value}`);
74
+ }
75
+ }
62
76
  withSchema(schema) {
77
+ Connection.assertSafeIdentifier(schema, "schema name");
63
78
  if (this.schema === schema)
64
79
  return this;
65
80
  return new Connection(this.config, { driver: this.driver, schema, ownsDriver: false });
@@ -70,8 +85,14 @@ export class Connection {
70
85
  return new Connection(this.config, { driver: this.driver, ownsDriver: false });
71
86
  }
72
87
  qualifyTable(table) {
73
- if (!this.schema || this.driverName === "sqlite" || table.includes("."))
88
+ if (table.includes(".")) {
89
+ Connection.assertSafeQualifiedIdentifier(table, "qualified table name");
90
+ return table;
91
+ }
92
+ if (!this.schema || this.driverName === "sqlite")
74
93
  return table;
94
+ Connection.assertSafeIdentifier(this.schema, "schema name");
95
+ Connection.assertSafeIdentifier(table, "table name");
75
96
  return `${this.schema}.${table}`;
76
97
  }
77
98
  quoteIdentifier(value) {
@@ -144,6 +165,7 @@ export class Connection {
144
165
  if (this.driverName !== "postgres") {
145
166
  throw new Error("search_path schema switching is only supported for PostgreSQL connections.");
146
167
  }
168
+ Connection.assertSafeIdentifier(schema, "schema name");
147
169
  return await this.transaction(async (connection) => {
148
170
  await connection.run(`SET LOCAL search_path TO ${connection.quoteIdentifier(schema)}`);
149
171
  return await callback(connection.withoutSchema());
@@ -1,25 +1,32 @@
1
1
  import { Connection } from "./Connection.js";
2
2
  import type { ConnectionConfig } from "../types/index.js";
3
3
  import type { ActiveTenantContext } from "./TenantContext.js";
4
- export type TenantResolution = {
4
+ export interface TenantCachePolicy {
5
+ ttl?: number;
6
+ closeOnPurge?: boolean;
7
+ }
8
+ type TenantResolutionOptions = TenantCachePolicy & {
9
+ cache?: TenantCachePolicy;
10
+ };
11
+ export type TenantResolution = ({
5
12
  strategy: "database";
6
13
  name: string;
7
14
  config: ConnectionConfig;
8
- } | {
15
+ } & TenantResolutionOptions) | ({
9
16
  strategy: "schema";
10
17
  name: string;
11
18
  config?: ConnectionConfig;
12
19
  connection?: string | Connection;
13
20
  schema: string;
14
21
  mode?: "qualify" | "search_path";
15
- } | {
22
+ } & TenantResolutionOptions) | ({
16
23
  strategy: "rls";
17
24
  name: string;
18
25
  config?: ConnectionConfig;
19
26
  connection?: string | Connection;
20
27
  tenantId?: string;
21
28
  setting?: string;
22
- };
29
+ } & TenantResolutionOptions);
23
30
  export type TenantResolver = (tenantId: string) => TenantResolution | Promise<TenantResolution>;
24
31
  export interface PoolConfig {
25
32
  maxConnections?: number;
@@ -50,6 +57,10 @@ export declare class ConnectionManager {
50
57
  static resolveTenant(tenantId: string): Promise<ActiveTenantContext>;
51
58
  static getResolvedTenant(tenantId: string): ActiveTenantContext | undefined;
52
59
  static purgeTenant(tenantId: string): void;
60
+ static purgeExpiredTenants(options?: {
61
+ close?: boolean;
62
+ }): Promise<string[]>;
53
63
  static closeTenant(tenantId: string): Promise<void>;
54
64
  static closeAll(): Promise<void>;
55
65
  }
66
+ export {};
@@ -139,14 +139,20 @@ export class ConnectionManager {
139
139
  }
140
140
  static async resolveTenant(tenantId) {
141
141
  const cached = this.tenantCache.get(tenantId);
142
- if (cached)
143
- return cached;
142
+ if (cached) {
143
+ if (!cached.expiresAt || cached.expiresAt > Date.now())
144
+ return cached;
145
+ await this.closeTenant(tenantId);
146
+ }
144
147
  if (!this.tenantResolver) {
145
148
  throw new Error("No tenant resolver configured.");
146
149
  }
147
150
  const resolution = await this.tenantResolver(tenantId);
151
+ const policy = { ...resolution.cache, ttl: resolution.ttl ?? resolution.cache?.ttl, closeOnPurge: resolution.closeOnPurge ?? resolution.cache?.closeOnPurge };
152
+ const resolvedAt = Date.now();
148
153
  const schema = resolution.strategy === "schema" ? resolution.schema : undefined;
149
154
  const schemaMode = resolution.strategy === "schema" ? resolution.mode || "qualify" : undefined;
155
+ let ownsConnection = false;
150
156
  let connection = (resolution.strategy === "schema" || resolution.strategy === "rls") && resolution.connection instanceof Connection
151
157
  ? resolution.connection
152
158
  : (resolution.strategy === "schema" || resolution.strategy === "rls") && typeof resolution.connection === "string"
@@ -167,6 +173,7 @@ export class ConnectionManager {
167
173
  }
168
174
  connection = new Connection(config, { schema });
169
175
  this.connections.set(resolution.name, connection);
176
+ ownsConnection = true;
170
177
  }
171
178
  else if (schema && schemaMode === "qualify") {
172
179
  connection = connection.withSchema(schema);
@@ -176,6 +183,10 @@ export class ConnectionManager {
176
183
  connection,
177
184
  connectionName: resolution.name,
178
185
  strategy: resolution.strategy,
186
+ resolvedAt,
187
+ expiresAt: policy.ttl ? resolvedAt + policy.ttl : undefined,
188
+ closeOnPurge: policy.closeOnPurge ?? ownsConnection,
189
+ ownsConnection,
179
190
  schema,
180
191
  schemaMode,
181
192
  rlsTenantId: resolution.strategy === "rls" ? resolution.tenantId || tenantId : undefined,
@@ -185,19 +196,53 @@ export class ConnectionManager {
185
196
  return context;
186
197
  }
187
198
  static getResolvedTenant(tenantId) {
188
- return this.tenantCache.get(tenantId);
199
+ const context = this.tenantCache.get(tenantId);
200
+ if (!context || !context.expiresAt || context.expiresAt > Date.now())
201
+ return context;
202
+ this.tenantCache.delete(tenantId);
203
+ return undefined;
189
204
  }
190
205
  static purgeTenant(tenantId) {
191
206
  this.tenantCache.delete(tenantId);
192
207
  }
208
+ static async purgeExpiredTenants(options = {}) {
209
+ const now = Date.now();
210
+ const purged = [];
211
+ for (const [tenantId, context] of [...this.tenantCache.entries()]) {
212
+ if (!context.expiresAt || context.expiresAt > now)
213
+ continue;
214
+ purged.push(tenantId);
215
+ if (options.close ?? context.closeOnPurge) {
216
+ await this.closeTenant(tenantId);
217
+ }
218
+ else {
219
+ this.tenantCache.delete(tenantId);
220
+ }
221
+ }
222
+ return purged;
223
+ }
193
224
  static async closeTenant(tenantId) {
194
225
  const context = this.tenantCache.get(tenantId);
195
226
  if (!context)
196
227
  return;
197
228
  this.tenantCache.delete(tenantId);
229
+ if (!context.closeOnPurge)
230
+ return;
198
231
  const connection = this.connections.get(context.connectionName);
199
- this.connections.delete(context.connectionName);
200
- await connection?.close();
232
+ if (connection === context.connection) {
233
+ this.connections.delete(context.connectionName);
234
+ await connection.close();
235
+ }
236
+ else if (context.ownsConnection) {
237
+ await context.connection.close();
238
+ }
239
+ const pool = this.pools.get(context.connectionName);
240
+ if (pool) {
241
+ this.pools.delete(context.connectionName);
242
+ for (const { connection } of pool) {
243
+ await connection.close().catch(() => null);
244
+ }
245
+ }
201
246
  }
202
247
  static async closeAll() {
203
248
  const connections = new Set(this.connections.values());
@@ -4,6 +4,10 @@ export interface ActiveTenantContext {
4
4
  connection: Connection;
5
5
  connectionName: string;
6
6
  strategy: "database" | "schema" | "rls";
7
+ resolvedAt: number;
8
+ expiresAt?: number;
9
+ closeOnPurge: boolean;
10
+ ownsConnection: boolean;
7
11
  schema?: string;
8
12
  schemaMode?: "qualify" | "search_path";
9
13
  rlsTenantId?: string;
@@ -1,6 +1,6 @@
1
1
  export { Connection } from "./connection/Connection.js";
2
2
  export { ConnectionManager } from "./connection/ConnectionManager.js";
3
- export type { TenantResolution, TenantResolver } from "./connection/ConnectionManager.js";
3
+ export type { TenantCachePolicy, TenantResolution, TenantResolver } from "./connection/ConnectionManager.js";
4
4
  export { TenantContext } from "./connection/TenantContext.js";
5
5
  export type { ActiveTenantContext } from "./connection/TenantContext.js";
6
6
  export { configureBunny } from "./config/BunnyConfig.js";
@@ -23,7 +23,10 @@ export { BelongsToMany } from "./model/BelongsToMany.js";
23
23
  export { IdentityMap } from "./model/IdentityMap.js";
24
24
  export { Migration } from "./migration/Migration.js";
25
25
  export { Migrator } from "./migration/Migrator.js";
26
- export type { MigrationEvent, MigrationEventListener, MigrationEventPayload } from "./migration/Migrator.js";
26
+ export type { MigrationEvent, MigrationEventListener, MigrationEventPayload, MigrationStatusRow, MigratorOptions } from "./migration/Migrator.js";
27
27
  export { MigrationCreator } from "./migration/MigrationCreator.js";
28
28
  export { TypeGenerator } from "./typegen/TypeGenerator.js";
29
29
  export { TypeMapper } from "./typegen/TypeMapper.js";
30
+ export { Seeder, SeederRunner } from "./seeding/Seeder.js";
31
+ export { Factory, factory } from "./seeding/Factory.js";
32
+ export type { FactoryDefinition, FactoryState } from "./seeding/Factory.js";
package/dist/src/index.js CHANGED
@@ -21,3 +21,5 @@ export { Migrator } from "./migration/Migrator.js";
21
21
  export { MigrationCreator } from "./migration/MigrationCreator.js";
22
22
  export { TypeGenerator } from "./typegen/TypeGenerator.js";
23
23
  export { TypeMapper } from "./typegen/TypeMapper.js";
24
+ export { Seeder, SeederRunner } from "./seeding/Seeder.js";
25
+ export { Factory, factory } from "./seeding/Factory.js";
@@ -1,5 +1,17 @@
1
1
  import { Connection } from "../connection/Connection.js";
2
2
  import type { TypeGeneratorOptions } from "../typegen/TypeGenerator.js";
3
+ export interface MigrationStatusRow {
4
+ migration: string;
5
+ status: string;
6
+ tenant: string | null;
7
+ checksum?: string;
8
+ storedChecksum?: string | null;
9
+ }
10
+ export interface MigratorOptions {
11
+ tenantId?: string | null;
12
+ lock?: boolean;
13
+ lockTimeoutMs?: number;
14
+ }
3
15
  export type MigrationEvent = "migrating" | "migrated" | "rollingBack" | "rolledBack" | "schemaDumped" | "schemaSquashed";
4
16
  export interface MigrationEventPayload {
5
17
  migration?: string;
@@ -12,25 +24,37 @@ export declare class Migrator {
12
24
  private path;
13
25
  private typesOutDir?;
14
26
  private typeGeneratorOptions;
27
+ private options;
15
28
  private static listeners;
16
- constructor(connection: Connection, path: string | string[], typesOutDir?: string | undefined, typeGeneratorOptions?: Omit<TypeGeneratorOptions, "outDir">);
29
+ constructor(connection: Connection, path: string | string[], typesOutDir?: string | undefined, typeGeneratorOptions?: Omit<TypeGeneratorOptions, "outDir">, options?: MigratorOptions);
17
30
  private getPaths;
18
31
  private ensureMigrationsTable;
32
+ private getTenantId;
33
+ private scopedMigrations;
34
+ private ensureMigrationLocksTable;
35
+ private getLockName;
36
+ private shouldLock;
37
+ private acquireLock;
38
+ private releaseLock;
19
39
  static on(event: MigrationEvent, listener: MigrationEventListener): () => void;
20
40
  static clearListeners(event?: MigrationEvent): void;
21
41
  private emit;
22
42
  private getLastBatchNumber;
23
43
  private getMigrationFiles;
44
+ private checksumFile;
24
45
  run(): Promise<void>;
25
- rollback(): Promise<void>;
46
+ rollback(steps?: number): Promise<void>;
47
+ private getRollbackBatches;
48
+ reset(): Promise<void>;
49
+ refresh(): Promise<void>;
50
+ fresh(): Promise<void>;
26
51
  private generateTypesIfNeeded;
27
- status(): Promise<{
28
- migration: string;
29
- status: string;
30
- }[]>;
52
+ status(): Promise<MigrationStatusRow[]>;
31
53
  dumpSchema(path: string): Promise<string>;
32
54
  squash(path: string): Promise<string>;
33
55
  private getSchemaDumpSql;
56
+ private dropAllTables;
34
57
  private resolve;
35
58
  private getRan;
59
+ private getRanRecords;
36
60
  }