Closed
Description
I know this is not a feature request but maybe this issue can help other people to upgrade. Because I see a lot of people struggling with version update to v0.3.x from v0.2.x.
I finally managed to update our codebase for v0.3.x and wanted to share some paths I followed.
- I had to move all custom repositories to independent services which are using plain repositories. No use for custom repositories anymore. (I don't like it but ok)
- I had to create my own DataSourceManager (for replacement of ConnectionManager in v0.2.x) because we are using singletenant DB structures, on the fly creating data sources and destroying them if necessary.
data-source.ts
import config from "config";
import "reflect-metadata";
import {
DataSource,
DataSourceOptions,
EntityTarget,
ObjectLiteral,
Repository,
} from "typeorm";
import { ORMLogger } from "./utils/ORMLogger";
export const dataSourceOptions: Map<string, DataSourceOptions> = new Map([
[
"default",
{
type: "mysql",
host: config.get("dbHost"),
charset: "utf8mb4_unicode_ci",
port: config.get("dbPort"),
username: config.get("dbUser"),
password: config.get("dbPass"),
database: config.get("adminDbName"),
logger: new ORMLogger(),
acquireTimeout: 50000,
connectTimeout: 50000,
logging: process.env.NODE_ENV !== "production",
migrationsRun: true,
entities: [__dirname + "/models/admin/*.{js,ts}"],
migrations: [__dirname + "/migrations/*.{js,ts}"],
subscribers: [__dirname + "/subscribers/**/*.{js,ts}"],
bigNumberStrings: true,
},
],
[
"mongo-logger",
{
type: "mongodb",
host: config.get("mongoHost"),
port: config.get("mongoPort"),
username: config.get("mongoUser"),
password: config.get("mongoPass"),
database: config.get("mongoDB"),
authSource: "admin",
synchronize: true,
logging: false,
useUnifiedTopology: true,
useNewUrlParser: true,
entities: [__dirname + "/models/mongo/*.{js,ts}"],
migrations: [__dirname + "/migrations/*.{js,ts}"],
subscribers: [__dirname + "/subscribers/*.{js,ts}"],
},
],
["companyContext", getCompanyDataSource(config.get("dbName"), true)],
]);
// to be used instead of getConnectionManager()
export class DataSourceManager {
private static instance: DataSourceManager;
private dataSources: Map<string, DataSource> = new Map();
private constructor() {}
public static getInstance(): DataSourceManager {
if (!DataSourceManager.instance) {
DataSourceManager.instance = new DataSourceManager();
}
return DataSourceManager.instance;
}
public async createDataSource(
name: string,
options?: DataSourceOptions
): Promise<DataSource> {
const _options = options || dataSourceOptions.get(name);
return this.dataSources
.set(name, await new DataSource(_options).initialize())
.get(name);
}
public getDataSource(dataSourceName: string): DataSource {
return this.dataSources.get(dataSourceName || "default");
}
private map() {
return Array.from(this.dataSources.values());
}
public getActiveDataSources() {
return this.map().filter((ds: DataSource) => ds.isInitialized);
}
public debug() {
console.log(
"DataSourceManager.debug",
this.getActiveDataSources().map((ds: DataSource) => {
return {
isInitialized: ds.isInitialized,
type: ds.options.type,
dbName: ds.options.database,
};
})
);
}
public async destroyDataSources() {
return Promise.all(
Array.from(this.dataSources.values()).map((dataStore) =>
dataStore.destroy()
)
)
.then((data) => {
console.log(`Destroyed (${data.length}) data source`);
})
.catch((errors) => {
console.log("Error: Destroying DataSources:", errors);
});
}
}
export function getCompanyDataSource(
databaseName: string,
migrationsRun = true
): DataSourceOptions {
return {
type: "mysql",
charset: "utf8mb4_unicode_ci",
host: config.get("dbHost"),
port: Number(config.get("dbPort")),
username: config.get("dbUser").toString(),
password: config.get("dbPass").toString(),
logger: new ORMLogger(),
database: databaseName,
acquireTimeout: 50000,
connectTimeout: 50000,
logging: process.env.NODE_ENV !== "production",
entities: [
__dirname + "/models/*.{js,ts}",
__dirname + "/modules/**/models/*.{js,ts}",
],
migrations: [__dirname + "/migrations/companyContext/*.{js,ts}"],
subscribers: [__dirname + "/subscribers/**/*.{js,ts}"],
migrationsRun,
bigNumberStrings: true,
};
}
// HELPER FUNCTIONS FOR BETTER TYPEORM v0.2.x -> v0.3.x UPDATE
// to be used instead of getRepository()
export function getDataRepository<Entity extends ObjectLiteral>(
entityClass: EntityTarget<Entity>,
dataSourceName?: string
): Repository<Entity> {
return DataSourceManager.getInstance()
.getDataSource(dataSourceName || "default")
.getRepository(entityClass);
}
// to be used instead of getConnection()
export function getDataSource(dataSourceName?: string): DataSource {
return DataSourceManager.getInstance().getDataSource(
dataSourceName || "default"
);
}
- For CLI I had to export some default dataSources from my own DataSourceManager in seperate files.
package.json old
"typeorm": "ts-node --transpile-only ./node_modules/typeorm/cli.js",
package.json new
"typeorm": "typeorm-ts-node-commonjs",
3.1. Migration run, generate, seed commmands had to change.
for default context from:
npm run typeorm migration:run
npm run typeorm migration:generate -- -n TestMigration
npm run typeorm migration:create -- -n TestSeeds
changed to:
npm run typeorm migration:run -- -d src/data-source-admin.ts
npm run typeorm migration:generate -- -d src/data-source-admin.ts src/migrations/TestMigration
npm run typeorm migration:create -- src/migrations/TestSeeds
for company context from:
npm run typeorm migration:run -- -c companyContext
npm run typeorm migration:generate -- -n TestMigration -c companyContext
npm run typeorm migration:create -- -n TestSeeds
changed to:
npm run typeorm migration:run -- -d src/data-source-company.ts
npm run typeorm migration:generate -- -d src/data-source-company.ts src/migrations/companyContext/TestMigration
npm run typeorm migration:create -- src/migrations/companyContext/TestSeeds
data-source-admin.ts (new file which is used for admin context migration cli)
import { DataSource } from 'typeorm';
import { dataSourceOptions } from './data-source';
const adminDataSourceOptions = dataSourceOptions.get('default');
// this file is only for cli migration utils
export default new DataSource(adminDataSourceOptions);
data-source-company.ts (new file which is used for company context migration cli)
import { DataSource } from 'typeorm';
import { dataSourceOptions } from './data-source';
const companyDataSourceOptions = dataSourceOptions.get('companyContext');
// this file is only for cli migration utils
export default new DataSource(companyDataSourceOptions);
- And I had to convert old usages to new usages. Here are some regex replacers I used for in VSCode:
find: findOne\(([\w.]+)\)
repl: findOne({where: {id: $1}})
find: findOne\(([\w.]+), \{
repl: findOne({where: {id: $1},
find: FindConditions
repl: FindOptionsWhere
- And also I did a lot of manual changes in the codebase for new usages