nope-js-browser
Version:
NoPE Runtime for the Browser. For nodejs please use nope-js-node
121 lines (120 loc) • 4.96 kB
JavaScript
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2021-11-12 12:25:30
* @modify date 2022-01-06 09:54:40
* @desc [description]
*/
import { memoize } from "lodash";
import { deepClone, flattenObject } from "../helpers/objectMethods";
import { comparePatternAndPath as _comparePatternAndPath, containsWildcards, MULTI_LEVEL_WILDCARD, } from "../helpers/pathMatchingMethods";
import { PubSubSystemBase } from "./nopePubSubSystem";
// Create a memoized function for the pattern matching (its way faster)
const comparePatternAndPath = memoize((pattern, path) => {
return _comparePatternAndPath(pattern, path);
}, (pattern, path) => {
return `${pattern}-${path}`;
});
/**
* Default implementation of {@link IDataPubSubSystem}
*
* Extends the {@link PubSubSystemBase} by adding the following properties and methods:
* - `pushData` to push data into the system.
* - `pullData` to pull data from the system. Will allways return the current data or the default value if no data is present at the given path.
* - `patternbasedPullData` to pull data with a given pattern. See the example for details.
* - `patternBasedPush` to push data with a given pattern into the system.
* - If you want to acces the root data please check the property `data` which will contain the entire data root that has been created.
*/
export class DataPubSubSystem extends PubSubSystemBase {
constructor() {
super(...arguments);
this._sendCurrentDataOnSubscription = true;
}
/**
* A Getter to return a COPY of the item. Outside of the system,
* you'll never receive the original object. It is allways a clone.
*
*
* @author M.Karkowski
* @readonly
* @type {unknown}
* @memberof PubSubSystemBase
*/
get data() {
return deepClone(this._data);
}
/**
* Option to push data into the system see {@link IDataPubSubSystem.pushData} @ {@link IDataPubSubSystem}
* @param path The path of the data.
* @param content The content of the Data.
* @param options The options used during pushing the data (see {@link IEventAdditionalData})
* @returns nothing.
*/
pushData(path, content, options = {}) {
return this._pushData(path, path, content, options);
}
/**
* Option to pull data from the system see {@link IDataPubSubSystem.pullData} @ {@link IDataPubSubSystem}
* @param topic the Topic to use.
* @param _default The default object, if nothing else is provided
* @returns The data. Defined as T
*/
pullData(topic, _default = null) {
return this._pullData(topic, _default);
}
/**
* Option to pull data from the system with a pattern see {@link IDataPubSubSystem.patternbasedPullData} @ {@link IDataPubSubSystem}
* @param pattern The pattern (see {@link })
* @param _default The Default object, if data is not present.
* @returns
*/
patternbasedPullData(pattern, _default = null) {
return this._patternbasedPullData(pattern, _default);
}
/**
* Option to push data to the system using a pattern see {@link IDataPubSubSystem.patternBasedPush} @ {@link IDataPubSubSystem}
* @param pattern The pattern (see {@link })
* @param data The data to push
* @param options The options used during pushing the data (see {@link IEventAdditionalData})
* @param fast If enabled, firstly, the data is pushed, afterwards, we just inform once.
* @returns Nothing
*/
patternBasedPush(pattern, data, options = {}, fast = false // Flag to emit single changes or all changes.
) {
// To extract the data based on a Pattern,
// we firstly, we check if we would affect the data.
if (!containsWildcards(pattern)) {
return this._pushData(pattern, pattern, data, options);
}
if (pattern.includes(MULTI_LEVEL_WILDCARD)) {
throw Error("You can only use single-level wildcards in this action");
}
const flattenData = flattenObject(this._data);
const _options = this._updateOptions(options);
for (const path of flattenData.keys()) {
if (comparePatternAndPath(pattern, path).affectedOnSameLevel) {
this._pushData(path, pattern, data, _options, fast);
}
}
if (fast) {
// Its better for us, to just store the incremental changes
// with the pattern
this.onIncrementalDataChange.emit({
path: pattern,
data,
..._options,
});
}
}
/**
* Describes the Data.
* @returns
*/
toDescription() {
const _data = super.toDescription();
return {
..._data,
data: this._data,
};
}
}