@clickup/ent-framework
Version:
A PostgreSQL graph-database-alike library with microsharding and row-level security
70 lines • 3.21 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Loader = void 0;
const p_defer_1 = __importDefault(require("p-defer"));
/**
* Loader allows to batch single-item requests into batches. It uses a different
* architecture than Facebook's DataLoader:
*
* - it's more developers-friendly: multi-parameter loadings, you may implement
* automatic deduplication of requests at onCollect stage, no requirement to
* serialize/deserialize requests into string keys;
* - strong-typed load() and handler arguments.
*
* To create your own specific loader:
* 1. Define a handler class with onCollect/onReturn/onFlush methods.
* 2. In onCollect, accumulate the incoming requests in the handler object's
* private property.
* 3. In onFlush, process what you accumulated so far and save to another
* handler object's private property (and by adding, say, delay(50) in the
* beginning of onFlush, you may group the requests coming within the 1st 50
* ms).
* 3. In onReturn, extract the result corresponding to the request and return
* it, so the caller will receive it seamlessly as a load() return value.
*
* In the future, Batcher may be refactored to use Loader as the underlying
* engine, but for now they're separate (Batcher is much more domain logic
* specific and Loader is completely abstract).
*/
class Loader {
constructor(handlerCreator) {
this.handlerCreator = handlerCreator;
this.session = null;
}
async load(...args) {
const session = (this.session ??= {
collected: 0,
handler: this.handlerCreator(),
abortWait: (0, p_defer_1.default)(),
flush: new Promise((resolve) => process.nextTick(async () => {
const waitPromise = session.handler.onWait?.();
if (waitPromise) {
// If we have onWait() handler, we should wait on it, but interrupt
// this wait in case session.abortWait resolves.
await Promise.race([waitPromise, session.abortWait.promise]);
// Often times, wait() returns a ClearablePromise (e.g. from delay
// module), so we can utilize it here to cancel the lingering timer.
if ("clear" in waitPromise &&
typeof waitPromise.clear === "function" &&
waitPromise.clear.length === 0) {
waitPromise.clear();
}
}
this.session = this.session === session ? null : this.session;
resolve(session.handler.onFlush(session.collected));
})),
});
session.collected++;
if (session.handler.onCollect(...args) === "flush") {
this.session = this.session === session ? null : this.session;
session.abortWait.resolve();
}
await session.flush;
return session.handler.onReturn(...args);
}
}
exports.Loader = Loader;
//# sourceMappingURL=Loader.js.map
;