UNPKG

@hot-updater/plugin-core

Version:

React Native OTA solution for self-hosted

91 lines (89 loc) 2.79 kB
import { merge } from "es-toolkit"; //#region src/createDatabasePlugin.ts /** * Creates a database plugin with lazy initialization and automatic hook execution. * * This factory function abstracts the double currying pattern used by all database plugins, * ensuring consistent lazy initialization behavior across different database providers. * Hooks are automatically executed at appropriate times without requiring manual invocation. * * @param options - Configuration options for the database plugin * @returns A double-curried function that lazily initializes the database plugin * * @example * ```typescript * export const postgres = createDatabasePlugin<PostgresConfig>({ * name: "postgres", * factory: (config) => { * const db = new Kysely(config); * return { * async getBundleById(bundleId) { ... }, * async getBundles(options) { ... }, * async getChannels() { ... }, * async commitBundle({ changedSets }) { ... } * }; * } * }); * ``` */ function createDatabasePlugin(options) { return (config, hooks) => { return () => { let cachedMethods = null; const getMethods = () => { if (!cachedMethods) cachedMethods = options.factory(config); return cachedMethods; }; const changedMap = /* @__PURE__ */ new Map(); const markChanged = (operation, data) => { changedMap.set(data.id, { operation, data }); }; return { name: options.name, async getBundleById(bundleId) { return getMethods().getBundleById(bundleId); }, async getBundles(options$1) { return getMethods().getBundles(options$1); }, async getChannels() { return getMethods().getChannels(); }, async onUnmount() { const methods = getMethods(); if (methods.onUnmount) return methods.onUnmount(); }, async commitBundle() { await getMethods().commitBundle({ changedSets: Array.from(changedMap.values()) }); await hooks?.onDatabaseUpdated?.(); changedMap.clear(); }, async updateBundle(targetBundleId, newBundle) { const pendingChange = changedMap.get(targetBundleId); if (pendingChange) { const updatedData = merge(pendingChange.data, newBundle); changedMap.set(targetBundleId, { operation: pendingChange.operation, data: updatedData }); return; } const currentBundle = await getMethods().getBundleById(targetBundleId); if (!currentBundle) throw new Error("targetBundleId not found"); markChanged("update", merge(currentBundle, newBundle)); }, async appendBundle(inputBundle) { markChanged("insert", inputBundle); }, async deleteBundle(deleteBundle) { markChanged("delete", deleteBundle); } }; }; }; } //#endregion export { createDatabasePlugin };