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

typeorm / typeorm / 13573761448

27 Feb 2025 06:53PM UTC coverage: 72.376% (+0.007%) from 72.369%
13573761448

push

github

web-flow
refactor: use ansis instead of chalk (#11263)

8657 of 12650 branches covered (68.43%)

Branch coverage included in aggregate %.

35 of 52 new or added lines in 11 files covered. (67.31%)

4 existing lines in 3 files now uncovered.

17895 of 24036 relevant lines covered (74.45%)

144036.91 hits per line

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

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

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

19
    builder(args: yargs.Argv) {
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("dr", {
47
                alias: "dryrun",
48
                type: "boolean",
49
                default: false,
50
                describe:
51
                    "Prints out the contents of the migration instead of writing it to a file",
52
            })
53
            .option("ch", {
54
                alias: "check",
55
                type: "boolean",
56
                default: false,
57
                describe:
58
                    "Verifies that the current database is up to date and that no migrations are needed. Otherwise exits with code 1.",
59
            })
60
            .option("t", {
61
                alias: "timestamp",
62
                type: "number",
63
                default: false,
64
                describe: "Custom timestamp for the migration name",
65
            })
66
    }
67

68
    async handler(args: yargs.Arguments<any & { path: string }>) {
69
        const timestamp = CommandUtils.getTimestamp(args.timestamp)
84✔
70
        const extension = args.outputJs ? ".js" : ".ts"
84✔
71
        const fullPath = args.path.startsWith("/")
84!
72
            ? args.path
73
            : path.resolve(process.cwd(), args.path)
74
        const filename = timestamp + "-" + path.basename(fullPath) + extension
84✔
75

76
        let dataSource: DataSource | undefined = undefined
84✔
77
        try {
84✔
78
            dataSource = await CommandUtils.loadDataSource(
84✔
79
                path.resolve(process.cwd(), args.dataSource as string),
80
            )
81
            dataSource.setOptions({
84✔
82
                synchronize: false,
83
                migrationsRun: false,
84
                dropSchema: false,
85
                logging: false,
86
            })
87
            await dataSource.initialize()
84✔
88

89
            const upSqls: string[] = [],
84✔
90
                downSqls: string[] = []
84✔
91

92
            try {
84✔
93
                const sqlInMemory = await dataSource.driver
84✔
94
                    .createSchemaBuilder()
95
                    .log()
96

97
                if (args.pretty) {
84!
98
                    sqlInMemory.upQueries.forEach((upQuery) => {
×
99
                        upQuery.query = MigrationGenerateCommand.prettifyQuery(
×
100
                            upQuery.query,
101
                        )
102
                    })
103
                    sqlInMemory.downQueries.forEach((downQuery) => {
×
104
                        downQuery.query =
×
105
                            MigrationGenerateCommand.prettifyQuery(
106
                                downQuery.query,
107
                            )
108
                    })
109
                }
110

111
                sqlInMemory.upQueries.forEach((upQuery) => {
84✔
112
                    upSqls.push(
93✔
113
                        "        await queryRunner.query(`" +
114
                            upQuery.query.replace(new RegExp("`", "g"), "\\`") +
115
                            "`" +
116
                            MigrationGenerateCommand.queryParams(
117
                                upQuery.parameters,
118
                            ) +
119
                            ");",
120
                    )
121
                })
122
                sqlInMemory.downQueries.forEach((downQuery) => {
84✔
123
                    downSqls.push(
93✔
124
                        "        await queryRunner.query(`" +
125
                            downQuery.query.replace(
126
                                new RegExp("`", "g"),
127
                                "\\`",
128
                            ) +
129
                            "`" +
130
                            MigrationGenerateCommand.queryParams(
131
                                downQuery.parameters,
132
                            ) +
133
                            ");",
134
                    )
135
                })
136
            } finally {
137
                await dataSource.destroy()
84✔
138
            }
139

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

157
            const fileContent = args.outputJs
84✔
158
                ? MigrationGenerateCommand.getJavascriptTemplate(
159
                      path.basename(fullPath),
160
                      timestamp,
161
                      upSqls,
162
                      downSqls.reverse(),
163
                  )
164
                : MigrationGenerateCommand.getTemplate(
165
                      path.basename(fullPath),
166
                      timestamp,
167
                      upSqls,
168
                      downSqls.reverse(),
169
                  )
170

171
            if (args.check) {
84!
172
                console.log(
×
173
                    ansi.yellow`Unexpected changes in database schema were found in check mode:\n\n${ansi.white(
174
                        fileContent,
175
                    )}`,
176
                )
177
                process.exit(1)
×
178
            }
179

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

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

208
    // -------------------------------------------------------------------------
209
    // Protected Static Methods
210
    // -------------------------------------------------------------------------
211

212
    /**
213
     * Formats query parameters for migration queries if parameters actually exist
214
     */
215
    protected static queryParams(parameters: any[] | undefined): string {
216
        if (!parameters || !parameters.length) {
186!
217
            return ""
186✔
218
        }
219

220
        return `, ${JSON.stringify(parameters)}`
×
221
    }
222

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

234
        return `import { MigrationInterface, QueryRunner } from "typeorm";
56✔
235

236
export class ${migrationName} implements MigrationInterface {
237
    name = '${migrationName}'
238

239
    public async up(queryRunner: QueryRunner): Promise<void> {
240
${upSqls.join(`
241
`)}
242
    }
243

244
    public async down(queryRunner: QueryRunner): Promise<void> {
245
${downSqls.join(`
246
`)}
247
    }
248

249
}
250
`
251
    }
252

253
    /**
254
     * Gets contents of the migration file in Javascript.
255
     */
256
    protected static getJavascriptTemplate(
257
        name: string,
258
        timestamp: number,
259
        upSqls: string[],
260
        downSqls: string[],
261
    ): string {
262
        const migrationName = `${camelCase(name, true)}${timestamp}`
28✔
263

264
        return `const { MigrationInterface, QueryRunner } = require("typeorm");
28✔
265

266
module.exports = class ${migrationName} {
267
    name = '${migrationName}'
268

269
    async up(queryRunner) {
270
${upSqls.join(`
271
`)}
272
    }
273

274
    async down(queryRunner) {
275
${downSqls.join(`
276
`)}
277
    }
278
}
279
`
280
    }
281

282
    /**
283
     *
284
     */
285
    protected static prettifyQuery(query: string) {
286
        const formattedQuery = format(query, { indent: "    " })
×
287
        return (
×
288
            "\n" + formattedQuery.replace(/^/gm, "            ") + "\n        "
289
        )
290
    }
291
}
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