8000 First working version of the IndexedDB quad backend. · antoniogarrote/rdfstore-js@562929c · GitHub
[go: up one dir, main page]

Skip to content

Commit 562929c

Browse files
First working version of the IndexedDB quad backend.
1 parent 24eecb2 commit 562929c

File tree

4 files changed

+144
-34
lines changed

4 files changed

+144
-34
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"jsonld": "^0.3.22",
4545
"lodash": "^2.4.1",
4646
"moment": "^2.9.0",
47-
"n3": "^0.4.2"
47+
"n3": "^0.4.2",
48+
"sqlite3": "^3.0.5"
4849
}
4950
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
var QuadBackend = require('../src/persistent_quad_backend').QuadBackend;
2+
var Pattern = require('../src/quad_index').Pattern;
3+
var NodeKey = require('../src/quad_index').NodeKey;
4+
5+
describe("PersistentQuadBackend", function(){
6+
7+
8+
it("Should be possible to index, retrieve and delete quads from the backend", function(done){
9+
new QuadBackend({}, function(backend){
10+
var key = new NodeKey({subject:1, predicate:2, object:3, graph:4});
11+
12+
backend.index(key, function(){
13+
14+
var pattern = new Pattern({subject:'s', predicate:2, object:3, graph:4});
15+
backend.range(pattern, function(results){
16+
expect(results.length).toBe(1);
17+
18+
backend.delete(results[0], function(){
19+
backend.db.close();
20+
done();
21+
});
22+
});
23+
});
24+
});
25+
});
26+
});

