domain_datumStreamMetadata.js

import { DatumStreamType, default as DatumStreamTypes } from "./datumStreamType.js";
import DatumSamplesTypes from "./datumSamplesType.js";

/**
 * Metadata about a datum stream.
 *
 * @alias module:domain~DatumStreamMetadata
 */
class DatumStreamMetadata {
	/**
	 * Constructor.
	 * @param {string} streamId         the stream ID
	 * @param {string} zone             the time zone ID
	 * @param {DatumStreamType} kind    the stream type
	 * @param {number} objectId         the node or location ID
	 * @param {string} sourceId         the source ID
	 * @param {string[]} iNames         the instantaneous property name array
	 * @param {string[]} aNames         the accumulating property name array
	 * @param {string[]} sNames         the status property name array
	 */
	constructor(streamId, zone, kind, objectId, sourceId, iNames, aNames, sNames) {
		this._streamId = streamId;
		this._zone = zone;
		this._kind = kind instanceof DatumStreamType ? kind : DatumStreamTypes.Node;
		this._objectId = objectId;
		this._sourceId = sourceId;
		this._iNames = Array.isArray(iNames) ? iNames : undefined;
		this._aNames = Array.isArray(aNames) ? aNames : undefined;
		this._sNames = Array.isArray(sNames) ? sNames : undefined;
		if (this.constructor === DatumStreamMetadata) {
			Object.freeze(this);
		}
	}

	/**
	 * Create a new node datum stream metadata instance.
	 * @param {string} streamId         the stream ID
	 * @param {string} zone             the time zone ID
	 * @param {number} nodeId           the node ID
	 * @param {string} sourceId         the source ID
	 * @param {string[]} iNames         the instantaneous property name array
	 * @param {string[]} aNames         the accumulating property name array
	 * @param {string[]} sNames         the status property name array
	 * @returns {DatumStreamMetadata} the new metadata instance
	 */
	static nodeMetadata(streamId, zone, nodeId, sourceId, iNames, aNames, sNames) {
		return new DatumStreamMetadata(
			streamId,
			zone,
			DatumStreamTypes.Node,
			nodeId,
			sourceId,
			iNames,
			aNames,
			sNames,
		);
	}

	/**
	 * Create a new location datum stream metadata instance.
	 * @param {string} streamId         the stream ID
	 * @param {string} zone             the time zone ID
	 * @param {number} locationId       the location ID
	 * @param {string} sourceId         the source ID
	 * @param {string[]} iNames         the instantaneous property name array
	 * @param {string[]} aNames         the accumulating property name array
	 * @param {string[]} sNames         the status property name array
	 * @returns {DatumStreamMetadata} the new metadata instance
	 */
	static locationMetadata(streamId, zone, locationId, sourceId, iNames, aNames, sNames) {
		return new DatumStreamMetadata(
			streamId,
			zone,
			DatumStreamTypes.Location,
			locationId,
			sourceId,
			iNames,
			aNames,
			sNames,
		);
	}

	/**
	 * The stream ID, for example `7714f762-2361-4ec2-98ab-7e96807b32a6`.
	 * @type {string}
	 */
	get streamId() {
		return this._streamId;
	}

	/**
	 * The stream time zone ID, for example `Pacific/Auckland`.
	 * @type {string}
	 */
	get timeZoneId() {
		return this._zone;
	}

	/**
	 * The stream type.
	 * @type {DatumStreamType}
	 */
	get kind() {
		return this._kind;
	}

	/**
	 * The stream objece (node or location) ID.
	 * @type {number}
	 */
	get objectId() {
		return this._objectId;
	}

	/**
	 * The stream object ID (if the `kind` is `Node`), otherwise `undefined`.
	 * @type {number}
	 */
	get nodeId() {
		return DatumStreamTypes.Node.equals(this._kind) ? this._objectId : undefined;
	}

	/**
	 * The stream object ID (if the `kind` is `Location`), otherewise `undefined`.
	 * @type {number}
	 */
	get locationId() {
		return DatumStreamTypes.Location.equals(this._kind) ? this._objectId : undefined;
	}

	/**
	 * The stream source ID.
	 * @type {string}
	 */
	get sourceId() {
		return this._sourceId;
	}

	/**
	 * The instantaneous property names array length.
	 * @type {number}
	 */
	get instantaneousLength() {
		return Array.isArray(this._iNames) ? this._iNames.length : 0;
	}

	/**
	 * The instantaneous property names array.
	 * @type {Array<String>}
	 */
	get instantaneousNames() {
		return this._iNames;
	}

