diffusion
Version:
Diffusion JavaScript client
244 lines (187 loc) • 7.59 kB
JavaScript
var AbstractRecordModel = require('data/record/model/abstract-record-model');
var FieldImpl = require('data/record/schema/field-impl');
var args2arr = require('util/array').argumentsToArray;
module.exports = function MutableRecordModelImpl(constructor, schema) {
AbstractRecordModel.call(this, constructor, schema);
var model = schema.createModel();
this.model = function() {
return model;
};
this.set = function(recordName, recordIndex, fieldName, fieldIndex, value) {
// Account for optional indices
if (arguments.length < 5) {
fieldIndex = 0;
}
if (arguments.length === 3) {
value = fieldName;
fieldName = recordIndex;
recordIndex = 0;
}
if (arguments.length === 2) {
value = recordIndex;
var key = parseKey(recordName);
recordName = key.recordName;
recordIndex = key.recordIndex;
fieldName = key.fieldName;
fieldIndex = key.fieldIndex;
}
var schemaRecord = schema.getRecord(recordName);
var record = getRecord(schemaRecord, recordIndex);
var schemaField = schemaRecord.getField(fieldName);
record[resolveFieldIndex(schemaField, record, fieldIndex)] = FieldImpl.normalise(schemaField, value);
return this;
};
this.add = function(recordName, recordIndex) {
var values = args2arr(arguments);
var schemaRecord;
var record;
if (arguments.length > 2 && typeof recordIndex === "number") {
values = values.slice(2);
schemaRecord = schema.getRecord(recordName);
record = getRecord(schemaRecord, recordIndex);
} else {
schemaRecord = schema.lastRecord();
if (model.length > schemaRecord.index) {
record = model[model.length - 1];
} else {
throw new Error("Variable record '" + schemaRecord.name + "' has no occurrences to add a field to");
}
}
addValuesToRecord(schemaRecord, record, values);
return this;
};
this.addRecord = function() {
var schemaRecord = schema.lastRecord();
if (!schemaRecord.isVariable) {
throw new Error("Record '" + schemaRecord.name + "' is not variable");
}
var max = schemaRecord.max;
if (max !== -1 && model.length - schemaRecord.index >= max) {
throw new Error("Record '" + schemaRecord.name + "' already has maximum number of occurrences");
}
model.push(schemaRecord.createModel());
return this;
};
this.removeRecord = function(index) {
var schemaRecord = schema.lastRecord();
if (!schemaRecord.isVariable) {
throw new Error("Record '" + schemaRecord.name + "' is not variable");
}
var actualIndex = resolveRecordIndex(schemaRecord, model, index);
if (model.length - schemaRecord.index - 1 < schemaRecord.min) {
throw new Error(
"Removing an occurrence of record '" + schemaRecord.name +
"' would violate the minimum number of occurrences");
}
model.splice(actualIndex, 1);
return this;
};
this.removeField = function(recordName, recordIndex, fieldIndex) {
var schemaRecord = schema.getRecord(recordName);
var record = getRecord(schemaRecord, recordIndex);
var schemaField = schemaRecord.lastField();
if (!schemaField.isVariable) {
throw new Error("Field '" + schemaField.name + "' is not a variable field");
}
var actualFieldIndex = resolveFieldIndex(schemaField, record, fieldIndex);
if (record.length - schemaField.index - 1 < schemaField.min) {
throw new Error(
"Removing an occurrence of field '" + schemaField.name +
"' would violate the minimum number of occurrences");
}
record.splice(actualFieldIndex, 1);
return this;
};
this.clearVariableRecords = function() {
var schemaRecord = schema.lastRecord();
model.length = schemaRecord.index + schemaRecord.min;
return this;
};
this.clearVariableFields = function(recordName, recordIndex) {
var schemaRecord = schema.getRecord(recordName);
var record = getRecord(schemaRecord, recordIndex);
var schemaField = schemaRecord.lastField();
record.length = schemaField.index + schemaField.min;
return this;
};
function addValuesToRecord(schemaRecord, record, values) {
var schemaField = schemaRecord.lastField();
if (!schemaField.isVariable) {
throw new Error("Final field of record '" + schemaRecord.name + "' is not variable");
}
var max = schemaField.max;
if (max !== -1) {
var current = record.length - schemaField.index;
if (current + values.length > max) {
throw new Error("Adding values would exceed maximum number of field occurrences");
}
}
values.forEach(function(value) {
record.push(FieldImpl.normalise(schemaField, value));
});
}
function getRecord(schemaRecord, index) {
return model[resolveRecordIndex(schemaRecord, model, index)];
}
function parseKey(key) {
var parts = key.split(".", 2);
var recordName;
var recordIndex;
var fieldKey;
if (parts.length === 1) {
recordName = schema.firstRecord().name;
recordIndex = 0;
fieldKey = parts[0];
} else {
var recordKeyParts = parseKeyPart(parts[0].trim());
recordName = recordKeyParts[0];
recordIndex = recordKeyParts[1];
fieldKey = parts[1];
}
var keyParts = parseKeyPart(fieldKey);
return {
recordName: recordName,
recordIndex: recordIndex,
fieldName: keyParts[0],
fieldIndex: keyParts[1]
};
}
function parseKeyPart(keyPart) {
if (keyPart.length === 0) {
throw new Error("No name specified");
}
var openIndex = keyPart.indexOf("(");
if (openIndex === -1) {
return [keyPart, 0];
}
if (openIndex === 0) {
throw new Error("No name specified");
}
var closeIndex = keyPart.indexOf(")");
if (closeIndex === -1 || closeIndex < openIndex) {
throw new Error("'(' found without closing ')");
}
if (closeIndex < keyPart.length - 1) {
throw new Error("Characters found after closing ')");
}
return [keyPart.substring(0, openIndex), parseInt(keyPart.substring(openIndex + 1, closeIndex), 10)];
}
};
function resolveRecordIndex(record, records, index) {
var actualIndex = record.getAbsoluteIndex(index);
if (actualIndex > records.length - 1) {
throw new Error(
"Index '" + index +
"' does not have a matching entry for variable occurence record: '" + record.name + "'");
}
return actualIndex;
}
function resolveFieldIndex(field, fields, index) {
var actualIndex = field.getAbsoluteIndex(index);
if (actualIndex > fields.length - 1) {
throw new Error(
"Index '" + index +
"' does not have a matching entry for variable occurence field: '" + field.name + "'");
}
return actualIndex;
}