BulkOperationService
Semester imports, date shifting, and batch cancellations
Overview
BulkOperationService handles large-scale booking operations such as semester imports, date shifting, and batch cancellations. Each operation is tracked as a BulkOperation with progress reporting and conflict counting.
Optional. Enable with features: { bulkOperations: true } in your module registration. Requires BulkOperationStorage to be provided.
import { BulkOperationService } from '@roomkit/nestjs';Types
SemesterImportPayload
interface SemesterImportPayload {
entries: {
roomId: string;
startsAt: Date;
endsAt: Date;
requesterId: string;
purposeType: string;
title: string;
recurrence?: RecurrenceInput;
}[];
}BulkOperation
interface BulkOperation {
id: string;
type: 'semester_import' | 'date_shift' | 'batch_cancel';
status: 'pending' | 'processing' | 'completed' | 'failed';
totalItems: number;
processedItems: number;
conflictsDetected: number;
resultSummary: Record<string, unknown>;
triggeredBy: string;
createdAt: Date;
updatedAt: Date;
}Methods
semesterImport
Create a bulk operation that imports an entire semester of bookings. Iterates through all entries in the payload. Entries with a recurrence field create recurring series via RecurrenceService; entries without create single bookings. Conflicts are counted but do not abort the operation.
Progress is emitted every 10 items via the BulkOperationProgress event. Emits BulkOperationCompleted when the import finishes.
async semesterImport(
payload: SemesterImportPayload,
triggeredBy: string,
): Promise<BulkOperation>| Parameter | Type | Description |
|---|---|---|
payload | SemesterImportPayload | Import payload containing an array of booking entries |
triggeredBy | string | ID of the user or system triggering the import |
const operation = await bulkOperationService.semesterImport(
{
entries: [
{
roomId: 'room-a1',
startsAt: new Date('2026-09-01T09:00:00Z'),
endsAt: new Date('2026-09-01T10:00:00Z'),
requesterId: 'dept-cs',
purposeType: 'LECTURE',
title: 'CS 101 - Intro to Computer Science',
recurrence: {
frequency: 'weekly',
interval: 1,
until: new Date('2026-12-15T10:00:00Z'),
},
},
{
roomId: 'room-b2',
startsAt: new Date('2026-09-02T14:00:00Z'),
endsAt: new Date('2026-09-02T15:30:00Z'),
requesterId: 'dept-math',
purposeType: 'SEMINAR',
title: 'MATH 201 - Linear Algebra',
},
],
},
'admin-1',
);
console.log(operation.status); // 'processing' or 'completed'
console.log(operation.conflictsDetected); // number of conflicts encounteredThrows BulkOperationPartialError if the operation completes with failures.
dateShift
Find matching bookings and shift each booking's start and end times by a number of days. Uses BookingService.modify with optimistic concurrency for each update. Emits BulkOperationProgress events during processing.
async dateShift(
filter: {
recurrenceRuleId?: string;
roomId?: string;
timeRange?: TimeRange;
},
shiftDays: number,
triggeredBy: string,
): Promise<BulkOperation>| Parameter | Type | Description |
|---|---|---|
filter | object | Filter criteria to select bookings for shifting |
filter.recurrenceRuleId | string | Optional recurrence rule ID to match |
filter.roomId | string | Optional room ID to match |
filter.timeRange | TimeRange | Optional time range to match |
shiftDays | number | Number of days to shift (positive = forward, negative = backward) |
triggeredBy | string | ID of the user or system triggering the shift |
// Shift all bookings in room-a1 forward by 7 days
const operation = await bulkOperationService.dateShift(
{
roomId: 'room-a1',
timeRange: {
startsAt: new Date('2026-03-01'),
endsAt: new Date('2026-06-30'),
},
},
7,
'admin-1',
);batchCancel
Find all non-terminal bookings matching the filter and cancel each via BookingService.cancel. Emits BulkOperationProgress events during processing and BulkOperationCompleted when done.
async batchCancel(
filter: {
roomId?: string;
timeRange?: TimeRange;
requesterId?: string;
},
reason: string,
triggeredBy: string,
): Promise<BulkOperation>| Parameter | Type | Description |
|---|---|---|
filter | object | Filter criteria to select bookings for cancellation |
filter.roomId | string | Optional room ID to match |
filter.timeRange | TimeRange | Optional time range to match |
filter.requesterId | string | Optional requester ID to match |
reason | string | Cancellation reason applied to each booking |
triggeredBy | string | ID of the user or system triggering the cancellation |
// Cancel all bookings in a room due to renovation
const operation = await bulkOperationService.batchCancel(
{
roomId: 'room-a1',
timeRange: {
startsAt: new Date('2026-06-01'),
endsAt: new Date('2026-08-31'),
},
},
'Room under renovation',
'facilities-admin',
);
console.log(operation.totalItems); // total bookings found
console.log(operation.processedItems); // bookings cancelled so far