space cleanup

This commit is contained in:
hannathkadher
2024-12-24 08:12:56 +04:00
parent fef44b3c4f
commit 97b53bf417
32 changed files with 12 additions and 732 deletions

View File

@ -9,7 +9,7 @@ import { EmailService } from './util/email.service';
import { ErrorMessageService } from 'src/error-message/error-message.service'; import { ErrorMessageService } from 'src/error-message/error-message.service';
import { TuyaService } from './integrations/tuya/services/tuya.service'; import { TuyaService } from './integrations/tuya/services/tuya.service';
import { SceneDeviceRepository } from './modules/scene-device/repositories'; import { SceneDeviceRepository } from './modules/scene-device/repositories';
import { SpaceProductItemRepository, SpaceRepository } from './modules/space'; import { SpaceRepository } from './modules/space';
import { import {
SpaceModelRepository, SpaceModelRepository,
SubspaceModelRepository, SubspaceModelRepository,
@ -26,7 +26,6 @@ import { SubspaceRepository } from './modules/space/repositories/subspace.reposi
SubspaceRepository, SubspaceRepository,
SubspaceModelRepository, SubspaceModelRepository,
SpaceModelRepository, SpaceModelRepository,
SpaceProductItemRepository,
], ],
exports: [ exports: [
CommonService, CommonService,

View File

@ -11,10 +11,7 @@ import { PermissionTypeEntity } from '../modules/permission/entities';
import { import {
SpaceEntity, SpaceEntity,
SpaceLinkEntity, SpaceLinkEntity,
SpaceProductItemEntity,
SubspaceEntity, SubspaceEntity,
SubspaceProductEntity,
SubspaceProductItemEntity,
} from '../modules/space/entities'; } from '../modules/space/entities';
import { UserSpaceEntity } from '../modules/user/entities'; import { UserSpaceEntity } from '../modules/user/entities';
import { DeviceUserPermissionEntity } from '../modules/device/entities'; import { DeviceUserPermissionEntity } from '../modules/device/entities';
@ -28,7 +25,6 @@ import { CommunityEntity } from '../modules/community/entities';
import { DeviceStatusLogEntity } from '../modules/device-status-log/entities'; import { DeviceStatusLogEntity } from '../modules/device-status-log/entities';
import { SceneEntity, SceneIconEntity } from '../modules/scene/entities'; import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
import { SceneDeviceEntity } from '../modules/scene-device/entities'; import { SceneDeviceEntity } from '../modules/scene-device/entities';
import { SpaceProductEntity } from '../modules/space/entities/space-product.entity';
import { ProjectEntity } from '../modules/project/entities'; import { ProjectEntity } from '../modules/project/entities';
import { import {
SpaceModelEntity, SpaceModelEntity,
@ -65,7 +61,6 @@ import {
SpaceEntity, SpaceEntity,
SpaceLinkEntity, SpaceLinkEntity,
SubspaceEntity, SubspaceEntity,
SpaceProductEntity,
UserSpaceEntity, UserSpaceEntity,
DeviceUserPermissionEntity, DeviceUserPermissionEntity,
RoleTypeEntity, RoleTypeEntity,
@ -81,10 +76,6 @@ import {
SpaceModelEntity, SpaceModelEntity,
SubspaceModelEntity, SubspaceModelEntity,
TagModel, TagModel,
SpaceProductEntity,
SpaceProductItemEntity,
SubspaceProductEntity,
SubspaceProductItemEntity,
InviteUserEntity, InviteUserEntity,
InviteUserSpaceEntity, InviteUserSpaceEntity,
], ],

View File

@ -6,15 +6,10 @@ import {
Unique, Unique,
Index, Index,
JoinColumn, JoinColumn,
OneToOne,
} from 'typeorm'; } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { DeviceDto, DeviceUserPermissionDto } from '../dtos/device.dto'; import { DeviceDto, DeviceUserPermissionDto } from '../dtos/device.dto';
import { import { SpaceEntity, SubspaceEntity } from '../../space/entities';
SpaceEntity,
SpaceProductItemEntity,
SubspaceEntity,
} from '../../space/entities';
import { ProductEntity } from '../../product/entities'; import { ProductEntity } from '../../product/entities';
import { UserEntity } from '../../user/entities'; import { UserEntity } from '../../user/entities';
import { DeviceNotificationDto } from '../dtos'; import { DeviceNotificationDto } from '../dtos';
@ -79,11 +74,6 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
@OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {}) @OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {})
sceneDevices: SceneDeviceEntity[]; sceneDevices: SceneDeviceEntity[];
@OneToOne(() => SpaceProductItemEntity, (tag) => tag.device, {
nullable: true,
})
public tag?: SpaceProductItemEntity;
constructor(partial: Partial<DeviceEntity>) { constructor(partial: Partial<DeviceEntity>) {
super(); super();
Object.assign(this, partial); Object.assign(this, partial);

View File

@ -2,7 +2,6 @@ import { Column, Entity, OneToMany } from 'typeorm';
import { ProductDto } from '../dtos'; import { ProductDto } from '../dtos';
import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { DeviceEntity } from '../../device/entities'; import { DeviceEntity } from '../../device/entities';
import { SpaceProductEntity } from '../../space/entities/space-product.entity';
import { TagModel } from '../../space-model'; import { TagModel } from '../../space-model';
@Entity({ name: 'product' }) @Entity({ name: 'product' })
@ -28,9 +27,6 @@ export class ProductEntity extends AbstractEntity<ProductDto> {
}) })
public prodType: string; public prodType: string;
@OneToMany(() => SpaceProductEntity, (spaceProduct) => spaceProduct.product)
spaceProducts: SpaceProductEntity[];
@OneToMany(() => TagModel, (tag) => tag.product) @OneToMany(() => TagModel, (tag) => tag.product)
tagModels: TagModel[]; tagModels: TagModel[];

