server: rebuild runtime (colorsJson fix)

This commit is contained in:
2026-10-01 12:24:37 +03:30
parent 6c2e3fd786
commit ac0cd63dbd
4 changed files with 60 additions and 48 deletions
+15 -13
View File
@@ -131920,6 +131920,19 @@ var require_product_color_json_dto = __commonJS({
(0, class_validator_1.IsString)({ each: true }), (0, class_validator_1.IsString)({ each: true }),
__metadata2("design:type", Array) __metadata2("design:type", Array)
], ProductColorJsonItemDto.prototype, "imageUrls", void 0); ], ProductColorJsonItemDto.prototype, "imageUrls", void 0);
function mergeColorImageUrls(imageUrls, imageUrl) {
const merged = [];
const push = /* @__PURE__ */ __name((u) => {
const t = u?.trim();
if (t && !merged.includes(t))
merged.push(t);
}, "push");
for (const u of imageUrls ?? [])
push(u);
push(imageUrl);
return merged;
}
__name(mergeColorImageUrls, "mergeColorImageUrls");
function transformColorsJson(value) { function transformColorsJson(value) {
if (value === void 0 || value === null) if (value === void 0 || value === null)
return void 0; return void 0;
@@ -131950,19 +131963,6 @@ var require_product_color_json_dto = __commonJS({
return out; return out;
} }
__name(transformColorsJson, "transformColorsJson"); __name(transformColorsJson, "transformColorsJson");
function mergeColorImageUrls(imageUrls, imageUrl) {
const merged = [];
const push = /* @__PURE__ */ __name((u) => {
const t = u?.trim();
if (t && !merged.includes(t))
merged.push(t);
}, "push");
for (const u of imageUrls ?? [])
push(u);
push(imageUrl);
return merged;
}
__name(mergeColorImageUrls, "mergeColorImageUrls");
function serializeColorsJsonForDb(raw2, fallbackColor) { function serializeColorsJsonForDb(raw2, fallbackColor) {
if (raw2 === void 0 || raw2 === null) if (raw2 === void 0 || raw2 === null)
return void 0; return void 0;
@@ -132581,6 +132581,7 @@ var require_product_dto = __commonJS({
], CreateProductDto.prototype, "isNew", void 0); ], CreateProductDto.prototype, "isNew", void 0);
__decorate2([ __decorate2([
(0, class_validator_1.IsOptional)(), (0, class_validator_1.IsOptional)(),
(0, class_transformer_1.Transform)(({ value }) => (0, product_color_json_dto_1.transformColorsJson)(value)),
(0, class_validator_1.IsArray)(), (0, class_validator_1.IsArray)(),
(0, class_validator_1.ValidateNested)({ each: true }), (0, class_validator_1.ValidateNested)({ each: true }),
(0, class_transformer_1.Type)(() => product_color_json_dto_1.ProductColorJsonItemDto), (0, class_transformer_1.Type)(() => product_color_json_dto_1.ProductColorJsonItemDto),
@@ -132605,6 +132606,7 @@ var require_product_dto = __commonJS({
exports2.UpdateProductDto = UpdateProductDto; exports2.UpdateProductDto = UpdateProductDto;
__decorate2([ __decorate2([
(0, class_validator_1.IsOptional)(), (0, class_validator_1.IsOptional)(),
(0, class_transformer_1.Transform)(({ value }) => (0, product_color_json_dto_1.transformColorsJson)(value)),
(0, class_validator_1.IsArray)(), (0, class_validator_1.IsArray)(),
(0, class_validator_1.ValidateNested)({ each: true }), (0, class_validator_1.ValidateNested)({ each: true }),
(0, class_transformer_1.Type)(() => product_color_json_dto_1.ProductColorJsonItemDto), (0, class_transformer_1.Type)(() => product_color_json_dto_1.ProductColorJsonItemDto),
+22 -16
View File
@@ -38,26 +38,32 @@ describe('product image separation', () => {
]); ]);
}); });
it('recovers color name from product.color when validation stripped nested fields', () => { it('reads object colorsJson with images for API colors/colorImages', () => {
const db = serializeColorsJsonForDb( const entries = parseColorEntries(
[{ imageUrl: 'data:image/jpeg;base64,xyz' }], [
{
name: 'قرمز شرابی',
imageUrl: 'data:image/jpeg;base64,abc',
imageUrls: ['data:image/jpeg;base64,abc'],
},
],
'قرمز شرابی', 'قرمز شرابی',
); );
expect(db).toEqual([ expect(entries[0]?.imageUrls[0]).toBe('data:image/jpeg;base64,abc');
{
name: 'قرمز شرابی',
imageUrl: 'data:image/jpeg;base64,xyz',
imageUrls: ['data:image/jpeg;base64,xyz'],
},
]);
const entries = parseColorEntries(db, 'قرمز شرابی');
expect(entries[0]?.imageUrls).toEqual(['data:image/jpeg;base64,xyz']);
expect(entries.map((e) => e.name)).toEqual(['قرمز شرابی']);
}); });
it('falls back to product.color when colorsJson rows are empty objects', () => { it('fills color name from product.color when json row has only images', () => {
const entries = parseColorEntries([{}], 'قرمز شرابی'); const entries = parseColorEntries(
expect(entries).toEqual([{ name: 'قرمز شرابی', imageUrls: [] }]); [{ imageUrl: 'data:image/jpeg;base64,x', imageUrls: ['data:image/jpeg;base64,x'] }],
'قرمز شرابی',
);
expect(entries).toEqual([
{
name: 'قرمز شرابی',
imageUrl: 'data:image/jpeg;base64,x',
imageUrls: ['data:image/jpeg;base64,x'],
},
]);
}); });
it('does not merge color images into general list when only imageUrlsJson is set', () => { it('does not merge color images into general list when only imageUrlsJson is set', () => {
+16 -17
View File
@@ -15,6 +15,20 @@ export class ProductColorJsonItemDto {
imageUrls?: string[]; imageUrls?: string[];
} }
function mergeColorImageUrls(
imageUrls?: string[],
imageUrl?: string,
): string[] {
const merged: string[] = [];
const push = (u?: string) => {
const t = u?.trim();
if (t && !merged.includes(t)) merged.push(t);
};
for (const u of imageUrls ?? []) push(u);
push(imageUrl);
return merged;
}
/** نرمال‌سازی colorsJson (رشتهٔ legacy یا آبجکت ادمین) قبل از اعتبارسنجی */ /** نرمال‌سازی colorsJson (رشتهٔ legacy یا آبجکت ادمین) قبل از اعتبارسنجی */
export function transformColorsJson(value: unknown): ProductColorJsonItemDto[] | undefined { export function transformColorsJson(value: unknown): ProductColorJsonItemDto[] | undefined {
if (value === undefined || value === null) return undefined; if (value === undefined || value === null) return undefined;
@@ -50,21 +64,7 @@ export function transformColorsJson(value: unknown): ProductColorJsonItemDto[] |
return out; return out;
} }
function mergeColorImageUrls( /** ذخیره در Prisma — imageUrl + imageUrls برای هر رنگ (از body خام، نه فقط DTO اعتبارسنجی‌شده) */
imageUrls?: string[],
imageUrl?: string,
): string[] {
const merged: string[] = [];
const push = (u?: string) => {
const t = u?.trim();
if (t && !merged.includes(t)) merged.push(t);
};
for (const u of imageUrls ?? []) push(u);
push(imageUrl);
return merged;
}
/** ذخیره در Prisma — imageUrl + imageUrls برای هر رنگ (از body خام یا DTO) */
export function serializeColorsJsonForDb( export function serializeColorsJsonForDb(
raw: unknown, raw: unknown,
fallbackColor?: string, fallbackColor?: string,
@@ -73,8 +73,7 @@ export function serializeColorsJsonForDb(
if (!Array.isArray(raw)) return undefined; if (!Array.isArray(raw)) return undefined;
const colorFallback = fallbackColor?.trim() || ''; const colorFallback = fallbackColor?.trim() || '';
const out: Array<{ name: string; imageUrl?: string; imageUrls?: string[] }> = const out: unknown[] = [];
[];
for (let i = 0; i < raw.length; i++) { for (let i = 0; i < raw.length; i++) {
const item = raw[i]; const item = raw[i];
+7 -2
View File
@@ -9,8 +9,11 @@ import {
MinLength, MinLength,
ValidateNested, ValidateNested,
} from 'class-validator'; } from 'class-validator';
import { Type } from 'class-transformer'; import { Transform, Type } from 'class-transformer';
import { ProductColorJsonItemDto } from './product-color-json.dto'; import {
ProductColorJsonItemDto,
transformColorsJson,
} from './product-color-json.dto';
export class CreateProductDto { export class CreateProductDto {
@IsString() @IsString()
@@ -134,6 +137,7 @@ export class CreateProductDto {
isNew?: boolean; isNew?: boolean;
@IsOptional() @IsOptional()
@Transform(({ value }) => transformColorsJson(value))
@IsArray() @IsArray()
@ValidateNested({ each: true }) @ValidateNested({ each: true })
@Type(() => ProductColorJsonItemDto) @Type(() => ProductColorJsonItemDto)
@@ -153,6 +157,7 @@ export class UpdateProductDto extends PartialType(
OmitType(CreateProductDto, ['companyId'] as const), OmitType(CreateProductDto, ['companyId'] as const),
) { ) {
@IsOptional() @IsOptional()
@Transform(({ value }) => transformColorsJson(value))
@IsArray() @IsArray()
@ValidateNested({ each: true }) @ValidateNested({ each: true })
@Type(() => ProductColorJsonItemDto) @Type(() => ProductColorJsonItemDto)