import { Effect } from "effect"; import type { StorageFailure } from "./fuma-runtime"; import type { Owner } from "./ids"; export type PluginStorageSchema = { readonly Type: object; }; export type PluginStorageSchemaType = TSchema["Type"]; export type PluginStorageIndexField = Extract; export type PluginStorageIndexSpec = | PluginStorageIndexField | readonly PluginStorageIndexField[]; export type PluginStorageRuntimeIndexSpec = string | readonly string[]; export interface PluginStorageRuntimeCollectionDefinition { readonly name: string; readonly schema: PluginStorageSchema; readonly indexes: readonly PluginStorageRuntimeIndexSpec[]; } export interface PluginStorageCollectionDefinition< TName extends string = string, TData extends object = Record, TIndexes extends readonly PluginStorageIndexSpec[] = readonly PluginStorageIndexSpec[], > extends PluginStorageRuntimeCollectionDefinition { readonly name: TName; readonly schema: PluginStorageSchema; readonly indexes: TIndexes; } export type PluginStorageConfig = Readonly< Record >; export const definePluginStorageCollection = < const TName extends string, const TSchema extends PluginStorageSchema, const TIndexes extends readonly PluginStorageIndexSpec>[] = readonly [], >( name: TName, schema: TSchema, options?: { readonly indexes?: TIndexes; }, ): PluginStorageCollectionDefinition, TIndexes> => ({ name, schema, indexes: (options?.indexes ?? []) as TIndexes, }); export type PluginStorageCollectionData = TDefinition extends PluginStorageCollectionDefinition ? TData : never; export type PluginStorageIndexFields = TIndexes extends readonly (infer TIndex)[] ? TIndex extends readonly (infer TField)[] ? Extract : Extract : never; export type PluginStorageCollectionIndexedField = TDefinition extends PluginStorageCollectionDefinition ? PluginStorageIndexFields : never; export interface PluginStorageWhereFilter { readonly eq?: TValue; readonly in?: readonly TValue[]; readonly gt?: TValue; readonly gte?: TValue; readonly lt?: TValue; readonly lte?: TValue; } export type PluginStorageWhereValue = TValue | PluginStorageWhereFilter; export type PluginStorageCollectionWhere = { readonly [TField in PluginStorageCollectionIndexedField]?: PluginStorageWhereValue< TField extends keyof PluginStorageCollectionData ? PluginStorageCollectionData[TField] : never >; }; export interface PluginStorageCollectionOrderBy { readonly field: PluginStorageCollectionIndexedField; readonly direction?: "asc" | "desc"; } export interface PluginStorageKeyInput { readonly collection: string; readonly key: string; } export interface PluginStorageScopedKeyInput extends PluginStorageKeyInput { readonly owner: Owner; } export interface PluginStorageListInput { readonly collection: string; readonly keyPrefix?: string; } export interface PluginStoragePutInput extends PluginStorageScopedKeyInput { readonly data: unknown; } export interface PluginStoragePutManyEntry extends PluginStorageKeyInput { readonly data: unknown; } export interface PluginStoragePutManyInput { readonly owner: Owner; readonly entries: readonly PluginStoragePutManyEntry[]; } export interface PluginStorageRemoveManyInput { readonly owner: Owner; readonly entries: readonly PluginStorageKeyInput[]; } export interface PluginStorageCollectionKeyInput { readonly key: string; } export interface PluginStorageCollectionScopedKeyInput extends PluginStorageCollectionKeyInput { readonly owner: Owner; } export interface PluginStorageCollectionListInput { readonly keyPrefix?: string; } export interface PluginStorageCollectionPutInput< TData extends object, > extends PluginStorageCollectionScopedKeyInput { readonly data: TData; } export interface PluginStorageCollectionQueryInput { readonly keyPrefix?: string; readonly where?: PluginStorageCollectionWhere; readonly orderBy?: readonly PluginStorageCollectionOrderBy[]; readonly limit?: number; readonly offset?: number; } export interface PluginStorageEntry { readonly id: string; readonly owner: Owner; readonly pluginId: string; readonly collection: string; readonly key: string; readonly data: T; readonly createdAt: Date; readonly updatedAt: Date; } export interface PluginStorageCollectionFacade< TDefinition extends PluginStorageCollectionDefinition = PluginStorageCollectionDefinition, > { readonly get: ( input: PluginStorageCollectionKeyInput, ) => Effect.Effect< PluginStorageEntry> | null, StorageFailure >; readonly getForOwner: ( input: PluginStorageCollectionScopedKeyInput, ) => Effect.Effect< PluginStorageEntry> | null, StorageFailure >; readonly list: ( input?: PluginStorageCollectionListInput, ) => Effect.Effect< readonly PluginStorageEntry>[], StorageFailure >; readonly put: ( input: PluginStorageCollectionPutInput>, ) => Effect.Effect>, StorageFailure>; readonly query: ( input?: PluginStorageCollectionQueryInput, ) => Effect.Effect< readonly PluginStorageEntry>[], StorageFailure >; readonly count: ( input?: Omit, "orderBy" | "limit" | "offset">, ) => Effect.Effect; readonly remove: ( input: PluginStorageCollectionScopedKeyInput, ) => Effect.Effect; } export interface PluginStorageFacade { readonly collection: ( definition: TDefinition, ) => PluginStorageCollectionFacade; readonly get: ( input: PluginStorageKeyInput, ) => Effect.Effect | null, StorageFailure>; readonly getForOwner: ( input: PluginStorageScopedKeyInput, ) => Effect.Effect | null, StorageFailure>; readonly list: ( input: PluginStorageListInput, ) => Effect.Effect[], StorageFailure>; readonly put: ( input: PluginStoragePutInput, ) => Effect.Effect, StorageFailure>; readonly putMany: (input: PluginStoragePutManyInput) => Effect.Effect; readonly remove: (input: PluginStorageScopedKeyInput) => Effect.Effect; readonly removeMany: (input: PluginStorageRemoveManyInput) => Effect.Effect; } export const pluginStorageId = (input: { readonly pluginId: string; readonly collection: string; readonly key: string; }): string => JSON.stringify([input.pluginId, input.collection, input.key]);