@depup/typeorm-extension 4.0.0-depup.0 → 4.1.0-depup.0

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
@@ -27,6 +27,7 @@ This is a library to
27
27
  - [Create](#create)
28
28
  - [Drop](#drop)
29
29
  - [Schema Drift](#schema-drift)
30
+ - [Generate Migration](#generate-migration)
30
31
  - [Repair Migrations](#repair-migrations)
31
32
  - [Instances](#instances)
32
33
  - [Single](#single)
@@ -288,6 +289,27 @@ import { assertSchemaMatchesMetadata, getSchemaDrift } from 'typeorm-extension';
288
289
 
289
290
  The same check is available on the command line as `typeorm-extension db drift`, which exits with code `1` on drift.
290
291
 
292
+ #### Generate Migration
293
+
294
+ `generateMigration` writes a migration file from the same schema comparison, using typeorm's own statements and file
295
+ templates. The data source must already be initialized.
296
+
297
+ ```typescript
298
+ import { generateMigration } from 'typeorm-extension';
299
+
300
+ (async () => {
301
+ await generateMigration({
302
+ dataSource,
303
+ name: 'add-role',
304
+ directoryPath: 'src/migrations',
305
+ });
306
+ })();
307
+ ```
308
+
309
+ The file is written as `<timestamp>-<name>.<language>`, by default into `migrations/`. Set `language: 'js'` (plus
310
+ `esm: true` for `export class` syntax) for a JavaScript migration, or `preview: true` to receive the statements without
311
+ writing a file.
312
+
291
313
  #### Repair Migrations
292
314
 
293
315
  Renaming a constraint is dialect-asymmetric and easy to get wrong. These helpers read the current state back from the
package/README.md CHANGED
@@ -13,8 +13,8 @@ npm install @depup/typeorm-extension
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [typeorm-extension](https://www.npmjs.com/package/typeorm-extension) @ 4.0.0 |
17
- | Processed | 2026-08-16 |
16
+ | Original | [typeorm-extension](https://www.npmjs.com/package/typeorm-extension) @ 4.1.0 |
17
+ | Processed | 2026-08-23 |
18
18
  | Smoke test | failed |
19
19
  | Deps updated | 2 |
20
20
 
package/changes.json CHANGED
@@ -9,6 +9,6 @@
9
9
  "to": "^1.6.2"
10
10
  }
11
11
  },
12
- "timestamp": "2026-08-16T00:30:51.033Z",
12
+ "timestamp": "2026-08-23T00:28:11.616Z",
13
13
  "totalUpdated": 2
14
14
  }
package/dist/index.d.mts CHANGED
@@ -592,7 +592,7 @@ type DatabaseCreateContext = Omit<DatabaseBaseContext, 'findOptions'> & {
592
592
  */
593
593
  synchronize: boolean;
594
594
  };
595
- type DatabaseCreateContextInput = Partial<DatabaseCreateContext>;
595
+ type DatabaseCreateContextInput = Partial<DatabaseCreateContext> & Pick<DatabaseBaseContext, 'findOptions'>;
596
596
  type DatabaseDropContext = Omit<DatabaseBaseContext, 'findOptions'> & {
597
597
  /**
598
598
  * Only drop database if existed.
@@ -601,7 +601,7 @@ type DatabaseDropContext = Omit<DatabaseBaseContext, 'findOptions'> & {
601
601
  */
602
602
  ifExist?: boolean;
603
603
  };
604
- type DatabaseDropContextInput = Partial<DatabaseDropContext>;
604
+ type DatabaseDropContextInput = Partial<DatabaseDropContext> & Pick<DatabaseBaseContext, 'findOptions'>;
605
605
  //#endregion
606
606
  //#region src/database/methods/create/module.d.ts
607
607
  /**
@@ -944,6 +944,19 @@ type MigrationGenerateCommandContext = {
944
944
  * Prettify sql statements.
945
945
  */
946
946
  prettify?: boolean;
947
+ /**
948
+ * Language of the generated migration file. It also determines the file extension.
949
+ *
950
+ * @default 'ts'
951
+ */
952
+ language?: 'ts' | 'js';
953
+ /**
954
+ * Generate an ESM (export class) instead of a CommonJS (module.exports) migration.
955
+ * Only applies to the language js.
956
+ *
957
+ * @default false
958
+ */
959
+ esm?: boolean;
947
960
  /**
948
961
  * Only return up- & down-statements instead of backing up the migration to the file system.
949
962
  */
package/dist/index.mjs CHANGED
@@ -6,9 +6,9 @@ import { Brackets, DataSource, InstanceChecker, MigrationExecutor, MssqlParamete
6
6
  import { oneOf, read as read$1, readArray, readBool, readInt, toArray, toBool } from "envix";
7
7
  import { createMerger } from "smob";
8
8
  import { DriverFactory } from "typeorm/driver/DriverFactory.js";
9
- import { pascalCase } from "pascal-case";
10
- import process$1 from "node:process";
9
+ import { CommandUtils } from "typeorm/commands/CommandUtils.js";
11
10
  import { MigrationGenerateCommand } from "typeorm/commands/MigrationGenerateCommand.js";
11
+ import { pascalCase } from "pascal-case";
12
12
  //#region src/errors/base.ts
13
13
  var TypeormExtensionError = class extends Error {};
14
14
  //#endregion
@@ -2434,73 +2434,44 @@ async function dropDatabase(input = {}) {
2434
2434
  }
2435
2435
  //#endregion
2436
2436
  //#region src/database/utils/migration.ts
2437
+ /**
2438
+ * typeorm keeps the statement escaping, the query-parameter formatting and both file
2439
+ * templates as protected statics on its migration:generate command. Subclassing is the
2440
+ * only way to reach them, and reusing them keeps the generated file byte-identical to
2441
+ * the output of `typeorm migration:generate`.
2442
+ */
2437
2443
  var GenerateCommand = class extends MigrationGenerateCommand {
2438
- static prettify(query) {
2439
- return this.prettifyQuery(query);
2444
+ static buildStatement(query, parameters, prettify) {
2445
+ const statement = prettify ? this.prettifyQuery(query) : query;
2446
+ return `await queryRunner.query(\`${this.escapeTemplateLiteral(statement)}\`${this.queryParams(parameters)});`;
2447
+ }
2448
+ static buildContent(context, up, down) {
2449
+ const upStatements = up.map((statement) => ` ${statement}`);
2450
+ const downStatements = down.map((statement) => ` ${statement}`);
2451
+ if (context.language === "js") return this.getJavascriptTemplate(context.name, context.timestamp, upStatements, downStatements, context.esm);
2452
+ return this.getTemplate(context.name, context.timestamp, upStatements, downStatements);
2440
2453
  }
2441
2454
  };
2442
- function queryParams(parameters) {
2443
- if (!parameters || !parameters.length) return "";
2444
- return `, ${JSON.stringify(parameters)}`;
2445
- }
2446
- function buildTemplate(name, timestamp, upStatements, downStatements) {
2447
- const migrationName = `${pascalCase(name)}${timestamp}`;
2448
- const up = upStatements.map((statement) => ` ${statement}`);
2449
- const down = downStatements.map((statement) => ` ${statement}`);
2450
- return `import type { MigrationInterface, QueryRunner } from 'typeorm';
2451
-
2452
- export class ${migrationName} implements MigrationInterface {
2453
- name = '${migrationName}';
2454
-
2455
- public async up(queryRunner: QueryRunner): Promise<void> {
2456
- ${up.join(`
2457
- `)}
2458
- }
2459
- public async down(queryRunner: QueryRunner): Promise<void> {
2460
- ${down.join(`
2461
- `)}
2462
- }
2463
- }
2464
- `;
2465
- }
2466
2455
  async function generateMigration(context) {
2467
- context.name = context.name || "Default";
2468
- const timestamp = context.timestamp || (/* @__PURE__ */ new Date()).getTime();
2469
- const fileName = `${timestamp}-${context.name}.ts`;
2470
- const { dataSource } = context;
2471
- const up = [];
2472
- const down = [];
2473
- const sqlInMemory = await dataSource.driver.createSchemaBuilder().log();
2474
- if (context.prettify) {
2475
- sqlInMemory.upQueries.forEach((upQuery) => {
2476
- upQuery.query = GenerateCommand.prettify(upQuery.query);
2477
- });
2478
- sqlInMemory.downQueries.forEach((downQuery) => {
2479
- downQuery.query = GenerateCommand.prettify(downQuery.query);
2480
- });
2481
- }
2482
- sqlInMemory.upQueries.forEach((upQuery) => {
2483
- up.push(`await queryRunner.query(\`${upQuery.query.replace(/`/g, "\\`")}\`${queryParams(upQuery.parameters)});`);
2484
- });
2485
- sqlInMemory.downQueries.forEach((downQuery) => {
2486
- down.push(`await queryRunner.query(\`${downQuery.query.replace(/`/g, "\\`")}\`${queryParams(downQuery.parameters)});`);
2487
- });
2456
+ const name = context.name || "Default";
2457
+ const timestamp = context.timestamp ?? Date.now();
2458
+ const language = context.language || "ts";
2459
+ const sqlInMemory = await context.dataSource.driver.createSchemaBuilder().log();
2460
+ const up = sqlInMemory.upQueries.map((query) => GenerateCommand.buildStatement(query.query, query.parameters, context.prettify));
2461
+ const down = sqlInMemory.downQueries.map((query) => GenerateCommand.buildStatement(query.query, query.parameters, context.prettify)).reverse();
2488
2462
  if (up.length === 0 && down.length === 0) return {
2489
2463
  up,
2490
2464
  down
2491
2465
  };
2492
- const content = buildTemplate(context.name, timestamp, up, down.reverse());
2466
+ const content = GenerateCommand.buildContent({
2467
+ name,
2468
+ timestamp,
2469
+ language,
2470
+ esm: context.esm || false
2471
+ }, up, down);
2493
2472
  if (!context.preview) {
2494
- let directoryPath;
2495
- if (context.directoryPath) if (!path.isAbsolute(context.directoryPath)) directoryPath = path.join(process$1.cwd(), context.directoryPath);
2496
- else directoryPath = context.directoryPath;
2497
- else directoryPath = path.join(process$1.cwd(), "migrations");
2498
- try {
2499
- await fs.promises.access(directoryPath, fs.constants.R_OK | fs.constants.W_OK);
2500
- } catch {
2501
- await fs.promises.mkdir(directoryPath, { recursive: true });
2502
- }
2503
- await fs.promises.writeFile(path.join(directoryPath, fileName), content, { encoding: "utf-8" });
2473
+ const directoryPath = resolveFilePath(context.directoryPath || "migrations");
2474
+ await CommandUtils.createFile(path.join(directoryPath, `${timestamp}-${name}.${language}`), content);
2504
2475
  }
2505
2476
  return {
2506
2477
  up,