My App
CourseKitBackend

Prisma Adapter

Out-of-the-box Prisma storage adapters for all CourseKit entities

Overview

CourseKit ships with Prisma adapters for every storage interface. The adapters map between Prisma's generated types and CourseKit's structural types without importing @prisma/client in the core package.

Available Adapters

AdapterStorage InterfacePrisma Models Used
PrismaTimetableEventAdapterTimetableEventStoragetimetableEvent, eventException, eventInstructor, eventGroup
PrismaRoomAdapterRoomStorageroom
PrismaInstructorAdapterInstructorStorageinstructor
PrismaGroupAdapterGroupStoragegroup, studentGroup
PrismaAvailabilityAdapterAvailabilityStorageavailability
PrismaAcademicPeriodAdapterAcademicPeriodStorageacademicPeriod
PrismaCourseAdapterCourseStoragecourse
PrismaLocationDistanceAdapterLocationDistanceStoragelocationDistance

Instantiation

Each adapter takes Prisma delegate(s) as constructor arguments:

import { PrismaClient } from '@prisma/client';
import {
    PrismaTimetableEventAdapter,
    PrismaRoomAdapter,
    PrismaInstructorAdapter,
    PrismaGroupAdapter,
    PrismaAvailabilityAdapter,
    PrismaAcademicPeriodAdapter,
    PrismaCourseAdapter,
    PrismaLocationDistanceAdapter,
} from '@hfu.digital/coursekit-nestjs';

const prisma = new PrismaClient();

// TimetableEventAdapter needs 4 delegates
const eventStorage = new PrismaTimetableEventAdapter(
    prisma.timetableEvent,
    prisma.eventException,
    prisma.eventInstructor,
    prisma.eventGroup,
);

// GroupAdapter needs 2 delegates
const groupStorage = new PrismaGroupAdapter(prisma.group, prisma.studentGroup);

// All others need 1 delegate
const roomStorage = new PrismaRoomAdapter(prisma.room);
const instructorStorage = new PrismaInstructorAdapter(prisma.instructor);
const availabilityStorage = new PrismaAvailabilityAdapter(prisma.availability);
const periodStorage = new PrismaAcademicPeriodAdapter(prisma.academicPeriod);
const courseStorage = new PrismaCourseAdapter(prisma.course);
const locationStorage = new PrismaLocationDistanceAdapter(prisma.locationDistance);

Prisma Schema

See the Getting Started page for the full Prisma schema definition.

Structural Typing

CourseKit uses structural typing (duck typing) instead of importing @prisma/client:

// CourseKit defines this interface
interface TimetableEvent {
    id: string;
    title: string;
    startTime: Date;
    durationMin: number;
    // ...
}

// Prisma generates a compatible type
// The adapter maps between them without coupling

This means:

  • The core package has zero ORM dependencies
  • Adapters can be swapped without changing domain logic
  • Custom adapters for other ORMs only need to match the interface shape

Optimistic Concurrency

The PrismaTimetableEventAdapter supports optimistic concurrency via the version field. Pass expectedVersion to update() to ensure the event hasn't been modified since you last read it:

await eventStorage.update('event-1', { title: 'Updated' }, 3);
// Throws if current version !== 3

On this page