CerberusMVC Documentation

Model


Models within the system extend from the base model class, give the ability to abstract your database through inherited basic functions, transactions and also allow you to override and build on this in the individual models themselves. Use the basic built in methods, map data on inserts, get, find, updated, insert, delete and more. Want something a little more specific or want to change a base function, roll your own.

Each model connects to a table or not, allowing you to create table models or abstract models. Access the bas knex method through this.db to perform advanced functionaility.

Base class methods inherited...

  • db() - the knex method
  • model() - the knex method wrapped to this table
  • get(id) - get a row by id, return a single row
  • find(where) - get rows based on object containing keys and values
  • all() - get all rows
  • transaction(func) - generate a transaction as per knex
  • insert(data, returning) - insert data and stipulate return data for inserted row
  • transactInsert(trx, data, returning) - as above but pass in transaction
  • update(where, data, returning) - update rows and return data
  • transactUpdate(trx, where, data, returning) - as above but pass in transaction as per knex
  • delete(id) - delete a row based on id
  • softDelete(id) - soft delete, flags a deleted column with timestamp
  • softRestore(id) - unflags a soft deleted data
  • mapDataToColumn(data, partial) - uses the columns getter in the model to check data before inserting/updating checking required and removing anything else
  • mapDataArrayToColumn(data, partial) - as above but takes an array of data to map

Abstract model (no table)

Constructor connects to db but not table (no this.model as no table, use this.db)

'use strict';

const Model = require('cerberus-mvc/Base/Model');

/**
 * @namespace API/Model/Health
 * @class Health
 * @extends Model
 * @description Model class for checking system health
 * @author Paul Smith (ulsmith)  
 * @copyright 2020 Paul Smith (ulsmith) all rights reserved
 * @license MIT
 */
class Health extends Model {

	/**
	 * @public @method constructor
	 * @description Base method when instantiating class
	 */
	constructor () {
		super('db_name');
	}

    /**
     * @public @method health
     * @description Ping the db to check availability
     * @return Promise a response from db service
     */
	getHealth() {
		return this.db.raw("SELECT 'healthy' AS status").then((data) => data.rows[0]);
	}
}

module.exports = Health;

Table model

Contructor takes database and table properties, extended class adds new method.

'use strict';

const Model = require('cerberus-mvc/Base/Model');
const SystemError = require('cerberus-mvc/Error/System');
const Crypto = require('cerberus-mvc/Library/Crypto');

const UserIdentityModel = require('../../../Model/DBName/Identity/UserIdentity.js');
const UserAccountModel = require('../../../Model/DBName/Identity/UserAccount.js');
const UserGroupModel = require('../../../Model/DBName/Identity/UserGroup.js');

/**
 * @namespace API/Model/Identity
 * @class User
 * @extends Model
 * @description Model class for identity.user table
 * @author Paul Smith (ulsmith)  
 * @copyright 2020 Paul Smith (ulsmith) all rights reserved
 * @license MIT
 */
class User extends Model {

	/**
	 * @public @method constructor
	 * @description Base method when instantiating class
	 */
	constructor () {
		super('db_name', 'identity.user');
	}

    /**
	 * @public @get @method columns
	 * @description Columns that we allow to be changed through requests to API
     * @return {Object} The columns data that are accessable
     */
	get columns() {
		return {
			active: { type: 'boolean', required: false, description: 'User is active' },
			name: { type: 'string', required: true, description: 'Full user name' },
			type: { type: 'enum[client][advisor][provider][admin]', required: true, description: 'User type' }
		};
	}

	/**
	 * @public @method getDetails
	 * @description Get details for all users
     * @param {Object} conditions The conditions to alter the data with e.g {limit: ..., offset: ..., order:..., direction:... }
     * @return {Promise} a resulting promise of data or error on failure
     */
	getAllDetails(conditions) {
		let query = this.db
			.select(
				'user.*',
				'user_account.id AS user_account_id',
				'user_account.ip_address AS user_account_ip_address',
				'user_account.user_agent AS user_account_user_agent',
				'user_account.login_current AS user_account_login_current',
				'user_account.login_previous AS user_account_login_previous',
				'user_identity.id AS user_identity_id',
				'user_identity.identity AS user_identity_identity',
				'user_identity.type AS user_identity_type',
				'user_identity.primary AS user_identity_primary',
				'organisation.id AS organisation_id',
				'organisation.name AS organisation_name'
			)
			.from('identity.user')
			.leftJoin('identity.user_account', 'user.id', 'user_account.user_id')
			.leftJoin('identity.user_identity', 'user.id', 'user_identity.user_id')
			.leftJoin('identity.user__department', 'user.id', 'user__department.user_id')
			.leftJoin('identity.organisation', 'user__department.department_organisation_id', 'organisation.id')
		
		if (conditions && conditions.limit) query = query.limit(Number(conditions.limit));
		if (conditions && conditions.offset) query = query.offset(Number(conditions.offset));
		console.log(22, conditions.order, conditions.direction);
		if (conditions && conditions.order) query = query.orderBy(conditions.order, conditions.direction || 'asc');

		return query.then((rows) => {
				if (rows.length < 1) [];

				let users = {};
				let ui_ids = [];
				let org_ids = [];
				for (let row of rows) {
					if (!users[row.id]) users[row.id] = { id: row.id, name: row.name, type: row.type, active: row.active, user_identity: [], organisation: [] };

					if (row.user_account_id) {
						users[row.id].user_account = {
							id: row.user_account_id,
							ipAddress: row.user_account_ip_address,
							userAgent: row.user_account_user_agent,
							loginCurrent: row.user_account_login_current,
							loginPrevious: row.user_account_login_previous
						};
					}
					
					if (row.user_identity_id && ui_ids.indexOf(row.user_identity_id) < 0) {
						users[row.id].user_identity.push({ id: row.user_identity_id, identity: row.user_identity_identity, type: row.user_identity_type, primary: row.user_identity_primary });
						ui_ids.push(row.user_identity_id);
					}

					if (row.organisation_id && org_ids.indexOf(row.organisation_id) < 0) {
						users[row.id].organisation.push({ id: row.organisation_id, name: row.organisation_name });
						ui_ids.push(row.organisation_id);
					}
				}

				return Object.values(users);
			});
	}
}

module.exports = User;