View File

@ -1,4 +1,2 @@
export * from './space.dto'; export * from './space.dto';
export * from './subspace.dto'; export * from './subspace.dto';
export * from './space-product-item.dto';
export * from './space-product.dto';

View File

@ -1,15 +0,0 @@
import { IsString, IsNotEmpty } from 'class-validator';
export class SpaceProductItemDto {
@IsString()
@IsNotEmpty()
uuid: string;
@IsString()
@IsNotEmpty()
tag: string;
@IsString()
@IsNotEmpty()
spaceProductUuid: string;
}

View File

@ -1,19 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';
import { SpaceProductItemDto } from './space-product-item.dto';
export class SpaceProductModelDto {
@IsString()
@IsNotEmpty()
uuid: string;
@IsString()
@IsNotEmpty()
productUuid: string;
@ApiProperty({
description: 'List of individual items with specific names for the product',
type: [SpaceProductItemDto],
})
items: SpaceProductItemDto[];
}

View File

@ -1,5 +1,3 @@
export * from './space.entity'; export * from './space.entity';
export * from './subspace'; export * from './subspace';
export * from './space-product.entity';
export * from './space-product-item.entity';
export * from './space-link.entity'; export * from './space-link.entity';

View File

@ -1,29 +0,0 @@
import { Column, Entity, ManyToOne, OneToOne } from 'typeorm';
import { SpaceProductEntity } from './space-product.entity';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { SpaceProductItemDto } from '../dtos';
import { DeviceEntity } from '../../device/entities';
@Entity({ name: 'space-product-item' })
export class SpaceProductItemEntity extends AbstractEntity<SpaceProductItemDto> {
@Column({
nullable: false,
})
public tag: string;
@ManyToOne(() => SpaceProductEntity, (spaceProduct) => spaceProduct.items, {
nullable: false,
})
public spaceProduct: SpaceProductEntity;
@Column({
nullable: false,
default: false,
})
public disabled: boolean;
@OneToOne(() => DeviceEntity, (device) => device.tag, {
nullable: true,
})
public device?: DeviceEntity;
}

View File

