var util = require('util'); var uuid = require('uuid'); var ensure = require('./common/utils/ensure'); function toNumber(obj) { if (typeof obj === 'number') return obj; if (typeof obj !== 'object') throw new TypeError(util.format("'%s' is not a number.", obj)); if (!obj.hasOwnProperty('low') || !obj.hasOwnProperty('high') || !obj.hasOwnProperty('unsigned')) throw new Error("Invalid number."); return (obj.low + (obj.high * 0xffffffff)); } /** * @param {!number} commitPosition * @param {!number} preparePosition * @constructor * @property {!number} commitPosition * @property {!number} preparePosition */ function Position(commitPosition, preparePosition) { Object.defineProperties(this, { commitPosition: { enumerable: true, value: toNumber(commitPosition) }, preparePosition: { enumerable: true, value: toNumber(preparePosition) } }); } Position.prototype.compareTo = function(other) { if (this.commitPosition < other.commitPosition || (this.commitPosition === other.commitPosition && this.preparePosition < other.preparePosition)) return -1; if (this.commitPosition > other.commitPosition || (this.commitPosition === other.commitPosition && this.preparePosition > other.preparePosition)) return 1; return 0; }; Position.prototype.toString = function() { return util.format("%d/%d", this.commitPosition, this.preparePosition); }; const EventReadStatus = { Success: 'success', NotFound: 'notFound', NoStream: 'noStream', StreamDeleted: 'streamDeleted' }; /** * @param {object} ev * @constructor * @property {string} eventStreamId * @property {string} eventId * @property {number} eventNumber * @property {string} eventType * @property {number} createdEpoch * @property {?Buffer} data * @property {?Buffer} metadata * @property {boolean} isJson */ function RecordedEvent(ev) { Object.defineProperties(this, { eventStreamId: {enumerable: true, value: ev.event_stream_id}, eventId: {enumerable: true, value: uuid.unparse(ev.event_id.buffer, ev.event_id.offset)}, eventNumber: {enumerable: true, value: ev.event_number}, eventType: {enumerable: true, value: ev.event_type}, //Javascript doesn't have .Net precision for time, so we use created_epoch for created created: {enumerable: true, value: new Date(ev.created_epoch || 0)}, createdEpoch: {enumerable: true, value: ev.created_epoch ? toNumber(ev.created_epoch) : 0}, data: {enumerable: true, value: ev.data ? ev.data.toBuffer() : new Buffer(0)}, metadata: {enumerable: true, value: ev.metadata ? ev.metadata.toBuffer() : new Buffer(0)}, isJson: {enumerable: true, value: ev.data_content_type == 1} }); } /** * @param {object} ev * @constructor * @property {?RecordedEvent} event * @property {?RecordedEvent} link * @property {?RecordedEvent} originalEvent * @property {boolean} isResolved * @property {?Position} originalPosition * @property {string} originalStreamId * @property {number} originalEventNumber */ function ResolvedEvent(ev) { Object.defineProperties(this, { event: { enumerable: true, value: ev.event === null ? null : new RecordedEvent(ev.event) }, link: { enumerable: true, value: ev.link === null ? null : new RecordedEvent(ev.link) }, originalEvent: { enumerable: true, get: function() { return this.link || this.event; } }, isResolved: { enumerable: true, get: function() { return this.link !== null && this.event !== null; } }, originalPosition: { enumerable: true, value: (ev.commit_position && ev.prepare_position) ? new Position(ev.commit_position, ev.prepare_position) : null }, originalStreamId: { enumerable: true, get: function() { return this.originalEvent.eventStreamId; } }, originalEventNumber: { enumerable: true, get: function() { return this.originalEvent.eventNumber; } } }); } /** * * @param {string} status * @param {string} stream * @param {number} eventNumber * @param {object} event * @constructor * @property {string} status * @property {string} stream * @property {number} eventNumber * @property {ResolvedEvent} event */ function EventReadResult(status, stream, eventNumber, event) { Object.defineProperties(this, { status: {enumerable: true, value: status}, stream: {enumerable: true, value: stream}, eventNumber: {enumerable: true, value: eventNumber}, event: { enumerable: true, value: status === EventReadStatus.Success ? new ResolvedEvent(event) : null } }); } /** * @param {number} nextExpectedVersion * @param {Position} logPosition * @constructor * @property {number} nextExpectedVersion * @property {Position} logPosition */ function WriteResult(nextExpectedVersion, logPosition) { Object.defineProperties(this, { nextExpectedVersion: { enumerable: true, value: nextExpectedVersion }, logPosition: { enumerable: true, value: logPosition } }); } /** * @param {string} status * @param {string} stream * @param {number} fromEventNumber * @param {string} readDirection * @param {object[]} events * @param {number} nextEventNumber * @param {number} lastEventNumber * @param {boolean} isEndOfStream * @constructor * @property {string} status * @property {string} stream * @property {number} fromEventNumber * @property {string} readDirection * @property {ResolvedEvent[]} events * @property {number} nextEventNumber * @property {number} lastEventNumber * @property {boolean} isEndOfStream */ function StreamEventsSlice( status, stream, fromEventNumber, readDirection, events, nextEventNumber, lastEventNumber, isEndOfStream ) { Object.defineProperties(this, { status: { enumerable: true, value: status }, stream: { enumerable: true, value: stream }, fromEventNumber: { enumerable: true, value: fromEventNumber }, readDirection: { enumerable: true, value: readDirection }, events: { enumerable: true, value: events ? events.map(function(ev) { return new ResolvedEvent(ev); }) : [] }, nextEventNumber: { enumerable: true, value: nextEventNumber }, lastEventNumber: { enumerable: true, value: lastEventNumber }, isEndOfStream: { enumerable: true, value: isEndOfStream } }) } /** * @param {string} readDirection * @param {Position} fromPosition * @param {Position} nextPosition * @param {ResolvedEvent[]} events * @constructor * @property {string} readDirection * @property {Position} fromPosition * @property {Position} nextPosition * @property {ResolvedEvent[]} events */ function AllEventsSlice(readDirection, fromPosition, nextPosition, events) { Object.defineProperties(this, { readDirection: { enumerable: true, value: readDirection }, fromPosition: { enumerable: true, value: fromPosition }, nextPosition: { enumerable: true, value: nextPosition }, events: { enumerable: true, value: events ? events.map(function(ev){ return new ResolvedEvent(ev); }) : [] }, isEndOfStream: { enumerable: true, value: events === null || events.length === 0 } }); } /** * @param {Position} logPosition * @constructor * @property {Position} logPosition */ function DeleteResult(logPosition) { Object.defineProperties(this, { logPosition: { enumerable: true, value: logPosition } }); } /** * @param {string} stream * @param {boolean} isStreamDeleted * @param {number} metastreamVersion * @param {object} streamMetadata * @constructor * @property {string} stream * @property {boolean} isStreamDeleted * @property {number} metastreamVersion * @property {object} streamMetadata */ function RawStreamMetadataResult(stream, isStreamDeleted, metastreamVersion, streamMetadata) { ensure.notNullOrEmpty(stream); Object.defineProperties(this, { stream: {enumerable: true, value: stream}, isStreamDeleted: {enumerable: true, value: isStreamDeleted}, metastreamVersion: {enumerable: true, value: metastreamVersion}, streamMetadata: {enumerable: true, value: streamMetadata} }); } // Exports Constructors module.exports.Position = Position; module.exports.toNumber = toNumber; module.exports.ResolvedEvent = ResolvedEvent; module.exports.EventReadStatus = EventReadStatus; module.exports.EventReadResult = EventReadResult; module.exports.WriteResult = WriteResult; module.exports.StreamEventsSlice = StreamEventsSlice; module.exports.AllEventsSlice = AllEventsSlice; module.exports.DeleteResult = DeleteResult; module.exports.RawStreamMetadataResult = RawStreamMetadataResult;