Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 127 additions & 26 deletions lib/business/business-base.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ const filterFields = {
ModifiedByUser: "Modified_"
}

const OperationMode = {
load: 'load',
list: 'list',
lookupList: 'lookupList',
};

const dateTypeFields = ["date", "dateTime"];

const IsDeletedColumn = "IsDeleted";
Expand Down Expand Up @@ -254,17 +260,33 @@ class BusinessBase {
return BusinessBase.businessObject.sql.createRequest(this.logger);
}

createWhere({ alias = "Main", filterDeleted = true } = {}) {
/**
* Generates a WHERE clause object based on the current business object's configuration and optional parameters.
* @param {Object} [options]
* @param {string} [options.alias="Main"] - The alias to use for table references in the WHERE clause.
* @param {boolean} [options.isStandard] - When true, apply soft-delete filtering (IsDeleted = 0) if enabled.
* @returns {Promise<Object>} A WHERE clause object that can be passed to sql.addParameters({ forWhere: true }).
*/
Comment thread
durlabhjain marked this conversation as resolved.
async createWhere({ alias = "Main", ...options } = {}) {
const where = {};
if (this.clientBased && this.user.scopeId) {
where[`${alias}.ClientId`] = this.user.scopeId;
}
if (filterDeleted && this.softDelete !== false) {
if (options.isStandard && this.softDelete !== false) {
where[`${alias}.IsDeleted`] = 0;
}
if (typeof this.customizeWhere === 'function') {
await this.customizeWhere({ where, alias, ...options });
}
Comment thread
durlabhjain marked this conversation as resolved.
return where;
}

/**
* customizeWhere - Optional hook for customizing the WHERE clause in SQL queries.
* @param {Object} param0 - An object containing the current WHERE clause, alias, and additional options.
* @returns {Promise<void>} A promise that resolves when the customization is complete.
*/

Comment thread
durlabhjain marked this conversation as resolved.
pluralize(str) {
return str + 's';
}
Expand All @@ -278,7 +300,7 @@ class BusinessBase {

let query = this.getSelectStatement();

const where = await this.createWhere({ filterDeleted: this.standardTable });
const where = await this.createWhere({ isStandard: this.standardTable, operationMode: OperationMode.load });
Comment thread
durlabhjain marked this conversation as resolved.
where[keyField] = id;
const request = this.createRequest();

Expand Down Expand Up @@ -620,8 +642,20 @@ class BusinessBase {
return await sql.insertUpdate({ tableName: this.getTableName(), keyField, id, json: values, update: true, logger: this.logger });
}

getListStatement() {
return this.listStatement || (this.standardTable && this.useView !== false ? `SELECT * FROM vw${this.getTableName()}List Main` : this.getSelectStatement());
async getListStatement(listParameters) {
const listStatement = this.listStatement || (this.standardTable && this.useView !== false ? `SELECT * FROM vw${this.getTableName()}List Main` : this.getSelectStatement());
const isStandard = this.standardTable === true && listStatement.indexOf("vw") === -1;
return { listStatement, isStandard };
}

normalizeListStatement(result) {
if(typeof result === 'string') {
return {
listStatement: result,
isStandard: this.standardTable === true && result.indexOf("vw") === -1
}
}
return result;
Comment thread
durlabhjain marked this conversation as resolved.
}

async lookupList({ scopeId }) {
Expand All @@ -634,8 +668,20 @@ class BusinessBase {
}
const sql = BusinessBase.businessObject.sql;

let listStatement = this.getListStatement();
const isStandard = this.standardTable === true && listStatement.indexOf("vw") === -1;
let { listStatement, isStandard } = this.normalizeListStatement(
await this.getListStatement({
scopeId,
operationMode: OperationMode.lookupList,
keyField,
lookupSortOrder,
defaultSortOrder,
displayField,
clientBased,
lookupListStatement,
tableName,
sort
})
);
const labelField = displayField || sort || this.sort;
if (!labelField) {
this.logger.error('No displayField or sort field defined for lookupList label.');
Expand All @@ -644,7 +690,7 @@ class BusinessBase {
listStatement = listStatement.replace(/^.+ FROM/i, `SELECT [${keyField}] value, [${labelField}] label FROM `);

let query = listStatement;
const where = await this.createWhere({ filterDeleted: isStandard, tableName });
const where = await this.createWhere({ isStandard, tableName, operationMode: OperationMode.lookupList });
if (!clientBased && scopeId) {
where.ScopeId = scopeId;
}
Expand All @@ -660,7 +706,23 @@ class BusinessBase {
return result.recordset;
}

async list({ start = 0, limit = 100, sort, filter, groupBy, include, exclude, returnCount = true }) {
/**
* addAdditionalColumns - Optional hook for adding custom JOINs and columns to the list SQL statement.
* @param {Object} param0 - An object containing the current SQL statement, request, and additional parameters for context.
* @returns {Promise<Object>} An object that can include a modified listStatement and an array of additionalColumns to be added to the SELECT clause.
*/

/**
* customizeList - Optional hook for customizing the list results
* @param {Object} param0 - An object containing the current SQL statement, request, and additional parameters for context.
* @returns {Promise<void>} A promise that resolves when the customization is complete.
*/

/**
* List records with optional hooks for extensibility
* Supports hooks: customizeWhere, addAdditionalColumns,customizeList
*/
Comment thread
durlabhjain marked this conversation as resolved.
async list({ start = 0, limit = 100, sort, filter, groupBy, include, exclude, returnCount = true, ...options }) {
sort = sort || this.defaultSortOrder;
const request = this.createRequest();
const { keyField } = this;
Expand All @@ -669,9 +731,31 @@ class BusinessBase {
let totalStatement = "SELECT COUNT(1) AS TotalCount";

const { relations = [] } = this;
let listStatement = this.getListStatement();
const isStandard = this.standardTable === true && listStatement.indexOf("vw") === -1;

const hookParameters = {
...options,
sql,
request,
keyField,
start,
limit,
sort,
filter,
groupBy,
include,
exclude,
returnCount,
relations,
operationMode: OperationMode.list
};

let { listStatement, isStandard } = this.normalizeListStatement(await this.getListStatement(hookParameters));
const isDataFromView = listStatement.indexOf("vw") > -1;

hookParameters.listStatement = listStatement;
hookParameters.isStandard = isStandard;
hookParameters.isDataFromView = isDataFromView;

const additionalColumns = [];
if (isStandard) {
listStatement += '\r\n LEFT OUTER JOIN (SELECT UserId Created_UserId, UserName as CreatedByUser FROM Security_User) Created_ ON Created_.Created_UserId = Main.CreatedByUserId'
Expand All @@ -697,12 +781,27 @@ class BusinessBase {

}
}

// Hook: addAdditionalColumns - Allow adding custom JOINs and columns
if (typeof this.addAdditionalColumns === 'function' ) {
const result = await this.addAdditionalColumns(hookParameters);
Comment thread
durlabhjain marked this conversation as resolved.

if (result) {
listStatement = result.listStatement || listStatement;
if (result.additionalColumns && result.additionalColumns.length > 0) {
additionalColumns.push(...result.additionalColumns);
}
}
}

if (additionalColumns.length > 0) {
listStatement = listStatement.replace(/ from /i, ', ' + additionalColumns.join(', ') + ' FROM ');
}

let query = listStatement;
const where = this.createWhere({ filterDeleted: isStandard });
hookParameters.listStatement = listStatement;
const where = await this.createWhere(hookParameters);
let query = hookParameters.listStatement;

if (typeof include === 'string') {
include = include.split(',').map(item => Number(item));
}
Expand Down Expand Up @@ -782,25 +881,27 @@ class BusinessBase {

const result = await request.query(query);

if (returnCount) {
let recordCount;
const listResult = {
records: result.recordset
};

if (returnCount) {
if (limit > 0) {
recordCount = result.recordsets[1][0].TotalCount;
listResult.recordCount = result.recordsets[1][0].TotalCount;
} else {
recordCount = result.rowsAffected[0];
listResult.recordCount = result.rowsAffected[0];
}
}

return {
records: result.recordset,
recordCount
}
} else {
return {
records: result.recordset
}
hookParameters.listResult = listResult;

// Hook: customizeList - Allow result post-processing
if (typeof this.customizeList === 'function') {
await this.customizeList(hookParameters);
}

return hookParameters.listResult;

}

static async handleMultiSelectValues({ multiSelectValues, multiSelectColumns, getTableName, keyField, id, user, sql, isUpdate, softDelete }) {
Expand Down Expand Up @@ -883,6 +984,6 @@ const classMap = {
}
};

export { RelationshipTypes, BusinessBase, classMap };
export { RelationshipTypes, BusinessBase, classMap, OperationMode };

export default BusinessBase;