/** * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved. * Node module: @schukai/monster * * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3). * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html * * For those who do not wish to adhere to the AGPLv3, a commercial license is available. * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms. * For more information about purchasing a commercial license, please contact schukai GmbH. * * SPDX-License-Identifier: AGPL-3.0 */ import { instanceSymbol } from "../../constants.mjs"; import { isArray, isFunction, isObject } from "../../types/is.mjs"; import { Datasource } from "../datasource.mjs"; import { diff } from "../diff.mjs"; import { Pathfinder } from "../pathfinder.mjs"; import { Pipe } from "../pipe.mjs"; export { Server }; /** * @private * @type {symbol} */ const serverVersionSymbol = Symbol("serverVersion"); /** * Base class for all server data sources * * @license AGPLv3 * @since 3.4.0 * @copyright schukai GmbH * @memberOf Monster.Data.Datasource * @summary The Server class encapsulates the access to a server datasource */ class Server extends Datasource { /** * This method is called by the `instanceof` operator. * @returns {symbol} */ static get [instanceSymbol]() { return Symbol.for("@schukai/monster/data/datasource/server"); } /** * This prepares the data that comes from the server. * Should not be called directly. * * @private * @param {Object} payload * @returns {Object} */ transformServerPayload(payload) { payload = doTransform.call(this, "read", payload); this[serverVersionSymbol] = payload; const dataPath = this.getOption("read.path"); if (dataPath) { payload = new Pathfinder(payload).getVia(dataPath); } return payload; } /** * This prepares the data for writing and should not be called directly. * * @private * @param {Object} payload * @returns {Object} */ prepareServerPayload(payload) { payload = doTransform.call(this, "write", payload); payload = doDiff.call(this, payload); const sheathingObject = this.getOption("write.sheathing.object"); const sheathingPath = this.getOption("write.sheathing.path"); if (sheathingObject && sheathingPath) { const sub = payload; payload = sheathingObject; new Pathfinder(payload).setVia(sheathingPath, sub); } return payload; } } /** * * @param obj * @returns {*} */ function doDiff(obj) { if ( this[serverVersionSymbol] === null || this[serverVersionSymbol] === undefined ) { return obj; } const callback = this.getOption("write.partial.callback"); if (!isFunction(callback)) { return obj; } const results = diff(this[serverVersionSymbol], obj); if (!results) { return obj; } obj = callback(obj, results); this[serverVersionSymbol] = obj; return obj; } /** * @private * @param {string} type * @param {Object} obj * @returns {Object} */ function doTransform(type, obj) { const transformation = this.getOption(`${type}.mapping.transformer`); if (transformation !== undefined && transformation !== null) { const pipe = new Pipe(transformation); const callbacks = this.getOption(`${type}.mapping.callbacks`); if (isArray(callbacks)) { for (const callback of callbacks) { if (typeof callback === "function") { pipe.setCallback(callback); } } } if (isObject(callbacks)) { for (const key in callbacks) { if ( callbacks.hasOwnProperty(key) && typeof callbacks[key] === "function" ) { pipe.setCallback(key, callbacks[key]); } } } obj = pipe.run(obj); } return obj; }