@furystack/repository
Version:
Repository implementation for FuryStack
65 lines • 2.56 kB
JavaScript
import { defineService } from '@furystack/inject';
import { DataSet } from './data-set.js';
/**
* Resolves a {@link StoreToken} to a {@link PhysicalStore} whose
* `TWritableData` generic matches the owning data set. `StoreToken` defaults
* `TWritableData` to `WithOptionalId`, while a {@link DataSet} may narrow it
* (e.g. to strip system-owned fields). The write surface of `PhysicalStore`
* is contravariant in `TWritableData` — a store that accepts
* `WithOptionalId<T, TPK>` also accepts any narrower shape — but TypeScript
* cannot express that with the default generic, so the cast is localized
* here with this explanation rather than scattered at call sites.
*/
const resolvePhysicalStore = (ctx, store) => ctx.inject(store);
/**
* Defines a singleton {@link DataSet} token backed by a {@link StoreToken}.
* The token mirrors the store's `model` and `primaryKey` so reflection
* tools (entity sync, OpenAPI generators, test harnesses) can discover the
* dataset's shape from the token alone. Disposal of the owning injector
* tears down the dataset's event subscriptions.
*
* @example
* ```ts
* const UserStore = defineStore({
* name: 'my-app/UserStore',
* model: User,
* primaryKey: 'username',
* factory: () => new InMemoryStore({ model: User, primaryKey: 'username' }),
* })
*
* export const UserDataSet = defineDataSet({
* name: 'my-app/UserDataSet',
* store: UserStore,
* settings: {
* authorizeAdd: async ({ injector, entity }) => ({ isAllowed: true }),
* },
* })
*
* const ds = injector.get(UserDataSet)
* await ds.add(injector, { username: 'alice', roles: [] })
* ```
*/
export const defineDataSet = (options) => {
const token = defineService({
name: options.name,
lifetime: 'singleton',
factory: (ctx) => {
const physicalStore = resolvePhysicalStore(ctx, options.store);
const dataSet = new DataSet({
...options.settings,
physicalStore,
});
// Disposal is delegated to the injector via `onDispose`; the dataset
// outlives this factory invocation and is torn down on scope teardown.
// eslint-disable-next-line furystack/prefer-using-wrapper
ctx.onDispose(() => dataSet[Symbol.dispose]());
return dataSet;
},
});
const result = Object.assign(token, {
model: options.store.model,
primaryKey: options.store.primaryKey,
});
return result;
};
//# sourceMappingURL=define-data-set.js.map