UNPKG

data-interchange

Version:
173 lines (172 loc) 8.35 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createInterchange = exports.READ_RESULT_DEFAULT = void 0; const layerr_1 = require("layerr"); const promise_1 = require("./promise"); const boomerang_1 = require("./boomerang"); const queue_1 = require("./queue"); const types_1 = require("./types"); exports.READ_RESULT_DEFAULT = (res) => { if (typeof res === UNDEFINED || res === null) { return types_1.ReadAction.Fallback; } return types_1.ReadAction.Return; }; const UNDEFINED = "undefined"; const VALUE_NOOP = (val) => val; function createInterchange(sources, options = {}) { options.queue = options.queue || queue_1.createQueue(); return { read: (id) => processRead(sources, id, options), write: (value) => processWrite(sources, value, options) }; } exports.createInterchange = createInterchange; function processRead(sources, id, options = {}) { return __awaiter(this, void 0, void 0, function* () { let lastValue, lastConverters = null; yield boomerang_1.boomerang(sources, (source, sourceIndex, returning) => __awaiter(this, void 0, void 0, function* () { const { read = null, readError = () => types_1.ReadAction.Throw, readResult = exports.READ_RESULT_DEFAULT, write = null, writeMissingRead = true } = source; // Prepare value-conversion functions let convertRead = VALUE_NOOP, convertWrite = VALUE_NOOP; if (typeof source.convert === "object") { const { read: tempRead, write: tempWrite } = (source).convert; convertRead = tempRead || convertRead; convertWrite = tempWrite || convertWrite; } // Check if rolling back up the chain (boomerang) if (returning) { const [returnConvertRead] = lastConverters; // Convert value to next item format UP the chain lastValue = returnConvertRead(lastValue); lastConverters = [convertRead, convertWrite]; // Because all prior indexes (sources) did NOT // return a value, they should be written to if (writeMissingRead && typeof write === "function") { let writeResult = source.queueWriteKey ? queue_1.enqueue(options.queue, resolveQueueKey(lastValue, source.queueWriteKey), () => write(lastValue)) : write(lastValue); if (promise_1.isPromise(writeResult)) { writeResult = yield writeResult; } lastValue = typeof writeResult === UNDEFINED ? lastValue : writeResult; } return; } // Attempt to read if (typeof read === "function") { let initialValue; try { initialValue = source.queueReadKey ? queue_1.enqueue(options.queue, resolveQueueKey(id, source.queueReadKey), () => read(id)) : read(id); if (promise_1.isPromise(initialValue)) { initialValue = yield initialValue; } } catch (err) { const action = readError(err); if (action === types_1.ReadAction.Throw) { throw new layerr_1.Layerr(err, "Interchange read error"); } else if (action === types_1.ReadAction.Fallback && sourceIndex === sources.length - 1) { throw new layerr_1.Layerr(err, "Interchange fallback requested, but none available"); } else if (action === types_1.ReadAction.Return) { return lastValue; // Probably undefined } } lastValue = initialValue; lastConverters = [convertRead, convertWrite]; const readValueAction = readResult(lastValue); if (readValueAction === types_1.ReadAction.Return) { return boomerang_1.BOOMERANG_RETURN; } else if (readValueAction === types_1.ReadAction.Throw) { throw new layerr_1.Layerr(`readResult read handler flagged result as invalid for source ${sourceIndex}`); } // ReadAction.Fallback simply loops } })); return lastValue; }); } function resolveQueueKey(value, resolver) { return typeof resolver === "string" ? resolver : resolver(value); } function processWrite(sources, value, options = {}) { return __awaiter(this, void 0, void 0, function* () { const { writeMode = types_1.WriteMode.Series } = options; if (writeMode === types_1.WriteMode.Parallel) { // All sources are written with the same value in parallel yield Promise.all(sources.map((source) => __awaiter(this, void 0, void 0, function* () { const { writeWait = true } = source; if (typeof source.write !== "function") return; const result = source.queueWriteKey ? queue_1.enqueue(options.queue, resolveQueueKey(value, source.queueWriteKey), () => source.write(value)) : source.write(value); if (writeWait && promise_1.isPromise(result)) { yield result; } }))); return value; } else if (writeMode === types_1.WriteMode.Series) { // Run from first to last, converting, and then backwards // writing each value let lastValue = value; const values = sources.map((source, ind) => { if (ind === 0) return value; const { convert = {} } = source; const { write = VALUE_NOOP } = convert; lastValue = write(lastValue); return lastValue; }); // Run backwards writing lastValue = values[values.length - 1]; for (let ind = sources.length - 1; ind >= 0; ind -= 1) { const { queueWriteKey, write, writeWait = true } = sources[ind]; if (typeof write !== "function") continue; const writeResult = queueWriteKey ? queue_1.enqueue(options.queue, resolveQueueKey(lastValue, queueWriteKey), () => write(lastValue)) : write(lastValue); if (writeWait) { lastValue = promise_1.isPromise(writeResult) ? yield writeResult : writeResult; if (ind > 0) { const { convert = {} } = sources[ind]; const { read = VALUE_NOOP } = convert; // Convert this value lastValue = read(lastValue); } } else { // Not waiting, so set the lastValue to be the // correct pre-calculated value if (ind > 0) { lastValue = values[ind - 1]; } else { // First index lastValue = values[0]; } } } return lastValue; } else { throw new layerr_1.Layerr(`Invalid write mode: ${writeMode}`); } }); }