• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

typeorm / typeorm / 19549987525

20 Nov 2025 08:11PM UTC coverage: 80.769% (+4.3%) from 76.433%
19549987525

push

github

web-flow
ci: run tests on commits to master and next (#11783)

Co-authored-by: Oleg "OSA413" Sokolov <OSA413@users.noreply.github.com>

26500 of 32174 branches covered (82.36%)

Branch coverage included in aggregate %.

91252 of 113615 relevant lines covered (80.32%)

88980.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.86
/src/commands/MigrationGenerateCommand.ts
1
import { format } from "@sqltools/formatter/lib/sqlFormatter"
26✔
2
import ansi from "ansis"
26✔
3
import path from "path"
26✔
4
import process from "process"
26✔
5
import yargs from "yargs"
26✔
6
import { DataSource } from "../data-source"
26✔
7
import { PlatformTools } from "../platform/PlatformTools"
26✔
8
import { camelCase } from "../util/StringUtils"
26✔
9
import { CommandUtils } from "./CommandUtils"
26✔
10

26✔
11
/**
26✔
12
 * Generates a new migration file with sql needs to be executed to update schema.
26✔
13
 */
26✔
14
export class MigrationGenerateCommand implements yargs.CommandModule {
234✔
15
    command = "migration:generate <path>"
234✔
16
    describe =
234✔
17
        "Generates a new migration file with sql needs to be executed to update schema."
234✔
18

234✔
19
    builder(args: yargs.Argv) {
234✔
20
        return args
×
21
            .positional("path", {
×
22
                type: "string",
×
23
                describe: "Path of the migration file",
×
24
                demandOption: true,
×
25
            })
×
26
            .option("dataSource", {
×
27
                alias: "d",
×
28
                type: "string",
×
29
                describe:
×
30
                    "Path to the file where your DataSource instance is defined.",
×
31
                demandOption: true,
×
32
            })
×
33
            .option("p", {
×
34
                alias: "pretty",
×
35
                type: "boolean",
×
36
                default: false,
×
37
                describe: "Pretty-print generated SQL",
×
38
            })
×
39
            .option("o", {
×
40
                alias: "outputJs",
×
41
                type: "boolean",
×
42
                default: false,
×
43
                describe:
×
44
                    "Generate a migration file on Javascript instead of Typescript",
×
45
            })
×
46
            .option("esm", {
×
47
                type: "boolean",
×
48
                default: false,
×
49
                describe:
×
50
                    "Generate a migration file on ESM instead of CommonJS",
×
51
            })
×
52
            .option("dr", {
×
53
                alias: "dryrun",
×
54
                type: "boolean",
×
55
                default: false,
×
56
                describe:
×
57
                    "Prints out the contents of the migration instead of writing it to a file",
×
58
            })
×
59
            .option("ch", {
×
60
                alias: "check",
×
61
                type: "boolean",
×
62
                default: false,
×
63
                describe:
×
64
                    "Verifies that the current database is up to date and that no migrations are needed. Otherwise exits with code 1.",
×
65
            })
×
66
            .option("t", {
×
67
                alias: "timestamp",
×
68
                type: "number",
×
69
                default: false,
×
70
                describe: "Custom timestamp for the migration name",
×
71
            })
×
72
    }
×
73

234✔
74
    async handler(args: yargs.Arguments<any & { path: string }>) {
234✔
75
        const timestamp = CommandUtils.getTimestamp(args.timestamp)
69✔
76
        const extension = args.outputJs ? ".js" : ".ts"
69✔
77
        const fullPath = args.path.startsWith("/")
69✔
78
            ? args.path
69!
79
            : path.resolve(process.cwd(), args.path)
69✔
80
        const filename = timestamp + "-" + path.basename(fullPath) + extension
69✔
81

69✔
82
        let dataSource: DataSource | undefined = undefined
69✔
83
        try {
69✔
84
            dataSource = await CommandUtils.loadDataSource(
69✔
85
                path.resolve(process.cwd(), args.dataSource as string),
69✔
86
            )
69✔
87
            dataSource.setOptions({
69✔
88
                synchronize: false,
69✔
89
                migrationsRun: false,
69✔
90
                dropSchema: false,
69✔
91
                logging: false,
69✔
92
            })
69✔
93
            await dataSource.initialize()
69✔
94

69✔
95
            const upSqls: string[] = [],
69✔
96
                downSqls: string[] = []
69✔
97

69✔
98
            try {
69✔
99
                const sqlInMemory = await dataSource.driver
69✔
100
                    .createSchemaBuilder()
69✔
101
                    .log()
69✔
102

69✔
103
                if (args.pretty) {
69!
104
                    sqlInMemory.upQueries.forEach((upQuery) => {
×
105
                        upQuery.query = MigrationGenerateCommand.prettifyQuery(
×
106
                            upQuery.query,
×
107
                        )
×
108
                    })
×
109
                    sqlInMemory.downQueries.forEach((downQuery) => {
×
110
                        downQuery.query =
×
111
                            MigrationGenerateCommand.prettifyQuery(
×
112
                                downQuery.query,
×
113
                            )
×
114
                    })
×
115
                }
×
116

69✔
117
                sqlInMemory.upQueries.forEach((upQuery) => {
69✔
118
                    upSqls.push(
72✔
119
                        "        await queryRunner.query(`" +
72✔
120
                            upQuery.query.replaceAll("`", "\\`") +
72✔
121
                            "`" +
72✔
122
                            MigrationGenerateCommand.queryParams(
72✔
123
                                upQuery.parameters,
72✔
124
                            ) +
72✔
125
                            ");",
72✔
126
                    )
72✔
127
                })
69✔
128
                sqlInMemory.downQueries.forEach((downQuery) => {
69✔
129
                    downSqls.push(
72✔
130
                        "        await queryRunner.query(`" +
72✔
131
                            downQuery.query.replaceAll("`", "\\`") +
72✔
132
                            "`" +
72✔
133
                            MigrationGenerateCommand.queryParams(
72✔
134
                                downQuery.parameters,
72✔
135
                            ) +
72✔
136
                            ");",
72✔
137
                    )
72✔
138
                })
69✔
139
            } finally {
69✔
140
                await dataSource.destroy()
69✔
141
            }
69✔
142

69✔
143
            if (!upSqls.length) {
69!
144
                if (args.check) {
×
145
                    console.log(
×
146
                        ansi.green`No changes in database schema were found`,
×
147
                    )
×
148
                    process.exit(0)
×
149
                } else {
×
150
                    console.log(
×
151
                        ansi.yellow`No changes in database schema were found - cannot generate a migration. To create a new empty migration use "typeorm migration:create" command`,
×
152
                    )
×
153
                    process.exit(1)
×
154
                }
×
155
            } else if (!args.path) {
69!
156
                console.log(ansi.yellow`Please specify a migration path`)
×
157
                process.exit(1)
×
158
            }
×
159

69✔
160
            const fileContent = args.outputJs
69✔
161
                ? MigrationGenerateCommand.getJavascriptTemplate(
69✔
162
                      path.basename(fullPath),
23✔
163
                      timestamp,
23✔
164
                      upSqls,
23✔
165
                      downSqls.reverse(),
23✔
166
                      args.esm,
23✔
167
                  )
69✔
168
                : MigrationGenerateCommand.getTemplate(
69✔
169
                      path.basename(fullPath),
46✔
170
                      timestamp,
46✔
171
                      upSqls,
46✔
172
                      downSqls.reverse(),
46✔
173
                  )
69✔
174

69✔
175
            if (args.check) {
69!
176
                console.log(
×
177
                    ansi.yellow`Unexpected changes in database schema were found in check mode:\n\n${ansi.white(
×
178
                        fileContent,
×
179
                    )}`,
×
180
                )
×
181
                process.exit(1)
×
182
            }
×
183

69✔
184
            if (args.dryrun) {
69!
185
                console.log(
×
186
                    ansi.green(
×
187
                        `Migration ${ansi.blue(
×
188
                            fullPath + extension,
×
189
                        )} has content:\n\n${ansi.white(fileContent)}`,
×
190
                    ),
×
191
                )
×
192
            } else {
69✔
193
                const migrationFileName =
69✔
194
                    path.dirname(fullPath) + "/" + filename
69✔
195
                await CommandUtils.createFile(migrationFileName, fileContent)
69✔
196

69✔
197
                console.log(
69✔
198
                    ansi.green`Migration ${ansi.blue(
69✔
199
                        migrationFileName,
69✔
200
                    )} has been generated successfully.`,
69✔
201
                )
69✔
202
                if (args.exitProcess !== false) {
69!
203
                    process.exit(0)
×
204
                }
×
205
            }
69✔
206
        } catch (err) {
69!
207
            PlatformTools.logCmdErr("Error during migration generation:", err)
×
208
            process.exit(1)
×
209
        }
×
210
    }
69✔
211

234✔
212
    // -------------------------------------------------------------------------
234✔
213
    // Protected Static Methods
234✔
214
    // -------------------------------------------------------------------------
234✔
215

234✔
216
    /**
234✔
217
     * Formats query parameters for migration queries if parameters actually exist
234✔
218
     */
234✔
219
    protected static queryParams(parameters: any[] | undefined): string {
234✔
220
        if (!parameters || !parameters.length) {
144!
221
            return ""
144✔
222
        }
144✔
223

×
224
        return `, ${JSON.stringify(parameters)}`
×
225
    }
×
226

234✔
227
    /**
234✔
228
     * Gets contents of the migration file.
234✔
229
     */
234✔
230
    protected static getTemplate(
234✔
231
        name: string,
46✔
232
        timestamp: number,
46✔
233
        upSqls: string[],
46✔
234
        downSqls: string[],
46✔
235
    ): string {
46✔
236
        const migrationName = `${camelCase(name, true)}${timestamp}`
46✔
237

46✔
238
        return `import { MigrationInterface, QueryRunner } from "typeorm";
46✔
239

46✔
240
export class ${migrationName} implements MigrationInterface {
46✔
241
    name = '${migrationName}'
46✔
242

46✔
243
    public async up(queryRunner: QueryRunner): Promise<void> {
46✔
244
${upSqls.join(`
46✔
245
`)}
46✔
246
    }
46✔
247

46✔
248
    public async down(queryRunner: QueryRunner): Promise<void> {
46✔
249
${downSqls.join(`
46✔
250
`)}
46✔
251
    }
46✔
252

46✔
253
}
46✔
254
`
46✔
255
    }
46✔
256

234✔
257
    /**
234✔
258
     * Gets contents of the migration file in Javascript.
234✔
259
     */
234✔
260
    protected static getJavascriptTemplate(
234✔
261
        name: string,
23✔
262
        timestamp: number,
23✔
263
        upSqls: string[],
23✔
264
        downSqls: string[],
23✔
265
        esm: boolean,
23✔
266
    ): string {
23✔
267
        const migrationName = `${camelCase(name, true)}${timestamp}`
23✔
268

23✔
269
        const exportMethod = esm ? "export" : "module.exports ="
23!
270

23✔
271
        return `/**
23✔
272
 * @typedef {import('typeorm').MigrationInterface} MigrationInterface
23✔
273
 * @typedef {import('typeorm').QueryRunner} QueryRunner
23✔
274
 */
23✔
275

23✔
276
/**
23✔
277
 * @class
23✔
278
 * @implements {MigrationInterface}
23✔
279
 */
23✔
280
${exportMethod} class ${migrationName} {
23✔
281
    name = '${migrationName}'
23✔
282

23✔
283
    /**
23✔
284
     * @param {QueryRunner} queryRunner
23✔
285
     */
23✔
286
    async up(queryRunner) {
23✔
287
${upSqls.join(`
23✔
288
`)}
23✔
289
    }
23✔
290

23✔
291
    /**
23✔
292
     * @param {QueryRunner} queryRunner
23✔
293
     */
23✔
294
    async down(queryRunner) {
23✔
295
${downSqls.join(`
23✔
296
`)}
23✔
297
    }
23✔
298
}
23✔
299
`
23✔
300
    }
23✔
301

234✔
302
    /**
234✔
303
     *
234✔
304
     */
234✔
305
    protected static prettifyQuery(query: string) {
234✔
306
        const formattedQuery = format(query, { indent: "    " })
×
307
        return (
×
308
            "\n" + formattedQuery.replace(/^/gm, "            ") + "\n        "
×
309
        )
×
310
    }
×
311
}
234✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc