260322:1648 Correct Coresspondence / Doing RFA / Correct CI
CI Pipeline / build (push) Failing after 12m41s
Build and Deploy / deploy (push) Failing after 2m44s

This commit is contained in:
admin
2026-03-22 16:48:12 +07:00
parent e5deedb42e
commit 11984bfa29
683 changed files with 105251 additions and 29068 deletions
@@ -48,11 +48,11 @@ export class CreateJsonSchemaDto {
@IsObject()
@IsNotEmpty()
schemaDefinition!: Record<string, any>;
schemaDefinition!: Record<string, unknown>;
@IsObject()
@IsOptional()
uiSchema?: Record<string, any>;
uiSchema?: Record<string, unknown>;
@IsArray()
@IsOptional()
@@ -62,7 +62,7 @@ export class CreateJsonSchemaDto {
@IsObject()
@IsOptional()
migrationScript?: Record<string, any>;
migrationScript?: Record<string, unknown>;
@IsBoolean()
@IsOptional()
@@ -16,4 +16,3 @@ export class MigrateDataDto {
@IsOptional()
targetVersion?: number;
}
@@ -11,7 +11,7 @@ export class SearchJsonSchemaDto {
@Transform(({ value }) => {
if (value === 'true') return true;
if (value === 'false') return false;
return value;
return value as boolean | undefined;
})
isActive?: boolean;
@@ -117,7 +117,7 @@ export class JsonSchemaService implements OnModuleInit {
// ถ้าไม่ส่งมา ให้สร้าง UI Schema พื้นฐานให้อัตโนมัติ
createDto.uiSchema = this.uiSchemaService.generateDefaultUiSchema(
createDto.schemaDefinition
);
) as unknown as Record<string, unknown>;
}
// 3. จัดการ Versioning อัตโนมัติ (Auto-increment)
@@ -255,16 +255,17 @@ export class JsonSchemaService implements OnModuleInit {
async validateData(
schemaCode: string,
data: Record<string, unknown>,
options: ValidationOptions = {}
_options: ValidationOptions = {}
): Promise<ValidationResult> {
// 1. ดึงและ Compile Validator
const validate = await this.getValidator(schemaCode);
const schema = await this.findLatestByCode(schemaCode); // ดึง Full Schema เพื่อใช้ Config อื่นๆ
// 2. สำเนาข้อมูลเพื่อป้องกัน Side Effect และเตรียมสำหรับ AJV Mutation (Sanitization)
const dataToValidate: Record<string, unknown> = JSON.parse(
JSON.stringify(data)
);
const dataToValidate = JSON.parse(JSON.stringify(data)) as Record<
string,
unknown
>;
// 3. เริ่มการตรวจสอบ (AJV จะทำการ Coerce Type และ Remove Additional Properties ให้ด้วย)
const valid = validate(dataToValidate);
@@ -59,19 +59,21 @@ export class SchemaMigrationService {
// 2. Fetch Entity Data & Current Version
// Note: This assumes the entity table has 'details' (json) and 'schema_version' (int) columns
// If schema_version is not present, we assume version 1
const entity = await queryRunner.manager.query(
`SELECT details, schema_version FROM ${entityType} WHERE id = ?`,
[entityId]
);
const entities = await queryRunner.manager.query<
{ details: Record<string, unknown>; schema_version: number }[]
>(`SELECT details, schema_version FROM ${entityType} WHERE id = ?`, [
entityId,
]);
if (!entity || entity.length === 0) {
if (!entities || entities.length === 0) {
throw new BadRequestException(
`Entity ${entityType} with ID ${entityId} not found.`
);
}
const currentData = entity[0].details || {};
const currentVersion = entity[0].schema_version || 1;
const entity = entities[0];
const currentData = entity.details || {};
const currentVersion = entity.schema_version || 1;
if (currentVersion >= targetSchema.version) {
return {
@@ -83,7 +85,10 @@ export class SchemaMigrationService {
}
// 3. Find Migration Path (Iterative Upgrade)
let migratedData = JSON.parse(JSON.stringify(currentData));
let migratedData = JSON.parse(JSON.stringify(currentData)) as Record<
string,
unknown
>;
const migratedFields: string[] = [];
// Loop from current version up to target version
@@ -102,10 +107,11 @@ export class SchemaMigrationService {
// Apply steps defined in migrationScript
if (Array.isArray(script.steps)) {
for (const step of script.steps) {
migratedData = await this.applyMigrationStep(step, migratedData);
if (step.config.field || step.config.new_field) {
migratedFields.push(step.config.new_field || step.config.field);
for (const step of script.steps as MigrationStep[]) {
migratedData = this.applyMigrationStep(step, migratedData);
const config = step.config as Record<string, string>;
if (config.field || config.new_field) {
migratedFields.push(config.new_field || config.field);
}
}
}
@@ -158,10 +164,10 @@ export class SchemaMigrationService {
/**
* Apply a single migration step
*/
private async applyMigrationStep(
private applyMigrationStep(
step: MigrationStep,
data: Record<string, unknown>
): Promise<Record<string, unknown>> {
): Record<string, unknown> {
const newData = { ...data };
const field = step.config.field as string;
@@ -190,7 +196,11 @@ export class SchemaMigrationService {
if (newData[field] !== undefined) {
// Simple transform logic (e.g., map values)
if (step.config.transform === 'MAP_VALUES' && step.config.mapping) {
const oldVal = String(newData[field]);
const val = newData[field];
const oldVal =
typeof val === 'string' || typeof val === 'number'
? String(val)
: JSON.stringify(val);
const mapping = step.config.mapping as Record<string, unknown>;
newData[field] = mapping[oldVal] || newData[field];
}
@@ -198,7 +208,11 @@ export class SchemaMigrationService {
else if (step.config.transform === 'TO_NUMBER') {
newData[field] = Number(newData[field]);
} else if (step.config.transform === 'TO_STRING') {
newData[field] = String(newData[field]);
const val = newData[field];
newData[field] =
typeof val === 'string' || typeof val === 'number'
? String(val)
: JSON.stringify(val);
}
}
break;
@@ -83,7 +83,7 @@ export class UiSchemaService {
title: (value.title as string) || this.humanize(key),
description: value.description as string | undefined,
required: ((dataSchema.required as string[]) || []).includes(key),
widget: this.guessWidget(value) as WidgetType,
widget: this.guessWidget(value),
colSpan: 12, // Default full width
};
}
@@ -98,12 +98,12 @@ export class VirtualColumnService {
AND table_name = ?
AND index_name = ?
`;
const result = await queryRunner.query(checkIndexSql, [
const result = (await queryRunner.query(checkIndexSql, [
tableName,
indexName,
]);
])) as { count: number }[];
if (result[0].count == 0) {
if (result[0]?.count === 0) {
const sql = `CREATE ${config.index_type === 'UNIQUE' ? 'UNIQUE' : ''} INDEX ${indexName} ON ${tableName} (${config.column_name})`;
this.logger.log(`Creating Index: ${sql}`);
await queryRunner.query(sql);