UNPKG

@ocap/statedb-qldb

Version:

OCAP statedb adapter that uses amazon qldb as backend statedb

103 lines (83 loc) 3.27 kB
/* eslint-disable no-underscore-dangle */ const { StateDBTable } = require('@ocap/statedb'); const omit = require('lodash/omit'); const debug = require('debug')(require('../../package.json').name); class QLDBTable extends StateDBTable { constructor(name, driver, uniqIndex) { super(); this.name = name; this.driver = driver; this.uniqIndex = uniqIndex; this.indexes = []; } // TODO: we should support get record history: // - https://docs.aws.amazon.com/qldb/latest/developerguide/working.metadata.html // - https://docs.aws.amazon.com/qldb/latest/developerguide/working.history.html initialize() { return this.driver.executeLambda(async (txn) => { await txn.execute(`CREATE TABLE ${this.name}`); await txn.execute(`CREATE INDEX ON ${this.name} (${this.uniqIndex})`); for (let i = 0; i < this.indexes.length; i++) { // eslint-disable-next-line no-await-in-loop await txn.execute(`CREATE INDEX ON ${this.name} ("${this.indexes[i]}")`); } debug('create table and index', { name: this.name, index: this.uniqIndex }); this.markReady(); }); } async _create(key, attrs, { txn }) { const data = { [this.uniqIndex]: key, ...attrs }; debug(`insert ${this.name}`, data); const result = await txn.execute(`INSERT INTO ${this.name} ?`, data); debug(`insert ${this.name}`, key, result.getResultList()); return data; } async _get(key, { txn }) { if (!key) { return null; } const result = await txn.execute(`SELECT * FROM ${this.name} WHERE ${this.uniqIndex} = ?`, key); const item = result.getResultList().shift(); return item ? JSON.parse(JSON.stringify(item)) : null; } async _history(key, { txn }) { if (!key) { return []; } const metaResult = await txn.execute( `SELECT metadata FROM _ql_committed_${this.name} WHERE data.${this.uniqIndex} = ?`, key ); const item = metaResult.getResultList().shift(); if (!item) { return []; } const { metadata } = JSON.parse(JSON.stringify(item)); // TODO: since qldb does not support pagination, we may hit timeout here before retrieved all data const historyResult = await txn.execute(`SELECT * FROM history(${this.name}) WHERE metadata.id = ?`, metadata.id); return historyResult.getResultList().map((x) => JSON.parse(JSON.stringify(x))); } async _update(key, updates, { txn }) { // Each time we are doing an override const data = { [this.uniqIndex]: key, ...updates }; debug(`update ${this.name}`, data); const result = await txn.execute(`UPDATE ${this.name} AS t SET t = ? WHERE ${this.uniqIndex} = ?`, data, key); debug(`update ${this.name}`, key, result.getResultList()); return data; } async _reset({ txn }) { if (process.env.CI) { await txn.execute(`DELETE FROM ${this.name}`); } } updateOrCreate(exist, state, ctx) { if (!state[this.uniqIndex]) { throw new Error('Cannot update or create without uniq index'); } if (exist) { return this.update(state[this.uniqIndex], omit(state, [this.uniqIndex]), ctx); } return this.create(state[this.uniqIndex], omit(state, [this.uniqIndex]), ctx); } } module.exports = QLDBTable;