dreamstate
Version:
Store management library based on react context and observers
133 lines (130 loc) • 5.39 kB
JavaScript
import { __values } from 'tslib';
import { DreamstateError } from '../error/DreamstateError.js';
import { QUERY_METADATA_SYMBOL } from '../internals.js';
import { EDreamstateErrorCode } from '../../types/error.js';
/**
* Promisifies a query handler by wrapping it in a `Promise`.
*
* This function takes a query handler, and if it's asynchronous, it adds `.then` and `.catch` handlers to it.
* If the query handler is synchronous, it directly returns the result or rejects the promise in case of an error.
* It is useful for handling queries that may either return a promise or a direct result, ensuring consistent
* promise-based handling.
*
* @template R - The type of the response expected from the query handler.
* @template D - The type of data associated with the query request (optional).
* @template T - The type of the query (defaults to `TQueryType`).
* @param {TQueryListener<T, D, R>} callback - The query handler function that is called when the query is executed.
* It can either be synchronous or asynchronous.
* @param {IOptionalQueryRequest<D, T>} query - The query request containing necessary data for the query.
* @param {TAnyContextManagerConstructor | null} answerer - The context manager class reference
* that is handling the query.
* @returns {Promise<TQueryResponse<R>>} A promise that resolves with the query response, either from the
* synchronous result or the asynchronous operation.
*/
function promisifyQuery(callback, query, answerer) {
return new Promise(function (resolve, reject) {
try {
var timestamp_1 = Date.now();
var result = callback(query);
/*
* Not all query responders are sync or async.
* Here we expect it to be either sync or async and handle it in an async way.
*/
if (result instanceof Promise) {
return result.then(function (data) {
resolve({
answerer: answerer || callback,
type: query.type,
data: data,
timestamp: timestamp_1
});
}).catch(reject);
} else {
return resolve({
answerer: answerer || callback,
type: query.type,
data: result,
timestamp: timestamp_1
});
}
} catch (error) {
reject(error);
}
});
}
/**
* Finds the correct asynchronous listener or an array of listeners and returns the promise response or null.
*
* This function searches for a matching async listener based on the provided query type. If a listener is found,
* it invokes the corresponding method and returns the result as a promise. If no matching listener is found,
* the function returns `null`. It is useful for handling queries that require asynchronous processing and
* responding with a promise.
*
* @template R - The type of the response expected from the query.
* @template D - The type of the data associated with the query request.
* @template T - The type of the query.
* @template Q - The type of the query request (extends `IOptionalQueryRequest<D, T>`).
* @param {Q} query - The query request containing the necessary data for the query.
* @param {IRegistry} registry - An object containing registries for `CONTEXT_INSTANCES_REGISTRY`
* and `QUERY_PROVIDERS_REGISTRY`, which store context instances and query providers for the respective queries.
* @returns {Promise<TQueryResponse<R> | null>} A promise that resolves with the query response if a matching listener
* is found, or `null` if no listener matches the query type.
*/
function queryDataAsync(query, _a) {
var e_1, _b, e_2, _c;
var CONTEXT_INSTANCES_REGISTRY = _a.CONTEXT_INSTANCES_REGISTRY,
QUERY_PROVIDERS_REGISTRY = _a.QUERY_PROVIDERS_REGISTRY;
if (!query || !query.type) {
throw new DreamstateError(EDreamstateErrorCode.INCORRECT_PARAMETER, "Query must be an object with declared type or array of objects with type.");
}
try {
/*
* Managers classes are in priority over custom handlers.
* Registered in order of creation.
*/
for (var _d = __values(CONTEXT_INSTANCES_REGISTRY.values()), _e = _d.next(); !_e.done; _e = _d.next()) {
var service = _e.value;
try {
for (var _f = (e_2 = void 0, __values(service[QUERY_METADATA_SYMBOL])), _g = _f.next(); !_g.done; _g = _f.next()) {
var entry = _g.value;
if (query.type === entry[1]) {
var method = entry[0];
return promisifyQuery(service[method].bind(service), query, service.constructor);
}
}
} catch (e_2_1) {
e_2 = {
error: e_2_1
};
} finally {
try {
if (_g && !_g.done && (_c = _f.return)) _c.call(_f);
} finally {
if (e_2) throw e_2.error;
}
}
}
} catch (e_1_1) {
e_1 = {
error: e_1_1
};
} finally {
try {
if (_e && !_e.done && (_b = _d.return)) _b.call(_d);
} finally {
if (e_1) throw e_1.error;
}
}
/*
* From class providers fallback to manually listed query provider factories.
*/
if (QUERY_PROVIDERS_REGISTRY.has(query.type)) {
var handlerFunction = QUERY_PROVIDERS_REGISTRY.get(query.type)[0];
return promisifyQuery(handlerFunction, query, null);
}
/*
* Resolve null if nothing was found to handle request.
*/
return Promise.resolve(null);
}
export { queryDataAsync };