feat: schema-check (#25904)

This commit is contained in:
Jason Rasmussen
2026-02-12 17:59:00 -05:00
committed by GitHub
parent 7413356a2f
commit 8ef4e4d452
37 changed files with 449 additions and 213 deletions

View File

@@ -1,15 +1,59 @@
import { Injectable } from '@nestjs/common';
import { isAbsolute } from 'node:path';
import { isAbsolute, join } from 'node:path';
import { SALT_ROUNDS } from 'src/constants';
import { MaintenanceAuthDto } from 'src/dtos/maintenance.dto';
import { UserAdminResponseDto, mapUserAdmin } from 'src/dtos/user.dto';
import { MaintenanceAction, SystemMetadataKey } from 'src/enum';
import { BaseService } from 'src/services/base.service';
import { schemaDiff } from 'src/sql-tools';
import { createMaintenanceLoginUrl, generateMaintenanceSecret } from 'src/utils/maintenance';
import { getExternalDomain } from 'src/utils/misc';
export type SchemaReport = {
migrations: MigrationStatus[];
drift: ReturnType<typeof schemaDiff>;
};
type MigrationStatus = {
name: string;
status: 'applied' | 'missing' | 'deleted';
};
@Injectable()
export class CliService extends BaseService {
async schemaReport(): Promise<SchemaReport> {
// eslint-disable-next-line unicorn/prefer-module
const allFiles = await this.storageRepository.readdir(join(__dirname, '../schema/migrations'));
const files = allFiles.filter((file) => file.endsWith('.js')).map((file) => file.slice(0, -3));
const rows = await this.databaseRepository.getMigrations();
const filesSet = new Set(files);
const rowsSet = new Set(rows.map((item) => item.name));
const combined = [...filesSet, ...rowsSet].toSorted();
const migrations: MigrationStatus[] = [];
for (const name of combined) {
if (filesSet.has(name) && rowsSet.has(name)) {
migrations.push({ name, status: 'applied' });
continue;
}
if (filesSet.has(name) && !rowsSet.has(name)) {
migrations.push({ name, status: 'missing' });
continue;
}
if (!filesSet.has(name) && rowsSet.has(name)) {
migrations.push({ name, status: 'deleted' });
continue;
}
}
const drift = await this.databaseRepository.getSchemaDrift();
return { migrations, drift };
}
async listUsers(): Promise<UserAdminResponseDto[]> {
const users = await this.userRepository.getList({ withDeleted: true });
return users.map((user) => mapUserAdmin(user));