My App
CourseKitBackend

QueryService

Query schedules and find free time slots

Overview

QueryService provides methods to query materialized schedules and find free time slots across entities.

import { QueryService } from '@hfu.digital/coursekit-nestjs';

Methods

getSchedule

Get all materialized occurrences matching a query. Expands recurring events, applies exceptions, and filters by entities.

async getSchedule(query: ScheduleQuery): Promise<MaterializedOccurrence[]>

Returns occurrences sorted by start time.

const schedule = await query.getSchedule({
    dateRange: {
        start: new Date('2026-03-02'),
        end: new Date('2026-03-08'),
    },
    instructorIds: ['instructor-1'],
    roomIds: ['room-a1'],
});

getEntitySchedule

Convenience wrapper to get the schedule for a single entity.

async getEntitySchedule(
    entityType: 'instructor' | 'room' | 'group',
    entityId: string,
    dateRange: DateRange,
): Promise<MaterializedOccurrence[]>
const schedule = await query.getEntitySchedule('instructor', 'instructor-1', {
    start: new Date('2026-03-02'),
    end: new Date('2026-03-08'),
});

findFreeSlots

Find time slots where ALL specified entities are simultaneously free.

async findFreeSlots(query: FreeSlotQuery): Promise<FreeSlot[]>
const slots = await query.findFreeSlots({
    dateRange: {
        start: new Date('2026-03-02'),
        end: new Date('2026-03-06'),
    },
    durationMin: 90,
    entityIds: [
        { type: 'instructor', id: 'instructor-1' },
        { type: 'room', id: 'room-a1' },
    ],
});

How it works:

  1. For each entity, fetches and materializes all events in the date range
  2. Collects all occupied time intervals
  3. Sorts and merges overlapping intervals
  4. Returns gaps that meet the minimum duration requirement

ScheduleQuery

interface ScheduleQuery {
    dateRange: DateRange;
    instructorIds?: string[];
    roomIds?: string[];
    groupIds?: string[];
    courseIds?: string[];
    periodId?: string;
    tags?: Record<string, unknown>;
}

All filter fields are optional. When multiple filters are provided, they are combined (events must match all specified criteria).

FreeSlotQuery

interface FreeSlotQuery {
    dateRange: DateRange;
    durationMin: number;
    entityIds: Array<{ type: 'instructor' | 'room' | 'group'; id: string }>;
}

On this page