@live-change/db 0.3.61 → 0.5.2
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/Database.js +35 -19
- package/lib/Index.js +9 -7
- package/lib/ScriptContext.js +4 -3
- package/package.json +6 -13
package/lib/Database.js
CHANGED
|
@@ -7,8 +7,10 @@ const getRandomValues = require('get-random-values')
|
|
|
7
7
|
|
|
8
8
|
const ReactiveDao = require("@live-change/dao")
|
|
9
9
|
|
|
10
|
+
const debug = require('debug')('db')
|
|
11
|
+
|
|
10
12
|
class Database {
|
|
11
|
-
constructor(config, storeFactory, saveConfig, deleteStore, name) {
|
|
13
|
+
constructor(config, storeFactory, saveConfig, deleteStore, name, createScriptContext) {
|
|
12
14
|
this.name = name
|
|
13
15
|
this.config = {
|
|
14
16
|
tables: {},
|
|
@@ -23,6 +25,7 @@ class Database {
|
|
|
23
25
|
this.tables = new Map()
|
|
24
26
|
this.logs = new Map()
|
|
25
27
|
this.indexes = new Map()
|
|
28
|
+
this.createScriptContext = createScriptContext
|
|
26
29
|
|
|
27
30
|
this.configObservable = new ReactiveDao.ObservableValue(JSON.parse(JSON.stringify(this.config)))
|
|
28
31
|
this.tablesListObservable = new ReactiveDao.ObservableList(Object.keys(this.config.tables))
|
|
@@ -92,7 +95,7 @@ class Database {
|
|
|
92
95
|
this.tablesListObservable.remove(name)
|
|
93
96
|
this.tables.delete(name)
|
|
94
97
|
}
|
|
95
|
-
|
|
98
|
+
|
|
96
99
|
renameTable(name, newName) {
|
|
97
100
|
if(this.config.tables[newName]) throw new Error(`Table ${newName} already exists`)
|
|
98
101
|
const table = this.table(name)
|
|
@@ -226,25 +229,38 @@ class Database {
|
|
|
226
229
|
return summary
|
|
227
230
|
}
|
|
228
231
|
|
|
232
|
+
async openIndex(name) {
|
|
233
|
+
let config = this.config.indexes[name]
|
|
234
|
+
if(!config) {
|
|
235
|
+
debug("INDEX", name, "NOT EXISTS - WAITING!")
|
|
236
|
+
await new Promise(r => setTimeout(r, 500))
|
|
237
|
+
config = this.config.indexes[name]
|
|
238
|
+
}
|
|
239
|
+
let index, code
|
|
240
|
+
if(!config) throw new Error(`Index ${name} not found`)
|
|
241
|
+
code = config.code
|
|
242
|
+
const params = config.parameters
|
|
243
|
+
index = new Index(this, name, code, params, config)
|
|
244
|
+
try {
|
|
245
|
+
debug("STARTING INDEX", name)
|
|
246
|
+
await index.startIndex()
|
|
247
|
+
debug("STARTED INDEX", name)
|
|
248
|
+
} catch(error) {
|
|
249
|
+
console.error("INDEX", name, "ERROR", error, "CODE:\n", code)
|
|
250
|
+
console.error("DELETING INDEX", name)
|
|
251
|
+
delete this.config.indexes[name]
|
|
252
|
+
this.indexesListObservable.remove(name)
|
|
253
|
+
if(this.onAutoRemoveIndex && config) this.onAutoRemoveIndex(name, config.uid)
|
|
254
|
+
await this.saveConfig(this.config)
|
|
255
|
+
throw error
|
|
256
|
+
}
|
|
257
|
+
this.indexes.set(name, index)
|
|
258
|
+
return index
|
|
259
|
+
}
|
|
229
260
|
async index(name) {
|
|
230
261
|
let index = this.indexes.get(name)
|
|
231
262
|
if(!index) {
|
|
232
|
-
|
|
233
|
-
if(!config) throw new Error(`Index ${name} not found`)
|
|
234
|
-
const code = config.code
|
|
235
|
-
const params = config.parameters
|
|
236
|
-
index = new Index(this, name, code, params, config)
|
|
237
|
-
try {
|
|
238
|
-
await index.startIndex()
|
|
239
|
-
} catch(error) {
|
|
240
|
-
console.error("INDEX", name, "ERROR", error, "CODE:\n", index.code)
|
|
241
|
-
console.error("DELETING INDEX", name)
|
|
242
|
-
delete this.config.indexes[name]
|
|
243
|
-
this.indexesListObservable.remove(name)
|
|
244
|
-
if(this.onAutoRemoveIndex) this.onAutoRemoveIndex(name, config.uid)
|
|
245
|
-
await this.saveConfig(this.config)
|
|
246
|
-
throw error
|
|
247
|
-
}
|
|
263
|
+
index = this.openIndex(name)
|
|
248
264
|
this.indexes.set(name, index)
|
|
249
265
|
}
|
|
250
266
|
return index
|
|
@@ -272,7 +288,7 @@ class Database {
|
|
|
272
288
|
|
|
273
289
|
handleUnhandledRejectionInIndex(name, reason, promise) {
|
|
274
290
|
const config = this.config.indexes[name]
|
|
275
|
-
console.error("INDEX", name, "unhandledRejection", reason, "CODE:\n", config
|
|
291
|
+
console.error("INDEX", name, "unhandledRejection", reason, "CODE:\n", config?.code)
|
|
276
292
|
console.error("DELETING INDEX", name)
|
|
277
293
|
process.nextTick(() => {
|
|
278
294
|
if(!config) {
|
package/lib/Index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
const IntervalTree = require('node-interval-tree').default
|
|
2
2
|
const ReactiveDao = require("@live-change/dao")
|
|
3
3
|
const Table = require('./Table.js')
|
|
4
|
-
const ScriptContext = require('./ScriptContext.js')
|
|
5
4
|
const queryGet = require('./queryGet.js')
|
|
6
5
|
const profileLog = require('./profileLog.js')
|
|
7
6
|
const queryObservable = require('./queryObservable.js')
|
|
8
7
|
const { ChangeStream } = require('./ChangeStream.js')
|
|
9
8
|
|
|
9
|
+
const debug = require('debug')('db')
|
|
10
|
+
|
|
10
11
|
const opLogBatchSize = 128 /// TODO: incrase after testing
|
|
11
12
|
|
|
12
13
|
class ObjectReader extends ChangeStream {
|
|
@@ -64,6 +65,7 @@ class TableReader extends ChangeStream {
|
|
|
64
65
|
this.opLogReader = opLogReader
|
|
65
66
|
this.prefix = prefix
|
|
66
67
|
this.table = table
|
|
68
|
+
Promise.resolve(this.table).then(t=> {if(!t) throw new Error("TABLE NOT FOUND!!!")})
|
|
67
69
|
this.isLog = isLog
|
|
68
70
|
this.objectReaders = new Map()
|
|
69
71
|
this.rangeReaders = new Map()
|
|
@@ -437,15 +439,15 @@ class Index extends Table {
|
|
|
437
439
|
this.code = code
|
|
438
440
|
}
|
|
439
441
|
async startIndex() {
|
|
440
|
-
|
|
441
|
-
this.scriptContext =
|
|
442
|
+
debug("EXECUTING INDEX CODE", this.name)
|
|
443
|
+
this.scriptContext = this.database.createScriptContext({
|
|
442
444
|
/// TODO: script available routines
|
|
443
445
|
})
|
|
444
446
|
const queryFunction = this.scriptContext.run(this.code,`userCode:${this.database.name}/indexes/${this.name}`)
|
|
445
447
|
this.codeFunction = (input, output) => queryFunction(input, output, this.params)
|
|
446
448
|
this.writer = new IndexWriter(this)
|
|
447
449
|
this.reader = null
|
|
448
|
-
|
|
450
|
+
debug("STARTING INDEX", this.name)
|
|
449
451
|
const lastIndexOperations = await this.opLog.rangeGet({ reverse: true, limit: 1 })
|
|
450
452
|
const lastIndexOperation = lastIndexOperations[0]
|
|
451
453
|
let lastUpdateTimestamp = 0
|
|
@@ -475,11 +477,11 @@ class Index extends Table {
|
|
|
475
477
|
codePromise = this.codeFunction(this.reader, this.writer)
|
|
476
478
|
//console.log("READING!")
|
|
477
479
|
await this.reader.readMore()
|
|
478
|
-
|
|
480
|
+
debug("WAITING FOR CODE!", this.name)
|
|
479
481
|
await codePromise
|
|
480
482
|
this.state = INDEX_READY
|
|
481
483
|
const startTime = Date.now()
|
|
482
|
-
|
|
484
|
+
debug("INDEX STARTED!", this.name)
|
|
483
485
|
await this.opLog.put({
|
|
484
486
|
id: ((''+startTime).padStart(16, '0'))+':000000',
|
|
485
487
|
timestamp: startTime,
|
|
@@ -499,7 +501,7 @@ class Index extends Table {
|
|
|
499
501
|
if(existingSourceInfo) return
|
|
500
502
|
const newSourceInfo = { type: sourceType, name: sourceName }
|
|
501
503
|
config.sources.push(newSourceInfo)
|
|
502
|
-
|
|
504
|
+
debug("NEW INDEX", this.name, "SOURCE DETECTED", sourceType, sourceName)
|
|
503
505
|
this.configObservable.set(config)
|
|
504
506
|
this.database.config.indexes[this.name] = config
|
|
505
507
|
this.database.handleConfigUpdated()
|
package/lib/ScriptContext.js
CHANGED
|
@@ -35,6 +35,7 @@ const defaultContext = {
|
|
|
35
35
|
return new ChangeStreamPipe()
|
|
36
36
|
},
|
|
37
37
|
'performance': require('perf_hooks').performance,
|
|
38
|
+
constructor: null
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
const filenameRE = /scriptFile:(\d+):(\d+)\)$/g
|
|
@@ -47,9 +48,9 @@ class ScriptContext {
|
|
|
47
48
|
}
|
|
48
49
|
this.context = vm.createContext({ ...defaultContext, ...context, ...userContext })
|
|
49
50
|
/* vm.runInContext(`
|
|
50
|
-
(function() {
|
|
51
|
-
const allowed = ${JSON.stringify(nativeGlobals.concat(Object.keys(userContext)))}
|
|
52
|
-
const keys = Object.getOwnPropertyNames(this)
|
|
51
|
+
(function() {
|
|
52
|
+
const allowed = ${JSON.stringify(nativeGlobals.concat(Object.keys(userContext)))}
|
|
53
|
+
const keys = Object.getOwnPropertyNames(this)
|
|
53
54
|
keys.forEach((key) => {
|
|
54
55
|
const item = this[key]
|
|
55
56
|
if(!item) return
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Database with observable data for live queries",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -21,25 +21,18 @@
|
|
|
21
21
|
},
|
|
22
22
|
"homepage": "https://github.com/live-change/db",
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@live-change/db-store-level": "^0.
|
|
25
|
-
"@live-change/db-store-lmdb": "^0.
|
|
26
|
-
"encoding-down": "^6.3.0",
|
|
27
|
-
"level-rocksdb": "^4.0.0",
|
|
28
|
-
"leveldown": "^5.6.0",
|
|
29
|
-
"levelup": "^4.4.0",
|
|
30
|
-
"memdown": "^5.1.0",
|
|
24
|
+
"@live-change/db-store-level": "^0.5.2",
|
|
25
|
+
"@live-change/db-store-lmdb": "^0.5.2",
|
|
31
26
|
"minimist": ">=1.2.3",
|
|
32
|
-
"node-lmdb": "^0.8.0",
|
|
33
27
|
"rimraf": "^3.0.2",
|
|
34
|
-
"rocksdb": "^4.1.0",
|
|
35
28
|
"sockjs": "^0.3.21",
|
|
36
|
-
"subleveldown": "^4.1.4",
|
|
37
29
|
"tape": "^4.13.3",
|
|
38
30
|
"websocket-extensions": ">=0.1.4"
|
|
39
31
|
},
|
|
40
32
|
"dependencies": {
|
|
41
|
-
"@live-change/dao": "^0.
|
|
33
|
+
"@live-change/dao": "^0.3.3",
|
|
42
34
|
"get-random-values": "^1.2.2",
|
|
43
35
|
"node-interval-tree": "^1.3.3"
|
|
44
|
-
}
|
|
36
|
+
},
|
|
37
|
+
"gitHead": "af756efb8db9ba90d79774786201cffe9c2162cf"
|
|
45
38
|
}
|