Skip to content

Commit 349649c

Browse files
committed
Merge branch 'master' of github.com:mcollina/levelgraph-jsonld
2 parents 5996f54 + ed3469e commit 349649c

6 files changed

Lines changed: 679 additions & 95 deletions

File tree

README.md

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,10 @@ var levelup = require("levelup"),
7777
db = jsonld(levelgraph(yourDB), opts);
7878
```
7979

80-
By default `update`s (and `delete`s) **delete all triples associated to the `@id` of the document before updating it**, the `'preserve'` option will ensure that all `put`s and `delete`s only update the triples that are mentioned in the document:
81-
82-
83-
```javascript
84-
var levelup = require("levelup"),
85-
yourDB = levelup("./yourdb"),
86-
levelgraph = require('levelgraph'),
87-
jsonld = require('levelgraph-jsonld'),
88-
opts = {
89-
base: 'http://matteocollina.com/base',
90-
preserve: true
91-
},
92-
db = jsonld(levelgraph(yourDB), opts);
93-
```
80+
> From v1, overwriting and deleting is more conservative. If you rely on the previous behavior you can set the `overwrite` option to `true` (when creating the db or as options to `put` and `del`) to:
81+
> - overwrite all existing triples when using `put`
82+
> - delete all blank nodes recursively when using `del` (cf upcoming `cut` function)
83+
> This old api will be phased out.
9484
9585
### Put
9686

@@ -153,14 +143,6 @@ db.jsonld.put(nested, function(err, obj) {
153143
});
154144
```
155145

