DataSource.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import { DataSource, EntityTarget, LoggerOptions, ObjectLiteral, Repository } from 'typeorm'
  2. import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'
  3. import { Env } from './Env'
  4. import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
  5. import { SQLLegacyItem } from '../Infra/TypeORM/SQLLegacyItem'
  6. import { TypeORMNotification } from '../Infra/TypeORM/TypeORMNotification'
  7. import { TypeORMSharedVault } from '../Infra/TypeORM/TypeORMSharedVault'
  8. import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
  9. import { TypeORMSharedVaultInvite } from '../Infra/TypeORM/TypeORMSharedVaultInvite'
  10. import { TypeORMMessage } from '../Infra/TypeORM/TypeORMMessage'
  11. import { SQLItem } from '../Infra/TypeORM/SQLItem'
  12. export class AppDataSource {
  13. private _dataSource: DataSource | undefined
  14. constructor(
  15. private configuration: {
  16. env: Env
  17. runMigrations: boolean
  18. },
  19. ) {}
  20. getRepository<Entity extends ObjectLiteral>(target: EntityTarget<Entity>): Repository<Entity> {
  21. if (!this._dataSource) {
  22. throw new Error('DataSource not initialized')
  23. }
  24. return this._dataSource.getRepository(target)
  25. }
  26. async initialize(): Promise<void> {
  27. await this.dataSource.initialize()
  28. }
  29. get dataSource(): DataSource {
  30. this.configuration.env.load()
  31. const isConfiguredForMySQL = this.configuration.env.get('DB_TYPE') === 'mysql'
  32. const isConfiguredForHomeServerOrSelfHosting =
  33. this.configuration.env.get('MODE', true) === 'home-server' ||
  34. this.configuration.env.get('MODE', true) === 'self-hosted'
  35. const maxQueryExecutionTime = this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
  36. ? +this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
  37. : 45_000
  38. const migrationsSourceDirectoryName = isConfiguredForMySQL
  39. ? isConfiguredForHomeServerOrSelfHosting
  40. ? 'mysql'
  41. : 'mysql-legacy'
  42. : 'sqlite'
  43. const commonDataSourceOptions = {
  44. maxQueryExecutionTime,
  45. entities: [
  46. isConfiguredForHomeServerOrSelfHosting ? SQLItem : SQLLegacyItem,
  47. TypeORMNotification,
  48. TypeORMSharedVault,
  49. TypeORMSharedVaultUser,
  50. TypeORMSharedVaultInvite,
  51. TypeORMMessage,
  52. ],
  53. migrations: [`${__dirname}/../../migrations/${migrationsSourceDirectoryName}/*.js`],
  54. migrationsRun: this.configuration.runMigrations,
  55. logging: <LoggerOptions>this.configuration.env.get('DB_DEBUG_LEVEL', true) ?? 'info',
  56. }
  57. if (isConfiguredForMySQL) {
  58. const inReplicaMode = this.configuration.env.get('DB_REPLICA_HOST', true) ? true : false
  59. const replicationConfig = {
  60. master: {
  61. host: this.configuration.env.get('DB_HOST'),
  62. port: parseInt(this.configuration.env.get('DB_PORT')),
  63. username: this.configuration.env.get('DB_USERNAME'),
  64. password: this.configuration.env.get('DB_PASSWORD'),
  65. database: this.configuration.env.get('DB_DATABASE'),
  66. },
  67. slaves: [
  68. {
  69. host: this.configuration.env.get('DB_REPLICA_HOST', true),
  70. port: parseInt(this.configuration.env.get('DB_PORT')),
  71. username: this.configuration.env.get('DB_USERNAME'),
  72. password: this.configuration.env.get('DB_PASSWORD'),
  73. database: this.configuration.env.get('DB_DATABASE'),
  74. },
  75. ],
  76. removeNodeErrorCount: 10,
  77. restoreNodeTimeout: 5,
  78. }
  79. const mySQLDataSourceOptions: MysqlConnectionOptions = {
  80. ...commonDataSourceOptions,
  81. type: 'mysql',
  82. charset: 'utf8mb4',
  83. supportBigNumbers: true,
  84. bigNumberStrings: false,
  85. replication: inReplicaMode ? replicationConfig : undefined,
  86. host: inReplicaMode ? undefined : this.configuration.env.get('DB_HOST'),
  87. port: inReplicaMode ? undefined : parseInt(this.configuration.env.get('DB_PORT')),
  88. username: inReplicaMode ? undefined : this.configuration.env.get('DB_USERNAME'),
  89. password: inReplicaMode ? undefined : this.configuration.env.get('DB_PASSWORD'),
  90. database: inReplicaMode ? undefined : this.configuration.env.get('DB_DATABASE'),
  91. }
  92. this._dataSource = new DataSource(mySQLDataSourceOptions)
  93. } else {
  94. const sqliteDataSourceOptions: SqliteConnectionOptions = {
  95. ...commonDataSourceOptions,
  96. type: 'sqlite',
  97. database: this.configuration.env.get('DB_SQLITE_DATABASE_PATH'),
  98. enableWAL: true,
  99. busyErrorRetry: 2000,
  100. }
  101. this._dataSource = new DataSource(sqliteDataSourceOptions)
  102. }
  103. return this._dataSource
  104. }
  105. }