Skip to content

Commit

Permalink
refactor(server): access env via repository (#12987)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrasm91 authored Sep 27, 2024
1 parent 12da250 commit 36ee72c
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 18 deletions.
14 changes: 14 additions & 0 deletions server/src/interfaces/config.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { VectorExtension } from 'src/interfaces/database.interface';

export const IConfigRepository = 'IConfigRepository';

export interface EnvData {
database: {
skipMigrations: boolean;
vectorExtension: VectorExtension;
};
}

export interface IConfigRepository {
getEnv(): EnvData;
}
15 changes: 15 additions & 0 deletions server/src/repositories/config.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Injectable } from '@nestjs/common';
import { getVectorExtension } from 'src/database.config';
import { EnvData, IConfigRepository } from 'src/interfaces/config.interface';

@Injectable()
export class ConfigRepository implements IConfigRepository {
getEnv(): EnvData {
return {
database: {
skipMigrations: process.env.DB_SKIP_MIGRATIONS === 'true',
vectorExtension: getVectorExtension(),
},
};
}
}
3 changes: 3 additions & 0 deletions server/src/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IAlbumRepository } from 'src/interfaces/album.interface';
import { IKeyRepository } from 'src/interfaces/api-key.interface';
import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IAuditRepository } from 'src/interfaces/audit.interface';
import { IConfigRepository } from 'src/interfaces/config.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { IEventRepository } from 'src/interfaces/event.interface';
Expand Down Expand Up @@ -39,6 +40,7 @@ import { AlbumRepository } from 'src/repositories/album.repository';
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
import { AssetRepository } from 'src/repositories/asset.repository';
import { AuditRepository } from 'src/repositories/audit.repository';
import { ConfigRepository } from 'src/repositories/config.repository';
import { CryptoRepository } from 'src/repositories/crypto.repository';
import { DatabaseRepository } from 'src/repositories/database.repository';
import { EventRepository } from 'src/repositories/event.repository';
Expand Down Expand Up @@ -74,6 +76,7 @@ export const repositories = [
{ provide: IAlbumUserRepository, useClass: AlbumUserRepository },
{ provide: IAssetRepository, useClass: AssetRepository },
{ provide: IAuditRepository, useClass: AuditRepository },
{ provide: IConfigRepository, useClass: ConfigRepository },
{ provide: ICryptoRepository, useClass: CryptoRepository },
{ provide: IDatabaseRepository, useClass: DatabaseRepository },
{ provide: IEventRepository, useClass: EventRepository },
Expand Down
45 changes: 30 additions & 15 deletions server/src/services/database.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { DatabaseExtension, EXTENSION_NAMES, IDatabaseRepository } from 'src/interfaces/database.interface';
import { IConfigRepository } from 'src/interfaces/config.interface';
import {
DatabaseExtension,
EXTENSION_NAMES,
IDatabaseRepository,
VectorExtension,
} from 'src/interfaces/database.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { DatabaseService } from 'src/services/database.service';
import { newConfigRepositoryMock } from 'test/repositories/config.repository.mock';
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { Mocked } from 'vitest';

describe(DatabaseService.name, () => {
let sut: DatabaseService;
let configMock: Mocked<IConfigRepository>;
let databaseMock: Mocked<IDatabaseRepository>;
let loggerMock: Mocked<ILoggerRepository>;
let extensionRange: string;
Expand All @@ -16,9 +24,11 @@ describe(DatabaseService.name, () => {
let versionAboveRange: string;

beforeEach(() => {
configMock = newConfigRepositoryMock();
databaseMock = newDatabaseRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new DatabaseService(databaseMock, loggerMock);

sut = new DatabaseService(configMock, databaseMock, loggerMock);

extensionRange = '0.2.x';
databaseMock.getExtensionVersionRange.mockReturnValue(extensionRange);
Expand All @@ -33,11 +43,6 @@ describe(DatabaseService.name, () => {
});
});

afterEach(() => {
delete process.env.DB_SKIP_MIGRATIONS;
delete process.env.DB_VECTOR_EXTENSION;
});

it('should work', () => {
expect(sut).toBeDefined();
});
Expand All @@ -50,12 +55,12 @@ describe(DatabaseService.name, () => {
expect(databaseMock.getPostgresVersion).toHaveBeenCalledTimes(1);
});

describe.each([
describe.each(<Array<{ extension: VectorExtension; extensionName: string }>>[
{ extension: DatabaseExtension.VECTOR, extensionName: EXTENSION_NAMES[DatabaseExtension.VECTOR] },
{ extension: DatabaseExtension.VECTORS, extensionName: EXTENSION_NAMES[DatabaseExtension.VECTORS] },
])('should work with $extensionName', ({ extension, extensionName }) => {
beforeEach(() => {
process.env.DB_VECTOR_EXTENSION = extensionName;
configMock.getEnv.mockReturnValue({ database: { skipMigrations: false, vectorExtension: extension } });
});

it(`should start up successfully with ${extension}`, async () => {
Expand Down Expand Up @@ -236,18 +241,28 @@ describe(DatabaseService.name, () => {
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(loggerMock.fatal).not.toHaveBeenCalled();
});
});

it('should skip migrations if DB_SKIP_MIGRATIONS=true', async () => {
process.env.DB_SKIP_MIGRATIONS = 'true';
it('should skip migrations if DB_SKIP_MIGRATIONS=true', async () => {
configMock.getEnv.mockReturnValue({
database: {
skipMigrations: true,
vectorExtension: DatabaseExtension.VECTORS,
},
});

await expect(sut.onBootstrap()).resolves.toBeUndefined();
await expect(sut.onBootstrap()).resolves.toBeUndefined();

expect(databaseMock.runMigrations).not.toHaveBeenCalled();
});
expect(databaseMock.runMigrations).not.toHaveBeenCalled();
});

it(`should throw error if pgvector extension could not be created`, async () => {
process.env.DB_VECTOR_EXTENSION = 'pgvector';
configMock.getEnv.mockReturnValue({
database: {
skipMigrations: true,
vectorExtension: DatabaseExtension.VECTOR,
},
});
databaseMock.getExtensionVersion.mockResolvedValue({
installedVersion: null,
availableVersion: minVersionInRange,
Expand Down
9 changes: 6 additions & 3 deletions server/src/services/database.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Inject, Injectable } from '@nestjs/common';
import { Duration } from 'luxon';
import semver from 'semver';
import { getVectorExtension } from 'src/database.config';
import { OnEmit } from 'src/decorators';
import { IConfigRepository } from 'src/interfaces/config.interface';
import {
DatabaseExtension,
DatabaseLock,
Expand Down Expand Up @@ -67,6 +67,7 @@ export class DatabaseService {
private reconnection?: NodeJS.Timeout;

constructor(
@Inject(IConfigRepository) private configRepository: IConfigRepository,
@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
Expand All @@ -85,7 +86,8 @@ export class DatabaseService {
}

await this.databaseRepository.withLock(DatabaseLock.Migrations, async () => {
const extension = getVectorExtension();
const envData = this.configRepository.getEnv();
const extension = envData.database.vectorExtension;
const name = EXTENSION_NAMES[extension];
const extensionRange = this.databaseRepository.getExtensionVersionRange(extension);

Expand Down Expand Up @@ -116,7 +118,8 @@ export class DatabaseService {

await this.checkReindexing();

if (process.env.DB_SKIP_MIGRATIONS !== 'true') {
const { database } = this.configRepository.getEnv();
if (!database.skipMigrations) {
await this.databaseRepository.runMigrations();
}
});
Expand Down
14 changes: 14 additions & 0 deletions server/test/repositories/config.repository.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { IConfigRepository } from 'src/interfaces/config.interface';
import { DatabaseExtension } from 'src/interfaces/database.interface';
import { Mocked, vitest } from 'vitest';

export const newConfigRepositoryMock = (): Mocked<IConfigRepository> => {
return {
getEnv: vitest.fn().mockReturnValue({
database: {
skipMigration: false,
vectorExtension: DatabaseExtension.VECTORS,
},
}),
};
};

0 comments on commit 36ee72c

Please sign in to comment.