Skip to main content

Core Model

OIMDB's current app-level model is:

  • a shared OIMEventQueue
  • a collection model created with createOIMCollectionKit
  • indexes that live next to the collection
  • selectors for reactive reads

Collections remain the source of truth for entities. Indexes and ordered lists keep canonical collection slots, but they are not stored inside the collection.

Collection Model

import {
createOIMCollectionKit,
OIMEventQueue,
OIMEventQueueSchedulerFactory,
} from '@oimdb/core';

type User = {
id: string;
name: string;
teamId: string;
};

const queue = new OIMEventQueue({
scheduler: OIMEventQueueSchedulerFactory.createMicrotask(),
});

const users = createOIMCollectionKit<User, string>(queue, {
selectPk: (user) => user.id,
});

The model facade contains:

type TOIMCollectionKit<TEntity, TPk> = {
queue: OIMEventQueue;
collection: OIMReactiveCollection<TEntity, TPk>;
indexFactory: OIMCollectionIndexFactory<TEntity, TPk>;
select: OIMCollectionSelectors<TEntity, TPk>;
};

Slot-Returning Writes

Collection writes return canonical slots. Updating an entity keeps the same slot object and updates slot.item.

const firstSlot = users.collection.upsertOne({
id: 'u1',
name: 'Alice',
teamId: 'team1',
});

const updatedSlot = users.collection.upsertOneByPk('u1', {
name: 'Alicia',
});

console.log(firstSlot === updatedSlot); // true

This is what lets collection-bound indexes store stable slot references while still exposing PK projections such as getPksByKey.

Event Semantics

Batching & coalescing — multiple writes to the same key coalesce into a single notification per queue.flush(). Delivery is driven by updated key sets, not by every write.

Reentrancy — updates triggered inside a subscriber are collected into the next internal batch. queue.flush() is a full drain: work enqueued during a flush runs within the same call.

Key-scoped subscriptions — there is no "subscribe to everything". Delivery cost is proportional to the subscriber sets for changed keys only.