mirror of
https://github.com/hexastack/hexabot
synced 2025-01-22 18:45:57 +00:00
test: add unit tests
This commit is contained in:
parent
252857fbf7
commit
923a34c3e4
458
api/src/migration/migration.service.spec.ts
Normal file
458
api/src/migration/migration.service.spec.ts
Normal file
@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright © 2025 Hexastack. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||
*/
|
||||
|
||||
import { existsSync, writeFileSync } from 'fs';
|
||||
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { getModelToken } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { MetadataService } from '@/setting/services/metadata.service';
|
||||
|
||||
import { Migration } from './migration.schema';
|
||||
import { MigrationService } from './migration.service';
|
||||
import { MigrationAction } from './types';
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
describe('MigrationService', () => {
|
||||
let service: MigrationService;
|
||||
let loggerService: LoggerService;
|
||||
let metadataService: MetadataService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
// imports: [
|
||||
// rootMongooseTestModule(() => Promise.resolve()),
|
||||
// MongooseModule.forFeature([MigrationModel]),
|
||||
// ],
|
||||
providers: [
|
||||
MigrationService,
|
||||
{
|
||||
provide: LoggerService,
|
||||
useValue: {
|
||||
log: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: MetadataService,
|
||||
useValue: {
|
||||
get: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: HttpService,
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: ModuleRef,
|
||||
useValue: {
|
||||
get: jest.fn((token: string) => {
|
||||
if (token === 'MONGO_MIGRATION_DIR') {
|
||||
return '/migrations';
|
||||
}
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: getModelToken(Migration.name),
|
||||
useValue: jest.fn(),
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<MigrationService>(MigrationService);
|
||||
loggerService = module.get<LoggerService>(LoggerService);
|
||||
metadataService = module.get<MetadataService>(MetadataService);
|
||||
|
||||
jest.spyOn(service, 'exit').mockImplementation(); // Mock exit to avoid Jest process termination
|
||||
});
|
||||
|
||||
describe('validateMigrationPath', () => {
|
||||
it('should log an error and exit if the migration path does not exist', () => {
|
||||
(existsSync as jest.Mock).mockReturnValue(false);
|
||||
const exitSpy = jest.spyOn(service, 'exit').mockImplementation();
|
||||
|
||||
service.validateMigrationPath();
|
||||
|
||||
expect(loggerService.error).toHaveBeenCalledWith(
|
||||
'Migration directory "/migrations" not exists.',
|
||||
);
|
||||
expect(exitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not log an error or exit if the migration path exists', () => {
|
||||
(existsSync as jest.Mock).mockReturnValue(true);
|
||||
const exitSpy = jest.spyOn(service, 'exit').mockImplementation();
|
||||
|
||||
service.validateMigrationPath();
|
||||
|
||||
expect(loggerService.error).not.toHaveBeenCalled();
|
||||
expect(exitSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create a migration file and log success', () => {
|
||||
const mockFiles = ['12345-some-migration.migration.ts'];
|
||||
jest.spyOn(service, 'getMigrationFiles').mockReturnValue(mockFiles);
|
||||
jest
|
||||
.spyOn(service as any, 'getMigrationTemplate')
|
||||
.mockReturnValue('template');
|
||||
jest
|
||||
.spyOn(service as any, 'getMigrationName')
|
||||
.mockImplementation((file) => file);
|
||||
const exitSpy = jest.spyOn(service, 'exit').mockImplementation();
|
||||
|
||||
(existsSync as jest.Mock).mockReturnValue(true);
|
||||
(writeFileSync as jest.Mock).mockImplementation();
|
||||
|
||||
service.create('v2.2.0');
|
||||
|
||||
const expectedFilePath = expect.stringMatching(
|
||||
/\/migrations\/\d+-v-2-2-0.migration.ts$/,
|
||||
);
|
||||
expect(writeFileSync).toHaveBeenCalledWith(expectedFilePath, 'template');
|
||||
expect(loggerService.log).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/Migration file for "v2.2.0" created/),
|
||||
);
|
||||
expect(exitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should log an error and exit if a migration with the same name exists', () => {
|
||||
const mockFiles = ['12345-v-2-2-1.migration.ts'];
|
||||
jest.spyOn(service, 'getMigrationFiles').mockReturnValue(mockFiles);
|
||||
const exitSpy = jest.spyOn(service, 'exit').mockImplementation();
|
||||
|
||||
service.create('v2.2.1');
|
||||
|
||||
expect(loggerService.error).toHaveBeenCalledWith(
|
||||
'Migration file for "v2.2.1" already exists',
|
||||
);
|
||||
expect(exitSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onApplicationBootstrap', () => {
|
||||
it('should log a message and execute migrations when autoMigrate is true', async () => {
|
||||
process.env.HEXABOT_CLI = '';
|
||||
jest
|
||||
.spyOn(metadataService, 'get')
|
||||
.mockResolvedValue({ name: 'db-version', value: 'v2.1.9' });
|
||||
jest.spyOn(service, 'run').mockResolvedValue();
|
||||
|
||||
await service.onApplicationBootstrap();
|
||||
|
||||
expect(loggerService.log).toHaveBeenCalledWith(
|
||||
'Executing migrations ...',
|
||||
);
|
||||
expect(service.run).toHaveBeenCalledWith({
|
||||
action: 'up',
|
||||
version: 'v2.1.9',
|
||||
isAutoMigrate: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('run', () => {
|
||||
it('should call runUpgrades when version is not provided and isAutoMigrate is true', async () => {
|
||||
const runUpgradesSpy = jest
|
||||
.spyOn(service as any, 'runUpgrades')
|
||||
.mockResolvedValue('v2.2.0');
|
||||
|
||||
await service.run({
|
||||
action: MigrationAction.UP,
|
||||
version: null,
|
||||
isAutoMigrate: true,
|
||||
});
|
||||
|
||||
expect(runUpgradesSpy).toHaveBeenCalledWith('up', null);
|
||||
expect(service.exit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call runAll and exit when version is not provided and isAutoMigrate is false', async () => {
|
||||
const runAllSpy = jest
|
||||
.spyOn(service as any, 'runAll')
|
||||
.mockResolvedValue('v2.2.0');
|
||||
|
||||
await service.run({
|
||||
action: MigrationAction.UP,
|
||||
version: null,
|
||||
isAutoMigrate: false,
|
||||
});
|
||||
|
||||
expect(runAllSpy).toHaveBeenCalledWith('up');
|
||||
expect(service.exit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call runOne and exit when version is provided', async () => {
|
||||
const runOneSpy = jest
|
||||
.spyOn(service as any, 'runOne')
|
||||
.mockResolvedValue('v2.2.0');
|
||||
|
||||
await service.run({
|
||||
action: MigrationAction.UP,
|
||||
version: 'v2.1.9',
|
||||
isAutoMigrate: false,
|
||||
});
|
||||
|
||||
expect(runOneSpy).toHaveBeenCalledWith({
|
||||
action: 'up',
|
||||
version: 'v2.1.9',
|
||||
});
|
||||
expect(service.exit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('runOne', () => {
|
||||
let verifyStatusSpy: jest.SpyInstance;
|
||||
let loadMigrationFileSpy: jest.SpyInstance;
|
||||
let successCallbackSpy: jest.SpyInstance;
|
||||
let failureCallbackSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
verifyStatusSpy = jest
|
||||
.spyOn(service as any, 'verifyStatus')
|
||||
.mockResolvedValue({ exist: false, migrationDocument: {} });
|
||||
loadMigrationFileSpy = jest
|
||||
.spyOn(service as any, 'loadMigrationFile')
|
||||
.mockResolvedValue({
|
||||
up: jest.fn().mockResolvedValue(true),
|
||||
down: jest.fn().mockResolvedValue(true),
|
||||
});
|
||||
successCallbackSpy = jest
|
||||
.spyOn(service as any, 'successCallback')
|
||||
.mockResolvedValue(undefined);
|
||||
failureCallbackSpy = jest
|
||||
.spyOn(service as any, 'failureCallback')
|
||||
.mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
verifyStatusSpy.mockClear();
|
||||
loadMigrationFileSpy.mockClear();
|
||||
successCallbackSpy.mockClear();
|
||||
failureCallbackSpy.mockClear();
|
||||
});
|
||||
|
||||
it('should return false and not execute if migration already exists', async () => {
|
||||
verifyStatusSpy.mockResolvedValue({ exist: true, migrationDocument: {} });
|
||||
|
||||
const result = await (service as any).runOne({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
|
||||
expect(verifyStatusSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
expect(result).toBe(false);
|
||||
expect(loadMigrationFileSpy).not.toHaveBeenCalled();
|
||||
expect(successCallbackSpy).not.toHaveBeenCalled();
|
||||
expect(failureCallbackSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load the migration file and execute the migration action successfully', async () => {
|
||||
const migrationMock = {
|
||||
up: jest.fn().mockResolvedValue(true),
|
||||
};
|
||||
loadMigrationFileSpy.mockResolvedValue(migrationMock);
|
||||
|
||||
const result = await (service as any).runOne({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(verifyStatusSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
expect(loadMigrationFileSpy).toHaveBeenCalledWith('v2.1.9');
|
||||
expect(migrationMock.up).toHaveBeenCalledWith({
|
||||
logger: service['logger'],
|
||||
http: service['httpService'],
|
||||
});
|
||||
expect(successCallbackSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
migrationDocument: {},
|
||||
});
|
||||
expect(failureCallbackSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call failureCallback and log the error if the migration action throws an error', async () => {
|
||||
const migrationMock = {
|
||||
up: jest.fn().mockRejectedValue(new Error('Test Error')),
|
||||
};
|
||||
loadMigrationFileSpy.mockResolvedValue(migrationMock);
|
||||
const loggerSpy = jest.spyOn(service['logger'], 'log');
|
||||
|
||||
const result = await (service as any).runOne({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
expect(result).toBe(false);
|
||||
|
||||
expect(verifyStatusSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
expect(loadMigrationFileSpy).toHaveBeenCalledWith('v2.1.9');
|
||||
expect(migrationMock.up).toHaveBeenCalledWith({
|
||||
logger: service['logger'],
|
||||
http: service['httpService'],
|
||||
});
|
||||
expect(successCallbackSpy).not.toHaveBeenCalled();
|
||||
expect(failureCallbackSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
expect(loggerSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Test Error'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not call successCallback if the migration action returns false', async () => {
|
||||
const migrationMock = {
|
||||
up: jest.fn().mockResolvedValue(false),
|
||||
};
|
||||
loadMigrationFileSpy.mockResolvedValue(migrationMock);
|
||||
|
||||
const result = await (service as any).runOne({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
expect(result).toBe(false);
|
||||
expect(verifyStatusSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.1.9',
|
||||
action: 'up',
|
||||
});
|
||||
expect(loadMigrationFileSpy).toHaveBeenCalledWith('v2.1.9');
|
||||
expect(migrationMock.up).toHaveBeenCalledWith({
|
||||
logger: service['logger'],
|
||||
http: service['httpService'],
|
||||
});
|
||||
expect(successCallbackSpy).not.toHaveBeenCalled();
|
||||
expect(failureCallbackSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('runUpgrades', () => {
|
||||
let getAvailableUpgradeVersionsSpy: jest.SpyInstance;
|
||||
let isNewerVersionSpy: jest.SpyInstance;
|
||||
let runOneSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
getAvailableUpgradeVersionsSpy = jest
|
||||
.spyOn(service as any, 'getAvailableUpgradeVersions')
|
||||
.mockReturnValue(['v2.2.0', 'v2.3.0', 'v2.4.0']); // Mock available versions
|
||||
isNewerVersionSpy = jest
|
||||
.spyOn(service as any, 'isNewerVersion')
|
||||
.mockImplementation(
|
||||
(v1: string, v2: string) =>
|
||||
parseInt(v1.substring(1).replaceAll('.', '')) >
|
||||
parseInt(v2.substring(1).replaceAll('.', '')),
|
||||
); // Simplified mock for version comparison
|
||||
runOneSpy = jest.spyOn(service as any, 'runOne').mockResolvedValue(true);
|
||||
});
|
||||
|
||||
it('should filter versions and call runOne for each newer version', async () => {
|
||||
const result = await (service as any).runUpgrades('up', 'v2.2.0');
|
||||
|
||||
expect(getAvailableUpgradeVersionsSpy).toHaveBeenCalled();
|
||||
expect(runOneSpy).toHaveBeenCalledTimes(2); // Only for 'v2.3.0' and 'v2.4.0'
|
||||
expect(runOneSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.3.0',
|
||||
action: 'up',
|
||||
});
|
||||
expect(runOneSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.4.0',
|
||||
action: 'up',
|
||||
});
|
||||
expect(result).toBe('v2.4.0'); // Last processed version
|
||||
});
|
||||
|
||||
it('should return the initial version if no newer versions are available', async () => {
|
||||
isNewerVersionSpy.mockImplementation(() => false); // Mock to return no newer versions
|
||||
|
||||
const result = await (service as any).runUpgrades('up', 'v2.4.0');
|
||||
|
||||
expect(getAvailableUpgradeVersionsSpy).toHaveBeenCalled();
|
||||
expect(isNewerVersionSpy).toHaveBeenCalledTimes(3);
|
||||
expect(runOneSpy).not.toHaveBeenCalled();
|
||||
expect(result).toBe('v2.4.0'); // Initial version is returned
|
||||
});
|
||||
|
||||
it('should handle empty available versions gracefully', async () => {
|
||||
getAvailableUpgradeVersionsSpy.mockReturnValue([]);
|
||||
|
||||
const result = await (service as any).runUpgrades('up', 'v2.2.0');
|
||||
|
||||
expect(getAvailableUpgradeVersionsSpy).toHaveBeenCalled();
|
||||
expect(isNewerVersionSpy).not.toHaveBeenCalled();
|
||||
expect(runOneSpy).not.toHaveBeenCalled();
|
||||
expect(result).toBe('v2.2.0'); // Initial version is returned
|
||||
});
|
||||
|
||||
it('should propagate errors from runOne', async () => {
|
||||
runOneSpy.mockRejectedValue(new Error('Test Error'));
|
||||
|
||||
await expect(
|
||||
(service as any).runUpgrades('up', 'v2.2.0'),
|
||||
).rejects.toThrow('Test Error');
|
||||
|
||||
expect(getAvailableUpgradeVersionsSpy).toHaveBeenCalled();
|
||||
expect(isNewerVersionSpy).toHaveBeenCalled();
|
||||
expect(runOneSpy).toHaveBeenCalledWith({
|
||||
version: 'v2.3.0',
|
||||
action: 'up',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the migration name without the timestamp and file extension', () => {
|
||||
const result = (service as any).getMigrationName(
|
||||
'1234567890-v-1-0-1.migration.ts',
|
||||
);
|
||||
|
||||
expect(result).toBe('v-1-0-1');
|
||||
});
|
||||
|
||||
it('should load a valid migration file and return it', async () => {
|
||||
const version = 'v2.1.9';
|
||||
|
||||
const mockFiles = ['1234567890-v-2-1-9.migration.js'];
|
||||
jest.spyOn(service, 'getMigrationFiles').mockReturnValue(mockFiles);
|
||||
const mockMigration = {
|
||||
up: jest.fn(),
|
||||
down: jest.fn(),
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(service, 'migrationFilePath', 'get')
|
||||
.mockReturnValue('/migrations');
|
||||
jest.spyOn(service['logger'], 'error').mockImplementation();
|
||||
jest.mock(
|
||||
`/migrations/1234567890-v-2-1-9.migration.js`,
|
||||
() => mockMigration,
|
||||
{
|
||||
virtual: true,
|
||||
},
|
||||
);
|
||||
|
||||
const result = await (service as any).loadMigrationFile(version);
|
||||
|
||||
expect(result.default).toBe(mockMigration);
|
||||
expect(service['logger'].error).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -33,6 +33,9 @@ import {
|
||||
MigrationVersion,
|
||||
} from './types';
|
||||
|
||||
// Version starting which we added the migrations
|
||||
const INITIAL_DB_VERSION = 'v2.1.9';
|
||||
|
||||
@Injectable()
|
||||
export class MigrationService implements OnApplicationBootstrap {
|
||||
constructor(
|
||||
@ -43,7 +46,9 @@ export class MigrationService implements OnApplicationBootstrap {
|
||||
@InjectModel(Migration.name)
|
||||
private readonly migrationModel: Model<Migration>,
|
||||
) {
|
||||
this.validateMigrationPath();
|
||||
if (config.env !== 'test') {
|
||||
this.validateMigrationPath();
|
||||
}
|
||||
}
|
||||
|
||||
async onApplicationBootstrap() {
|
||||
@ -55,8 +60,8 @@ export class MigrationService implements OnApplicationBootstrap {
|
||||
const isCLI = Boolean(process.env.HEXABOT_CLI);
|
||||
if (!isCLI && config.mongo.autoMigrate) {
|
||||
this.logger.log('Executing migrations ...');
|
||||
const metadata = await this.metadataService.getMetadata('db-version');
|
||||
const version = metadata ? metadata.value : 'v2.1.9';
|
||||
const metadata = await this.metadataService.get('db-version');
|
||||
const version = metadata ? metadata.value : INITIAL_DB_VERSION;
|
||||
await this.run({
|
||||
action: MigrationAction.UP,
|
||||
version,
|
||||
@ -101,13 +106,12 @@ export class MigrationService implements OnApplicationBootstrap {
|
||||
* @throws If there is an issue writing the migration file.
|
||||
*/
|
||||
public create(version: MigrationVersion) {
|
||||
const fileName: string = kebabCase(version) + '.migration.ts';
|
||||
|
||||
const name = kebabCase(version) as MigrationName;
|
||||
// check if file already exists
|
||||
const files = this.getMigrationFiles();
|
||||
const exist = files.some((file) => {
|
||||
const migrationName = this.getMigrationName(file);
|
||||
return migrationName === fileName;
|
||||
return migrationName === name;
|
||||
});
|
||||
|
||||
if (exist) {
|
||||
@ -115,7 +119,7 @@ export class MigrationService implements OnApplicationBootstrap {
|
||||
this.exit();
|
||||
}
|
||||
|
||||
const migrationFileName = `${Date.now()}-${fileName}`;
|
||||
const migrationFileName = `${Date.now()}-${name}.migration.ts`;
|
||||
const filePath = join(this.migrationFilePath, migrationFileName);
|
||||
const template = this.getMigrationTemplate();
|
||||
try {
|
||||
@ -155,6 +159,11 @@ module.exports = {
|
||||
* Establishes a MongoDB connection
|
||||
*/
|
||||
private async connect() {
|
||||
// Disable for unit tests
|
||||
if (config.env === 'test') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = await mongoose.connect(config.mongo.uri, {
|
||||
dbName: config.mongo.dbName,
|
||||
@ -217,7 +226,7 @@ module.exports = {
|
||||
});
|
||||
|
||||
if (exist) {
|
||||
return true; // stop exec;
|
||||
return false; // stop exec;
|
||||
}
|
||||
|
||||
try {
|
||||
@ -226,6 +235,7 @@ module.exports = {
|
||||
logger: this.logger,
|
||||
http: this.httpService,
|
||||
});
|
||||
|
||||
if (result) {
|
||||
await this.successCallback({
|
||||
version,
|
||||
@ -233,12 +243,15 @@ module.exports = {
|
||||
migrationDocument,
|
||||
});
|
||||
}
|
||||
|
||||
return result; // stop exec;
|
||||
} catch (e) {
|
||||
this.failureCallback({
|
||||
version,
|
||||
action,
|
||||
});
|
||||
this.logger.log(e.stack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,9 +322,13 @@ module.exports = {
|
||||
private async runAll(action: MigrationAction) {
|
||||
const versions = this.getAvailableUpgradeVersions();
|
||||
|
||||
let lastVersion: MigrationVersion = INITIAL_DB_VERSION;
|
||||
for (const version of versions) {
|
||||
await this.runOne({ version, action });
|
||||
lastVersion = version;
|
||||
}
|
||||
|
||||
return lastVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -399,9 +416,10 @@ module.exports = {
|
||||
const files = this.getMigrationFiles();
|
||||
const migrationName = kebabCase(version) as MigrationName;
|
||||
return (
|
||||
files
|
||||
.map((file) => this.getMigrationName(file))
|
||||
.find((name) => migrationName === name) || null
|
||||
files.find((file) => {
|
||||
const name = this.getMigrationName(file);
|
||||
return migrationName === name;
|
||||
}) || null
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { HydratedDocument, Model } from 'mongoose';
|
||||
|
||||
import { Metadata } from '../schemas/metadata.schema';
|
||||
|
||||
@ -19,17 +20,35 @@ export class MetadataService {
|
||||
private readonly metadataModel: Model<Metadata>,
|
||||
) {}
|
||||
|
||||
private toClassObject(metadata: HydratedDocument<Metadata>) {
|
||||
return plainToClass(
|
||||
Metadata,
|
||||
metadata.toObject({ virtuals: true, getters: true }),
|
||||
{ excludePrefixes: ['_'] },
|
||||
);
|
||||
}
|
||||
|
||||
async createOrUpdate(dto: Metadata) {
|
||||
return await this.metadataModel.findOneAndUpdate({ name: dto.name }, dto, {
|
||||
upsert: true,
|
||||
});
|
||||
const metadata = await this.metadataModel.findOneAndUpdate(
|
||||
{ name: dto.name },
|
||||
dto,
|
||||
{
|
||||
upsert: true,
|
||||
},
|
||||
);
|
||||
return this.toClassObject(metadata);
|
||||
}
|
||||
|
||||
async getMetadata(name: string) {
|
||||
return await this.metadataModel.findOne({ name });
|
||||
async get(name: string) {
|
||||
const metadata = await this.metadataModel.findOne({ name });
|
||||
return this.toClassObject(metadata);
|
||||
}
|
||||
|
||||
async setMetadata(name: string, value: any) {
|
||||
return await this.metadataModel.updateOne({ name }, { $set: { value } });
|
||||
async set(name: string, value: any) {
|
||||
const metadata = await this.metadataModel.findOneAndUpdate(
|
||||
{ name },
|
||||
{ $set: { value } },
|
||||
);
|
||||
return this.toClassObject(metadata);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user