@helenejs/react
Version:
Real-time Web Apps for Node.js
124 lines • 5.8 kB
JavaScript
;
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