156-
By default, `put` **deletes all triples associated to the `@id` of the document before updating it**. If you want to instead only update the triples that are part of the document you can use the `{ preserve : true }` option (you can also [set it globally when you create the DB](#usage)):
157-
158-
```javascript
159-
db.jsonld.put(nested, { preserve : true }, function(err, obj) {
160-
// do something...
161-
});
162-
```
163-
164146
### Get
165147

166148
Retrieving a JSON-LD object from the store requires its `'@id'`:
@@ -212,19 +194,33 @@ db.jsonld.put(nested, function(err, obj) {
212194

213195
### Delete
214196

215-
In order to delete an object, you can just pass it's `'@id'` to the
216-
`'@del'` method:
197+
In order to delete an object, you need to pass the document to the `'del'` method which will delete only the properties specified in the document:
217198
```javascript
218-
db.jsonld.del(manu['@id'], function(err) {
199+
db.jsonld.del(manu, function(err) {
219200
// do something after it is deleted!
220201
});
221202
```
222203

223-
By default, `del` **deletes all triples associated to the `@id`**. If you want to instead only delete the triples that are part of the document, you can use the `{ preserve : true }` option (you can also [set it globally when you create the DB](#usage)):
204+
Note that blank nodes are ignored, so to delete blank nodes you need to pass the `cut: true` option (you can also add the `recurse: true`option) or use the `'cut'` method below.
224205

206+
> Note that since v1 `'del'` doesn't support passing an IRI anymore.
207+
208+
### Cut
209+
210+
In order to delete the blank nodes object, you can just pass it's `'@id'` to the
211+
`'cut'` method:
225212
```javascript
226-
db.jsonld.del(nested, { preserve : true }, function(err) {
227-
// do something...
213+
db.jsonld.cut(manu['@id'], function(err) {
214+
// do something after it is cut!
215+
});
216+
```
217+
218+
You can also pass an object, but in this case the properties are not used to determine which triples will be deleted and only the `@id`s are considered.
219+
220+
Using the `recurse` option you can follow all links and blank nodes (which might result in deleting more data than you expect)
221+
```javascript
222+
db.jsonld.cut(manu['@id'], { recurse: true }, function(err) {
223+
// do something after it is cut!
228224
});
229225
```
230226

index.js

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ function levelgraphJSONLD(db, jsonldOpts) {
127127

128128
function doDel(obj, options, callback) {
129129
var blanks = {};
130-
131130
jsonld.expand(obj, options, function(err, expanded) {
132131
if (err) {
133132
return callback && callback(err);
@@ -136,6 +135,7 @@ function levelgraphJSONLD(db, jsonldOpts) {
136135
var stream = graphdb.delStream();
137136
stream.on('close', callback);
138137
stream.on('error', callback);
138+
139139
if (options.base) {
140140
if (expanded['@context']) {
141141
expanded['@context']['@base'] = options.base;
@@ -190,6 +190,38 @@ function levelgraphJSONLD(db, jsonldOpts) {
190190
})
191191
}
192192

193+
function doCut(obj, options, callback) {
194+
var iri = obj;
195+
if (typeof obj !=='string') {
196+
iri = obj['@id'];
197+
}
198+
if (iri === undefined) {
199+
return callback && callback(null);
200+
}
201+
202+
var stream = graphdb.delStream();
203+
stream.on('close', callback);
204+
stream.on('error', callback);
205+
206+
(function delAllTriples(iri, done) {
207+
graphdb.get({ subject: iri }, function(err, triples) {
208+
async.each(triples, function(triple, cb) {
209+
stream.write(triple);
210+
if (triple.object.indexOf('_:') === 0 || (options.recurse && N3Util.isIRI(triple.object))) {
211+
delAllTriples(triple.object, cb);
212+
} else {
213+
cb();
214+
}
215+
}, done);
216+
});
217+
})(iri, function(err) {
218+
if (err) {
219+
return callback(err);
220+
}
221+
stream.end();
222+
});
223+
}
224+
193225
graphdb.jsonld.put = function(obj, options, callback) {
194226

195227
if (typeof obj === 'string') {
@@ -202,68 +234,59 @@ function levelgraphJSONLD(db, jsonldOpts) {
202234
}
203235

204236
options.base = options.base || this.options.base;
205-
options.preserve = options.preserve || this.options.preserve || false;
237+
options.overwrite = options.overwrite !== undefined ? options.overwrite : ( this.options.overwrite !== undefined ? this.options.overwrite : false );
206238

207-
graphdb.jsonld.del(obj, options, function(err) {
208-
if (err) {
209-
return callback && callback(err);
210-
}
239+
if (!options.overwrite) {
211240
doPut(obj, options, callback);
212-
});
241+
} else {
242+
graphdb.jsonld.del(obj, options, function(err) {
243+
if (err) {
244+
return callback && callback(err);
245+
}
246+
});
247+
doPut(obj, options, callback);
248+
}
213249
};
214250

215251
graphdb.jsonld.del = function(obj, options, callback) {
216-
var blanks = {};
252+
253+
if (typeof options === 'function') {
254+
callback = options;
255+
options = {};
256+
}
257+
258+
options.cut = options.cut !== undefined ? options.cut : ( this.options.cut !== undefined ? this.options.cut : false );
259+
options.recurse = options.recurse !== undefined ? options.recurse : ( this.options.recurse !== undefined ? this.options.recurse : false );
217260

218261
if (typeof obj === 'string') {
219262
try {
220263
obj = JSON.parse(obj);
221264
} catch (e) {
222-
// Handle case where we're trying to delete by passing an IRI
223-
if (!N3Util.isIRI(obj)) {
224-
throw e
265+
if (N3Util.isIRI(obj) && !options.cut) {
266+
callback(new Error("Passing an IRI to del is not supported anymore. Please pass a JSON-LD document."))
225267
}
226268
}
227269
}
228270

271+
if (!options.cut) {
272+
doDel(obj, options, callback)
273+
} else {
274+
doCut(obj, options, callback)
275+
}
276+
};
277+
278+
279+
graphdb.jsonld.cut = function(obj, options, callback) {
280+
229281
if (typeof options === 'function') {
230282
callback = options;
231283
options = {};
232284
}
233285

234-
options.preserve = options.preserve || this.options.preserve || false;
235-
236-
if (options.preserve === false) {
237-
var iri = obj;
238-
if (typeof obj !=='string') {
239-
iri = obj['@id'];
240-
}
241-
242-
var stream = graphdb.delStream();
243-
stream.on('close', callback);
244-
stream.on('error', callback);
286+
options.recurse = options.recurse || this.options.recurse || false;
245287

246-
(function delAllTriples(iri, done) {
247-
graphdb.get({ subject: iri }, function(err, triples) {
248-
async.each(triples, function(triple, cb) {
249-
stream.write(triple);
250-
if (triple.object.indexOf('_:') === 0) {
251-
delAllTriples(triple.object, cb);
252-
} else {
253-
cb();
254-
}
255-
}, done);
256-
});
257-
})(iri, function(err) {
258-
if (err) {
259-
return callback(err);
260-
}
261-
stream.end();
262-
});
263-
} else {
264-
doDel(obj, options, callback)
265-
}
266-
};
288+
doCut(obj, options, callback);
289+
}
267290

268291
// http://json-ld.org/spec/latest/json-ld-api/#data-round-tripping
269292
function getCoercedObject(object) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"async": "^2.1.4",
3737
"jsonld": "~0.4.6",
3838
"memdb": "^1.3.1",
39-
"n3": "^0.9.0",
39+
"n3": "iilab/N3.js#fix/object-is-not-IRI",
4040
"uuid": "^3.0.1"
4141
},
4242
"peerDependencies": {

test/cut_spec.js

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
var expect = require('chai').expect;
2+
var helper = require('./helper');
3+
4+
describe('jsonld.cut', function() {
5+
6+
var db, manu, tesla;
7+
8+
beforeEach(function() {
9+
db = helper.getDB({ jsonld: { base: 'http://levelgraph.io/' } });
10+
manu = helper.getFixture('manu.json');
11+
tesla = helper.getFixture('tesla.json');
12+
});
13+
14+
afterEach(function(done) {
15+
db.close(done);
16+
});
17+
18+
it('should accept a done callback', function(done) {
19+
db.jsonld.cut(manu, done);
20+
});
21+
22+
it('should cut a basic object', function(done) {
23+
db.jsonld.put(manu, function() {
24+
db.jsonld.cut(manu, function() {
25+
db.get({}, function(err, triples) {
26+
// getting the full db
27+
expect(triples).to.be.empty;
28+
done();
29+
});
30+
});
31+
});
32+
});
33+
34+
it('should cut nothing', function(done) {
35+
db.jsonld.put(manu, function() {
36+
db.jsonld.cut({}, function() {
37+
db.get({}, function(err, triples) {
38+
// getting the full db
39+
expect(triples).to.have.length(2);
40+
done();
41+
});
42+
});
43+
});
44+
});
45+
46+
it('should cut a complex object', function(done) {
47+
db.jsonld.put(tesla, function() {
48+
db.jsonld.cut(tesla, function() {
49+
db.get({}, function(err, triples) {
50+
// getting the full db
51+
expect(triples).to.have.length(0);
52+
done();
53+
});
54+
});
55+
});
56+
});
57+
58+
it('should del an iri with the cut option', function(done) {
59+
db.jsonld.put(manu, function() {
60+
db.jsonld.del(manu['@id'], function(err) {
61+
expect(err && err.message).to.equal("Passing an IRI to del is not supported anymore. Please pass a JSON-LD document.")
62+
db.get({}, function(err, triples) {
63+
// getting the full db
64+
expect(triples).to.have.length(2);
65+
done();
66+
});
67+
});
68+
});
69+
});
70+
71+
72+
it('should del a single object leaving blank nodes', function(done) {
73+
db.jsonld.put(manu, function() {
74+
db.jsonld.put(tesla, function() {
75+
db.jsonld.del(tesla, function() {
76+
db.get({}, function(err, triples) {
77+
// getting the full db
78+
expect(triples).to.have.length(10); // 2 triples from Manu and 8 from tesla blanks.
79+
done();
80+
});
81+
});
82+
});
83+
});
84+
});
85+
86+
it('should del a single object with the cut option leaving blank nodes', function(done) {
87+
// This should also be deprecated in favor of using a `cut` option or the `cut` function.
88+
db.jsonld.put(manu, function() {
89+
db.jsonld.put(tesla, function() {
90+
db.jsonld.del(tesla, {cut: true}, function() {
91+
db.get({}, function(err, triples) {
92+
// getting the full db
93+
expect(triples).to.have.length(2); // 2 triples from Manu.
94+
done();
95+
});
96+
});
97+
});
98+
});
99+
});
100+
101+
it('should del a single object with no blank nodes completely', function(done) {
102+
var library = helper.getFixture('library_framed.json');
103+
104+
db.jsonld.put(manu, function() {
105+
db.jsonld.put(library, function() {
106+
db.jsonld.del(library, function() {
107+
db.get({}, function(err, triples) {
108+
// getting the full db
109+
expect(triples).to.have.length(2);
110+
done();
111+
});
112+
});
113+
});
114+
});
115+
});
116+
117+
it('should del obj passed as stringified JSON', function(done) {
118+
var jld = {"@context": { "@vocab": "https://schema.org/"}, "name": "BigBlueHat"};
119+
120+
db.jsonld.put(JSON.stringify(jld), function() {
121+
db.jsonld.del(JSON.stringify(jld), function(err) {
122+
expect(err).to.not.exist;
123+
db.get({}, function(err, triples) {
124+
// getting the full db
125+
expect(triples).to.have.length(1);
126+
done();
127+
});
128+
});
129+
});
130+
});
131+
});

0 commit comments

Comments
 (0)