UNPKG

diffusion

Version:

Diffusion JavaScript client

217 lines (172 loc) 6.53 kB
var RecordV2Parser = require('data/record/recordv2-parser'); var BytesImpl = require('data/bytes-impl'); var utils = require('data/record/recordv2-utils'); var NO_CHANGE = new RecordV2DeltaImpl(new Buffer([])); NO_CHANGE.changes = function() { return []; }; var Type = { FIELD_CHANGED : "FIELD_CHANGED", FIELDS_ADDED : "FIELDS_ADDED", FIELDS_REMOVED : "FIELDS_REMOVED", RECORDS_ADDED : "RECORDS_ADDED", RECORDS_REMOVED : "RECORDS_REMOVED" }; function ChangeImpl(type, recordName, recordIndex, fieldName, fieldIndex) { this.type = type; this.recordName = recordName; this.recordIndex = recordIndex; this.fieldName = fieldName; this.fieldIndex = fieldIndex; var key = recordName + "(" + recordIndex + ")"; if (type !== Type.RECORDS_REMOVED && type !== Type.RECORDS_ADDED) { key += "." + fieldName + "(" + fieldIndex + ")"; } this.key = key; this.toString = function() { return type + " " + key; }; } function RecordV2DeltaImpl(buffer, offset, length, recordChanges, fieldChanges) { // eslint-disable-next-line no-underscore-dangle BytesImpl.__constructor.call(this, buffer, offset, length); var self = this; this.changes = function(schema) { var data = RecordV2Parser.parse(buffer, offset, length); var recordIndex = 0; var changes = []; schema.records().forEach(function(schemaRecord) { if (data.length < recordIndex + schemaRecord.min) { throw new Error("Insufficient records of type " + schemaRecord.name + " in delta for schema"); } if (schemaRecord.isVariable) { recordIndex = processVariableRecordChanges(schemaRecord, recordIndex, data, changes); } else { recordIndex = processFixedRecordChanges(schemaRecord, recordIndex, data, changes); } }); return changes; }; function processFixedRecordChanges(schemaRecord, startIndex, data, changes) { var recordIndex = startIndex; for (var i = 0; i < schemaRecord.min; ++i) { processRecordChanges(recordIndex, schemaRecord, i, data[recordIndex], changes); recordIndex++; } return recordIndex; } function processVariableRecordChanges(schemaRecord, startIndex, data, changes) { var numberOfNewRecords = data.length; var maxAllowed = schemaRecord.max; if (maxAllowed !== -1 && numberOfNewRecords > startIndex + maxAllowed) { throw new Error("Too many records of type " + schemaRecord.name + " in delta for schema"); } var recordIndex = startIndex; var matchRecordCount; if (recordChanges && recordChanges[0]) { matchRecordCount = recordChanges[1]; } else { matchRecordCount = numberOfNewRecords; } var varIndex = 0; for (; recordIndex < matchRecordCount; recordIndex++) { processRecordChanges(recordIndex, schemaRecord, varIndex, data[recordIndex], changes); varIndex++; } if (recordChanges) { changes.push(new ChangeImpl( recordChanges[0] ? Type.RECORDS_ADDED : Type.RECORDS_REMOVED, schemaRecord.name, recordChanges[1] - startIndex, "", 0)); } return recordIndex; } function processRecordChanges(dataRecordIndex, record, recordIndex, data, changes) { var fieldIndex = 0; record.fields().forEach(function(field) { if (field.isVariable) { fieldIndex = processVariableFieldChanges( record, recordIndex, dataRecordIndex, field, fieldIndex, data, changes); } else { fieldIndex = processFixedFieldChanges( record, recordIndex, field, fieldIndex, data, changes); } }); } function processFixedFieldChanges(record, recordIndex, field, startIndex, data, changes) { var numberOfFields = data.length; var fieldIndex = startIndex; for (var i = 0; i < field.min; ++i) { if (fieldIndex >= numberOfFields) { throw new Error( "Insufficient fields of type " + field.name + " in delta for schema record " + record.name); } if (data[fieldIndex] !== "") { changes.push(new ChangeImpl( Type.FIELD_CHANGED, record.name, recordIndex, field.name, i)); } fieldIndex++; } return fieldIndex; } function processVariableFieldChanges(record, recordIndex, dataRecordIndex, field, startIndex, data, changes) { var numberOfFields = data.length; var fieldIndex = startIndex; if (numberOfFields < fieldIndex + field.min) { throw new Error( "Insufficient fields of type " + field.name + " in delta for schema record " + record.name); } var fChanges = fieldChanges[dataRecordIndex]; var matchingFieldCount; if (fChanges) { matchingFieldCount = fChanges[1]; } else { matchingFieldCount = numberOfFields; } var varIndex = 0; for (; fieldIndex < matchingFieldCount; fieldIndex++) { if (data[fieldIndex] !== "") { changes.push(new ChangeImpl( Type.FIELD_CHANGED, record.name, recordIndex, field.name, varIndex)); } varIndex++; } if (fChanges) { changes.push(new ChangeImpl( fChanges[0] ? Type.FIELDS_ADDED : Type.FIELDS_REMOVED, record.name, recordIndex, field.name, fChanges[1])); } return fieldIndex; } this.toString = function() { return utils.bytesToString(self.$buffer, self.$offset, self.$length); }; } module.exports = RecordV2DeltaImpl; module.exports.NO_CHANGE = NO_CHANGE;