diff --git a/README.md b/README.md index 4a972c3..d12007b 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,16 @@ LevelGraph-JSONLD ![Logo](https://github.com/mcollina/node-levelgraph/raw/master/logo.png) +[![Build Status](https://travis-ci.org/mcollina/levelgraph-jsonld.png)](https://travis-ci.org/mcollina/levelgraph-jsonld) +[![Coverage Status](https://coveralls.io/repos/mcollina/levelgraph-jsonld/badge.png)](https://coveralls.io/r/mcollina/levelgraph-jsonld) +[![Dependency Status](https://david-dm.org/mcollina/levelgraph-jsonld.png?theme=shields.io)](https://david-dm.org/mcollina/levelgraph-jsonld) + __LevelGraph-JSONLD__ is a plugin for [LevelGraph](http://github.com/mcollina/levelgraph) that adds the ability to store, retrieve and delete JSON-LD objects. In fact, it is a full-bown Object-Document-Mapper (ODM) for __LevelGraph__. -[![Build -Status](https://travis-ci.org/mcollina/levelgraph-jsonld.png)](https://travis-ci.org/mcollina/levelgraph-jsonld) - ## Install on Node.js ```shell @@ -30,28 +31,33 @@ WORK IN PROGRESS! [#3](http://github.com/mcollina/levelgraph-jsonld/issues/3) Adding support for JSON-LD to LevelGraph is easy: ```javascript -var levelgraph = require("levelgraph") - , jsonld = require("levelgraph-jsonld") - , db = jsonld(levelgraph("yourdb")); +var levelgraph = require('levelgraph'), + jsonld = require('levelgraph-jsonld'), + db = jsonld(levelgraph('yourdb')); ``` ### Put Please keep in mind that LevelGraph-JSONLD __doesn't store the original -JSON-LD document but decomposes it into triples__! Storing triples from JSON-LD document is extremely easy: +JSON-LD document but decomposes it into triples__! It stores literals +double quoted with datatype if other then string. If you use plain +LevelGraph methods, instead trying to match number `42` you need to try +matching `"42"^^` + + Storing triples from JSON-LD document is extremely easy: ```javascript var manu = { - "@context": { - "name": "http://xmlns.com/foaf/0.1/name" - , "homepage": { - "@id": "http://xmlns.com/foaf/0.1/homepage" - , "@type": "@id" - } + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "homepage": { + "@id": "http://xmlns.com/foaf/0.1/homepage", + "@type": "@id" } - , "@id": "http://manu.sporny.org#person" - , "name": "Manu Sporny" - , "homepage": "http://manu.sporny.org/" -} + }, + "@id": "http://manu.sporny.org#person", + "name": "Manu Sporny", + "homepage": "http://manu.sporny.org/" +}; db.jsonld.put(manu, function(err, obj) { // do something after the obj is inserted @@ -61,35 +67,35 @@ db.jsonld.put(manu, function(err, obj) { if the top level objects have no `'@id'` key, one will be generated for each, using a UUID and the `'base'` argument, like so: ```javascript -delete manu["@id"]; -db.jsonld.put(manu, { base: "http://this/is/an/iri" }, function(err, obj) { - // obj["@id"] will be something like +delete manu['@id']; +db.jsonld.put(manu, { base: 'http://this/is/an/iri' }, function(err, obj) { + // obj['@id'] will be something like // http://this/is/an/iri/b1e783b0-eda6-11e2-9540-d7575689f4bc }); ``` `'base'` can also be specified when you create the db: ```javascript -var levelgraph = require("levelgraph") - , jsonld = require("levelgraph-jsonld") - , opts = { base: "http://matteocollina.com/base" } - , db = jsonld(levelgraph("yourdb"), opts); +var levelgraph = require('levelgraph'), + jsonld = require('levelgraph-jsonld'), + opts = { base: 'http://matteocollina.com/base' }, + db = jsonld(levelgraph('yourdb'), opts); ``` __LevelGraph-JSONLD__ also support nested objects, like so: ```javascript var nested = { - "@context": { - "name": "http://xmlns.com/foaf/0.1/name" - , "knows": "http://xmlns.com/foaf/0.1/knows" - } - , "@id": "http://matteocollina.com" - , "name": "matteo" - , "knows": [{ - "name": "daniele" - }, { - "name": "lucio" - }] + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "knows": "http://xmlns.com/foaf/0.1/knows" + }, + "@id": "http://matteocollina.com", + "name": "Matteo", + "knows": [{ + "name": "Daniele" + }, { + "name": "Lucio" + }] }; db.jsonld.put(nested, function(err, obj) { @@ -101,7 +107,7 @@ db.jsonld.put(nested, function(err, obj) { Retrieving a JSON-LD object from the store requires its `'@id'`: ```javascript -db.jsonld.get(manu["@id"], { "@context": manu["@context"] }, function(err, obj) { +db.jsonld.get(manu['@id'], { '@context': manu['@context'] }, function(err, obj) { // obj will be the very same of the manu object }); ``` @@ -113,35 +119,35 @@ As with `'put'` it correctly support nested objects. If nested objects didn't or them as *blank node identifiers*: ```javascript var nested = { - "@context": { - "name": "http://xmlns.com/foaf/0.1/name" - , "knows": "http://xmlns.com/foaf/0.1/knows" - } - , "@id": "http://matteocollina.com" - , "name": "matteo" - , "knows": [{ - "name": "daniele" - }, { - "name": "lucio" - }] + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "knows": "http://xmlns.com/foaf/0.1/knows" + }, + "@id": "http://matteocollina.com", + "name": "Matteo", + "knows": [{ + "name": "Daniele" + }, { + "name": "Lucio" + }] }; db.jsonld.put(nested, function(err, obj) { // obj will be // { - // "@context": { - // "name": "http://xmlns.com/foaf/0.1/name" - // , "knows": "http://xmlns.com/foaf/0.1/knows" - // } - // , "@id": "http://matteocollina.com" - // , "name": "matteo" - // , "knows": [{ - // "@id": "_:7053c150-5fea-11e3-a62e-adadc4e3df79" - // , "name": "daniele" - // }, { - // "@id": "_:9d2bb59d-3baf-42ff-ba5d-9f8eab34ada5" - // "name": "lucio" - // }] + // "@context": { + // "name": "http://xmlns.com/foaf/0.1/name", + // "knows": "http://xmlns.com/foaf/0.1/knows" + // }, + // "@id": "http://matteocollina.com", + // "name": "Matteo", + // "knows": [{ + // "@id": "_:7053c150-5fea-11e3-a62e-adadc4e3df79", + // "name": "Daniele" + // }, { + // "@id": "_:9d2bb59d-3baf-42ff-ba5d-9f8eab34ada5", + // "name": "Lucio" + // }] // } }); ``` @@ -151,7 +157,7 @@ db.jsonld.put(nested, function(err, obj) { In order to delete an object, you can just pass it's `'@id'` to the `'@del'` method: ```javascript -db.jsonld.del(manu["@id"], function(err) { +db.jsonld.del(manu['@id'], function(err) { // do something after it is deleted! }); ``` @@ -163,60 +169,58 @@ that problem is already solved by __LevelGraph__ itself. This example search finds friends living near Paris: ```javascript var manu = { - "@context": { - "@vocab": "http://xmlns.com/foaf/0.1/" - , "homepage": { "@type": "@id" } - , "knows": { "@type": "@id" } - , "based_near": { "@type": "@id" } - } - , "@id": "http://manu.sporny.org#person" - , "name": "Manu Sporny" - , "homepage": "http://manu.sporny.org/" - , "knows": [ - { - "@id": "https://my-profile.eu/people/deiu/card#me", - "name": "Andrei Vlad Sambra", - "based_near": "http://dbpedia.org/resource/Paris" - }, { - "@id": "http://melvincarvalho.com/#me", - "name": "Melvin Carvalho", - "based_near": "http://dbpedia.org/resource/Honolulu" - }, { - "@id": "http://bblfish.net/people/henry/card#me", - "name": "Henry Story", - "based_near": "http://dbpedia.org/resource/Paris" - }, { - "@id": "http://presbrey.mit.edu/foaf#presbrey", - "name": "Joe Presbrey", - "based_near": "http://dbpedia.org/resource/Cambridge" - } - ] -} + "@context": { + "@vocab": "http://xmlns.com/foaf/0.1/", + "homepage": { "@type": "@id" }, + "knows": { "@type": "@id" }, + "based_near": { "@type": "@id" } + }, + "@id": "http://manu.sporny.org#person", + "name": "Manu Sporny", + "homepage": "http://manu.sporny.org/", + "knows": [{ + "@id": "https://my-profile.eu/people/deiu/card#me", + "name": "Andrei Vlad Sambra", + "based_near": "http://dbpedia.org/resource/Paris" + }, { + "@id": "http://melvincarvalho.com/#me", + "name": "Melvin Carvalho", + "based_near": "http://dbpedia.org/resource/Honolulu" + }, { + "@id": "http://bblfish.net/people/henry/card#me", + "name": "Henry Story", + "based_near": "http://dbpedia.org/resource/Paris" + }, { + "@id": "http://presbrey.mit.edu/foaf#presbrey", + "name": "Joe Presbrey", + "based_near": "http://dbpedia.org/resource/Cambridge" + }] +}; -var paris = "http://dbpedia.org/resource/Paris"; +var paris = 'http://dbpedia.org/resource/Paris'; db.jsonld.put(manu, function(){ - db.join([{ - subject: manu["@id"], - predicate: "http://xmlns.com/foaf/0.1/knows", - object: db.v("webid") + db.search([{ + subject: manu['@id'], + predicate: 'http://xmlns.com/foaf/0.1/knows', + object: db.v('webid') }, { - subject: db.v("webid"), - predicate: "http://xmlns.com/foaf/0.1/based_near", + subject: db.v('webid'), + predicate: 'http://xmlns.com/foaf/0.1/based_near', object: paris }, { - subject: db.v("webid"), - predicate: "http://xmlns.com/foaf/0.1/name", - object: db.v("name") + subject: db.v('webid'), + predicate: 'http://xmlns.com/foaf/0.1/name', + object: db.v('name') } ], function(err, solution) { // solution contains // [{ - // webid: "http://bblfish.net/people/henry/card#me", - // name: "Henry Story" + // webid: 'http://bblfish.net/people/henry/card#me', + // name: '"Henry Story"' // }, { - // webid: "https://my-profile.eu/people/deiu/card#me", - // name: "Andrei Vlad Sambra" + // webid: 'https://my-profile.eu/people/deiu/card#me', + // name: '"Andrei Vlad Sambra"' // }] }); }); diff --git a/index.js b/index.js index 02faf94..6085bd5 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,10 @@ - -var jsonld = require("jsonld") - , uuid = require("uuid") - , IRI = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/i - , RDFTYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" - , async = require("async") - , blanksRegexp = /^_:b\d+$/; +var jsonld = require('jsonld'), + uuid = require('uuid'), + RDFTYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', + RDFLANGSTRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', + XSDTYPE = 'http://www.w3.org/2001/XMLSchema#', + async = require('async'), + N3Util = require('n3/lib/N3Util'); // with browserify require('n3').Util would bundle more then needed! function levelgraphJSONLD(db, jsonldOpts) { @@ -15,7 +15,7 @@ function levelgraphJSONLD(db, jsonldOpts) { var graphdb = Object.create(db); jsonldOpts = jsonldOpts || {}; - jsonldOpts.base = jsonldOpts.base || ""; + jsonldOpts.base = jsonldOpts.base || ''; graphdb.jsonld = { options: jsonldOpts @@ -28,27 +28,41 @@ function levelgraphJSONLD(db, jsonldOpts) { var stream = graphdb.putStream(); - stream.on("error", callback); - stream.on("close", function() { + stream.on('error', callback); + stream.on('close', function() { callback(null, obj); }); - triples["@default"].map(function(triple) { - return ["subject", "predicate", "object"].reduce(function(acc, key) { - var value = triple[key].value; - if (value.match(blanksRegexp)) { - if (!blanks[value]) { - blanks[value] = "_:" + uuid.v1(); + triples['@default'].map(function(triple) { + + return ['subject', 'predicate', 'object'].reduce(function(acc, key) { + var node = triple[key]; + // generate UUID to identify blank nodes + // uses type field set to 'blank node' by jsonld.js toRDF() + if (node.type === 'blank node') { + if (!blanks[node.value]) { + blanks[node.value] = '_:' + uuid.v1(); + } + node.value = blanks[node.value]; + } + // preserve object data types using double quotation for literals + if(key === 'object' && triple.object.datatype){ + if(triple.object.datatype.match(XSDTYPE)){ + if(triple.object.datatype === 'http://www.w3.org/2001/XMLSchema#string'){ + node.value = '"' + triple.object.value + '"'; + } else { + node.value = '"' + triple.object.value + '"^^<' + triple.object.datatype + '>'; + } + } else if(triple.object.datatype.match(RDFLANGSTRING)){ + node.value = '"' + triple.object.value + '"@' + triple.object.language; } - value = blanks[value]; } - acc[key] = value; + acc[key] = node.value; return acc; }, {}); }).forEach(function(triple) { stream.write(triple); }); - stream.end(); }); }; @@ -65,38 +79,38 @@ function levelgraphJSONLD(db, jsonldOpts) { options.base = options.base || this.options.base; - if (obj["@id"]) { - graphdb.jsonld.del(obj["@id"], options, function(err) { + if (obj['@id']) { + graphdb.jsonld.del(obj['@id'], options, function(err) { if (err) { return callback && callback(err); } doPut(obj, options, callback); }); } else { - obj["@id"] = options.base + uuid.v1(); + obj['@id'] = options.base + uuid.v1(); doPut(obj, options, callback); } }; graphdb.jsonld.del = function(iri, options, callback) { - if (typeof options === "function") { + if (typeof options === 'function') { callback = options; options = {}; } if (typeof iri !=='string') { - iri = iri["@id"]; + iri = iri['@id']; } var stream = graphdb.delStream(); - stream.on("close", callback); - stream.on("error", callback); + stream.on('close', callback); + stream.on('error', callback); (function delAllTriples(iri, done) { graphdb.get({ subject: iri }, function(err, triples) { async.each(triples, function(triple, cb) { stream.write(triple); - if (triple.object.indexOf("_:") === 0) { + if (triple.object.indexOf('_:') === 0) { delAllTriples(triple.object, cb); } else { cb(); @@ -111,8 +125,44 @@ function levelgraphJSONLD(db, jsonldOpts) { }); }; + // http://json-ld.org/spec/latest/json-ld-api/#data-round-tripping + var coerceLiteral = function(literal) { + var TYPES = { + PLAIN: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#PlainLiteral', + BOOLEAN: 'http://www.w3.org/2001/XMLSchema#boolean', + INTEGER: 'http://www.w3.org/2001/XMLSchema#integer', + DOUBLE: 'http://www.w3.org/2001/XMLSchema#double', + STRING: 'http://www.w3.org/2001/XMLSchema#string', + }; + var value = N3Util.getLiteralValue(literal); + var type = N3Util.getLiteralType(literal); + switch (type) { + case TYPES.STRING: + case TYPES.PLAIN: + literal = value; + break; + case TYPES.INTEGER: + literal = parseInt(value, 10); + break; + case TYPES.DOUBLE: + literal = parseFloat(value); + break; + case TYPES.BOOLEAN: + if (value === 'true' || value === '1') { + literal = true; + } + if (value === 'false' || value === '0') { + literal = false; + } + break; + default: + // FIXME deal with other types + } + return literal; + }; + var fetchExpandedTriples = function(iri, memo, callback) { - if (typeof memo === "function") { + if (typeof memo === 'function') { callback = memo; memo = {}; } @@ -126,21 +176,28 @@ function levelgraphJSONLD(db, jsonldOpts) { var key; if (!acc[triple.subject]) { - acc[triple.subject] = { "@id": triple.subject }; + acc[triple.subject] = { '@id': triple.subject }; } - if (triple.predicate === RDFTYPE) { - if (acc[triple.subject]["@type"]) { - acc[triple.subject]["@type"] = [acc[triple.subject]["@type"]]; - acc[triple.subject]["@type"].push(triple.object); + if (acc[triple.subject]['@type']) { + acc[triple.subject]['@type'] = [acc[triple.subject]['@type']]; + acc[triple.subject]['@type'].push(triple.object); } else { - acc[triple.subject]["@type"] = triple.object; + acc[triple.subject]['@type'] = triple.object; } cb(null, acc); - } else if (triple.object.indexOf("_:") !== 0) { - acc[triple.subject][triple.predicate] = {}; - key = (triple.object.match(IRI)) ? "@id" : "@value"; - acc[triple.subject][triple.predicate][key] = triple.object; + } else if (!N3Util.isBlank(triple.object)) { + var object = {}; + if (N3Util.isUri(triple.object)) { + object['@id'] = triple.object; + } else if (N3Util.isLiteral(triple.object)) { + object['@value'] = coerceLiteral(triple.object); + var language = N3Util.getLiteralLanguage(triple.object); + if (language) { + object['@language'] = language; + } + } + acc[triple.subject][triple.predicate] = object; cb(null, acc); } else { fetchExpandedTriples(triple.object, function(err, expanded) { diff --git a/package.json b/package.json index 5d875d9..2e197f5 100644 --- a/package.json +++ b/package.json @@ -29,17 +29,19 @@ "author": "Matteo Collina ", "license": "MIT", "dependencies": { - "jsonld": "0.1.0", + "jsonld": "~0.1.25", "uuid": "~1.4.1", - "async": "~0.2.9" + "async": "~0.2.9", + "n3": "~0.2.1" }, "peerDependencies": { - "levelgraph": "~0.6.1" + "levelgraph": "~0.7.1" }, "devDependencies": { - "mocha": "~1.10.0", - "levelgraph": "~0.6.1", - "level-test": "~1.4.0", - "chai": "~1.7.2" + "mocha": "~1.16.2", + "levelgraph": "~0.7.1", + "level-test": "~1.5.2", + "chai": "~1.8.1", + "lodash": "~2.4.1" } } diff --git a/test/common.js b/test/common.js index bbb6125..e9860be 100644 --- a/test/common.js +++ b/test/common.js @@ -1,14 +1,14 @@ -"use strict"; +'use strict'; -global.chai = require("chai"); -global.expect = require("chai").expect; +global.chai = require('chai'); +global.expect = require('chai').expect; -var fs = require("fs") +var fs = require('fs') , fixtures = {}; global.fixture = function(name) { if (!fixtures[name]) { - fixtures[name] = fs.readFileSync(__dirname + "/fixture/" + name); + fixtures[name] = fs.readFileSync(__dirname + '/fixture/' + name); } return JSON.parse(fixtures[name]); }; diff --git a/test/datatype_spec.js b/test/datatype_spec.js new file mode 100644 index 0000000..0e4e388 --- /dev/null +++ b/test/datatype_spec.js @@ -0,0 +1,243 @@ +// http://json-ld.org/spec/latest/json-ld-api/#data-round-tripping +var level = require('level-test')(), + graph = require('levelgraph'), + jsonld = require('../'); + +describe('jsonld.put data type', function() { + + var db, bbb; + + beforeEach(function() { + db = jsonld(graph(level())); + bbb = fixture('bigbuckbunny.json'); + }); + + describe('coerce', function() { + + it('preserves boolean true', function(done) { + bbb.isFamilyFriendly = true; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/isFamilyFriendly' + }, function(err, triples) { + expect(triples[0].object).to.equal('"true"^^'); + done(); + }); + }); + }); + + it('preserves boolean false', function(done) { + bbb.isFamilyFriendly = false; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/isFamilyFriendly' + }, function(err, triples) { + expect(triples[0].object).to.equal('"false"^^'); + done(); + }); + }); + }); + + it('preserves integer positive', function(done) { + bbb.version = 2; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/version' + }, function(err, triples) { + expect(triples[0].object).to.equal('"2"^^'); + done(); + }); + }); + }); + + it('preserves integer negative', function(done) { + bbb.version = -2; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/version' + }, function(err, triples) { + expect(triples[0].object).to.equal('"-2"^^'); + done(); + }); + }); + }); + + it('preserves integer zero', function(done) { + bbb.version = 0; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/version' + }, function(err, triples) { + expect(triples[0].object).to.equal('"0"^^'); + done(); + }); + }); + }); + + it('preserves double positive', function(done) { + bbb.version = 12.345; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/version' + }, function(err, triples) { + expect(triples[0].object).to.equal('"1.2345E1"^^'); + done(); + }); + }); + }); + + it('preserves double negative', function(done) { + bbb.version = -12.345; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/version' + }, function(err, triples) { + expect(triples[0].object).to.equal('"-1.2345E1"^^'); + done(); + }); + }); + }); + + it('does not preserve string', function(done) { + bbb.contentRating = 'MPAA PG-13'; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/contentRating' + }, function(err, triples) { + expect(triples[0].object).to.equal('"MPAA PG-13"'); + done(); + }); + }); + }); + }); +}); +describe('jsonld.get data type', function() { + + var db, bbb, triple; + + beforeEach(function() { + db = jsonld(graph(level())); + bbb = fixture('bigbuckbunny.json'); + triple = { + subject: bbb['@id'], + predicate: null, + object: null + }; + }); + + describe('coerce', function() { + + it('preserves boolean true', function(done) { + triple.predicate = 'http://schema.org/isFamilyFriendly'; + triple.object = '"true"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['isFamilyFriendly']).to.be.true; + done(); + }); + }); + }); + }); + + it('preserves boolean false', function(done) { + triple.predicate = 'http://schema.org/isFamilyFriendly'; + triple.object = '"false"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['isFamilyFriendly']).to.be.false; + done(); + }); + }); + }); + }); + + it('preserves integer positive', function(done) { + triple.predicate = 'http://schema.org/version'; + triple.object = '"2"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['version']).to.equal(2); + done(); + }); + }); + }); + }); + + it('preserves integer negative', function(done) { + triple.predicate = 'http://schema.org/version'; + triple.object = '"-2"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['version']).to.equal(-2); + done(); + }); + }); + }); + }); + + it('preserves integer zero', function(done) { + triple.predicate = 'http://schema.org/version'; + triple.object = '"0"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['version']).to.equal(0); + done(); + }); + }); + }); + }); + + it('preserves double positive', function(done) { + triple.predicate = 'http://schema.org/version'; + triple.object = '"1.2345E1"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['version']).to.equal(12.345); + done(); + }); + }); + }); + }); + + it('preserves double negative', function(done) { + triple.predicate = 'http://schema.org/version'; + triple.object = '"-1.2345E1"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['version']).to.equal(-12.345); + done(); + }); + }); + }); + }); + + it('does not preserve string', function(done) { + triple.predicate = 'http://schema.org/contentRating'; + triple.object = '"MPAA PG-13"^^'; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['contentRating']).to.equal('MPAA PG-13'); + done(); + }); + }); + }); + }); + + }); +}); diff --git a/test/del_spec.js b/test/del_spec.js index 0745898..bb6fd8d 100644 --- a/test/del_spec.js +++ b/test/del_spec.js @@ -1,26 +1,26 @@ -var level = require("level-test")() - , graph = require("levelgraph") - , jsonld = require("../"); +var level = require('level-test')(), + graph = require('levelgraph'), + jsonld = require('../'); -describe("jsonld.del", function() { +describe('jsonld.del', function() { var db, manu, tesla; beforeEach(function() { - db = jsonld(graph(level()), { base: "http://levelgraph.io/" }); - manu = fixture("manu.json"); - tesla = fixture("tesla.json"); + db = jsonld(graph(level()), { base: 'http://levelgraph.io/' }); + manu = fixture('manu.json'); + tesla = fixture('tesla.json'); }); afterEach(function(done) { db.close(done); }); - it("should accept a done callback", function(done) { + it('should accept a done callback', function(done) { db.jsonld.put(manu, done); }); - it("should del a basic object", function(done) { + it('should del a basic object', function(done) { db.jsonld.put(manu, function() { db.jsonld.del(manu, function() { db.get({}, function(err, triples) { @@ -32,7 +32,7 @@ describe("jsonld.del", function() { }); }); - it("should del a complex object", function(done) { + it('should del a complex object', function(done) { db.jsonld.put(tesla, function() { db.jsonld.del(tesla, function() { db.get({}, function(err, triples) { @@ -44,9 +44,9 @@ describe("jsonld.del", function() { }); }); - it("should del an iri", function(done) { + it('should del an iri', function(done) { db.jsonld.put(manu, function() { - db.jsonld.del(manu["@id"], function() { + db.jsonld.del(manu['@id'], function() { db.get({}, function(err, triples) { // getting the full db expect(triples).to.be.empty; @@ -56,7 +56,7 @@ describe("jsonld.del", function() { }); }); - it("should del a single object", function(done) { + it('should del a single object', function(done) { db.jsonld.put(manu, function() { db.jsonld.put(tesla, function() { db.jsonld.del(tesla, function() { diff --git a/test/fixture/bigbuckbunny.json b/test/fixture/bigbuckbunny.json new file mode 100644 index 0000000..cb6c321 --- /dev/null +++ b/test/fixture/bigbuckbunny.json @@ -0,0 +1,7 @@ +{ + "@context": { + "@vocab": "http://schema.org/" + }, + "@id": "http://www.bigbuckbunny.org/", + "name": "Big Buck Bunny" +} diff --git a/test/fixture/manu.json b/test/fixture/manu.json index fee6465..829a000 100644 --- a/test/fixture/manu.json +++ b/test/fixture/manu.json @@ -1,9 +1,9 @@ { - "@context": { - "@vocab": "http://xmlns.com/foaf/0.1/" - , "homepage": { "@type": "@id" } - } - , "@id": "http://manu.sporny.org#person" - , "name": "Manu Sporny" - , "homepage": "http://manu.sporny.org/" + "@context": { + "@vocab": "http://xmlns.com/foaf/0.1/", + "homepage": { "@type": "@id" } + }, + "@id": "http://manu.sporny.org#person", + "name": "Manu Sporny", + "homepage": "http://manu.sporny.org/" } diff --git a/test/fixture/nested.json b/test/fixture/nested.json index d4ea1aa..7c22db9 100644 --- a/test/fixture/nested.json +++ b/test/fixture/nested.json @@ -1,13 +1,13 @@ { - "@context": { - "name": "http://xmlns.com/foaf/0.1/name" - , "knows": "http://xmlns.com/foaf/0.1/knows" - } - , "@id": "http://matteocollina.com" - , "name": "matteo" - , "knows": [{ - "name": "daniele" - }, { - "name": "lucio" - }] + "@context": { + "name": "http://xmlns.com/foaf/0.1/name", + "knows": "http://xmlns.com/foaf/0.1/knows" + }, + "@id": "http://matteocollina.com", + "name": "matteo", + "knows": [{ + "name": "daniele" + }, { + "name": "lucio" + }] } diff --git a/test/fixture/person.json b/test/fixture/person.json index 8b6e521..84e700e 100644 --- a/test/fixture/person.json +++ b/test/fixture/person.json @@ -1,86 +1,73 @@ { - "@context": - { - "Person": "http://xmlns.com/foaf/0.1/Person", - "xsd": "http://www.w3.org/2001/XMLSchema#", - "name": "http://xmlns.com/foaf/0.1/name", - "nickname": "http://xmlns.com/foaf/0.1/nick", - "affiliation": "http://schema.org/affiliation", - "depiction": - { - "@id": "http://xmlns.com/foaf/0.1/depiction", - "@type": "@id" - }, - "image": - { - "@id": "http://xmlns.com/foaf/0.1/img", - "@type": "@id" - }, - "born": - { - "@id": "http://schema.org/birthDate", - "@type": "xsd:dateTime" - }, - "child": - { - "@id": "http://schema.org/children", - "@type": "@id" - }, - "colleague": - { - "@id": "http://schema.org/colleagues", - "@type": "@id" - }, - "knows": - { - "@id": "http://xmlns.com/foaf/0.1/knows", - "@type": "@id" - }, - "died": - { - "@id": "http://schema.org/deathDate", - "@type": "xsd:dateTime" - }, - "email": - { - "@id": "http://xmlns.com/foaf/0.1/mbox", - "@type": "@id" - }, - "familyName": "http://xmlns.com/foaf/0.1/familyName", - "givenName": "http://xmlns.com/foaf/0.1/givenName", - "gender": "http://schema.org/gender", - "homepage": - { - "@id": "http://xmlns.com/foaf/0.1/homepage", - "@type": "@id" - }, - "honorificPrefix": "http://schema.org/honorificPrefix", - "honorificSuffix": "http://schema.org/honorificSuffix", - "jobTitle": "http://xmlns.com/foaf/0.1/title", - "nationality": "http://schema.org/nationality", - "parent": - { - "@id": "http://schema.org/parent", - "@type": "@id" - }, - "sibling": - { - "@id": "http://schema.org/sibling", - "@type": "@id" - }, - "spouse": - { - "@id": "http://schema.org/spouse", - "@type": "@id" - }, - "telephone": "http://schema.org/telephone", - "Address": "http://www.w3.org/2006/vcard/ns#Address", - "address": "http://www.w3.org/2006/vcard/ns#address", - "street": "http://www.w3.org/2006/vcard/ns#street-address", - "locality": "http://www.w3.org/2006/vcard/ns#locality", - "region": "http://www.w3.org/2006/vcard/ns#region", - "country": "http://www.w3.org/2006/vcard/ns#country", - "postalCode": "http://www.w3.org/2006/vcard/ns#postal-code" - } + "@context": { + "Person": "http://xmlns.com/foaf/0.1/Person", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "name": "http://xmlns.com/foaf/0.1/name", + "nickname": "http://xmlns.com/foaf/0.1/nick", + "affiliation": "http://schema.org/affiliation", + "depiction": { + "@id": "http://xmlns.com/foaf/0.1/depiction", + "@type": "@id" + }, + "image": { + "@id": "http://xmlns.com/foaf/0.1/img", + "@type": "@id" + }, + "born": { + "@id": "http://schema.org/birthDate", + "@type": "xsd:dateTime" + }, + "child": { + "@id": "http://schema.org/children", + "@type": "@id" + }, + "colleague": { + "@id": "http://schema.org/colleagues", + "@type": "@id" + }, + "knows": { + "@id": "http://xmlns.com/foaf/0.1/knows", + "@type": "@id" + }, + "died": { + "@id": "http://schema.org/deathDate", + "@type": "xsd:dateTime" + }, + "email": { + "@id": "http://xmlns.com/foaf/0.1/mbox", + "@type": "@id" + }, + "familyName": "http://xmlns.com/foaf/0.1/familyName", + "givenName": "http://xmlns.com/foaf/0.1/givenName", + "gender": "http://schema.org/gender", + "homepage": { + "@id": "http://xmlns.com/foaf/0.1/homepage", + "@type": "@id" + }, + "honorificPrefix": "http://schema.org/honorificPrefix", + "honorificSuffix": "http://schema.org/honorificSuffix", + "jobTitle": "http://xmlns.com/foaf/0.1/title", + "nationality": "http://schema.org/nationality", + "parent": { + "@id": "http://schema.org/parent", + "@type": "@id" + }, + "sibling": { + "@id": "http://schema.org/sibling", + "@type": "@id" + }, + "spouse": { + "@id": "http://schema.org/spouse", + "@type": "@id" + }, + "telephone": "http://schema.org/telephone", + "Address": "http://www.w3.org/2006/vcard/ns#Address", + "address": "http://www.w3.org/2006/vcard/ns#address", + "street": "http://www.w3.org/2006/vcard/ns#street-address", + "locality": "http://www.w3.org/2006/vcard/ns#locality", + "region": "http://www.w3.org/2006/vcard/ns#region", + "country": "http://www.w3.org/2006/vcard/ns#country", + "postalCode": "http://www.w3.org/2006/vcard/ns#postal-code" + } } diff --git a/test/fixture/tesla.json b/test/fixture/tesla.json index cf3717e..91678ea 100644 --- a/test/fixture/tesla.json +++ b/test/fixture/tesla.json @@ -1,32 +1,32 @@ { - "@context": { - "gr": "http://purl.org/goodrelations/v1#" - , "pto": "http://www.productontology.org/id/" - , "foaf": "http://xmlns.com/foaf/0.1/" - , "xsd": "http://www.w3.org/2001/XMLSchema#" - , "foaf:page": { - "@type": "@id" - } - , "gr:acceptedPaymentMethods": { - "@type": "@id" - } - , "gr:hasBusinessFunction": { - "@type": "@id" - } + "@context": { + "gr": "http://purl.org/goodrelations/v1#", + "pto": "http://www.productontology.org/id/", + "foaf": "http://xmlns.com/foaf/0.1/", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "foaf:page": { + "@type": "@id" + }, + "gr:acceptedPaymentMethods": { + "@type": "@id" + }, + "gr:hasBusinessFunction": { + "@type": "@id" } - , "@id": "http://example.org/cars/for-sale#tesla" - , "@type": "gr:Offering" - , "gr:name": "Used Tesla Roadster" - , "gr:description": "Need to sell fast and furiously" - , "gr:hasBusinessFunction": "gr:Sell" - , "gr:acceptedPaymentMethods": "gr:Cash" - , "gr:hasPriceSpecification": { - "gr:hasCurrencyValue": "85000" - , "gr:hasCurrency": "USD" - } - , "gr:includes": { - "@type": ["gr:Individual", "pto:Vehicle"] - , "gr:name": "Tesla Roadster" - , "foaf:page": "http://www.teslamotors.com/roadster" + }, + "@id": "http://example.org/cars/for-sale#tesla", + "@type": "gr:Offering", + "gr:name": "Used Tesla Roadster", + "gr:description": "Need to sell fast and furiously", + "gr:hasBusinessFunction": "gr:Sell", + "gr:acceptedPaymentMethods": "gr:Cash", + "gr:hasPriceSpecification": { + "gr:hasCurrencyValue": "85000", + "gr:hasCurrency": "USD" + }, + "gr:includes": { + "@type": ["gr:Individual", "pto:Vehicle"], + "gr:name": "Tesla Roadster", + "foaf:page": "http://www.teslamotors.com/roadster" } } diff --git a/test/get_spec.js b/test/get_spec.js index 1cedf63..0acbe10 100644 --- a/test/get_spec.js +++ b/test/get_spec.js @@ -1,66 +1,65 @@ +var level = require('level-test')(), + graph = require('levelgraph'), + jsonld = require('../'), + fs = require('fs'); -var level = require("level-test")() - , graph = require("levelgraph") - , jsonld = require("../") - , fs = require("fs"); +describe('jsonld.get', function() { -describe("jsonld.get", function() { - - var db, manu = fixture("manu.json"); + var db, manu = fixture('manu.json'); beforeEach(function() { - db = jsonld(graph(level()), { base: "http://levelgraph.io/get" } ); + db = jsonld(graph(level()), { base: 'http://levelgraph.io/get' } ); }); afterEach(function(done) { db.close(done); }); - it("should get no object", function(done) { - db.jsonld.get("http://path/to/nowhere", { "@context": manu["@context"] }, function(err, obj) { + it('should get no object', function(done) { + db.jsonld.get('http://path/to/nowhere', { '@context': manu['@context'] }, function(err, obj) { expect(obj).to.be.null; done(); }); }); - describe("with one object loaded", function() { + describe('with one object loaded', function() { beforeEach(function(done) { db.jsonld.put(manu, done); }); - it("should load it", function(done) { - db.jsonld.get(manu["@id"], { "@context": manu["@context"] }, function(err, obj) { + it('should load it', function(done) { + db.jsonld.get(manu['@id'], { '@context': manu['@context'] }, function(err, obj) { expect(obj).to.eql(manu); done(); }); }); }); - describe("with an object with blank nodes", function() { + describe('with an object with blank nodes', function() { var tesla; beforeEach(function(done) { - tesla = fixture("tesla.json") + tesla = fixture('tesla.json') db.jsonld.put(tesla, done); }); - it("should load it properly", function(done) { - db.jsonld.get(tesla["@id"], { "@context": tesla["@context"] }, function(err, obj) { - tesla["gr:hasPriceSpecification"]["@id"] = obj["gr:hasPriceSpecification"]["@id"]; - tesla["gr:includes"]["@id"] = obj["gr:includes"]["@id"]; + it('should load it properly', function(done) { + db.jsonld.get(tesla['@id'], { '@context': tesla['@context'] }, function(err, obj) { + tesla['gr:hasPriceSpecification']['@id'] = obj['gr:hasPriceSpecification']['@id']; + tesla['gr:includes']['@id'] = obj['gr:includes']['@id']; expect(obj).to.eql(tesla); done(); }); }); }); - it("should support nested objects", function(done) { - var nested = fixture("nested.json"); + it('should support nested objects', function(done) { + var nested = fixture('nested.json'); db.jsonld.put(nested, function(err, obj) { - db.jsonld.get(obj["@id"], { "@context": obj["@context"] }, function(err, result) { - delete result["knows"][0]["@id"]; - delete result["knows"][1]["@id"]; + db.jsonld.get(obj['@id'], { '@context': obj['@context'] }, function(err, result) { + delete result['knows'][0]['@id']; + delete result['knows'][1]['@id']; expect(result).to.eql(nested); done(); }); diff --git a/test/iri_spec.js b/test/iri_spec.js new file mode 100644 index 0000000..ad185e4 --- /dev/null +++ b/test/iri_spec.js @@ -0,0 +1,70 @@ +var level = require('level-test')(), + graph = require('levelgraph'), + jsonld = require('../'), + _ = require('lodash'); + +describe('IRI', function() { + + var db, + manu = fixture('manu.json'); + + beforeEach(function() { + db = jsonld(graph(level()), { base: 'http://levelgraph.io/get' } ); + }); + + afterEach(function(done) { + db.close(done); + }); + + it('keeps literals as literals', function(done) { + var literal = 'http://dbpedia.org/resource/Honolulu'; + manu['based_near'] = literal; + + db.jsonld.put(manu, function(){ + db.jsonld.get(manu['@id'], { '@context': manu['@context'] }, function(err, obj) { + expect(obj['based_near']).to.eql(literal); + done(); + }); + }); + }); + + it('keeps @id as IRI', function(done) { + var id = { '@id': 'http://dbpedia.org/resource/Honolulu' }; + manu['based_near'] = id; + + db.jsonld.put(manu, function(){ + db.jsonld.get(manu['@id'], { '@context': manu['@context'] }, function(err, obj) { + expect(obj['based_near']).to.eql(id); + done(); + }); + }); + }); + + it('keeps literal as IRI if defined as @id through @context', function(done) { + var literal = 'http://dbpedia.org/resource/Honolulu'; + manu['based_near'] = literal; + + var oldContext = _.cloneDeep(manu['@context']); + manu['@context']['based_near'] = { '@type': '@id' }; + + var id = { '@id': 'http://dbpedia.org/resource/Honolulu' }; + + db.jsonld.put(manu, function(){ + db.jsonld.get(manu['@id'], { '@context': oldContext }, function(err, obj) { + expect(obj['based_near']).to.eql(id); + done(); + }); + }); + }); + + it('keeps @id as IRI not only for http: scheme', function(done) { + manu['@id'] = 'mailto:msporny@digitalbazar.com'; + + db.jsonld.put(manu, function(){ + db.jsonld.get(manu['@id'], { '@context': manu['@context'] }, function(err, obj) { + expect(manu).to.eql(manu); + done(); + }); + }); + }); +}); diff --git a/test/languagetags_spec.js b/test/languagetags_spec.js new file mode 100644 index 0000000..c856c7a --- /dev/null +++ b/test/languagetags_spec.js @@ -0,0 +1,91 @@ +var level = require('level-test')(), + graph = require('levelgraph'), + jsonld = require('../'); + +describe('jsonld.put language tags', function() { + + var db, bbb; + + beforeEach(function() { + db = jsonld(graph(level())); + bbb = fixture('bigbuckbunny.json'); + }); + + it('default set in context', function(done) { + bbb['@context']['@language'] = 'en'; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/name' + }, function(err, triples) { + expect(triples[0].object).to.equal('"Big Buck Bunny"@en'); + done(); + }); + }); + }); + + it('set for term in context', function(done) { + bbb['@context']['name'] = { '@id': 'http://schema.org/name', '@language': 'en' }; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/name' + }, function(err, triples) { + expect(triples[0].object).to.equal('"Big Buck Bunny"@en'); + done(); + }); + }); + }); + + it('language map', function(done) { + bbb['@context']['name'] = { '@id': 'http://schema.org/name', '@container': '@language' }; + bbb.name = { 'en': 'Big Buck Bunny' }; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/name' + }, function(err, triples) { + expect(triples[0].object).to.equal('"Big Buck Bunny"@en'); + done(); + }); + }); + }); + + it('value object', function(done) { + bbb.name = { '@language': 'en', '@value': 'Big Buck Bunny' }; + db.jsonld.put(bbb, function() { + db.get({ + predicate: 'http://schema.org/name' + }, function(err, triples) { + expect(triples[0].object).to.equal('"Big Buck Bunny"@en'); + done(); + }); + }); + }); + +}); + +describe('jsonld.get language tags', function() { + + var db, bbb, triple; + + beforeEach(function() { + db = jsonld(graph(level())); + bbb = fixture('bigbuckbunny.json'); + }); + + it('recognizes', function(done) { + triple = { + subject: bbb['@id'], + predicate: 'http://schema.org/name', + object: '"Big Buck Bunny"@en' + }; + + db.jsonld.put(bbb, function() { + db.put(triple, function() { + db.jsonld.get(bbb['@id'], bbb['@context'], function(err, doc) { + expect(doc['name']['@language']).to.equal('en'); + expect(doc['name']['@value']).to.equal('Big Buck Bunny'); + done(); + }); + }); + }); + }); +}); diff --git a/test/put_spec.js b/test/put_spec.js index 481b0ce..34193e3 100644 --- a/test/put_spec.js +++ b/test/put_spec.js @@ -1,31 +1,29 @@ +var level = require('level-test')(), + graph = require('levelgraph'), + jsonld = require('../'); -var level = require("level-test")() - , graph = require("levelgraph") - , jsonld = require("../"); - -describe("jsonld.put", function() { +describe('jsonld.put', function() { var db, manu; beforeEach(function() { db = jsonld(graph(level())); - manu = fixture("manu.json"); + manu = fixture('manu.json'); }); afterEach(function(done) { db.close(done); }); - it("should accept a done callback", function(done) { + it('should accept a done callback', function(done) { db.jsonld.put(manu, done); }); - it("should store a triple", function(done) { + it('should store a triple', function(done) { db.jsonld.put(manu, function() { db.get({ - subject: "http://manu.sporny.org#person" - , predicate: "http://xmlns.com/foaf/0.1/name" - , object: "Manu Sporny" + subject: 'http://manu.sporny.org#person', + predicate: 'http://xmlns.com/foaf/0.1/name' }, function(err, triples) { expect(triples).to.have.length(1); done(); @@ -33,10 +31,10 @@ describe("jsonld.put", function() { }); }); - it("should store two triples", function(done) { + it('should store two triples', function(done) { db.jsonld.put(manu, function() { db.get({ - subject: "http://manu.sporny.org#person" + subject: 'http://manu.sporny.org#person' }, function(err, triples) { expect(triples).to.have.length(2); done(); @@ -44,10 +42,10 @@ describe("jsonld.put", function() { }); }); - it("should store a JSON file", function(done) { + it('should store a JSON file', function(done) { db.jsonld.put(JSON.stringify(manu), function() { db.get({ - subject: "http://manu.sporny.org#person" + subject: 'http://manu.sporny.org#person' }, function(err, triples) { expect(triples).to.have.length(2); done(); @@ -55,13 +53,12 @@ describe("jsonld.put", function() { }); }); - it("should support a base IRI", function(done) { - manu["@id"] = "42" - db.jsonld.put(manu, { base: "http://levelgraph.org/tests/" }, function() { + it('should support a base IRI', function(done) { + manu['@id'] = '42' + db.jsonld.put(manu, { base: 'http://levelgraph.org/tests/' }, function() { db.get({ - subject: "http://levelgraph.org/tests/42" - , predicate: "http://xmlns.com/foaf/0.1/name" - , object: "Manu Sporny" + subject: 'http://levelgraph.org/tests/42', + predicate: 'http://xmlns.com/foaf/0.1/name' }, function(err, triples) { expect(triples).to.have.length(1); done(); @@ -69,40 +66,39 @@ describe("jsonld.put", function() { }); }); - it("should generate an @id for unknown objects", function(done) { - delete manu["@id"]; - var baseString = "http://levelgraph.org/tests/"; + it('should generate an @id for unknown objects', function(done) { + delete manu['@id']; + var baseString = 'http://levelgraph.org/tests/'; var baseRegEx = /^http:\/\/levelgraph.org\/tests\//; db.jsonld.put(manu, { base: baseString }, function() { - db.join({ - subject: db.v("subject") - , predicate: "http://xmlns.com/foaf/0.1/name" - , object: "Manu Sporny" - }, function(err, contexts) { - expect(contexts[0].subject).to.match(baseRegEx); + db.search({ + subject: db.v('subject'), + predicate: 'http://xmlns.com/foaf/0.1/name' + }, function(err, solutions) { + expect(solutions[0].subject).to.match(baseRegEx); done(); }); }); }); - it("should pass the generated @id to callback", function(done) { - delete manu["@id"]; - var baseString = "http://levelgraph.org/tests/"; + it('should pass the generated @id to callback', function(done) { + delete manu['@id']; + var baseString = 'http://levelgraph.org/tests/'; var baseRegEx = /^http:\/\/levelgraph.org\/tests\//; db.jsonld.put(manu, { base: baseString }, function(err, obj) { - expect(obj["@id"]).to.match(baseRegEx); + expect(obj['@id']).to.match(baseRegEx); done(); }); }); - it("should convert @type into http://www.w3.org/1999/02/22-rdf-syntax-ns#type", function(done) { - db.jsonld.put(fixture("tesla.json"), function() { + it('should convert @type into http://www.w3.org/1999/02/22-rdf-syntax-ns#type', function(done) { + db.jsonld.put(fixture('tesla.json'), function() { db.get({ - subject: "http://example.org/cars/for-sale#tesla" - , predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" - , object: "http://purl.org/goodrelations/v1#Offering" + subject: 'http://example.org/cars/for-sale#tesla', + predicate: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', + object: 'http://purl.org/goodrelations/v1#Offering' }, function(err, triples) { expect(triples).to.have.length(1); done(); @@ -110,14 +106,14 @@ describe("jsonld.put", function() { }); }); - it("should update a property", function(done) { + it('should update a property', function(done) { db.jsonld.put(manu, function(err, instance) { - instance.homepage = "http://another/website"; + instance.homepage = 'http://another/website'; db.jsonld.put(instance, function() { db.get({ - subject: "http://manu.sporny.org#person" - , predicate: "http://xmlns.com/foaf/0.1/homepage" - , object: "http://another/website" + subject: 'http://manu.sporny.org#person', + predicate: 'http://xmlns.com/foaf/0.1/homepage', + object: 'http://another/website' }, function(err, triples) { expect(triples).to.have.length(1); done(); @@ -126,16 +122,16 @@ describe("jsonld.put", function() { }); }); - it("should add a property", function(done) { + it('should add a property', function(done) { db.jsonld.put(manu, function(err, instance) { instance.age = 42; - instance["@context"].age = "http://xmlns.com/foaf/0.1/age"; + instance['@context'].age = 'http://xmlns.com/foaf/0.1/age'; db.jsonld.put(instance, function() { db.get({ - subject: "http://manu.sporny.org#person" - , predicate: "http://xmlns.com/foaf/0.1/age" - , object: 42 + subject: 'http://manu.sporny.org#person', + predicate: 'http://xmlns.com/foaf/0.1/age', + object: '"42"^^' }, function(err, triples) { expect(triples).to.have.length(1); done(); @@ -144,14 +140,14 @@ describe("jsonld.put", function() { }); }); - it("should delete a property", function(done) { + it('should delete a property', function(done) { db.jsonld.put(manu, function(err, instance) { delete instance.homepage db.jsonld.put(instance, function() { db.get({ - subject: "http://manu.sporny.org#person" - , predicate: "http://xmlns.com/foaf/0.1/homepage" + subject: 'http://manu.sporny.org#person', + predicate: 'http://xmlns.com/foaf/0.1/homepage' }, function(err, triples) { expect(triples).to.be.empty; done(); @@ -160,14 +156,14 @@ describe("jsonld.put", function() { }); }); - it("should delete a nested object", function(done) { - db.jsonld.put(fixture("tesla.json"), function(err, instance) { - delete instance["gr:hasPriceSpecification"]; + it('should delete a nested object', function(done) { + db.jsonld.put(fixture('tesla.json'), function(err, instance) { + delete instance['gr:hasPriceSpecification']; db.jsonld.put(instance, function() { db.get({ - subject: "http://example.org/cars/for-sale#tesla" - , predicate: "http://purl.org/goodrelations/v1#" + subject: 'http://example.org/cars/for-sale#tesla', + predicate: 'http://purl.org/goodrelations/v1#' }, function(err, triples) { expect(triples).to.be.empty; done(); @@ -177,26 +173,25 @@ describe("jsonld.put", function() { }); }); -describe("jsonld.put with default base", function() { +describe('jsonld.put with default base', function() { var db, manu; beforeEach(function() { - db = jsonld(graph(level()), { base: "http://levelgraph.io/ahah/" }); - manu = fixture("manu.json"); + db = jsonld(graph(level()), { base: 'http://levelgraph.io/ahah/' }); + manu = fixture('manu.json'); }); afterEach(function(done) { db.close(done); }); - it("should use it", function(done) { - manu["@id"] = "42" + it('should use it', function(done) { + manu['@id'] = '42' db.jsonld.put(manu, function() { db.get({ - subject: "http://levelgraph.io/ahah/42" - , predicate: "http://xmlns.com/foaf/0.1/name" - , object: "Manu Sporny" + subject: 'http://levelgraph.io/ahah/42', + predicate: 'http://xmlns.com/foaf/0.1/name' }, function(err, triples) { expect(triples).to.have.length(1); done(); @@ -204,27 +199,27 @@ describe("jsonld.put with default base", function() { }); }); - it("should correctly generate blank nodes as subjects", function(done) { - var tesla = fixture("tesla.json"); + it('should correctly generate blank nodes as subjects', function(done) { + var tesla = fixture('tesla.json'); db.jsonld.put(tesla, function() { - db.join([{ - subject: "http://example.org/cars/for-sale#tesla" - , predicate: "http://purl.org/goodrelations/v1#hasPriceSpecification" - , object: db.v("bnode") + db.search([{ + subject: 'http://example.org/cars/for-sale#tesla', + predicate: 'http://purl.org/goodrelations/v1#hasPriceSpecification', + object: db.v('bnode') }, { - subject: db.v("bnode") - , predicate: "http://purl.org/goodrelations/v1#hasCurrency" - , object: "USD" - }], function(err, contexts) { - expect(contexts[0].bnode).to.exist; + subject: db.v('bnode'), + predicate: 'http://purl.org/goodrelations/v1#hasCurrency', + object: '"USD"' + }], function(err, solutions) { + expect(solutions[0].bnode).to.exist; done(); }); }); }); - it("should not store undefined objects", function(done) { - var tesla = fixture("tesla.json"); + it('should not store undefined objects', function(done) { + var tesla = fixture('tesla.json'); db.jsonld.put(tesla, function() { db.get({}, function(err, triples) { @@ -236,8 +231,8 @@ describe("jsonld.put with default base", function() { }); }); - it("should support nested objects", function(done) { - var nested = fixture("nested.json"); + it('should support nested objects', function(done) { + var nested = fixture('nested.json'); db.jsonld.put(nested, function() { db.get({}, function(err, triples) { diff --git a/test/search_spec.js b/test/search_spec.js index a1ea422..25b756a 100644 --- a/test/search_spec.js +++ b/test/search_spec.js @@ -1,18 +1,17 @@ +var level = require('level-test')(), + graph = require('levelgraph'), + jsonld = require('../'); -var level = require("level-test")() - , graph = require("levelgraph") - , jsonld = require("../"); - -describe("jsonld.put", function() { +describe('db.search', function() { var db, gang, manu; beforeEach(function() { db = jsonld(graph(level())); - manu = fixture("manu.json"); - manu["@context"]["knows"] = { "@type": "@id" }; - manu["@context"]["based_near"] = { "@type": "@id" }; - manu["knows"] = [ + manu = fixture('manu.json'); + manu['@context']['knows'] = { "@type": "@id" }; + manu['@context']['based_near'] = { "@type": "@id" }; + manu['knows'] = [ { "@id": "https://my-profile.eu/people/deiu/card#me", "name": "Andrei Vlad Sambra", @@ -37,31 +36,30 @@ describe("jsonld.put", function() { db.close(done); }); - it("should find homies in Paris", function(done) { - var paris = "http://dbpedia.org/resource/Paris"; + it('should find homies in Paris', function(done) { + var paris = 'http://dbpedia.org/resource/Paris'; var parisians = [{ - webid: "http://bblfish.net/people/henry/card#me", - name: "Henry Story" + webid: 'http://bblfish.net/people/henry/card#me', + name: '"Henry Story"' }, { - webid: "https://my-profile.eu/people/deiu/card#me", - name: "Andrei Vlad Sambra" + webid: 'https://my-profile.eu/people/deiu/card#me', + name: '"Andrei Vlad Sambra"' }]; db.jsonld.put(manu, function(){ - db.join([{ - subject: manu["@id"], - predicate: "http://xmlns.com/foaf/0.1/knows", - object: db.v("webid") + db.search([{ + subject: manu['@id'], + predicate: 'http://xmlns.com/foaf/0.1/knows', + object: db.v('webid') }, { - subject: db.v("webid"), - predicate: "http://xmlns.com/foaf/0.1/based_near", + subject: db.v('webid'), + predicate: 'http://xmlns.com/foaf/0.1/based_near', object: paris }, { - subject: db.v("webid"), - predicate: "http://xmlns.com/foaf/0.1/name", - object: db.v("name") - } - ], function(err, solution) { + subject: db.v('webid'), + predicate: 'http://xmlns.com/foaf/0.1/name', + object: db.v('name') + }], function(err, solution) { expect(solution).to.eql(parisians); done(); });