1 10
import appRootPath from "app-root-path";
2
import {ConnectionOptions} from "./ConnectionOptions";
3 10
import {PlatformTools} from "../platform/PlatformTools";
4 10
import {ConnectionOptionsEnvReader} from "./options-reader/ConnectionOptionsEnvReader";
5 10
import {ConnectionOptionsYmlReader} from "./options-reader/ConnectionOptionsYmlReader";
6 10
import {ConnectionOptionsXmlReader} from "./options-reader/ConnectionOptionsXmlReader";
7

8
/**
9
 * Reads connection options from the ormconfig.
10
 * Can read from multiple file extensions including env, json, js, xml and yml.
11
 */
12 10
export class ConnectionOptionsReader {
13

14
    // -------------------------------------------------------------------------
15
    // Constructor
16
    // -------------------------------------------------------------------------
17

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

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

32
    // -------------------------------------------------------------------------
33
    // Public Methods
34
    // -------------------------------------------------------------------------
35

36
    /**
37
     * Returns all connection options read from the ormconfig.
38
     */
39 10
    async all(): Promise<ConnectionOptions[]> {
40 10
        const options = await this.load();
41 10
        if (!options)
42 0
            throw new Error(`No connection options were found in any orm configuration files.`);
43

44 10
        return options;
45
    }
46

47
    /**
48
     * Gets a connection with a given name read from ormconfig.
49
     * If connection with such name would not be found then it throw error.
50
     */
51 10
    async get(name: string): Promise<ConnectionOptions> {
52 10
        const allOptions = await this.all();
53 10
        const targetOptions = allOptions.find(options => options.name === name || (name === "default" && !options.name));
54 10
        if (!targetOptions)
55 0
            throw new Error(`Cannot find connection ${name} because its not defined in any orm configuration files.`);
56

57 10
        return targetOptions;
58
    }
59

60
    /**
61
     * Checks if there is a TypeORM configuration file.
62
     */
63 10
    async has(name: string): Promise<boolean> {
64 0
        const allOptions = await this.load();
65 0
        if (!allOptions)
66 0
            return false;
67

68 0
        const targetOptions = allOptions.find(options => options.name === name || (name === "default" && !options.name));
69 0
        return !!targetOptions;
70
    }
71

72
    // -------------------------------------------------------------------------
73
    // Protected Methods
74
    // -------------------------------------------------------------------------
75

76
    /**
77
     * Loads all connection options from a configuration file.
78
     *
79
     * todo: get in count NODE_ENV somehow
80
     */
81 10
    protected async load(): Promise<ConnectionOptions[]|undefined> {
82 10
        let connectionOptions: ConnectionOptions|ConnectionOptions[]|undefined = undefined;
83

84 10
        const fileFormats = ["env", "js", "cjs", "ts", "json", "yml", "yaml", "xml"];
85

86
        // Detect if baseFilePath contains file extension
87 10
        const possibleExtension = this.baseFilePath.substr(this.baseFilePath.lastIndexOf("."));
88 10
        const fileExtension = fileFormats.find(extension => `.${extension}` === possibleExtension);
89

90
        // try to find any of following configuration formats
91 10
        const foundFileFormat = fileExtension || fileFormats.find(format => {
92 10
            return PlatformTools.fileExist(this.baseFilePath + "." + format);
93
        });
94

95
        // Determine config file name
96 10
        const configFile = fileExtension ? this.baseFilePath : this.baseFilePath + "." + foundFileFormat;
97

98
        // if .env file found then load all its variables into process.env using dotenv package
99 10
        if (foundFileFormat === "env") {
100 10
            PlatformTools.dotenv(configFile);
101 10
        } else if (PlatformTools.fileExist(this.baseDirectory + "/.env")) {
102 0
            PlatformTools.dotenv(this.baseDirectory + "/.env");
103
        }
104

105
        // try to find connection options from any of available sources of configuration
106 10
        if (PlatformTools.getEnvVariable("TYPEORM_CONNECTION") || PlatformTools.getEnvVariable("TYPEORM_URL")) {
107 10
            connectionOptions = await new ConnectionOptionsEnvReader().read();
108

109 10
        } else if (foundFileFormat === "js" || foundFileFormat === "cjs" || foundFileFormat === "ts") {
110 10
            const configModule = await require(configFile);
111

112 10
            if (configModule && "__esModule" in configModule && "default" in configModule) {
113 10
                connectionOptions = configModule.default;
114
            } else {
115 10
                connectionOptions = configModule;
116
            }
117

118 10
        } else if (foundFileFormat === "json") {
119 10
            connectionOptions = require(configFile);
120

121 0
        } else if (foundFileFormat === "yml") {
122 0
            connectionOptions = await new ConnectionOptionsYmlReader().read(configFile);
123

124 0
        } else if (foundFileFormat === "yaml") {
125 0
            connectionOptions = await new ConnectionOptionsYmlReader().read(configFile);
126

127 0
        } else if (foundFileFormat === "xml") {
128 0
            connectionOptions = await new ConnectionOptionsXmlReader().read(configFile);
129
        }
130

131
        // normalize and return connection options
132 10
        if (connectionOptions) {
133 10
            return this.normalizeConnectionOptions(connectionOptions);
134
        }
135

136 0
        return undefined;
137
    }
138

139
    /**
140
     * Normalize connection options.
141
     */
142 10
    protected normalizeConnectionOptions(connectionOptions: ConnectionOptions|ConnectionOptions[]): ConnectionOptions[] {
143 10
        if (!(Array.isArray(connectionOptions)))
144 10
            connectionOptions = [connectionOptions];
145

146 10
        connectionOptions.forEach(options => {
147 10
            if (options.entities) {
148 10
                const entities = (options.entities as any[]).map(entity => {
149 10
                    if (typeof entity === "string" && entity.substr(0, 1) !== "/")
150 0
                        return this.baseDirectory + "/" + entity;
151

152 10
                    return entity;
153
                });
154 10
                Object.assign(connectionOptions, { entities: entities });
155
            }
156 10
            if (options.subscribers) {
157 10
                const subscribers = (options.subscribers as any[]).map(subscriber => {
158 0
                    if (typeof subscriber === "string" && subscriber.substr(0, 1) !== "/")
159 0
                        return this.baseDirectory + "/" + subscriber;
160

161 0
                    return subscriber;
162
                });
163 10
                Object.assign(connectionOptions, { subscribers: subscribers });
164
            }
165 10
            if (options.migrations) {
166 10
                const migrations = (options.migrations as any[]).map(migration => {
167 0
                    if (typeof migration === "string" && migration.substr(0, 1) !== "/")
168 0
                        return this.baseDirectory + "/" + migration;
169

170 0
                    return migration;
171
                });
172 10
                Object.assign(connectionOptions, { migrations: migrations });
173
            }
174

175
            // make database path file in sqlite relative to package.json
176 10
            if (options.type === "sqlite" || options.type === "better-sqlite3") {
177 10
                if (typeof options.database === "string" &&
178 10
                    options.database.substr(0, 1) !== "/" &&  // unix absolute
179 10
                    options.database.substr(1, 2) !== ":\\" && // windows absolute
180 10
                    options.database !== ":memory:") {
181 10
                    Object.assign(options, {
182
                        database: this.baseDirectory + "/" + options.database
183
                    });
184
                }
185
            }
186
        });
187

188 10
        return connectionOptions;
189
    }
190

191
    /**
192
     * Gets directory where configuration file should be located and configuration file name.
193
     */
194 10
    protected get baseFilePath(): string {
195 10
        return this.baseDirectory + "/" + this.baseConfigName;
196
    }
197

198
    /**
199
     * Gets directory where configuration file should be located.
200
     */
201 10
    protected get baseDirectory(): string {
202 10
        if (this.options && this.options.root)
203 10
            return this.options.root;
204

205 10
        return appRootPath.path;
206
    }
207

208
    /**
209
     * Gets configuration file name.
210
     */
211 10
    protected get baseConfigName(): string {
212 10
        if (this.options && this.options.configName)
213 10
            return this.options.configName;
214

215 10
        return "ormconfig";
216
    }
217

218 10
}

Read our documentation on viewing source code .

Loading