spec/quad_backend_spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe("QuadBackend", function(){
6363
expect(index.root.keys[0].key.graph).toBe(4);
6464
}
6565

66-
var pattern = new Pattern({subject:null, object:2, predicate:3, graph:4});
66+
var pattern = new Pattern({subject:'s', predicate:2, object:3, graph:4});
6767
backend.range(pattern, function(results){
6868
expect(results.length).toBe(1);
6969

src/persistent_quad_backend.js

Lines changed: 115 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var _ = require('lodash');
1313
* GSP (s, ?, ?, g), (s, p, ?, g)
1414
* OS (s, ?, o, ?)
1515
*
16-
* @param configuration['treeOrder'] Tree order for the indices that are going to be created
16+
* @param configuration['dbName'] Name for the IndexedDB
1717
* @return The newly created backend.
1818
*/
1919
QuadBackend = function (configuration, callback) {
@@ -22,23 +22,27 @@ QuadBackend = function (configuration, callback) {
2222
if (arguments !== 0) {
2323

2424
if(typeof(window) === 'undefined') {
25+
var sqlite3 = require('sqlite3')
2526
var indexeddbjs = require("indexeddb-js");
26-
var indexEngine = new sqlite3.Database(':memory:');
27-
that.indexedDB = new indexeddbjs.indexedDB('sqlite3', indexEngine);
27+
var engine = new sqlite3.Database(':memory:');
28+
var scope = indexeddbjs.makeScope('sqlite3', engine);
29+
that.indexedDB = scope.indexedDB;
30+
that.IDBKeyRange = scope.IDBKeyRange;
2831
} else {
2932
// In the following line, you should include the prefixes of implementations you want to test.
3033
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
34+
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
3135
// DON'T use "var indexedDB = ..." if you're not in a function.
3236
// Moreover, you may need references to some window.IDB* objects:
3337
if (!window.indexedDB) {
3438
callback(null,new Error("The browser does not support IndexDB."));
3539
} else {
3640
that.indexedDB = window.indexedDB;
41+
that.IDBKeyRange = window.IDBKeyRange;
3742
}
3843
}
3944

4045
this.indexMap = {};
41-
this.treeOrder = configuration['treeOrder'];
4246
this.indices = ['SPOG', 'GP', 'OGS', 'POG', 'GSP', 'OS'];
4347
this.componentOrders = {
4448
SPOG:['subject', 'predicate', 'object', 'graph'],
@@ -60,67 +64,146 @@ QuadBackend = function (configuration, callback) {
6064
};
6165
request.onupgradeneeded = function(event) {
6266
var db = event.target.result;
63-
db.createObjectStore(index, { keyPath: 'SPOG'});
67+
var objectStore = db.createObjectStore(that.dbName, { keyPath: 'SPOG'});
6468
_.each(that.indices, function(index){
6569
if(index !== 'SPOG') {
66-
db.createIndex(index,index,{unique: false});
70+
objectStore.createIndex(index,index,{unique: false});
6771
}
6872
});
6973
};
7074
}
7175
};
7276

73-
QuadBackend.prototype._genIndexKey = function(quad,index) {
74-
return _.map(indexComponents, function(component){
75-
return ""+(quad[component] || -1);
76-
}).join('.');
77-
};
7877

7978
QuadBackend.prototype.index = function (quad, callback) {
8079
var that = this;
8180
_.each(this.indices, function(index){
82-
quad[index] = that._genIndexKey(quad, that.componentOrders[index]);
81+
quad[index] = that._genMinIndexKey(quad, index);
8382
});
8483

85-
var transaction = that.db.transaction([that.dbName],"write");
84+
var transaction = that.db.transaction([that.dbName],"readwrite");
8685
transaction.oncomplete = function(event) {
87-
callback(true)
86+
//callback(true)
8887
};
8988
transaction.onerror = function(event) {
9089
callback(null, new Error(event.target.statusCode));
9190
};
9291
var objectStore = transaction.objectStore(that.dbName);
93-
objectStore.add(quad);
92+
var request = objectStore.add(quad);
93+
request.onsuccess = function(event) {
94+
// event.target.result == customerData[i].ssn;
95+
callback(true)
96+
};
9497
};
9598

9699
QuadBackend.prototype.range = function (pattern, callback) {
100+
var that = this;
101+
var objectStore = that.db.transaction([that.dbName]).objectStore(that.dbName);
97102
var indexKey = this._indexForPattern(pattern);
98-
var index = this.indexMap[indexKey];
99-
index.range(pattern, function (quads) {
100-
callback(quads);
101-
});
103+
var minIndexKeyValue = this._genMinIndexKey(pattern,indexKey);
104+
var maxIndexKeyValue = this._genMaxIndexKey(pattern,indexKey);
105+
var keyRange = that.IDBKeyRange.bound(minIndexKeyValue, maxIndexKeyValue, false, false);
106+
var quads = [];
107+
var cursorSource;
108+
109+
if(indexKey === 'SPOG') {
110+
cursorSource = objectStore;
111+
} else {
112+
cursorSource = objectStore.index(indexKey);
113+
}
114+
115+
cursorSource.openCursor(keyRange).onsuccess = function(event) {
116+
var cursor = event.target.result;
117+
if (cursor) {
118+
quads.push(cursor.value);
119+
cursor.continue();
120+
} else {
121+
callback(quads);
122+
}
123+
}
102124
};
103125

104126
QuadBackend.prototype.search = function (quad, callback) {
105-
var index = this.indexMap['SPOG'];
106-
107-
index.search(quad, function (result) {
108-
callback(result != null);
109-
});
127+
var objectStore = that.db.transaction([this.dbName]).objectStore(that.dbName);
128+
var indexKey = that._genMinIndexKey(quad, 'SPOG');
129+
var request = objectStore.get(indexKey);
130+
request.onerror = function(event) {
131+
callback(null, new Error(event.target.statusCode));
132+
};
133+
request.onsuccess = function(event) {
134+
callback(event.target.result != null);
135+
};
110136
};
111137

112138

113139
QuadBackend.prototype.delete = function (quad, callback) {
114140
var that = this;
141+
var indexKey = that._genMinIndexKey(quad, 'SPOG');
142+
var request = that.db.transaction([that.dbName], "readwrite")
143+
.objectStore(that.dbName)
144+
.delete(indexKey);
145+
request.onsuccess = function() {
146+
callback(true);
147+
};
148+
request.onerror = function(event) {
149+
callback(null, new Error(event.target.statusCode));
150+
};
151+
};
115152

116-
async.eachSeries(this.indices, function(indexKey,k){
117-
var index = that.indexMap[indexKey];
118-
index.delete(quad, function(){
119-
k();
120-
})
121-
},function(){
122-
callback(that);
123-
});
153+
QuadBackend.prototype._genMinIndexKey = function(quad,index) {
154+
var indexComponents = this.componentOrders[index];
155+
return _.map(indexComponents, function(component){
156+
if(typeof(quad[component]) === 'string' || quad[component] == null) {
157+
return "-1";
158+
} else {
159+
return ""+quad[component];
160+
}
161+
}).join('.');
162+
};
163+
164+
QuadBackend.prototype._genMaxIndexKey = function(quad,index) {
165+
var indexComponents = this.componentOrders[index];
166+
var acum = [];
167+
var foundFirstMissing = false;
168+
for(var i=0; i<indexComponents.length; i++){
169+
var component = indexComponents[i];
170+
var componentValue= quad[component];
171+
if(typeof(componentValue) === 'string') {
172+
if (foundFirstMissing === false) {
173+
foundFirstMissing = true;
174+
if (i - 1 >= 0) {
175+
acum[i - 1] = acum[i - 1] + 1
176+
}
177+
}
178+
acum[i] = -1;
179+
} else {
180+
acum[i] = componentValue;
181+
}
182+
}
183+
return _.map(acum, function(componentValue){
184+
return ""+componentValue
185+
}).join('.');
124186
};
125187

188+
189+
QuadBackend.prototype._indexForPattern = function (pattern) {
190+
var indexKey = pattern.indexKey;
191+
192+
for (var i = 0; i < this.indices.length; i++) {
193+
var index = this.indices[i];
194+
var indexComponents = this.componentOrders[index];
195+
for (var j = 0; j < indexComponents.length; j++) {
196+
if (_.include(indexKey, indexComponents[j]) === false) {
197+
break;
198+
}
199+
if (j == indexKey.length - 1) {
200+
return index;
201+
}
202+
}
203+
}
204+
205+
return 'SPOG'; // If no other match, we return the more generic index
206+
};
207+
208+
126209
module.exports.QuadBackend = QuadBackend;

0 commit comments

Comments
 (0)
0