My App
LoopKitBackend

Storage Interface

Abstract storage class for implementing custom database adapters

Overview

LoopKitStorage is the abstract class that all storage adapters must implement. It uses structural typing — no ORM imports are required.

import { LoopKitStorage } from '@loopkit/nestjs';

Card Operations

Standard CRUD plus query methods used by the review session engine.

abstract createCard(input: CreateCardInput): Promise<CardBase>;
abstract createManyCards(inputs: CreateCardInput[]): Promise<number>;
abstract getCard(id: string): Promise<CardBase>;
abstract findCards(deckId: string, filters?: { state?: string }): Promise<CardBase[]>;
abstract updateCard(id: string, input: UpdateCardInput): Promise<CardBase>;
abstract updateManyCards(ids: string[], input: UpdateCardInput): Promise<number>;
abstract deleteCard(id: string): Promise<void>;
abstract deleteCardsByNote(noteId: string): Promise<number>;
abstract deleteCardsByTemplate(templateId: string): Promise<number>;

Queue-building methods — these power the review session:

// Find review cards past their due date, sorted by due date ascending
abstract findDueCards(deckIds: string[], now: Date, limit?: number): Promise<CardBase[]>;

// Find cards in 'new' state, sorted by creation date
abstract findNewCards(deckIds: string[], limit?: number): Promise<CardBase[]>;

// Find cards in 'learning' or 'relearning' state
abstract findLearningCards(deckIds: string[], now: Date): Promise<CardBase[]>;

// Aggregate card counts by state across all provided deck IDs
abstract countByState(deckIds: string[]): Promise<DeckCounts>;

Note Operations

abstract createNote(input: CreateNoteInput & { id?: string }): Promise<NoteBase>;
abstract getNote(id: string): Promise<NoteBase>;
abstract findNotes(filters?: NoteFilters): Promise<NoteBase[]>;
abstract updateNote(id: string, input: UpdateNoteInput): Promise<NoteBase>;
abstract deleteNote(id: string): Promise<void>;

Deck Operations

abstract createDeck(input: CreateDeckInput & { id?: string }): Promise<DeckBase>;
abstract getDeck(id: string): Promise<DeckBase>;
abstract findDecks(filters?: DeckFilters): Promise<DeckBase[]>;
abstract updateDeck(id: string, input: UpdateDeckInput): Promise<DeckBase>;
abstract deleteDeck(id: string): Promise<void>;

// Recursively find all child deck IDs (children, grandchildren, etc.)
abstract getDescendantDeckIds(deckId: string): Promise<string[]>;

Preset Operations

abstract createPreset(input: CreatePresetInput & { id?: string }): Promise<DeckPreset>;
abstract getPreset(id: string): Promise<DeckPreset>;
abstract findPresets(): Promise<DeckPreset[]>;
abstract updatePreset(id: string, input: UpdatePresetInput): Promise<DeckPreset>;
abstract deletePreset(id: string): Promise<void>;

NoteType Operations

abstract createNoteType(input: CreateNoteTypeInput & { id?: string }): Promise<NoteType>;
abstract getNoteType(id: string): Promise<NoteType>;
abstract findNoteTypes(): Promise<NoteType[]>;
abstract updateNoteType(id: string, input: UpdateNoteTypeInput): Promise<NoteType>;
abstract deleteNoteType(id: string): Promise<void>;

ReviewLog Operations

abstract createReviewLog(input: CreateReviewLogInput & { id?: string }): Promise<ReviewLog>;
abstract getReviewLog(id: string): Promise<ReviewLog>;
abstract findReviewLogs(filters?: ReviewLogFilters): Promise<ReviewLog[]>;
abstract deleteReviewLog(id: string): Promise<void>;

// Count reviews since dayStart for daily limit enforcement
abstract countReviewsToday(deckIds: string[], dayStart: Date): Promise<number>;

// Count new cards studied since dayStart for daily limit enforcement
abstract countNewCardsToday(deckIds: string[], dayStart: Date): Promise<number>;

Sync Helpers

Used for syncing data between devices or services:

// Find cards modified after the given timestamp
abstract findModifiedSince(since: Date): Promise<CardBase[]>;

// Find review logs created after the given timestamp
abstract findReviewLogsSince(since: Date): Promise<ReviewLog[]>;

Transaction Support

abstract transaction<T>(fn: (storage: LoopKitStorage) => Promise<T>): Promise<T>;

Executes a callback within a database transaction. The callback receives a transactional storage instance. All operations within the callback are atomic — they either all succeed or all roll back.

await storage.transaction(async (tx) => {
    const note = await tx.createNote({
        noteTypeId: 'basic',
        fields: [{ name: 'Front', value: 'Q', ordinal: 0 }],
    });
    await tx.createCard({ noteId: note.id, templateId: 't1', deckId: 'deck-1' });
});

On this page