	/**
	 * The accumulating property names array length.
	 * @type {number}
	 */
	get accumulatingLength() {
		return Array.isArray(this._aNames) ? this._aNames.length : 0;
	}

	/**
	 * The accumulating property names array.
	 * @type {Array<String>}
	 */
	get accumulatingNames() {
		return this._aNames;
	}

	/**
	 * The status property names array length.
	 * @type {number}
	 */
	get statusLength() {
		return Array.isArray(this._sNames) ? this._sNames.length : 0;
	}

	/**
	 * The status property names array.
	 * @type {Array<String>}
	 */
	get statusNames() {
		return this._sNames;
	}

	/**
	 * The total number of instantaneous, accumulating, and status property names.
	 * @type {number}
	 */
	get propertyNamesLength() {
		return this.instantaneousLength + this.accumulatingLength + this.statusLength;
	}

	/**
	 * Get all stream property names, in order of instantaneous, accumulating, and status.
	 * @type {string[]}
	 */
	get propertyNames() {
		const len = this.propertyNamesLength;
		if (len < 1) {
			return null;
		}
		let names = [];
		if (this.instantaneousLength > 0) {
			names = names.concat(this._iNames);
		}
		if (this.accumulatingLength > 0) {
			names = names.concat(this._aNames);
		}
		if (this.statusLength > 0) {
			names = names.concat(this._sNames);
		}
		return names;
	}

	/**
	 * Get the property names for a given samples type.
	 * @param {DatumSamplesType} samplesType the type of property names to return; `Tag` is not supported
	 * @returns {string[]} the property names for the given type, or `null` if none available
	 */
	propertyNamesForType(samplesType) {
		if (DatumSamplesTypes.Instantaneous.equals(samplesType)) {
			return this._iNames;
		} else if (DatumSamplesTypes.Accumulating.equals(samplesType)) {
			return this._aNames;
		} else if (DatumSamplesTypes.Status.equals(samplesType)) {
			return this._sNames;
		}
		return null;
	}

	/**
	 * Get this object as a standard JSON encoded string value.
	 *
	 * An example result looks like this:
	 *
	 * ```
	 * {
	 *       "streamId": "7714f762-2361-4ec2-98ab-7e96807b32a6",
	 *       "zone": "Pacific/Auckland",
	 *       "kind": "n",
	 *       "objectId": 123,
	 *       "sourceId": "/power/1",
	 *       "i": ["watts", "current",  "voltage", "frequency"],
	 *       "a": ["wattHours"]
	 * }
	 * ```
	 *
	 * @return {string} the JSON encoded string
	 */
	toJsonEncoding() {
		const result = {
			streamId: this._streamId,
			zone: this._zone,
			kind: this._kind ? this._kind.key : DatumSamplesTypes.Node.key,
			objectId: this._objectId,
			sourceId: this._sourceId,
		};
		if (this.instantaneousLength > 0) {
			result.i = this._iNames;
		}
		if (this.accumulatingLength > 0) {
			result.a = this._aNames;
		}
		if (this.statusLength > 0) {
			result.s = this._sNames;
		}
		return JSON.stringify(result);
	}

	/**
	 * Parse a JSON string into a {@link module:domain~DatumStreamMetadata} instance.
	 *
	 * The JSON must be encoded the same way {@link module:domain~DatumStreamMetadata#toJsonEncoding} does.
	 *
	 * @param {string} json the JSON to parse
	 * @returns {module:domain~DatumStreamMetadata} the stream metadata instance
	 */
	static fromJsonEncoding(json) {
		return this.fromJsonObject(JSON.parse(json));
	}

	/**
	 * Create a metadata instance from an object parsed from a JSON string.
	 *
	 * The object must have been parsed from JSON that was encoded the same way {@link module:domain~DatumStreamMetadata#toJsonEncoding} does.
	 *
	 * @param {string} obj the object parsed from JSON
	 * @returns {module:domain~DatumStreamMetadata} the stream metadata instance
	 */
	static fromJsonObject(obj) {
		let kind, i, a, s;
		if (obj) {
			kind = DatumStreamType.valueOf(obj.kind);
			i = Array.isArray(obj.i) ? obj.i : undefined;
			a = Array.isArray(obj.a) ? obj.a : undefined;
			s = Array.isArray(obj.s) ? obj.s : undefined;
			return new DatumStreamMetadata(
				obj.streamId,
				obj.zone,
				kind,
				obj.objectId,
				obj.sourceId,
				i,
				a,
				s,
			);
		}
		return null;
	}
}

export default DatumStreamMetadata;