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

typeorm / typeorm / 15219332477

23 May 2025 09:13PM UTC coverage: 17.216% (-59.1%) from 76.346%
15219332477

Pull #11332

github

naorpeled
cr comments - move if block
Pull Request #11332: feat: add new undefined and null behavior flags

1603 of 12759 branches covered (12.56%)

Branch coverage included in aggregate %.

0 of 31 new or added lines in 3 files covered. (0.0%)

14132 existing lines in 166 files now uncovered.

4731 of 24033 relevant lines covered (19.69%)

60.22 hits per line

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

71.43
/src/connection/ConnectionOptionsReader.ts
1
import appRootPath from "app-root-path"
1✔
2
import path from "path"
1✔
3

4
import { DataSourceOptions } from "../data-source/DataSourceOptions"
5
import { TypeORMError } from "../error"
1✔
6
import { PlatformTools } from "../platform/PlatformTools"
1✔
7
import { importOrRequireFile } from "../util/ImportUtils"
1✔
8
import { isAbsolute } from "../util/PathUtils"
1✔
9
import { ConnectionOptionsEnvReader } from "./options-reader/ConnectionOptionsEnvReader"
1✔
10

11
/**
12
 * Reads connection options from the ormconfig.
13
 */
14
export class ConnectionOptionsReader {
1✔
15
    // -------------------------------------------------------------------------
16
    // Constructor
17
    // -------------------------------------------------------------------------
18

19
    constructor(
20
        protected options?: {
11✔
21
            /**
22
             * Directory where ormconfig should be read from.
23
             * By default its your application root (where your app package.json is located).
24
             */
25
            root?: string
26

27
            /**
28
             * Filename of the ormconfig configuration. By default its equal to "ormconfig".
29
             */
30
            configName?: string
31
        },
32
    ) {}
33

34
    // -------------------------------------------------------------------------
35
    // Public Methods
36
    // -------------------------------------------------------------------------
37

38
    /**
39
     * Returns all connection options read from the ormconfig.
40
     */
41
    async all(): Promise<DataSourceOptions[]> {
42
        const options = await this.load()
10✔
43
        if (!options)
10!
44
            throw new TypeORMError(
×
45
                `No connection options were found in any orm configuration files.`,
46
            )
47

48
        return options
10✔
49
    }
50

51
    /**
52
     * Gets a connection with a given name read from ormconfig.
53
     * If connection with such name would not be found then it throw error.
54
     */
55
    async get(name: string): Promise<DataSourceOptions> {
56
        const allOptions = await this.all()
6✔
57
        const targetOptions = allOptions.find(
6✔
58
            (options) =>
59
                options.name === name || (name === "default" && !options.name),
7!
60
        )
61
        if (!targetOptions)
6!
62
            throw new TypeORMError(
×
63
                `Cannot find connection ${name} because its not defined in any orm configuration files.`,
64
            )
65

66
        return targetOptions
6✔
67
    }
68

69
    /**
70
     * Checks if there is a TypeORM configuration file.
71
     */
72
    async has(name: string): Promise<boolean> {
73
        const allOptions = await this.load()
×
74
        if (!allOptions) return false
×
75

76
        const targetOptions = allOptions.find(
×
77
            (options) =>
78
                options.name === name || (name === "default" && !options.name),
×
79
        )
80
        return !!targetOptions
×
81
    }
82

83
    // -------------------------------------------------------------------------
84
    // Protected Methods
85
    // -------------------------------------------------------------------------
86

87
    /**
88
     * Loads all connection options from a configuration file.
89
     *
90
     * todo: get in count NODE_ENV somehow
91
     */
92
    protected async load(): Promise<DataSourceOptions[] | undefined> {
93
        let connectionOptions:
94
            | DataSourceOptions
95
            | DataSourceOptions[]
96
            | undefined = undefined
10✔
97

98
        const fileFormats = [
10✔
99
            "env",
100
            "js",
101
            "mjs",
102
            "cjs",
103
            "ts",
104
            "mts",
105
            "cts",
106
            "json",
107
        ]
108

109
        // Detect if baseFilePath contains file extension
110
        const possibleExtension = this.baseFilePath.substr(
10✔
111
            this.baseFilePath.lastIndexOf("."),
112
        )
113
        const fileExtension = fileFormats.find(
10✔
114
            (extension) => `.${extension}` === possibleExtension,
66✔
115
        )
116

117
        // try to find any of following configuration formats
118
        const foundFileFormat =
119
            fileExtension ||
10✔
120
            fileFormats.find((format) => {
121
                return PlatformTools.fileExist(this.baseFilePath + "." + format)
17✔
122
            })
123

124
        // Determine config file name
125
        const configFile = fileExtension
10✔
126
            ? this.baseFilePath
127
            : this.baseFilePath + "." + foundFileFormat
128

129
        // if .env file found then load all its variables into process.env using dotenv package
130
        if (foundFileFormat === "env") {
10✔
131
            PlatformTools.dotenv(configFile)
3✔
132
        } else if (PlatformTools.fileExist(this.baseDirectory + "/.env")) {
7!
133
            PlatformTools.dotenv(this.baseDirectory + "/.env")
×
134
        }
135

136
        // try to find connection options from any of available sources of configuration
137
        if (
10✔
138
            PlatformTools.getEnvVariable("TYPEORM_CONNECTION") ||
17✔
139
            PlatformTools.getEnvVariable("TYPEORM_URL")
140
        ) {
141
            connectionOptions = await new ConnectionOptionsEnvReader().read()
3✔
142
        } else if (
7!
143
            foundFileFormat === "js" ||
9!
144
            foundFileFormat === "mjs" ||
145
            foundFileFormat === "cjs" ||
146
            foundFileFormat === "ts" ||
147
            foundFileFormat === "mts" ||
148
            foundFileFormat === "cts"
149
        ) {
150
            const [importOrRequireResult, moduleSystem] =
151
                await importOrRequireFile(configFile)
7✔
152
            const configModule = await importOrRequireResult
7✔
153

154
            if (
7✔
155
                moduleSystem === "esm" ||
22✔
156
                (configModule &&
157
                    "__esModule" in configModule &&
158
                    "default" in configModule)
159
            ) {
160
                connectionOptions = configModule.default
1✔
161
            } else {
162
                connectionOptions = configModule
6✔
163
            }
UNCOV
164
        } else if (foundFileFormat === "json") {
×
UNCOV
165
            connectionOptions = require(configFile)
×
166
        }
167

168
        // normalize and return connection options
169
        if (connectionOptions) {
10✔
170
            return this.normalizeConnectionOptions(connectionOptions)
10✔
171
        }
172

173
        return undefined
×
174
    }
175

176
    /**
177
     * Normalize connection options.
178
     */
179
    protected normalizeConnectionOptions(
180
        connectionOptions: DataSourceOptions | DataSourceOptions[],
181
    ): DataSourceOptions[] {
182
        if (!Array.isArray(connectionOptions))
10✔
183
            connectionOptions = [connectionOptions]
3✔
184

185
        connectionOptions.forEach((options) => {
10✔
186
            options.baseDirectory = this.baseDirectory
14✔
187
            if (options.entities) {
14✔
188
                const entities = (options.entities as any[]).map((entity) => {
4✔
189
                    if (
1!
190
                        typeof entity === "string" &&
1!
191
                        entity.substr(0, 1) !== "/"
192
                    )
193
                        return this.baseDirectory + "/" + entity
×
194

195
                    return entity
1✔
196
                })
197
                Object.assign(connectionOptions, { entities: entities })
4✔
198
            }
199
            if (options.subscribers) {
14✔
200
                const subscribers = (options.subscribers as any[]).map(
3✔
201
                    (subscriber) => {
202
                        if (
×
203
                            typeof subscriber === "string" &&
×
204
                            subscriber.substr(0, 1) !== "/"
205
                        )
206
                            return this.baseDirectory + "/" + subscriber
×
207

208
                        return subscriber
×
209
                    },
210
                )
211
                Object.assign(connectionOptions, { subscribers: subscribers })
3✔
212
            }
213
            if (options.migrations) {
14✔
214
                const migrations = (options.migrations as any[]).map(
3✔
215
                    (migration) => {
216
                        if (
×
217
                            typeof migration === "string" &&
×
218
                            migration.substr(0, 1) !== "/"
219
                        )
220
                            return this.baseDirectory + "/" + migration
×
221

222
                        return migration
×
223
                    },
224
                )
225
                Object.assign(connectionOptions, { migrations: migrations })
3✔
226
            }
227

228
            // make database path file in sqlite relative to package.json
229
            if (
14✔
230
                options.type === "sqlite" ||
21✔
231
                options.type === "better-sqlite3"
232
            ) {
233
                if (
9✔
234
                    typeof options.database === "string" &&
42✔
235
                    !isAbsolute(options.database) &&
236
                    options.database.substr(0, 1) !== "/" && // unix absolute
237
                    options.database.substr(1, 2) !== ":\\" && // windows absolute
238
                    options.database !== ":memory:"
239
                ) {
240
                    Object.assign(options, {
4✔
241
                        database: this.baseDirectory + "/" + options.database,
242
                    })
243
                }
244
            }
245
        })
246

247
        return connectionOptions
10✔
248
    }
249

250
    /**
251
     * Gets directory where configuration file should be located and configuration file name.
252
     */
253
    protected get baseFilePath(): string {
254
        return path.resolve(this.baseDirectory, this.baseConfigName)
47✔
255
    }
256

257
    /**
258
     * Gets directory where configuration file should be located.
259
     */
260
    protected get baseDirectory(): string {
261
        return this.options?.root ?? appRootPath.path
72!
262
    }
263

264
    /**
265
     * Gets configuration file name.
266
     */
267
    protected get baseConfigName(): string {
268
        return this.options?.configName ?? "ormconfig"
47✔
269
    }
270
}
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

© 2025 Coveralls, Inc