@ -1,38 +0,0 @@
import { Column, Entity, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
import { SpaceEntity } from './space.entity';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { ProductEntity } from '../../product/entities';
import { SpaceProductItemEntity } from './space-product-item.entity';
@Entity({ name: 'space-product' })
export class SpaceProductEntity extends AbstractEntity<SpaceProductEntity> {
@ManyToOne(() => SpaceEntity, (space) => space.spaceProducts, {
nullable: false,
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'space_uuid' })
space: SpaceEntity;
@ManyToOne(() => ProductEntity, (product) => product.spaceProducts, {
nullable: false,
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'product_uuid' })
product: ProductEntity;
@Column({
nullable: false,
default: false,
})
public disabled: boolean;
@OneToMany(() => SpaceProductItemEntity, (item) => item.spaceProduct, {
cascade: true,
})
public items: SpaceProductItemEntity[];
constructor(partial: Partial<SpaceProductEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -13,7 +13,6 @@ import { DeviceEntity } from '../../device/entities';
import { CommunityEntity } from '../../community/entities'; import { CommunityEntity } from '../../community/entities';
import { SubspaceEntity } from './subspace'; import { SubspaceEntity } from './subspace';
import { SpaceLinkEntity } from './space-link.entity'; import { SpaceLinkEntity } from './space-link.entity';
import { SpaceProductEntity } from './space-product.entity';
import { SceneEntity } from '../../scene/entities'; import { SceneEntity } from '../../scene/entities';
import { SpaceModelEntity } from '../../space-model'; import { SpaceModelEntity } from '../../space-model';
import { InviteUserSpaceEntity } from '../../Invite-user/entities'; import { InviteUserSpaceEntity } from '../../Invite-user/entities';
@ -100,9 +99,6 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
}) })
public icon: string; public icon: string;
@OneToMany(() => SpaceProductEntity, (spaceProduct) => spaceProduct.space)
spaceProducts: SpaceProductEntity[];
@OneToMany(() => SceneEntity, (scene) => scene.space) @OneToMany(() => SceneEntity, (scene) => scene.space)
scenes: SceneEntity[]; scenes: SceneEntity[];

View File

@ -1,3 +1 @@
export * from './subspace.entity'; export * from './subspace.entity';
export * from './subspace-product.entity';
export * from './subspace-product-item.entity';

View File

