diff --git a/builder/codegen.js b/builder/codegen.js index 9228fd2..5b2c0ed 100644 --- a/builder/codegen.js +++ b/builder/codegen.js @@ -122,10 +122,12 @@ module.exports = function generateCode (hyperdb) { return str } -function toArrayFunction (fn) { +function toArrowFunction (str, async) { + let fn = genFunc()(str).toString() const i = fn.indexOf('(') const isArrow = !fn.slice(0, i).includes('function') fn = fn.slice(i) + if (async) fn = 'async ' + fn if (isArrow) return fn return fn.replace('{', '=> {') } @@ -138,9 +140,8 @@ function generateCommonPrefix (id, type) { str += '\n' if (type.isMapped) { - const fn = genFunc() - fn(type.map) - str += `const ${id}_map = ${toArrayFunction(fn.toString())}\n` + str += `// ${s(type.fqn)} has the following schema defined key map\n` + str += `const ${id}_map = ${toArrowFunction(type.map, false)}\n` str += '\n' } @@ -165,6 +166,12 @@ function generateCommonPrefix (id, type) { function generateCollectionDefinition (id, collection) { let str = generateCommonPrefix(id, collection) + if (collection.trigger) { + str += `// ${s(collection.fqn)} has the following schema defined trigger\n` + str += `const ${id}_trigger = ${toArrowFunction(collection.trigger, true)}\n` + str += '\n' + } + str += `// ${s(collection.fqn)} reconstruction function\n` str += `function ${id}_reconstruct (version, keyBuf, valueBuf) {\n` str += ' // TODO: This should be fully code generated\n' @@ -185,6 +192,7 @@ function generateCollectionDefinition (id, collection) { str += ` name: ${s(collection.fqn)},\n` str += ` id: ${collection.id},\n` str += ` stats: ${collection.stats},\n` + str += ` trigger: ${collection.trigger ? id + '_trigger' : 'null'},\n` str += ` encodeKey: ${generateEncodeCollectionKey(id, collection)},\n` str += ` encodeKeyRange: ${generateEncodeKeyRange(id, collection)},\n` str += ` encodeValue: ${generateEncodeCollectionValue(collection)},\n` diff --git a/builder/index.js b/builder/index.js index c2a6818..29bdbec 100644 --- a/builder/index.js +++ b/builder/index.js @@ -75,6 +75,7 @@ class Collection extends DBType { this.key = description.key || [] this.fullKey = this.key + this.trigger = (typeof description.trigger === 'function') ? description.trigger.toString() : description.trigger this.keyEncoding = [] this.valueEncoding = this.fqn + '/value' diff --git a/index.js b/index.js index 64eaa55..b1a329e 100644 --- a/index.js +++ b/index.js @@ -301,7 +301,7 @@ class HyperDB { const collection = this.definition.resolveCollection(collectionName) if (collection === null) return null - const key = collection.encodeKey(doc) + const key = b4a.isBuffer(doc) ? doc : collection.encodeKey(doc) const u = this.updates.get(key) const value = u !== null ? u.value : await this.engine.get(this.engineSnapshot, key) @@ -348,6 +348,11 @@ class HyperDB { return value } + // TODO: needs to wait for pending inserts/deletes and then lock all future ones whilst it runs + _runTrigger (collection, key, doc) { + return collection.trigger(this, key, doc, this.context) + } + async delete (collectionName, doc) { maybeClosed(this) @@ -361,6 +366,7 @@ class HyperDB { let prevValue = null this.updates.mutating++ try { + if (collection.trigger !== null) await this._runTrigger(collection, key, doc) prevValue = await this._getPrev(key, collection) } finally { this.updates.mutating-- @@ -400,6 +406,7 @@ class HyperDB { let prevValue = null this.updates.mutating++ try { + if (collection.trigger !== null) await this._runTrigger(collection, key, doc) prevValue = await this._getPrev(key, collection) } finally { this.updates.mutating-- diff --git a/lib/engine/rocks.js b/lib/engine/rocks.js index 5c96bcb..5b06efb 100644 --- a/lib/engine/rocks.js +++ b/lib/engine/rocks.js @@ -25,6 +25,7 @@ module.exports = class RocksEngine { this.clock = 0 this.refs = 0 this.db = typeof storage === 'object' ? storage : new RocksDB(storage) + this.db.ready().catch(noop) } get closed () { @@ -103,3 +104,5 @@ async function getWrapped (read, key, value) { function getSnapshot (snap) { return snap === null ? null : snap.snapshot } + +function noop () {} diff --git a/package.json b/package.json index 8f6d4d5..8e663c2 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "generate-function": "^2.3.1", "generate-object-property": "^2.0.0", "generate-string": "^1.0.1", - "hyperschema": "^0.0.14", + "hyperschema": "^0.0.16", "rocksdb-native": "^2.3.1", "streamx": "^2.20.0" }, diff --git a/test/fixtures/definition.js b/test/fixtures/definition.js index b5afd6f..b858bd5 100644 --- a/test/fixtures/definition.js +++ b/test/fixtures/definition.js @@ -22,6 +22,9 @@ const struct = { const membersCollection = { name: 'members', + stats: false, + id: 0, + trigger: null, encodeKey (doc) { return memberKey.encode([doc.id]) }, @@ -40,6 +43,8 @@ const membersCollection = { const membersByAgeIndex = { name: 'members/by-age', offset: 0, + stats: false, + id: 1, encodeKeys (doc) { return [memberByAge.encode([doc.age, doc.id])] }, diff --git a/test/fixtures/generated/1/hyperdb/db.json b/test/fixtures/generated/1/hyperdb/db.json index 331f659..544c054 100644 --- a/test/fixtures/generated/1/hyperdb/db.json +++ b/test/fixtures/generated/1/hyperdb/db.json @@ -12,6 +12,7 @@ "@db/members-by-age" ], "schema": "@db/member", + "derived": false, "key": [ "id" ] diff --git a/test/fixtures/generated/1/hyperdb/index.js b/test/fixtures/generated/1/hyperdb/index.js index e54c97e..9220d5a 100644 --- a/test/fixtures/generated/1/hyperdb/index.js +++ b/test/fixtures/generated/1/hyperdb/index.js @@ -36,6 +36,7 @@ const collection0 = { name: '@db/members', id: 0, stats: false, + trigger: null, encodeKey: function encodeKey (record) { const key = [record.id] return collection0_key.encode(key) @@ -80,9 +81,8 @@ const index0 = { name: '@db/members-by-age', id: 1, stats: false, - encodeKeys: function encodeKeys (record) { - const key = [record.age, record.id] - return [index0_key.encode(key)] + encodeKeys: function encodeKeys (record, context) { + return [index0_key.encode([record.age, record.id])] }, encodeKeyRange: function encodeKeyRange ({ gt, lt, gte, lte } = {}) { return index0_key.encodeRange({ diff --git a/test/fixtures/generated/2/hyperdb/db.json b/test/fixtures/generated/2/hyperdb/db.json index e73f2cf..f41e745 100644 --- a/test/fixtures/generated/2/hyperdb/db.json +++ b/test/fixtures/generated/2/hyperdb/db.json @@ -12,6 +12,7 @@ "@db/members-by-age" ], "schema": "@db/member", + "derived": false, "key": [ "id" ] @@ -24,6 +25,7 @@ "type": 1, "indexes": [], "schema": "stats", + "derived": false, "key": [ "id" ] diff --git a/test/fixtures/generated/2/hyperdb/index.js b/test/fixtures/generated/2/hyperdb/index.js index 09c43a7..6ec7589 100644 --- a/test/fixtures/generated/2/hyperdb/index.js +++ b/test/fixtures/generated/2/hyperdb/index.js @@ -36,6 +36,7 @@ const collection0 = { name: '@db/members', id: 0, stats: true, + trigger: null, encodeKey: function encodeKey (record) { const key = [record.id] return collection0_key.encode(key) @@ -86,6 +87,7 @@ const collection1 = { name: 'stats', id: 1, stats: false, + trigger: null, encodeKey: function encodeKey (record) { const key = [record.id] return collection1_key.encode(key) @@ -130,9 +132,8 @@ const index0 = { name: '@db/members-by-age', id: 2, stats: false, - encodeKeys: function encodeKeys (record) { - const key = [record.age, record.id] - return [index0_key.encode(key)] + encodeKeys: function encodeKeys (record, context) { + return [index0_key.encode([record.age, record.id])] }, encodeKeyRange: function encodeKeyRange ({ gt, lt, gte, lte } = {}) { return index0_key.encodeRange({ diff --git a/test/fixtures/generated/2/hyperdb/messages.js b/test/fixtures/generated/2/hyperdb/messages.js index 153e5ff..b9b9a9b 100644 --- a/test/fixtures/generated/2/hyperdb/messages.js +++ b/test/fixtures/generated/2/hyperdb/messages.js @@ -1,9 +1,9 @@ // This file is autogenerated by the hyperschema compiler -// Schema Version: 2 +// Schema Version: 1 /* eslint-disable camelcase */ /* eslint-disable quotes */ -const VERSION = 2 +const VERSION = 1 const { c } = require('hyperschema/runtime') // eslint-disable-next-line no-unused-vars @@ -61,8 +61,8 @@ const encoding2 = { }, decode (state) { const res = {} - if (version >= 2) res.id = 0 - if (version >= 2) res.count = 0 + res.id = 0 + res.count = 0 res.id = c.uint.decode(state) res.count = c.uint.decode(state) @@ -81,7 +81,7 @@ const encoding3 = { }, decode (state) { const res = {} - if (version >= 2) res.count = 0 + res.count = 0 res.count = c.uint.decode(state)