import CreateBy from "../Types/Database/CreateBy"; import DeleteBy from "../Types/Database/DeleteBy"; import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks"; import Query from "../Types/Database/Query"; import QueryHelper from "../Types/Database/QueryHelper"; import UpdateBy from "../Types/Database/UpdateBy"; import DatabaseService from "./DatabaseService"; import SortOrder from "../../Types/BaseDatabase/SortOrder"; import LIMIT_MAX from "../../Types/Database/LimitMax"; import BadDataException from "../../Types/Exception/BadDataException"; import ObjectID from "../../Types/ObjectID"; import PositiveNumber from "../../Types/PositiveNumber"; import Model from "../../Models/DatabaseModels/StatusPageHeaderLink"; import CaptureSpan from "../Utils/Telemetry/CaptureSpan"; export class Service extends DatabaseService { public constructor() { super(Model); } @CaptureSpan() protected override async onBeforeCreate( createBy: CreateBy, ): Promise> { if (!createBy.data.statusPageId) { throw new BadDataException("statusPageId is required"); } if (!createBy.data.order) { const query: Query = { statusPageId: createBy.data.statusPageId, }; const count: PositiveNumber = await this.countBy({ query: query, props: { isRoot: true, }, }); createBy.data.order = count.toNumber() + 1; } await this.rearrangeOrder( createBy.data.order, createBy.data.statusPageId, true, ); return { createBy: createBy, carryForward: null, }; } @CaptureSpan() protected override async onBeforeDelete( deleteBy: DeleteBy, ): Promise> { if (!deleteBy.query._id && !deleteBy.props.isRoot) { throw new BadDataException( "_id should be present when deleting status page header link. Please try the delete with objectId", ); } let resource: Model | null = null; if (!deleteBy.props.isRoot) { resource = await this.findOneBy({ query: deleteBy.query, props: { isRoot: true, }, select: { order: true, statusPageId: true, }, }); } return { deleteBy, carryForward: resource, }; } @CaptureSpan() protected override async onDeleteSuccess( onDelete: OnDelete, _itemIdsBeforeDelete: ObjectID[], ): Promise> { const deleteBy: DeleteBy = onDelete.deleteBy; const resource: Model | null = onDelete.carryForward; if (!deleteBy.props.isRoot && resource) { if (resource && resource.order && resource.statusPageId) { await this.rearrangeOrder(resource.order, resource.statusPageId, false); } } return { deleteBy: deleteBy, carryForward: null, }; } @CaptureSpan() protected override async onBeforeUpdate( updateBy: UpdateBy, ): Promise> { if (updateBy.data.order && !updateBy.props.isRoot && updateBy.query._id) { const resource: Model | null = await this.findOneBy({ query: { _id: updateBy.query._id!, }, props: { isRoot: true, }, select: { order: true, statusPageId: true, _id: true, }, }); const currentOrder: number = resource?.order as number; const newOrder: number = updateBy.data.order as number; const resources: Array = await this.findBy({ query: { statusPageId: resource?.statusPageId as ObjectID, }, limit: LIMIT_MAX, skip: 0, props: { isRoot: true, }, select: { order: true, statusPageId: true, _id: true, }, }); if (currentOrder > newOrder) { // moving up. for (const resource of resources) { if (resource.order! >= newOrder && resource.order! < currentOrder) { // increment order. await this.updateOneBy({ query: { _id: resource._id!, }, data: { order: resource.order! + 1, }, props: { isRoot: true, }, }); } } } if (newOrder > currentOrder) { // moving down. for (const resource of resources) { if (resource.order! <= newOrder) { // increment order. await this.updateOneBy({ query: { _id: resource._id!, }, data: { order: resource.order! - 1, }, props: { isRoot: true, }, }); } } } } return { updateBy, carryForward: null }; } private async rearrangeOrder( currentOrder: number, statusPageId: ObjectID, increaseOrder: boolean = true, ): Promise { // get status page resource with this order. const resources: Array = await this.findBy({ query: { order: QueryHelper.greaterThanEqualTo(currentOrder), statusPageId: statusPageId, }, limit: LIMIT_MAX, skip: 0, props: { isRoot: true, }, select: { _id: true, order: true, }, sort: { order: SortOrder.Ascending, }, }); let newOrder: number = currentOrder; for (const resource of resources) { if (increaseOrder) { newOrder = resource.order! + 1; } else { newOrder = resource.order! - 1; } await this.updateOneBy({ query: { _id: resource._id!, }, data: { order: newOrder, }, props: { isRoot: true, }, }); } } } export default new Service();