diffusion
Version:
Diffusion JavaScript client
217 lines (172 loc) • 6.53 kB
JavaScript
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;