178 lines
6.2 KiB
TypeScript
178 lines
6.2 KiB
TypeScript
|
|
/**
|
||
|
|
* Service Repository
|
||
|
|
* Handles CRUD operations for services table
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { BaseRepository } from '../base.repository.ts';
|
||
|
|
import type { TBindValue } from '../types.ts';
|
||
|
|
import type { IService, IPlatformRequirements } from '../../types.ts';
|
||
|
|
import { logger } from '../../logging.ts';
|
||
|
|
import { getErrorMessage } from '../../utils/error.ts';
|
||
|
|
|
||
|
|
export class ServiceRepository extends BaseRepository {
|
||
|
|
async create(service: Omit<IService, 'id'>): Promise<IService> {
|
||
|
|
const now = Date.now();
|
||
|
|
this.query(
|
||
|
|
`INSERT INTO services (
|
||
|
|
name, image, registry, env_vars, port, domain, container_id, status,
|
||
|
|
created_at, updated_at,
|
||
|
|
use_onebox_registry, registry_repository, registry_image_tag,
|
||
|
|
auto_update_on_push, image_digest, platform_requirements
|
||
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||
|
|
[
|
||
|
|
service.name,
|
||
|
|
service.image,
|
||
|
|
service.registry || null,
|
||
|
|
JSON.stringify(service.envVars),
|
||
|
|
service.port,
|
||
|
|
service.domain || null,
|
||
|
|
service.containerID || null,
|
||
|
|
service.status,
|
||
|
|
now,
|
||
|
|
now,
|
||
|
|
service.useOneboxRegistry ? 1 : 0,
|
||
|
|
service.registryRepository || null,
|
||
|
|
service.registryImageTag || 'latest',
|
||
|
|
service.autoUpdateOnPush ? 1 : 0,
|
||
|
|
service.imageDigest || null,
|
||
|
|
JSON.stringify(service.platformRequirements || {}),
|
||
|
|
]
|
||
|
|
);
|
||
|
|
|
||
|
|
return this.getByName(service.name)!;
|
||
|
|
}
|
||
|
|
|
||
|
|
getByName(name: string): IService | null {
|
||
|
|
const rows = this.query('SELECT * FROM services WHERE name = ?', [name]);
|
||
|
|
if (rows.length > 0) {
|
||
|
|
logger.info(`getServiceByName: raw row data: ${JSON.stringify(rows[0])}`);
|
||
|
|
const service = this.rowToService(rows[0]);
|
||
|
|
logger.info(`getServiceByName: service object containerID: ${service.containerID}`);
|
||
|
|
return service;
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
getById(id: number): IService | null {
|
||
|
|
const rows = this.query('SELECT * FROM services WHERE id = ?', [id]);
|
||
|
|
return rows.length > 0 ? this.rowToService(rows[0]) : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
getAll(): IService[] {
|
||
|
|
const rows = this.query('SELECT * FROM services ORDER BY created_at DESC');
|
||
|
|
return rows.map((row) => this.rowToService(row));
|
||
|
|
}
|
||
|
|
|
||
|
|
update(id: number, updates: Partial<IService>): void {
|
||
|
|
const fields: string[] = [];
|
||
|
|
const values: TBindValue[] = [];
|
||
|
|
|
||
|
|
if (updates.image !== undefined) {
|
||
|
|
fields.push('image = ?');
|
||
|
|
values.push(updates.image);
|
||
|
|
}
|
||
|
|
if (updates.registry !== undefined) {
|
||
|
|
fields.push('registry = ?');
|
||
|
|
values.push(updates.registry);
|
||
|
|
}
|
||
|
|
if (updates.envVars !== undefined) {
|
||
|
|
fields.push('env_vars = ?');
|
||
|
|
values.push(JSON.stringify(updates.envVars));
|
||
|
|
}
|
||
|
|
if (updates.port !== undefined) {
|
||
|
|
fields.push('port = ?');
|
||
|
|
values.push(updates.port);
|
||
|
|
}
|
||
|
|
if (updates.domain !== undefined) {
|
||
|
|
fields.push('domain = ?');
|
||
|
|
values.push(updates.domain);
|
||
|
|
}
|
||
|
|
if (updates.containerID !== undefined) {
|
||
|
|
fields.push('container_id = ?');
|
||
|
|
values.push(updates.containerID);
|
||
|
|
}
|
||
|
|
if (updates.status !== undefined) {
|
||
|
|
fields.push('status = ?');
|
||
|
|
values.push(updates.status);
|
||
|
|
}
|
||
|
|
if (updates.useOneboxRegistry !== undefined) {
|
||
|
|
fields.push('use_onebox_registry = ?');
|
||
|
|
values.push(updates.useOneboxRegistry ? 1 : 0);
|
||
|
|
}
|
||
|
|
if (updates.registryRepository !== undefined) {
|
||
|
|
fields.push('registry_repository = ?');
|
||
|
|
values.push(updates.registryRepository);
|
||
|
|
}
|
||
|
|
if (updates.registryImageTag !== undefined) {
|
||
|
|
fields.push('registry_image_tag = ?');
|
||
|
|
values.push(updates.registryImageTag);
|
||
|
|
}
|
||
|
|
if (updates.autoUpdateOnPush !== undefined) {
|
||
|
|
fields.push('auto_update_on_push = ?');
|
||
|
|
values.push(updates.autoUpdateOnPush ? 1 : 0);
|
||
|
|
}
|
||
|
|
if (updates.imageDigest !== undefined) {
|
||
|
|
fields.push('image_digest = ?');
|
||
|
|
values.push(updates.imageDigest);
|
||
|
|
}
|
||
|
|
if (updates.platformRequirements !== undefined) {
|
||
|
|
fields.push('platform_requirements = ?');
|
||
|
|
values.push(JSON.stringify(updates.platformRequirements));
|
||
|
|
}
|
||
|
|
|
||
|
|
fields.push('updated_at = ?');
|
||
|
|
values.push(Date.now());
|
||
|
|
values.push(id);
|
||
|
|
|
||
|
|
this.query(`UPDATE services SET ${fields.join(', ')} WHERE id = ?`, values);
|
||
|
|
}
|
||
|
|
|
||
|
|
delete(id: number): void {
|
||
|
|
this.query('DELETE FROM services WHERE id = ?', [id]);
|
||
|
|
}
|
||
|
|
|
||
|
|
private rowToService(row: any): IService {
|
||
|
|
let envVars = {};
|
||
|
|
const envVarsRaw = row.env_vars || row[4];
|
||
|
|
if (envVarsRaw && envVarsRaw !== 'undefined' && envVarsRaw !== 'null') {
|
||
|
|
try {
|
||
|
|
envVars = JSON.parse(String(envVarsRaw));
|
||
|
|
} catch (e) {
|
||
|
|
logger.warn(`Failed to parse env_vars for service: ${getErrorMessage(e)}`);
|
||
|
|
envVars = {};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let platformRequirements: IPlatformRequirements | undefined;
|
||
|
|
const platformReqRaw = row.platform_requirements;
|
||
|
|
if (platformReqRaw && platformReqRaw !== 'undefined' && platformReqRaw !== 'null' && platformReqRaw !== '{}') {
|
||
|
|
try {
|
||
|
|
platformRequirements = JSON.parse(String(platformReqRaw));
|
||
|
|
} catch (e) {
|
||
|
|
logger.warn(`Failed to parse platform_requirements for service: ${getErrorMessage(e)}`);
|
||
|
|
platformRequirements = undefined;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
id: Number(row.id || row[0]),
|
||
|
|
name: String(row.name || row[1]),
|
||
|
|
image: String(row.image || row[2]),
|
||
|
|
registry: (row.registry || row[3]) ? String(row.registry || row[3]) : undefined,
|
||
|
|
envVars,
|
||
|
|
port: Number(row.port || row[5]),
|
||
|
|
domain: (row.domain || row[6]) ? String(row.domain || row[6]) : undefined,
|
||
|
|
containerID: (row.container_id || row[7]) ? String(row.container_id || row[7]) : undefined,
|
||
|
|
status: String(row.status || row[8]) as IService['status'],
|
||
|
|
createdAt: Number(row.created_at || row[9]),
|
||
|
|
updatedAt: Number(row.updated_at || row[10]),
|
||
|
|
useOneboxRegistry: row.use_onebox_registry ? Boolean(row.use_onebox_registry) : undefined,
|
||
|
|
registryRepository: row.registry_repository ? String(row.registry_repository) : undefined,
|
||
|
|
registryImageTag: row.registry_image_tag ? String(row.registry_image_tag) : undefined,
|
||
|
|
autoUpdateOnPush: row.auto_update_on_push ? Boolean(row.auto_update_on_push) : undefined,
|
||
|
|
imageDigest: row.image_digest ? String(row.image_digest) : undefined,
|
||
|
|
platformRequirements,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|