UNPKG

@helenejs/react

Version:

Real-time Web Apps for Node.js

124 lines 5.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.useData = useData; const data_1 = require("@helenejs/data"); const browser_storage_1 = require("@helenejs/data/lib/browser/browser-storage"); const utils_1 = require("@helenejs/utils"); const useCreation_1 = __importDefault(require("ahooks/lib/useCreation")); const useDebounceFn_1 = __importDefault(require("ahooks/lib/useDebounceFn")); const isEmpty_1 = __importDefault(require("lodash/isEmpty")); const set_1 = __importDefault(require("lodash/set")); const react_1 = require("react"); const use_client_1 = require("./use-client"); const use_event_1 = require("./use-event"); const use_find_1 = require("./use-find"); const use_object_1 = require("./use-object"); const use_throttled_events_1 = require("./use-throttled-events"); const browserStorage = new browser_storage_1.BrowserStorage(); function useData({ method, channel, params, filter = {}, sort, projection, selectiveSync = false, authenticated = false, collectionName = null, collection = null, single = false, }) { const name = (0, useCreation_1.default)(() => collection?.name ?? collectionName ?? `collection:${method}`, [method, collectionName]); const innerCollection = (0, useCreation_1.default)(() => collection ?? new data_1.Collection({ name, storage: browserStorage, timestamps: true, autoload: true, }), [name, collection]); const [loading, setLoading] = (0, react_1.useState)(() => true); const client = (0, use_client_1.useClient)(); const result = (0, useCreation_1.default)(() => ({}), []); const data = (0, use_find_1.useFind)(innerCollection, filter, sort, projection); const refresh = (0, useDebounceFn_1.default)(async () => { if (!innerCollection) return; if (authenticated && !client.authenticated) { setLoading(false); return; } setLoading(true); const count = await innerCollection.count({}); try { let response; /** * @todo Create method utility that checks if ids are still present in the collection to sync deletions. */ if (count && selectiveSync) { const [{ updatedAt: lastUpdatedAt = null } = {}] = (await innerCollection .find(filter) .projection({ updatedAt: 1 }) .sort({ updatedAt: -1 })) ?? [{}]; response = await client.call(method, { ...params, lastUpdatedAt }); for (const datum of Array.isArray(response) ? response : [response]) { if (await innerCollection.findOne({ ...filter, _id: datum._id, })) { await innerCollection.remove({ ...filter, _id: datum._id, }); } } } else { response = await client.call(method, params); } if (response) { const existingIds = (await innerCollection.find(filter).projection({ _id: 1 })).map((datum) => datum._id); if (!Array.isArray(response)) { response = [response]; } const retrievedIds = response.map((datum) => datum._id); for (const datum of response) { if (existingIds.includes(datum._id)) { const existing = await innerCollection.findOne({ _id: datum._id }); const removedFields = Object.keys(existing).filter(key => !(key in datum)); await innerCollection.update({ ...filter, _id: datum._id }, { $set: datum, $unset: removedFields.reduce((acc, key) => { acc[key] = ''; return acc; }, {}), }); } else { await innerCollection.insert(datum); } } for (const id of existingIds) { if (!retrievedIds.includes(id)) { await innerCollection.remove({ ...filter, _id: id }); } } } } catch (error) { await innerCollection.remove(filter, { multi: true }); console.error(error); } setLoading(false); }, { wait: 100, leading: false, trailing: true }); (0, react_1.useEffect)(() => { (0, set_1.default)(window, `collections.${innerCollection.name}`, innerCollection); setLoading(true); refresh.run(); }, [innerCollection, (0, use_object_1.useObject)(filter), (0, use_object_1.useObject)(params)]); (0, use_throttled_events_1.useThrottledEvents)(client, [utils_1.ClientEvents.INITIALIZED, utils_1.ClientEvents.CONTEXT_CHANGED], refresh.run, [refresh.run], 500); (0, use_event_1.useRemoteEvent)({ event: utils_1.HeleneEvents.METHOD_REFRESH, channel, }, (refreshMethod) => { if (refreshMethod === method) refresh.run(); }, [refresh.run]); result.collection = innerCollection; result.data = single ? data[0] : data; result.loading = (0, isEmpty_1.default)(data) && loading; result.client = client; result.refresh = refresh.run; return result; } //# sourceMappingURL=use-data.js.map