@ -1,32 +0,0 @@
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
import { SpaceProductItemDto } from '../../dtos';
import { Column, Entity, ManyToOne } from 'typeorm';
import { SubspaceProductEntity } from './subspace-product.entity';
@Entity({ name: 'subspace-product-item' })
export class SubspaceProductItemEntity extends AbstractEntity<SpaceProductItemDto> {
@Column({
nullable: false,
})
public tag: string;
@ManyToOne(
() => SubspaceProductEntity,
(subspaceProduct) => subspaceProduct.items,
{
nullable: false,
},
)
public subspaceProduct: SubspaceProductEntity;
@Column({
nullable: false,
default: false,
})
public disabled: boolean;
constructor(partial: Partial<SubspaceProductItemEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -1,38 +0,0 @@
import { ProductEntity } from '@app/common/modules/product/entities';
import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
import { SubspaceEntity } from './subspace.entity';
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
import { SubspaceProductItemEntity } from './subspace-product-item.entity';
import { SpaceProductModelDto } from '../../dtos';
@Entity({ name: 'subspace-product' })
export class SubspaceProductEntity extends AbstractEntity<SpaceProductModelDto> {
@Column({
type: 'uuid',
default: () => 'gen_random_uuid()',
nullable: false,
})
public uuid: string;
@Column({
nullable: false,
default: false,
})
public disabled: boolean;
@ManyToOne(() => SubspaceEntity, (subspace) => subspace.subspaceProducts, {
nullable: false,
})
public subspace: SubspaceEntity;
@ManyToOne(() => ProductEntity, (product) => product.spaceProducts, {
nullable: false,
})
public product: ProductEntity;
@OneToMany(() => SubspaceProductItemEntity, (item) => item.subspaceProduct, {
nullable: true,
})
public items: SubspaceProductItemEntity[];
}

View File

@ -4,7 +4,6 @@ import { SubspaceModelEntity } from '@app/common/modules/space-model';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm'; import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { SubspaceDto } from '../../dtos'; import { SubspaceDto } from '../../dtos';
import { SpaceEntity } from '../space.entity'; import { SpaceEntity } from '../space.entity';
import { SubspaceProductEntity } from './subspace-product.entity';
@Entity({ name: 'subspace' }) @Entity({ name: 'subspace' })
export class SubspaceEntity extends AbstractEntity<SubspaceDto> { export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
@ -41,15 +40,6 @@ export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
@JoinColumn({ name: 'subspace_model_uuid' }) @JoinColumn({ name: 'subspace_model_uuid' })
subSpaceModel?: SubspaceModelEntity; subSpaceModel?: SubspaceModelEntity;
@OneToMany(
() => SubspaceProductEntity,
(subspaceProduct) => subspaceProduct.subspace,
{
nullable: true,
},
)
public subspaceProducts: SubspaceProductEntity[];
constructor(partial: Partial<SubspaceEntity>) { constructor(partial: Partial<SubspaceEntity>) {
super(); super();
Object.assign(this, partial); Object.assign(this, partial);

View File

@ -1,11 +1,6 @@
import { DataSource, Repository } from 'typeorm'; import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { SpaceProductEntity } from '../entities/space-product.entity'; import { SpaceEntity, SpaceLinkEntity } from '../entities';
import {
SpaceEntity,
SpaceLinkEntity,
SpaceProductItemEntity,
} from '../entities';
@Injectable() @Injectable()
export class SpaceRepository extends Repository<SpaceEntity> { export class SpaceRepository extends Repository<SpaceEntity> {
@ -20,16 +15,3 @@ export class SpaceLinkRepository extends Repository<SpaceLinkEntity> {
super(SpaceLinkEntity, dataSource.createEntityManager()); super(SpaceLinkEntity, dataSource.createEntityManager());
} }
} }
@Injectable()
export class SpaceProductRepository extends Repository<SpaceProductEntity> {
constructor(private dataSource: DataSource) {
super(SpaceProductEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class SpaceProductItemRepository extends Repository<SpaceProductItemEntity> {
constructor(private dataSource: DataSource) {
super(SpaceProductItemEntity, dataSource.createEntityManager());
}
}

View File

@ -1,9 +1,5 @@
import { DataSource, Repository } from 'typeorm'; import { DataSource, Repository } from 'typeorm';
import { import { SubspaceEntity } from '../entities';
SubspaceEntity,
SubspaceProductEntity,
SubspaceProductItemEntity,
} from '../entities';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
@ -12,17 +8,3 @@ export class SubspaceRepository extends Repository<SubspaceEntity> {
super(SubspaceEntity, dataSource.createEntityManager()); super(SubspaceEntity, dataSource.createEntityManager());
} }
} }
@Injectable()
export class SubspaceProductRepository extends Repository<SubspaceProductEntity> {
constructor(private dataSource: DataSource) {
super(SubspaceProductEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class SubspaceProductItemRepository extends Repository<SubspaceProductItemEntity> {
constructor(private dataSource: DataSource) {
super(SubspaceProductItemEntity, dataSource.createEntityManager());
}
}

View File

@ -1,17 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { SpaceEntity, SubspaceEntity, SubspaceProductEntity } from './entities'; import { SpaceEntity, SubspaceEntity } from './entities';
@Module({ @Module({
providers: [], providers: [],
exports: [], exports: [],
controllers: [], controllers: [],
imports: [ imports: [TypeOrmModule.forFeature([SpaceEntity, SubspaceEntity])],
TypeOrmModule.forFeature([
SpaceEntity,
SubspaceEntity,
SubspaceProductEntity,
]),
],
}) })
export class SpaceRepositoryModule {} export class SpaceRepositoryModule {}

View File

@ -17,11 +17,7 @@ import { ProductRepository } from '@app/common/modules/product/repositories';
import { PropogateSubspaceHandler } from './handlers'; import { PropogateSubspaceHandler } from './handlers';
import { CqrsModule } from '@nestjs/cqrs'; import { CqrsModule } from '@nestjs/cqrs';
import { SpaceRepository } from '@app/common/modules/space'; import { SpaceRepository } from '@app/common/modules/space';
import { import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
SubspaceProductItemRepository,
SubspaceProductRepository,
SubspaceRepository,
} from '@app/common/modules/space/repositories/subspace.repository';
const CommandHandlers = [PropogateSubspaceHandler]; const CommandHandlers = [PropogateSubspaceHandler];
@ -38,8 +34,6 @@ const CommandHandlers = [PropogateSubspaceHandler];
SubspaceModelRepository, SubspaceModelRepository,
ProductRepository, ProductRepository,
SubspaceRepository, SubspaceRepository,
SubspaceProductRepository,
SubspaceProductItemRepository,
TagModelService, TagModelService,
TagModelRepository, TagModelRepository,
], ],

View File

@ -12,35 +12,6 @@ import {
} from 'class-validator'; } from 'class-validator';
import { AddSubspaceDto } from './subspace'; import { AddSubspaceDto } from './subspace';
export class CreateSpaceProductItemDto {
@ApiProperty({
description: 'Specific name for the product item',
example: 'Light 1',
})
@IsNotEmpty()
@IsString()
tag: string;
}
export class ProductAssignmentDto {
@ApiProperty({
description: 'UUID of the product to be assigned',
example: 'prod-uuid-1234',
})
@IsNotEmpty()
productId: string;
@ApiProperty({
description: 'Specific names for each product item',
type: [CreateSpaceProductItemDto],
example: [{ tag: 'Light 1' }, { tag: 'Light 2' }, { tag: 'Light 3' }],
})
@IsArray()
@ValidateNested({ each: true })
@Type(() => CreateSpaceProductItemDto)
items: CreateSpaceProductItemDto[];
}
export class AddSpaceDto { export class AddSpaceDto {
@ApiProperty({ @ApiProperty({
description: 'Name of the space (e.g., Floor 1, Unit 101)', description: 'Name of the space (e.g., Floor 1, Unit 101)',
@ -97,17 +68,6 @@ export class AddSpaceDto {
@IsOptional() @IsOptional()
direction?: string; direction?: string;
@ApiProperty({
description: 'List of products assigned to this space',
type: [ProductAssignmentDto],
required: false,
})
@IsArray()
@ValidateNested({ each: true })
@IsOptional()
@Type(() => ProductAssignmentDto)
products?: ProductAssignmentDto[];
@ApiProperty({ @ApiProperty({
description: 'List of subspaces included in the model', description: 'List of subspaces included in the model',
type: [AddSubspaceDto], type: [AddSubspaceDto],

View File

@ -1,13 +1,5 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer'; import { IsNotEmpty, IsString } from 'class-validator';
import {
IsArray,
IsNotEmpty,
IsOptional,
IsString,
ValidateNested,
} from 'class-validator';
import { ProductAssignmentDto } from '../add.space.dto';
export class AddSubspaceDto { export class AddSubspaceDto {
@ApiProperty({ @ApiProperty({
@ -17,15 +9,4 @@ export class AddSubspaceDto {
@IsNotEmpty() @IsNotEmpty()
@IsString() @IsString()
subspaceName: string; subspaceName: string;
@ApiProperty({
description: 'List of products assigned to this space',
type: [ProductAssignmentDto],
required: false,
})
@IsArray()
@ValidateNested({ each: true })
@IsOptional()
@Type(() => ProductAssignmentDto)
products?: ProductAssignmentDto[];
} }

View File

@ -4,6 +4,4 @@ export * from './space-device.service';
export * from './subspace'; export * from './subspace';
export * from './space-link'; export * from './space-link';
export * from './space-scene.service'; export * from './space-scene.service';
export * from './space-products';
export * from './space-product-items';
export * from './space-validation.service'; export * from './space-validation.service';

View File

@ -1 +0,0 @@
export * from './space-product-items.service';

View File

@ -1,56 +0,0 @@
import {
SpaceEntity,
SpaceProductEntity,
SpaceProductItemRepository,
} from '@app/common/modules/space';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateSpaceProductItemDto } from '../../dtos';
import { QueryRunner } from 'typeorm';
import { BaseProductItemService } from '../../common';
@Injectable()
export class SpaceProductItemService extends BaseProductItemService {
constructor(
private readonly spaceProductItemRepository: SpaceProductItemRepository,
) {
super();
}
async createProductItem(
itemModelDtos: CreateSpaceProductItemDto[],
spaceProduct: SpaceProductEntity,
space: SpaceEntity,
queryRunner: QueryRunner,
) {
if (!itemModelDtos?.length) return;
const incomingTags = itemModelDtos.map((item) => item.tag);
await this.validateTags(incomingTags, queryRunner, space.uuid);
try {
const productItems = itemModelDtos.map((dto) =>
queryRunner.manager.create(this.spaceProductItemRepository.target, {
tag: dto.tag,
spaceProduct,
}),
);
await this.saveProductItems(
productItems,
this.spaceProductItemRepository.target,
queryRunner,
);
} catch (error) {
if (error instanceof HttpException) {
throw error;
}
throw new HttpException(
error.message ||
'An unexpected error occurred while creating product items.',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
}

View File

@ -1 +0,0 @@
export * from './space-products.service';

View File

@ -1,176 +0,0 @@
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { ProductRepository } from '@app/common/modules/product/repositories';
import { SpaceEntity } from '@app/common/modules/space/entities';
import { SpaceProductEntity } from '@app/common/modules/space/entities/space-product.entity';
import { In, QueryRunner } from 'typeorm';
import { ProductAssignmentDto } from '../../dtos';
import { SpaceProductItemService } from '../space-product-items';
import { ProductEntity } from '@app/common/modules/product/entities';
import { ProductService } from 'src/product/services';
@Injectable()
export class SpaceProductService {
constructor(
private readonly productRepository: ProductRepository,
private readonly spaceProductItemService: SpaceProductItemService,
private readonly productService: ProductService,
) {}
async assignProductsToSpace(
space: SpaceEntity,
products: ProductAssignmentDto[],
queryRunner: QueryRunner,
): Promise<SpaceProductEntity[]> {
let updatedProducts: SpaceProductEntity[] = [];
try {
const uniqueProducts = this.validateUniqueProducts(products);
const productEntities = await this.getProductEntities(uniqueProducts);
const existingSpaceProducts = await this.getExistingSpaceProducts(
space,
queryRunner,
);
if (existingSpaceProducts) {
updatedProducts = await this.updateExistingProducts(
existingSpaceProducts,
uniqueProducts,
productEntities,
queryRunner,
);
}
const newProducts = await this.createNewProducts(
uniqueProducts,
productEntities,
space,
queryRunner,
);
return [...updatedProducts, ...newProducts];
} catch (error) {
if (!(error instanceof HttpException)) {
throw new HttpException(
`An error occurred while assigning products to the space ${error}`,
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
throw error;
}
}
private validateUniqueProducts(
products: ProductAssignmentDto[],
): ProductAssignmentDto[] {
const productIds = new Set();
const uniqueProducts = [];
for (const product of products) {
if (productIds.has(product.productId)) {
throw new HttpException(
`Duplicate product ID found: ${product.productId}`,
HttpStatus.BAD_REQUEST,
);
}
productIds.add(product.productId);
uniqueProducts.push(product);
}
return uniqueProducts;
}
private async getProductEntities(
products: ProductAssignmentDto[],
): Promise<Map<string, any>> {
try {
const productIds = products.map((p) => p.productId);
const productEntities = await this.productRepository.find({
where: { uuid: In(productIds) },
});
return new Map(productEntities.map((p) => [p.uuid, p]));
} catch (error) {
console.error('Error fetching product entities:', error);
throw new HttpException(
'Failed to fetch product entities',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
private async getExistingSpaceProducts(
space: SpaceEntity,
queryRunner: QueryRunner,
): Promise<SpaceProductEntity[]> {
return queryRunner.manager.find(SpaceProductEntity, {
where: { space: { uuid: space.uuid } },
relations: ['product'],
});
}
private async updateExistingProducts(
existingSpaceProducts: SpaceProductEntity[],
uniqueProducts: ProductAssignmentDto[],
productEntities: Map<string, any>,
queryRunner: QueryRunner,
): Promise<SpaceProductEntity[]> {
const updatedProducts = [];
for (const { productId } of uniqueProducts) {
productEntities.get(productId);
const existingProduct = existingSpaceProducts.find(
(spaceProduct) => spaceProduct.product.uuid === productId,
);
updatedProducts.push(existingProduct);
}
if (updatedProducts.length > 0) {
await queryRunner.manager.save(SpaceProductEntity, updatedProducts);
}
return updatedProducts;
}
private async createNewProducts(
uniqueSpaceProducts: ProductAssignmentDto[],
productEntities: Map<string, any>,
space: SpaceEntity,
queryRunner: QueryRunner,
): Promise<SpaceProductEntity[]> {
const newProducts = [];
for (const uniqueSpaceProduct of uniqueSpaceProducts) {
const product = productEntities.get(uniqueSpaceProduct.productId);
await this.getProduct(uniqueSpaceProduct.productId);
newProducts.push(
queryRunner.manager.create(SpaceProductEntity, {
space,
product,
}),
);
}
if (newProducts.length > 0) {
await queryRunner.manager.save(SpaceProductEntity, newProducts);
await Promise.all(
uniqueSpaceProducts.map((dto, index) => {
const spaceProduct = newProducts[index];
return this.spaceProductItemService.createProductItem(
dto.items,
spaceProduct,
space,
queryRunner,
);
}),
);
}
return newProducts;
}
async getProduct(productId: string): Promise<ProductEntity> {
const product = await this.productService.findOne(productId);
return product.data;
}
}

View File

@ -17,7 +17,6 @@ import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { SpaceEntity } from '@app/common/modules/space/entities'; import { SpaceEntity } from '@app/common/modules/space/entities';
import { generateRandomString } from '@app/common/helper/randomString'; import { generateRandomString } from '@app/common/helper/randomString';
import { SpaceLinkService } from './space-link'; import { SpaceLinkService } from './space-link';
import { SpaceProductService } from './space-products';
import { CreateSubspaceModelDto } from 'src/space-model/dtos'; import { CreateSubspaceModelDto } from 'src/space-model/dtos';
import { SubSpaceService } from './subspace'; import { SubSpaceService } from './subspace';
import { DataSource, Not } from 'typeorm'; import { DataSource, Not } from 'typeorm';
@ -30,7 +29,6 @@ export class SpaceService {
private readonly dataSource: DataSource, private readonly dataSource: DataSource,
private readonly spaceRepository: SpaceRepository, private readonly spaceRepository: SpaceRepository,
private readonly spaceLinkService: SpaceLinkService, private readonly spaceLinkService: SpaceLinkService,
private readonly spaceProductService: SpaceProductService,
private readonly subSpaceService: SubSpaceService, private readonly subSpaceService: SubSpaceService,
private readonly validationService: ValidationService, private readonly validationService: ValidationService,
) {} ) {}
@ -102,13 +100,6 @@ export class SpaceService {
); );
} }
if (products && products.length > 0) {
await this.spaceProductService.assignProductsToSpace(
newSpace,
products,
queryRunner,
);
}
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
return new SuccessResponseDto({ return new SuccessResponseDto({
@ -264,14 +255,9 @@ export class SpaceService {
Object.assign(space, updateSpaceDto, { parent }); Object.assign(space, updateSpaceDto, { parent });
// Save the updated space // Save the updated space
const updatedSpace = await queryRunner.manager.save(space); await queryRunner.manager.save(space);
if (products && products.length > 0) { if (products && products.length > 0) {
await this.spaceProductService.assignProductsToSpace(
updatedSpace,
products,
queryRunner,
);
} }
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();

View File

@ -1,4 +1,2 @@
export * from './subspace.service'; export * from './subspace.service';
export * from './subspace-device.service'; export * from './subspace-device.service';
export * from './subspace-product-item.service';
export * from './subspace-product.service';

View File

@ -1,50 +0,0 @@
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { QueryRunner } from 'typeorm';
import {
SpaceEntity,
SubspaceProductEntity,
SubspaceProductItemEntity,
} from '@app/common/modules/space';
import { SubspaceProductItemRepository } from '@app/common/modules/space/repositories/subspace.repository';
import { CreateSpaceProductItemDto } from '../../dtos';
import { BaseProductItemService } from '../../common';
@Injectable()
export class SubspaceProductItemService extends BaseProductItemService {
constructor(
private readonly productItemRepository: SubspaceProductItemRepository,
) {
super();
}
async createItemFromDtos(
product: SubspaceProductEntity,
itemDto: CreateSpaceProductItemDto[],
queryRunner: QueryRunner,
space: SpaceEntity,
) {
if (!itemDto?.length) return;
const incomingTags = itemDto.map((item) => item.tag);
await this.validateTags(incomingTags, queryRunner, space.uuid);
try {
const productItems = itemDto.map((dto) =>
queryRunner.manager.create(SubspaceProductItemEntity, {
tag: dto.tag,
subspaceProduct: product,
}),
);
await queryRunner.manager.save(
this.productItemRepository.target,
productItems,
);
} catch (error) {
throw new HttpException(
error.message || 'An error occurred while creating product items.',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
}

View File

@ -1,65 +0,0 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { QueryRunner } from 'typeorm';
import {
SpaceEntity,
SubspaceEntity,
SubspaceProductEntity,
} from '@app/common/modules/space';
import { SubspaceProductItemService } from './subspace-product-item.service';
import { ProductAssignmentDto } from 'src/space/dtos';
import { ProductService } from 'src/product/services';
import { ProductEntity } from '@app/common/modules/product/entities';
@Injectable()
export class SubspaceProductService {
constructor(
private readonly subspaceProductItemService: SubspaceProductItemService,
private readonly productService: ProductService,
) {}
async createFromDto(
productDtos: ProductAssignmentDto[],
subspace: SubspaceEntity,
queryRunner: QueryRunner,
space: SpaceEntity,
): Promise<void> {
try {
const newSpaceProducts = await Promise.all(
productDtos.map(async (dto) => {
const product = await this.getProduct(dto.productId);
return queryRunner.manager.create(SubspaceProductEntity, {
subspace,
product,
});
}),
);
const subspaceProducts = await queryRunner.manager.save(
SubspaceProductEntity,
newSpaceProducts,
);
await Promise.all(
productDtos.map((dto, index) =>
this.subspaceProductItemService.createItemFromDtos(
subspaceProducts[index],
dto.items,
queryRunner,
space,
),
),
);
} catch (error) {
throw new HttpException(
`Failed to create subspace products from DTOs. Error: ${error.message}`,
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async getProduct(productId: string): Promise<ProductEntity> {
const product = await this.productService.findOne(productId);
return product.data;
}
}

View File

@ -19,14 +19,12 @@ import {
} from '@app/common/modules/space-model'; } from '@app/common/modules/space-model';
import { ValidationService } from '../space-validation.service'; import { ValidationService } from '../space-validation.service';
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository'; import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
import { SubspaceProductService } from './subspace-product.service';
@Injectable() @Injectable()
export class SubSpaceService { export class SubSpaceService {
constructor( constructor(
private readonly subspaceRepository: SubspaceRepository, private readonly subspaceRepository: SubspaceRepository,
private readonly validationService: ValidationService, private readonly validationService: ValidationService,
private readonly productService: SubspaceProductService,
) {} ) {}
async createSubspaces( async createSubspaces(
@ -82,17 +80,6 @@ export class SubSpaceService {
const subspaces = await this.createSubspaces(subspaceData, queryRunner); const subspaces = await this.createSubspaces(subspaceData, queryRunner);
await Promise.all(
addSubspaceDtos.map((dto, index) =>
this.productService.createFromDto(
dto.products,
subspaces[index],
queryRunner,
space,
),
),
);
return subspaces; return subspaces;
} catch (error) { } catch (error) {
throw new Error( throw new Error(

View File

@ -12,20 +12,15 @@ import {
import { import {
SpaceDeviceService, SpaceDeviceService,
SpaceLinkService, SpaceLinkService,
SpaceProductItemService,
SpaceProductService,
SpaceSceneService, SpaceSceneService,
SpaceService, SpaceService,
SpaceUserService, SpaceUserService,
SubspaceDeviceService, SubspaceDeviceService,
SubspaceProductItemService,
SubSpaceService, SubSpaceService,
} from './services'; } from './services';
import { import {
SpaceProductRepository,
SpaceRepository, SpaceRepository,
SpaceLinkRepository, SpaceLinkRepository,
SpaceProductItemRepository,
} from '@app/common/modules/space/repositories'; } from '@app/common/modules/space/repositories';
import { CommunityRepository } from '@app/common/modules/community/repositories'; import { CommunityRepository } from '@app/common/modules/community/repositories';
import { import {
@ -48,12 +43,7 @@ import { ProjectRepository } from '@app/common/modules/project/repositiories';
import { SpaceModelRepository } from '@app/common/modules/space-model'; import { SpaceModelRepository } from '@app/common/modules/space-model';
import { CommunityModule } from 'src/community/community.module'; import { CommunityModule } from 'src/community/community.module';
import { ValidationService } from './services'; import { ValidationService } from './services';
import { import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
SubspaceProductItemRepository,
SubspaceProductRepository,
SubspaceRepository,
} from '@app/common/modules/space/repositories/subspace.repository';
import { SubspaceProductService } from './services';
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule, CommunityModule], imports: [ConfigModule, SpaceRepositoryModule, CommunityModule],
@ -75,9 +65,9 @@ import { SubspaceProductService } from './services';
SpaceLinkService, SpaceLinkService,
SubspaceDeviceService, SubspaceDeviceService,
SpaceRepository, SpaceRepository,
SubspaceRepository,
DeviceRepository, DeviceRepository,
CommunityRepository, CommunityRepository,
SubspaceRepository,
SpaceLinkRepository, SpaceLinkRepository,
UserSpaceRepository, UserSpaceRepository,
UserRepository, UserRepository,
@ -88,19 +78,11 @@ import { SubspaceProductService } from './services';
SceneRepository, SceneRepository,
DeviceService, DeviceService,
DeviceStatusFirebaseService, DeviceStatusFirebaseService,
SubspaceProductItemRepository,
DeviceStatusLogRepository, DeviceStatusLogRepository,
SceneDeviceRepository, SceneDeviceRepository,
SpaceProductService,
SpaceProductRepository,
ProjectRepository, ProjectRepository,
SpaceModelRepository, SpaceModelRepository,
SubspaceRepository,
SpaceProductItemService,
SpaceProductItemRepository,
SubspaceProductService,
SubspaceProductItemService,
SubspaceProductRepository,
], ],
exports: [SpaceService], exports: [SpaceService],
}) })