@digigov-oss/auditrecord-couchdb-engine
Version:
CouchDB storage database for use with audit mechanism of GSIS
164 lines (163 loc) • 5.43 kB
JavaScript
import Nano from "nano";
/**
* @description AuditEngine implementation
* @note This class is used to implement the methods that must be implemented by the AuditEngine
* @class CouchDBEngine
* @implements AuditEngine
* @param {string} connectionString - connect to db via connection string `http://user:pass@$dbHost:dbPort`
* @param {DatabaseSettings} dbSettings - database settings (please note the tableName is actualy a DB name for couchdb)
*/
export class CouchDBEngine {
#dbname;
#connection;
#client;
#pnreset;
async couch() {
const nano = Nano(this.#connection);
const dbList = await nano.db.list(); // list all databases
try {
if (!dbList.includes(this.#dbname)) {
// create a new DB if database doesn't exist.
await nano.db.create(this.#dbname);
const db = nano.use(this.#dbname);
console.log("database created successfully");
return db;
}
else {
const db = nano.use(this.#dbname);
return db;
}
}
catch (err) {
throw new Error(err);
}
}
;
/**
* @description constructor
* @param {string} connectionString - connect to couchdb via connection string
* @param {DatabaseSettings} settings - settings for the database
* @memberof CouchDBEngine
*/
constructor(connectionString = "", dbSettings = {}, pnreset = "innumerable") {
this.#connection = connectionString != "" ? connectionString : "http://admin:admin@localhost:5984";
this.#dbname = dbSettings.tableName || "audit_records"; //this is actualy a DB name
const init = async () => {
return await this.couch();
};
this.#client = init();
this.#pnreset = pnreset;
}
/**
* @description Store a record in the database
* @param {AuditRecord} record - record to be stored
* @returns {AuditRecord} - the record stored
* @memberof FileEngine
* @method put
*/
put(record) {
return this.#client.then(async (db) => {
try {
const doc = {
_id: record.auditTransactionId,
...record
};
const _rdoc = await db.insert(doc);
return record;
}
catch (error) {
throw error;
}
});
}
/**
* @description Get a record from the database
* @param auditTransactionId: string - transaction id
* @returns {AuditRecord}
* @memberof FileEngine
* @method get
*/
get(auditTransactionId) {
return this.#client.then(async (db) => {
try {
const rdoc = await db.get(auditTransactionId);
return rdoc;
}
catch (error) {
throw error;
}
});
}
/**
* @description Generate a new sequence number
* @param path
* @returns number
* @memberof CouchDBEngine
* @method seq
*/
seq() {
// from update_seq get the numeric part and add 1
return this.#client.then(async (db) => {
try {
const rdoc = await db.info();
//get integer part from 1-xxxx
const seq = parseInt(rdoc.update_seq.split("-")[0]);
return seq + 1;
}
catch (error) {
throw error;
}
});
}
/**
* @description Generate a new protocol number
* @param path
* @returns string
* @memberof CouchDBEngine
* @method protocol
*/
pn() {
return this.#client.then(async (db) => {
const pnreset = this.#pnreset;
try {
let protocol_split = "aion";
let protocol_date = new Date().toISOString().split('T')[0];
switch (pnreset) {
case "daily":
protocol_split = protocol_date;
break;
case "monthly":
protocol_split = protocol_date.split('-')[0] + "-" + protocol_date.split('-')[1];
break;
case "yearly":
protocol_split = protocol_date.split('-')[0];
break;
case "innumerable":
protocol_split = "aion";
break;
}
//Create indexes based on pnreset daily, monthly, yearly, innumerable
const seqName = "prot_" + protocol_split.replace(/-/g, '');
//create document in couchdb
let doc = {
_id: seqName,
rev: "1"
};
//get the document
try {
doc = await db.get(seqName);
}
catch (error) {
//document doesn't exist
}
doc = await db.insert(doc);
const protocol = parseInt(doc['rev'].split("-")[0]);
return protocol + "/" + protocol_date;
}
catch (error) {
throw error;
}
});
}
}
export default CouchDBEngine;