UNPKG

@kothique/moleculer-rethinkdbdash

Version:

Moleculer service ensuring specified dbs, tables, and indices exist, and giving access to the driver.

131 lines (109 loc) 4.87 kB
'use strict'; const Promise = require('bluebird'); const r = require('rethinkdbdash'); const _ = require('lodash'); const { MoleculerClientError } = require('moleculer').Errors; /** * Service mixin to access `rethinkdbdash` driver. */ module.exports = { r: null, rTable: null, async created() { this.r = r({ silent: true, /* All logs are automatically forwarded to the service logger. This can be easily overrided. */ log: message => this.logger.debug(message), ...this.schema.rOptions }); const createdIndices = {}; if (this.schema.rInitial) { if (!_.isFunction(this.schema.rInitial) && !_.isObject(this.schema.rInitial)) { throw new MoleculerClientError('Expected this.rInitial to be a function or an object.', null, 'ERR_INVALID_R_INITIAL'); } const rInitial = _.isFunction(this.schema.rInitial) ? this.schema.rInitial(this.r) : this.schema.rInitial; if (_.isFunction(this.schema.rInitial) && !_.isObject(rInitial)) { throw new MoleculerClientError('Expected this.rInitial(r) to return an object.', null, 'ERR_INVALID_R_INITIAL_RESULT'); } const dbNames = await this.r.dbList(); await Promise.all(Object.keys(rInitial).map(async dbName => { const dbInitial = rInitial[dbName]; createdIndices[dbName] = {}; if (!dbNames.includes(dbName)) { try { await this.r.dbCreate(dbName); this.logger.debug(`Created DB: '${dbName}'.`); } catch (error) { if (error.name !== 'ReqlOpFailedError') { throw error; } } } if (dbInitial !== true && !_.isObject(dbInitial)) { throw new MoleculerClientError(`Expected this.rInitial.${dbName} to be true or an object.`, null, 'ERR_INVALID_DB_INITIAL'); } if (dbInitial === true) { return; } // Skip creating tables and indices const tableNames = await this.r.db(dbName).tableList(); await Promise.all(Object.keys(dbInitial).map(async tableName => { if (tableName.startsWith('$')) { return; } const tableInitial = dbInitial[tableName]; createdIndices[dbName][tableName] = []; if (tableInitial !== true && !_.isObject(tableInitial)) { throw new MoleculerClientError(`Expected this.rInitial.${dbName}.${tableName} to be true or an object.`, null, 'ERR_INVALID_TABLE_INITIAL'); } if (!tableNames.includes(tableName)) { try { await this.r.db(dbName).tableCreate(tableName, tableInitial.$options); this.logger.debug(`Created${tableInitial.$default ? ' default' : ''} table: ${dbName}.${tableName}`, { options: tableInitial.$options }); } catch (error) { if (error.name !== 'ReqlOpFailedError') { throw error; } } } if (tableInitial.$default === true) { this.rTable = this.r.db(dbName).table(tableName); } if (tableInitial === true) { return; } // Skip creating indices const indexNames = await this.r.db(dbName).table(tableName).indexList(); await Promise.all(Object.keys(tableInitial).map(async indexName => { if (indexName.startsWith('$')) { return; } const indexInitial = tableInitial[indexName]; if (tableInitial !== true && !_.isObject(tableInitial)) { throw new MoleculerClientError(`Expected this.rInitial.${dbName}.${tableName}.${indexName} to be true or an object.`, null, 'ERR_INVALID_INDEX_INITIAL'); } if (!indexNames.includes(indexName)) { try { await this.r.db(dbName).table(tableName).indexCreate( indexName, ...indexInitial.$function ? [indexInitial.$function] : [], ...indexInitial.$options ? [indexInitial.$options] : [] ); createdIndices[dbName][tableName].push(indexName); this.logger.debug(`Created index: ${dbName}.${tableName}.${indexName}`, { options: indexInitial.$options }); } catch (error) { if (error.name !== 'ReqlOpFailedError') { throw error; } } } })); })); })); } if (_.isFunction(this.schema.rOnReady)) { /* Wait for indices to be created. */ await Promise.all(Object.keys(createdIndices).map(dbName => Promise.all(Object.keys(createdIndices[dbName]).map(tableName => this.r.db(dbName).table(tableName).indexWait(...createdIndices[dbName][tableName]) )) )); this.schema.rOnReady.call(this); } } };