1 | 'use strict';
|
2 | var Promise = require('bluebird');
|
3 | var utils = require('./utils');
|
4 | var MemStore = require('./memmap');
|
5 | var uuid = require('node-uuid');
|
6 | var insert = require('./insert');
|
7 | var remove = require('./remove');
|
8 | var append = require('./append');
|
9 | var bulk = require('./bulk');
|
10 | var query = require('./query');
|
11 | var extend = require('xtend');
|
12 | var queryStream = require('./queryStream');
|
13 | var Batches = require('./batches');
|
14 |
|
15 | module.exports = RTree;
|
16 | function promisify(store) {
|
17 | var out = {};
|
18 | ['get', 'put', 'del', 'batch'].forEach(function (key) {
|
19 | out[key] = Promise.promisify(store[key], store);
|
20 | });
|
21 | return out;
|
22 | }
|
23 | function RTree(store, opts) {
|
24 | opts = extend({
|
25 | MIN: 3,
|
26 | MAX: 9
|
27 | }, opts);
|
28 | this.MAX = opts.MAX;
|
29 | this.MIN = opts.MIN;
|
30 | this.store = promisify(store || new MemStore());
|
31 | this.root = false;
|
32 | this.queue = [];
|
33 | this.inProgress = false;
|
34 | }
|
35 | RTree.prototype.insert = function (id, bbox, cb) {
|
36 | return this.taskQueue(insert, this, id, bbox, false, false).nodeify(cb);
|
37 | };
|
38 | RTree.prototype.append = function (id, bbox, cb) {
|
39 | return this.taskQueue(append, this, id, bbox, false, false).nodeify(cb);
|
40 | };
|
41 | RTree.prototype.remove = function (id, bbox, cb) {
|
42 | if (!Array.isArray(bbox)) {
|
43 | cb = bbox;
|
44 | bbox = void 0;
|
45 | }
|
46 | return this.taskQueue(remove, this, id, bbox, false).nodeify(cb);
|
47 | };
|
48 | RTree.prototype.bulk = function (array, cb) {
|
49 | return this.taskQueue(bulk, this, array).nodeify(cb);
|
50 | };
|
51 | RTree.prototype.query = function (bbox, cb) {
|
52 | if (cb) {
|
53 | return query(this, bbox).nodeify(cb);
|
54 | }
|
55 | return queryStream(this, bbox);
|
56 | };
|
57 | RTree.prototype.taskQueue = function (func) {
|
58 | var args = new Array(arguments.length -1);
|
59 | var len = arguments.length;
|
60 | var i = 0;
|
61 | while (++i < len) {
|
62 | args[i - 1] = arguments[i];
|
63 | }
|
64 | var self = this;
|
65 | function after(resp) {
|
66 | if (self.queue.length) {
|
67 | self.flushQueue();
|
68 | } else {
|
69 | self.inProgress = false;
|
70 | }
|
71 | }
|
72 | if (!this.inProgress) {
|
73 | this.inProgress = true;
|
74 | var res = func.apply(undefined, args);
|
75 | res.then(after);
|
76 | return res;
|
77 | } else {
|
78 | return new Promise (function (fulfill, reject) {
|
79 | self.queue.push({
|
80 | error: reject,
|
81 | fulfill: fulfill,
|
82 | args: args,
|
83 | func: func
|
84 | });
|
85 | });
|
86 | }
|
87 | };
|
88 | RTree.prototype.flushQueue = function () {
|
89 | var self = this;
|
90 | if (!this.queue.length) {
|
91 | self.inProgress = false;
|
92 | return;
|
93 | }
|
94 | if (this.queue.length === 1) {
|
95 | var item = this.queue.pop();
|
96 | var res = item.func.apply(undefined, item.args);
|
97 | item.fulfill(res);
|
98 | res.then(function () {
|
99 | if (self.queue.length) {
|
100 | self.flushQueue();
|
101 | } else {
|
102 | self.inProgress = false;
|
103 | }
|
104 | });
|
105 | return;
|
106 | }
|
107 | var store = new Batches(self.store);
|
108 | var promise = Promise.resolve(true);
|
109 | var fullfill;
|
110 | var done = new Promise(function (f) {
|
111 | fullfill = f;
|
112 | });
|
113 | var i = 0;
|
114 | this.queue.forEach(function (item){
|
115 | item.args.push(store);
|
116 | promise = promise.then(function () {
|
117 | var result = item.func.apply(undefined, item.args);
|
118 | item.fulfill(done.then(function () {
|
119 | return result;
|
120 | }));
|
121 | return result.catch(function () {
|
122 |
|
123 | });
|
124 | });
|
125 |
|
126 | });
|
127 | this.queue = [];
|
128 | promise.then(function () {
|
129 | return store.save();
|
130 | }).then(function (resp) {
|
131 | fullfill(resp);
|
132 | self.flushQueue();
|
133 | });
|
134 | };
|
135 |
|