modelld
Version:
A JavaScript API for selecting and manipulating linked data subgraphs
302 lines (268 loc) • 11.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Field = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.fieldFactory = fieldFactory;
var _clone = require('lodash/clone');
var _clone2 = _interopRequireDefault(_clone);
var _nodeUuid = require('node-uuid');
var _nodeUuid2 = _interopRequireDefault(_nodeUuid);
var _rdflib = require('rdflib');
var _rdflib2 = _interopRequireDefault(_rdflib);
var _util = require('./util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* A Field represents, for an implicit subject, a predicate and a value.
*
* @typedef {Object} Field
* @property {Object=} quad - The RDF quad object which this field may have been
* constructed from. A field either has a quad or a predicate.
* @property {Object=} predicate- The RDF predicate which this field represents.
* A field either has a quad or a predicate.
* @property {String} id - A UUID.
* @property value - The value of this field.
* @param {NamedNode} namedGraph - The URI of a named graph which will be used
* to hold new fields.
*/
/**
* Generates a factory for creating fields.
*
* @param {String|NamedNode} namedGraph - The URI of a named graph which will be
* used to hold new fields.
* @returns {Function} A factory function of one argument, an RDF predicate,
* which in turn returns a fully configured field object. The return function
* also has a `fromQuad` method, which can construct a fully configured field
* from an RDF quad object.
*/
function fieldFactory(predicate) {
var fieldCreator = function fieldCreator(value, namedGraph) {
var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
return new Field({
predicate: predicate,
value: value,
namedNode: options.namedNode,
namedGraph: namedGraph
});
};
fieldCreator.fromQuad = function (quad) {
return new Field({
predicate: quad.predicate,
originalObject: quad.object,
originalNamedGraph: quad.graph
});
};
fieldCreator.predicate = predicate;
return fieldCreator;
}
var Field = exports.Field = function () {
/**
* Fields are constructed with a predicate and value. The value status can
* either be passed in as 'options.value' or inferred through an RDF object
* node.
*
* In order to fully specify a field, you *must* always pass in
* 'options.predicate' and one of the following two options:
* - `value` and `namedGraph` for an ad-hoc field
* - `originalObject` and `originalNamedGraph` for a field tracking a quad
* which may have modified its value
*
* @param {Object} options - An options object specifying named parameters.
* @param {Object=} options.originalObject - The original RDF object node that
* this field represents if it is being constructed from an existing quad.
* @param {Object=} options.predicate - The RDF predicate which this field
* represents. Must either provide a quad or a predicate.
* @param options.value - Optionally specifies the current value of this
* field. Should only be provided by this field class internally when
* updating a field.
* @param {Boolean=} options.namedNode - Whether or not this field is a
* NamedNode.
* @param {String|NamedNode} options.namedGraph - The URI of the named graph
* for this field.
* @returns {Object} the newly constructed field.
*/
function Field() {
var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var predicate = _ref.predicate;
var namedGraph = _ref.namedGraph;
var value = _ref.value;
var namedNode = _ref.namedNode;
var originalObject = _ref.originalObject;
var originalNamedGraph = _ref.originalNamedGraph;
_classCallCheck(this, Field);
if (!(0, _util.isDefined)(predicate) || !((0, _util.isDefined)(value) && (0, _util.isDefined)(namedGraph)) && !((0, _util.isDefined)(originalObject) && (0, _util.isDefined)(originalNamedGraph))) {
throw new Error('Insufficient arguments.');
}
this.predicate = predicate;
// Set default value from the original RDF quad's object and source
// properties. This may be overridden by the current value of 'value'.
if ((0, _util.isDefined)(originalObject)) {
this.originalObject = originalObject;
this.value = rdfToJs(originalObject);
}
if ((0, _util.isDefined)(originalNamedGraph)) {
this.originalNamedGraph = _rdflib2.default.NamedNode.fromValue(originalNamedGraph);
this.namedGraph = this.originalNamedGraph;
}
if ((0, _util.isDefined)(namedGraph)) {
this.namedGraph = _rdflib2.default.NamedNode.fromValue(namedGraph);
}
if ((0, _util.isDefined)(value)) {
this.value = value;
}
if ((0, _util.isDefined)(namedNode)) {
this.namedNode = namedNode || false;
}
this.id = _nodeUuid2.default.v4();
Object.freeze(this);
}
/**
* Generates an RDF quad representing this field's current state.
*
* @param {Object} rdf - An RDF library, currently assumed to be rdflib.js
* @param {Object} subject - The implicit subject for this field.
* Particularly, an RDF subject, currently assumed to be an rdflib.js subject.
* @returns {Object} An RDF quad representing the current state of this field.
*/
_createClass(Field, [{
key: 'toQuad',
value: function toQuad(rdf, subject) {
var object = void 0;
if ((0, _util.isDefined)(this.originalObject)) {
object = (0, _clone2.default)(this.originalObject);
// Convert the native JS value back to the corresponding RDF string value
object.value = this.originalObject.constructor.fromValue(this.value).value;
if ((0, _util.isDefined)(object.uri)) {
object.uri = this.value;
}
} else {
object = this.namedNode ? rdf.NamedNode.fromValue(this.value) : rdf.Literal.fromValue(this.value);
}
return rdf.quad(subject, this.predicate, object, this.namedGraph || this.originalNamedGraph);
}
/**
* Returns the quad that a field was constructed from or null if it's an
* ad-hoc field.
*
* @param {Object} rdf - An RDF library, currently assumed to be rdflib.js
* @param {Object} subject - The implicit subject for this field.
* Particularly, an RDF subject, currently assumed to be an rdflib.js subject.
* @returns {Object} An RDF quad representing the original state of this
* field.
*/
}, {
key: 'originalQuad',
value: function originalQuad(rdf, subject) {
if (!(0, _util.isDefined)(this.originalObject) && !(0, _util.isDefined)(this.originalNamedGraph)) {
return null;
}
return rdf.quad(subject, this.predicate, this.originalObject, this.originalNamedGraph);
}
/**
* Returns a field with the specified state.
*
* @param {Object} options - An options object specifying named parameters.
* @param options.value - The new field value.
* @returns {Field} A field with the specified state.
*/
}, {
key: 'set',
value: function set(_ref2) {
var _ref2$value = _ref2.value;
var value = _ref2$value === undefined ? null : _ref2$value;
var _ref2$namedGraph = _ref2.namedGraph;
var namedGraph = _ref2$namedGraph === undefined ? null : _ref2$namedGraph;
var _ref2$namedNode = _ref2.namedNode;
var namedNode = _ref2$namedNode === undefined ? false : _ref2$namedNode;
return new Field({
originalObject: this.originalObject,
originalNamedGraph: this.originalNamedGraph,
namedGraph: namedGraph || this.namedGraph,
predicate: this.predicate,
value: value !== null ? value : this.value,
namedNode: namedNode
});
}
/**
* Updpates a field such that it starts tracking its current state rather than
* its past state.
*
* Note that this field returned from this function no longer remembers
* anything from its previous state. Therefore if this field used to live on
* a non-default graph and you toggled listed and then call this function, if
* you toggle listed again it won't return to the original graph but rather
* the default.
*
* @param {Object} rdf - An RDF library, currently assumed to be rdflib.js
* @param {Object} subject - The implicit subject for this field. Particularly,
* an RDF subject, currently assumed to be an rdflib.js subject.
* @param {Field} field - This field to be rebuilt from its current state.
* @returns {Field} A new field tracking the provided field's state as its
* original state.
*/
}, {
key: 'fromCurrentState',
value: function fromCurrentState(rdf, subject) {
var currentQuad = this.toQuad(rdf, subject);
return new Field({
predicate: this.predicate,
originalObject: currentQuad.object,
originalNamedGraph: currentQuad.graph,
namedNode: this.namedNode
});
}
}]);
return Field;
}();
/**
* Extracts the value of an rdf node into the native JS representation of that
* node's type/value. For example, it will extract booleans from a node with a
* datatype of xsd:boolean and a value of '0' or '1'.
*
* @param {Object} node - The rdf node object.
* @returns The value of that node.
*/
function rdfToJs(node) {
var value = void 0;
var rdfVal = node.value;
var datatype = node.datatype;
var throwError = function throwError() {
throw new Error('Cannot parse rdf type/value to JS value. Given value [' + rdfVal + '] of type [' + datatype + '].');
};
if (datatype) {
var XMLSchema = 'http://www.w3.org/2001/XMLSchema#';
switch (datatype.value) {
case XMLSchema + 'boolean':
if (rdfVal === '1') {
value = true;
} else if (rdfVal === '0') {
value = false;
} else {
throwError();
}
break;
case XMLSchema + 'dateTime':
// Format of date string can be found at: http://books.xmlschemata.org/relaxng/ch19-77049.html
value = new Date(rdfVal);
break;
case XMLSchema + 'decimal':
case XMLSchema + 'double':
value = Number.parseFloat(rdfVal);
break;
case XMLSchema + 'integer':
value = Number.parseInt(rdfVal);
break;
case 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString':
case XMLSchema + 'string':
default:
value = rdfVal;
break;
}
} else {
// Assume string if there's no provided datatype
value = rdfVal;
}
return value;
}