@live-change/db 0.9.60 → 0.9.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ChangeStream.js +77 -6
- package/lib/Index.js +32 -0
- package/lib/queryGet.js +23 -1
- package/lib/queryObservable.js +32 -9
- package/lib/utils.js +41 -0
- package/package.json +5 -5
package/lib/ChangeStream.js
CHANGED
|
@@ -4,21 +4,44 @@ class ChangeStream {
|
|
|
4
4
|
onChange() {
|
|
5
5
|
throw new Error("abstract method - not implemented")
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
async rangeGet(range) {
|
|
8
|
+
throw new Error("abstract method - not implemented")
|
|
9
|
+
}
|
|
10
|
+
range(range) {
|
|
11
|
+
throw new Error("abstract method - not implemented")
|
|
12
|
+
}
|
|
13
|
+
async objectGet(id) {
|
|
14
|
+
throw new Error("abstract method - not implemented")
|
|
9
15
|
}
|
|
16
|
+
object(id) {
|
|
17
|
+
throw new Error("abstract method - not implemented")
|
|
18
|
+
}
|
|
19
|
+
async to(output) {
|
|
20
|
+
return this.onChange(async (obj, oldObj, id, timestamp) => {
|
|
21
|
+
if(obj || oldObj) await output.change(obj, oldObj, id, timestamp)
|
|
22
|
+
})
|
|
23
|
+
await this.observerPromise
|
|
24
|
+
}
|
|
10
25
|
filter(func) {
|
|
11
26
|
const pipe = new ChangeStreamPipe()
|
|
12
|
-
const observerPromise = this.onChange((obj, oldObj, id, timestamp) =>
|
|
13
|
-
|
|
27
|
+
const observerPromise = this.onChange(async (obj, oldObj, id, timestamp) => {
|
|
28
|
+
const newObj = obj && await func(obj)
|
|
29
|
+
const newOldObj = oldObj && await func(oldObj)
|
|
30
|
+
if(!(newObj || newOldObj)) return
|
|
31
|
+
pipe.change(newObj, newOldObj, id, timestamp)
|
|
32
|
+
})
|
|
14
33
|
pipe.master = this
|
|
15
34
|
pipe.observerPromise = observerPromise
|
|
16
35
|
return pipe
|
|
17
36
|
}
|
|
18
37
|
map(func) {
|
|
19
38
|
const pipe = new ChangeStreamPipe()
|
|
20
|
-
const observerPromise = this.onChange((obj, oldObj, id, timestamp) =>
|
|
21
|
-
|
|
39
|
+
const observerPromise = this.onChange(async (obj, oldObj, id, timestamp) => {
|
|
40
|
+
const newObj = obj && await func(obj)
|
|
41
|
+
const newOldObj = oldObj && await func(oldObj)
|
|
42
|
+
if(!(newObj || newOldObj)) return
|
|
43
|
+
pipe.change(newObj, newOldObj, id, timestamp)
|
|
44
|
+
})
|
|
22
45
|
pipe.master = this
|
|
23
46
|
pipe.observerPromise = observerPromise
|
|
24
47
|
return pipe
|
|
@@ -42,6 +65,54 @@ class ChangeStream {
|
|
|
42
65
|
pipe.observerPromise = observerPromise
|
|
43
66
|
return pipe
|
|
44
67
|
}
|
|
68
|
+
async readInBuckets(bucketCallback, bucketSize = 128) {
|
|
69
|
+
let position = ''
|
|
70
|
+
let readed = 0
|
|
71
|
+
do {
|
|
72
|
+
const bucket = await this.rangeGet({ gt: position, limit: bucketSize })
|
|
73
|
+
readed = bucket.length
|
|
74
|
+
if(!bucket.length) break
|
|
75
|
+
position = bucket[bucket.length - 1].id
|
|
76
|
+
await bucketCallback(bucket)
|
|
77
|
+
} while(readed === bucketSize)
|
|
78
|
+
}
|
|
79
|
+
cross(other, selfToRange, otherToRange, bucketSize = 128) {
|
|
80
|
+
const pipe = new ChangeStreamPipe()
|
|
81
|
+
const observerPromise = this.onChange(async (obj, oldObj, id, timestamp) => {
|
|
82
|
+
const otherRange = await selfToRange(obj || oldObj)
|
|
83
|
+
if(!otherRange) return // ignore
|
|
84
|
+
if(typeof otherRange === 'string') { // single id
|
|
85
|
+
const otherObj = await other.objectGet(otherRange)
|
|
86
|
+
await pipe.change([obj, otherObj], [oldObj, otherObj], [id, otherRange], timestamp)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
await other.range(otherRange).readInBuckets(async bucket => {
|
|
90
|
+
for(const otherObj of bucket) {
|
|
91
|
+
const otherId = otherObj.id
|
|
92
|
+
await pipe.change([obj, otherObj], [oldObj, otherObj], [id, otherId], timestamp)
|
|
93
|
+
}
|
|
94
|
+
}, bucketSize)
|
|
95
|
+
})
|
|
96
|
+
const otherObserverPromise = other.onChange(async (otherObj, oldOtherObj, id, timestamp) => {
|
|
97
|
+
const selfRange = await otherToRange(otherObj || oldOtherObj)
|
|
98
|
+
if(!selfRange) return // ignore
|
|
99
|
+
const otherId = id
|
|
100
|
+
if(typeof selfRange === 'string') { // single id
|
|
101
|
+
const obj = await this.objectGet(selfRange)
|
|
102
|
+
await pipe.change([obj, otherObj], [obj, oldOtherObj], [selfRange, otherId], timestamp)
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
await this.range(selfRange).readInBuckets(async bucket => {
|
|
106
|
+
for(const obj of bucket) {
|
|
107
|
+
const id = obj.id
|
|
108
|
+
await pipe.change([obj, otherObj], [obj, oldOtherObj], [id, otherId], timestamp)
|
|
109
|
+
}
|
|
110
|
+
}, bucketSize)
|
|
111
|
+
})
|
|
112
|
+
pipe.master = this
|
|
113
|
+
pipe.observerPromise = Promise.all([observerPromise, otherObserverPromise])
|
|
114
|
+
return pipe
|
|
115
|
+
}
|
|
45
116
|
}
|
|
46
117
|
|
|
47
118
|
class ChangeStreamPipe extends ChangeStream {
|
package/lib/Index.js
CHANGED
|
@@ -6,6 +6,7 @@ import queryGet from './queryGet.js'
|
|
|
6
6
|
import profileLog from './profileLog.js'
|
|
7
7
|
import nextTick from 'next-tick'
|
|
8
8
|
import { ChangeStream } from './ChangeStream.js'
|
|
9
|
+
import { rangeIntersection } from './utils.js'
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
import Debug from 'debug'
|
|
@@ -37,6 +38,19 @@ class ObjectReader extends ChangeStream {
|
|
|
37
38
|
async get() {
|
|
38
39
|
return await (await this.tableReader.table).objectGet(this.id)
|
|
39
40
|
}
|
|
41
|
+
async rangeGet(range) {
|
|
42
|
+
return await (await this.tableReader.table).rangeGet(rangeIntersection(unitRange(this.id), range))
|
|
43
|
+
}
|
|
44
|
+
range(range) {
|
|
45
|
+
return new RangeReader(this.tableReader, unitRange(this.id))
|
|
46
|
+
}
|
|
47
|
+
object(id) {
|
|
48
|
+
return new ObjectReader(this.tableReader, id)
|
|
49
|
+
}
|
|
50
|
+
async objectGet(id) {
|
|
51
|
+
return await (await this.tableReader.table).objectGet(id)
|
|
52
|
+
}
|
|
53
|
+
|
|
40
54
|
dispose() {}
|
|
41
55
|
}
|
|
42
56
|
|
|
@@ -63,9 +77,21 @@ class RangeReader extends ChangeStream {
|
|
|
63
77
|
async change(obj, oldObj, id, timestamp) {
|
|
64
78
|
for(const callback of this.callbacks) await callback(obj, oldObj, id, timestamp)
|
|
65
79
|
}
|
|
80
|
+
async rangeGet(range) {
|
|
81
|
+
return await (await this.tableReader.table).rangeGet(rangeIntersection(this.range, range))
|
|
82
|
+
}
|
|
83
|
+
range(range) {
|
|
84
|
+
return new RangeReader(this.tableReader, rangeIntersection(this.range, range))
|
|
85
|
+
}
|
|
66
86
|
async get() {
|
|
67
87
|
return await (await this.tableReader.table).rangeGet(this.range)
|
|
68
88
|
}
|
|
89
|
+
async objectGet(id) {
|
|
90
|
+
return await (await this.tableReader.table).objectGet(id)
|
|
91
|
+
}
|
|
92
|
+
object(id) {
|
|
93
|
+
return new ObjectReader(this.tableReader, id)
|
|
94
|
+
}
|
|
69
95
|
}
|
|
70
96
|
|
|
71
97
|
class TableReader extends ChangeStream {
|
|
@@ -138,6 +164,9 @@ class TableReader extends ChangeStream {
|
|
|
138
164
|
for(const callback of this.callbacks) await callback(obj, oldObj, id, timestamp)
|
|
139
165
|
if(profileOp) await profileLog.end(profileOp)
|
|
140
166
|
}
|
|
167
|
+
async rangeGet(range) {
|
|
168
|
+
return await this.table.rangeGet(range)
|
|
169
|
+
}
|
|
141
170
|
range(range) {
|
|
142
171
|
const key = JSON.stringify(range)
|
|
143
172
|
let reader = this.rangeReaders.get(key)
|
|
@@ -149,6 +178,9 @@ class TableReader extends ChangeStream {
|
|
|
149
178
|
return reader
|
|
150
179
|
return new RangeReader(this, range)
|
|
151
180
|
}
|
|
181
|
+
async objectGet(id) {
|
|
182
|
+
return await (await this.table).objectGet(id)
|
|
183
|
+
}
|
|
152
184
|
object(id) {
|
|
153
185
|
let reader = this.objectReaders.get(id)
|
|
154
186
|
if(!reader) {
|
package/lib/queryGet.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TableWriter, LogWriter } from './queryUpdate.js'
|
|
2
2
|
import { ChangeStream } from './ChangeStream.js'
|
|
3
|
-
|
|
3
|
+
import { unitRange, rangeIntersection } from './utils.js'
|
|
4
4
|
const maxGetLimit = 256
|
|
5
5
|
|
|
6
6
|
class ObjectReader extends ChangeStream {
|
|
@@ -22,6 +22,12 @@ class ObjectReader extends ChangeStream {
|
|
|
22
22
|
async get() {
|
|
23
23
|
return await (await this.#table).objectGet(this.#id)
|
|
24
24
|
}
|
|
25
|
+
async rangeGet(range) {
|
|
26
|
+
return await (await this.#table).rangeGet(rangeIntersection(unitRange(this.#id), range))
|
|
27
|
+
}
|
|
28
|
+
range(range) {
|
|
29
|
+
return new RangeReader(this.#table, rangeIntersection(unitRange(this.#id), range))
|
|
30
|
+
}
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
class RangeReader extends ChangeStream {
|
|
@@ -45,6 +51,19 @@ class RangeReader extends ChangeStream {
|
|
|
45
51
|
async get() {
|
|
46
52
|
return await (await this.#table).rangeGet(this.#range)
|
|
47
53
|
}
|
|
54
|
+
|
|
55
|
+
async rangeGet(range) {
|
|
56
|
+
return await (await this.#table).rangeGet(rangeIntersection(this.#range, range))
|
|
57
|
+
}
|
|
58
|
+
range(range) {
|
|
59
|
+
return new RangeReader(this.#table, rangeIntersection(this.#range, range), this.#time)
|
|
60
|
+
}
|
|
61
|
+
object(id) {
|
|
62
|
+
return new ObjectReader(this.#table, id, this.#time)
|
|
63
|
+
}
|
|
64
|
+
objectGet(id) {
|
|
65
|
+
return this.#table.objectGet(id)
|
|
66
|
+
}
|
|
48
67
|
}
|
|
49
68
|
|
|
50
69
|
class TableReader extends ChangeStream {
|
|
@@ -73,6 +92,9 @@ class TableReader extends ChangeStream {
|
|
|
73
92
|
return results
|
|
74
93
|
}
|
|
75
94
|
unobserve(obs) {}
|
|
95
|
+
rangeGet(range) {
|
|
96
|
+
return new RangeReader(this.#table, range, this.#time)
|
|
97
|
+
}
|
|
76
98
|
range(range) {
|
|
77
99
|
return new RangeReader(this.#table, range, this.#time)
|
|
78
100
|
}
|
package/lib/queryObservable.js
CHANGED
|
@@ -31,7 +31,7 @@ class ObjectObserver {
|
|
|
31
31
|
}
|
|
32
32
|
readPromise() {
|
|
33
33
|
return this.#valuePromise
|
|
34
|
-
}
|
|
34
|
+
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
class RangeObserver {
|
|
@@ -119,11 +119,12 @@ class Reader extends ChangeStream {
|
|
|
119
119
|
class ObjectReader extends Reader {
|
|
120
120
|
#table = null
|
|
121
121
|
#id = null
|
|
122
|
-
|
|
123
|
-
constructor(queryReader, table, id) {
|
|
122
|
+
#tableReader = null
|
|
123
|
+
constructor(queryReader, table, id, tableReader) {
|
|
124
124
|
super(queryReader)
|
|
125
125
|
this.#table = table
|
|
126
126
|
this.#id = id
|
|
127
|
+
this.#tableReader = tableReader
|
|
127
128
|
}
|
|
128
129
|
observableFactory() {
|
|
129
130
|
return this.#table.objectObservable(this.#id)
|
|
@@ -132,19 +133,29 @@ class ObjectReader extends Reader {
|
|
|
132
133
|
return this.startObserver((r) => new ObjectObserver(r, cb))
|
|
133
134
|
}
|
|
134
135
|
get() {
|
|
135
|
-
//console.log("OBJ GET", this.#table.name, this.#id)
|
|
136
136
|
return this.#table.objectGet(this.#id)
|
|
137
137
|
}
|
|
138
|
+
async rangeGet(range) {
|
|
139
|
+
return this.#tableReader.rangeGet(rangeIntersection(unitRange(this.#id), range))
|
|
140
|
+
}
|
|
141
|
+
async objectGet(id) {
|
|
142
|
+
return this.#table.objectGet(id)
|
|
143
|
+
}
|
|
144
|
+
object(id) {
|
|
145
|
+
return this.#tableReader.object(id)
|
|
146
|
+
}
|
|
138
147
|
}
|
|
139
148
|
|
|
140
149
|
class RangeReader extends Reader {
|
|
141
150
|
#table = null
|
|
142
151
|
#range = null
|
|
152
|
+
#tableReader = null
|
|
143
153
|
|
|
144
|
-
constructor(queryReader, table, range) {
|
|
154
|
+
constructor(queryReader, table, range, tableReader) {
|
|
145
155
|
super(queryReader)
|
|
146
156
|
this.#table = table
|
|
147
157
|
this.#range = range
|
|
158
|
+
this.#tableReader = tableReader
|
|
148
159
|
}
|
|
149
160
|
async observableFactory() {
|
|
150
161
|
return await (await this.#table).rangeObservable(this.#range)
|
|
@@ -155,6 +166,15 @@ class RangeReader extends Reader {
|
|
|
155
166
|
async get() {
|
|
156
167
|
return await (await this.#table).rangeGet(this.#range)
|
|
157
168
|
}
|
|
169
|
+
async rangeGet(range) {
|
|
170
|
+
return await this.#tableReader.rangeGet(rangeIntersection(this.#range, range))
|
|
171
|
+
}
|
|
172
|
+
async objectGet(id) {
|
|
173
|
+
return await this.#table.objectGet(id)
|
|
174
|
+
}
|
|
175
|
+
object(id) {
|
|
176
|
+
return this.#tableReader.object(id)
|
|
177
|
+
}
|
|
158
178
|
}
|
|
159
179
|
|
|
160
180
|
class TableReader extends Reader {
|
|
@@ -172,16 +192,19 @@ class TableReader extends Reader {
|
|
|
172
192
|
onChange(cb) {
|
|
173
193
|
return this.startObserver((r) => new RangeObserver(r, cb))
|
|
174
194
|
}
|
|
195
|
+
async rangeGet(range) {
|
|
196
|
+
return await this.#table.rangeGet(range)
|
|
197
|
+
}
|
|
175
198
|
range(range) {
|
|
176
199
|
return this._queryReader.getExistingReaderOrCreate(this.#prefix+':'+JSON.stringify(range),
|
|
177
|
-
() => new RangeReader(this._queryReader, this.#table, range))
|
|
200
|
+
() => new RangeReader(this._queryReader, this.#table, range, this))
|
|
178
201
|
}
|
|
179
202
|
object(id) {
|
|
180
203
|
return this._queryReader.getExistingReaderOrCreate(this.#prefix+'#'+id,
|
|
181
|
-
() => new ObjectReader(this._queryReader, this.#table, id))
|
|
204
|
+
() => new ObjectReader(this._queryReader, this.#table, id, this))
|
|
182
205
|
}
|
|
183
|
-
objectGet(id) {
|
|
184
|
-
return this.#table.objectGet(id)
|
|
206
|
+
async objectGet(id) {
|
|
207
|
+
return await this.#table.objectGet(id)
|
|
185
208
|
}
|
|
186
209
|
async get(range = {}) {
|
|
187
210
|
return await (await this.#table).rangeGet(range)
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function min(a, b) {
|
|
2
|
+
if(a === undefined) return b
|
|
3
|
+
if(b === undefined) return a
|
|
4
|
+
return a < b ? a : b
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function max(a, b) {
|
|
8
|
+
if(a === undefined) return b
|
|
9
|
+
if(b === undefined) return a
|
|
10
|
+
return a > b ? a : b
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function rangeIntersection(range1, range2) {
|
|
14
|
+
return {
|
|
15
|
+
reverse: range2.reverse,
|
|
16
|
+
gt: max(range1.gt, range2.gt),
|
|
17
|
+
lt: min(range1.lt, range2.lt),
|
|
18
|
+
gte: max(range1.gte, range2.gte),
|
|
19
|
+
lte: min(range1.lte, range2.lte),
|
|
20
|
+
limit: range2.limit
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function rangeUnion(range1, range2) {
|
|
25
|
+
return {
|
|
26
|
+
reverse: range1.reverse,
|
|
27
|
+
gt: min(range1.gt, range2.gt),
|
|
28
|
+
lt: max(range1.lt, range2.lt),
|
|
29
|
+
gte: min(range1.gte, range2.gte),
|
|
30
|
+
lte: max(range1.lte, range2.lte),
|
|
31
|
+
limit: range1.limit + range2.limit
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function unitRange(id) {
|
|
36
|
+
return {
|
|
37
|
+
gte: id,
|
|
38
|
+
lt: id,
|
|
39
|
+
limit: 1
|
|
40
|
+
}
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/db",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.62",
|
|
4
4
|
"description": "Database with observable data for live queries",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"type": "module",
|
|
23
23
|
"homepage": "https://github.com/live-change/live-change-stack",
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@live-change/db-store-level": "^0.9.
|
|
26
|
-
"@live-change/db-store-lmdb": "^0.9.
|
|
25
|
+
"@live-change/db-store-level": "^0.9.62",
|
|
26
|
+
"@live-change/db-store-lmdb": "^0.9.62",
|
|
27
27
|
"minimist": ">=1.2.3",
|
|
28
28
|
"next-tick": "^1.1.0",
|
|
29
29
|
"rimraf": "^5.0.5",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"websocket-extensions": ">=0.1.4"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@live-change/dao": "^0.9.
|
|
35
|
+
"@live-change/dao": "^0.9.62",
|
|
36
36
|
"get-random-values": "^1.2.2",
|
|
37
37
|
"node-interval-tree": "^1.3.3"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "b1b605b7f1fa4fc3de4720afbb401e2cfff080cf"
|
|
40
40
|
}
|