@live-change/db 0.9.61 → 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.
@@ -4,21 +4,44 @@ class ChangeStream {
4
4
  onChange() {
5
5
  throw new Error("abstract method - not implemented")
6
6
  }
7
- to(output) {
8
- return this.onChange((obj, oldObj, id, timestamp) => output.change(obj, oldObj, id, timestamp))
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
- pipe.change(obj && func(obj) ? obj : null, oldObj && func(oldObj) ? oldObj : null, id, timestamp))
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
- pipe.change(obj && func(obj), oldObj && func(oldObj), id, timestamp))
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
  }
@@ -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.61",
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.61",
26
- "@live-change/db-store-lmdb": "^0.9.61",
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.61",
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": "f750f29f912b9a76b5ffa2bdf5c46954cc7e7a67"
39
+ "gitHead": "b1b605b7f1fa4fc3de4720afbb401e2cfff080cf"
40
40
  }