sharp-db
Version:
Classes for running SQL and building select queries for MySQL in Node
145 lines (137 loc) • 3.93 kB
JavaScript
const Db = require('../Db/Db.js');
const Select = require('../Select/Select.js');
/**
* Class for working with real data in unit tests
*/
class DataBroker {
/**
* Create a new data broker
* @param {Db} db The database to read/write into
*/
constructor(db = null) {
/**
* The database to read/write to
* @type {Db}
*/
this.db = db || Db.factory();
/**
* The current date
* @type {Date}
*/
this.now = new Date();
/**
* A unique id suitable for a unit test
* @type {String}
*/
this.uniqid = Math.random().toString(36).slice(2);
/**
* Arrays of deleted indexed by table name
* @type {Object}
*/
this.deleted = {};
/**
* Arrays of newly inserted ids indexed by table name
* @type {Object}
*/
this.ids = {};
}
/**
* Insert records that can be cleaned up later
* @param {String} table The name of the table to insert into
* @param {Object} values The record to insert
* @param {Object} options Additional options
* @property {Array} options.compositeKey An array of column names that form a composite key
* @returns {Promise<Number|Object>} Resolves with the id of the new record or the composite key
*/
async insert(table, values, options = {}) {
const { insertId } = await this.db.insertInto(table, values);
if (!Array.isArray(this.ids[table])) {
this.ids[table] = [];
}
if (Array.isArray(options.compositeKey)) {
const composite = {};
for (const column of options.compositeKey) {
composite[column] = values[column];
}
this.ids[table].push(composite);
return composite;
} else {
this.ids[table].push(insertId);
return insertId;
}
}
/**
* Delete records that can be re-inserted later
* @param {String} table The name of the table to delete from
* @param {Object} criteria The criteria to match the records
* @returns {Promise<Object[]>} An array of all the records
*/
async delete(table, criteria) {
const query = Select.init(this.db);
query.table(table);
query.where(criteria);
const { results: recordset } = await query.fetch();
await this.db.deleteFrom(table, criteria);
if (!Array.isArray(this.deleted[table])) {
this.deleted[table] = [];
}
this.deleted[table].push(...recordset);
return recordset;
}
/**
* Delete insertions and restore deleted
* @returns {Promise<Number>} The total number of rows affected
*/
async cleanup() {
// cleanup inserted records
let totalAffectedRows = 0;
for (const table of Object.keys(this.ids)) {
for (const idOrCompositeKey of this.ids[table]) {
const where =
typeof idOrCompositeKey === 'number'
? { id: idOrCompositeKey }
: idOrCompositeKey;
const { affectedRows } = await this.db.deleteFrom(table, where, 1);
totalAffectedRows += affectedRows;
}
}
// re-insert deleted records
this.ids = {};
for (const table of Object.keys(this.deleted)) {
const { affectedRows } = await this.db.insertExtended(
table,
this.deleted[table]
);
totalAffectedRows += affectedRows;
}
this.deleted = {};
return totalAffectedRows;
}
/**
* Get value for createdAt, createdBy, modifiedAt and modifiedBy
* @param {Number} userId The user id to use for createdBy and modifiedBy
* @returns {{createdAt: Date, createdBy: Number, modifiedAt: Date, modifiedBy: Number}}
*/
createdAndModified(userId = 0) {
return {
createdAt: this.now,
createdBy: userId,
modifiedAt: this.now,
modifiedBy: userId,
};
}
/**
* Get value for created_at, created_by, modified_at and modified_by
* @param {Number} userId The user id to use for created_by and modified_by
* @returns {{modified_by: Number, created_at: Date, modified_at: Date, created_by: Number}}
*/
created_and_modified(userId = 0) {
return {
created_at: this.now,
created_by: userId,
modified_at: this.now,
modified_by: userId,
};
}
}
module.exports = DataBroker;