Skip to content
Merged
Show file tree
Hide file tree
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
24 changes: 14 additions & 10 deletions src/controllers/v1/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ module.exports = class Entities extends Abstract {
}

/**
* @api {GET} v1/entities/subEntityList/663339bc0cb19f01c459853b?type=school&search=&page=1&limit=100&parentInfoRequired=true
* @api {GET} v1/entities/subEntityList/663339bc0cb19f01c459853b?type=school&search=&page=1&limit=100&parentInfoRequired=true&sortOrder=asc&sortKey=name
* Get sub entity list for the given entity.
* @apiVersion 1.0.0
* @apiGroup Entities
Expand Down Expand Up @@ -868,14 +868,16 @@ module.exports = class Entities extends Abstract {
}

/**
* Get the immediate entities .
* @method
* @name subEntityList
* @param {Request} req request body.
* @param {String} req.params._id - entityId
* @param {String} req.query.type - Entity Type
* @param {String} req.query.language - language Code
* @returns {JSON} Returns list of immediate entities
* Get the immediate entities .
* @method
* @name subEntityList
* @param {Request} req request body.
* @param {String} req.params._id - entityId
* @param {String} req.query.type - Entity Type
* @param {String} req.query.language - language Code
* @param {String} [req.query.sortOrder] - Sort order for results. Allowed values: 'asc'|'desc' (case-insensitive). If provided, 'sortKey' must also be provided.
* @param {String} [req.query.sortKey] - Sort key for results. Allowed values: 'name'|'externalId'. If provided, 'sortOrder' must also be provided.
* @returns {JSON} Returns list of immediate entities
*/

subEntityList(req) {
Expand All @@ -899,7 +901,9 @@ module.exports = class Entities extends Abstract {
req.pageNo,
req.query.language ? req.query.language : '',
req.userDetails,
req.query.parentInfoRequired ? req.query.parentInfoRequired : false
req.query.parentInfoRequired ? req.query.parentInfoRequired : false,
req?.query?.sortOrder,
req?.query?.sortKey
)
return resolve(entityDocuments)
} catch (error) {
Expand Down
134 changes: 74 additions & 60 deletions src/module/entities/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ module.exports = class UserProjectsHelper {
pageNo,
language,
userDetails,
parentInfoRequired = false
parentInfoRequired = false,
sortOrder = '',
sortKey = ''
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update function signature

) {
return new Promise(async (resolve, reject) => {
try {
Expand All @@ -249,13 +251,13 @@ module.exports = class UserProjectsHelper {
}
// Retrieve sub-entities using 'this.subEntities' for a single entity
if (entityId !== '') {
result = await this.subEntities(obj, language, tenantId)
result = await this.subEntities(obj, language, tenantId, sortOrder, sortKey)
} else {
// Retrieve sub-entities using 'this.subEntities' for multiple entities
await Promise.all(
entities.map(async (entity) => {
obj['entityId'] = entity
let entitiesDocument = await this.subEntities(obj, language, tenantId)
let entitiesDocument = await this.subEntities(obj, language, tenantId, sortOrder, sortKey)

if (Array.isArray(entitiesDocument.data) && entitiesDocument.data.length > 0) {
result = entitiesDocument
Expand Down Expand Up @@ -341,7 +343,6 @@ module.exports = class UserProjectsHelper {
// Process the results more efficiently
result.data = result.data.map((entity) => ({
...entity,
[entity.entityType]: entity.name,
label: entity.name,
value: entity._id,
...hierarchyLevels.reduce((entityTypeNameMap, entityType) => {
Expand Down Expand Up @@ -482,10 +483,12 @@ module.exports = class UserProjectsHelper {
* @name subEntities
* @param {body} entitiesData
* @param {String} tenantId
* @param {String} sortOrder
* @param {String} sortKey
* @returns {Array} - List of all immediate entities or traversal data.
*/

static subEntities(entitiesData, language, tenantId) {
static subEntities(entitiesData, language, tenantId, sortOrder = '', sortKey = '') {
return new Promise(async (resolve, reject) => {
try {
let entitiesDocument
Expand All @@ -499,7 +502,9 @@ module.exports = class UserProjectsHelper {
entitiesData.limit,
entitiesData.pageNo,
language,
tenantId
tenantId,
sortOrder,
sortKey
)
} else {
// Retrieve immediate entities
Expand Down Expand Up @@ -573,7 +578,16 @@ module.exports = class UserProjectsHelper {
})

if (Array.isArray(immediateEntitiesIds) && immediateEntitiesIds.length > 0) {
let searchImmediateData = await this.search(searchText, pageSize, pageNo, immediateEntitiesIds)
let searchImmediateData = await this.search(
searchText,
pageSize,
pageNo,
immediateEntitiesIds,
language,
tenantId,
sortOrder,
sortKey
)

immediateEntities = searchImmediateData[0]
}
Expand All @@ -596,10 +610,22 @@ module.exports = class UserProjectsHelper {
* @param {Number} pageNo - Page no.
* @param {String} searchText - Search Text.
* @param {String} tenantId - user's tenant id
* @param {String} sortOrder - Sort order key for sorting
* @param {String} sortKey - sort key for sorting
* @returns {Array} - List of all immediateEntities based on entityId.
*/

static entityTraversal(entityId, entityTraversalType = '', searchText = '', pageSize, pageNo, language, tenantId) {
static entityTraversal(
entityId,
entityTraversalType = '',
searchText = '',
pageSize,
pageNo,
language,
tenantId,
sortOrder = '',
sortKey = ''
) {
return new Promise(async (resolve, reject) => {
try {
let entityTraversal = `groups.${entityTraversalType}`
Expand All @@ -626,7 +652,9 @@ module.exports = class UserProjectsHelper {
pageNo,
entitiesDocument[0].groups[entityTraversalType],
language,
tenantId
tenantId,
sortOrder,
sortKey
)

result = entityTraversalData[0]
Expand All @@ -647,10 +675,12 @@ module.exports = class UserProjectsHelper {
* @param {Number} pageSize - total page size.
* @param {Number} pageNo - Page no.
* @param {String} tenantId - user's tenantId
* @param {String} sortOrder - Sort order key for sorting
* @param {String} sortKey - Sort key for sorting
* @param {Array} [entityIds = false] - Array of entity ids.
*/

static search(searchText, pageSize, pageNo, entityIds = false, language, tenantId) {
static search(searchText, pageSize, pageNo, entityIds = false, language, tenantId, sortOrder = '', sortKey = '') {
return new Promise(async (resolve, reject) => {
try {
let queryObject = {}
Expand All @@ -674,50 +704,36 @@ module.exports = class UserProjectsHelper {
}

let finalEntityDocuments = []
// Perform aggregation query to retrieve entity documents based on search criteria

if (!language || language == CONSTANTS.common.ENGLISH_LANGUGE_CODE) {
let entityDocuments = await entitiesQueries.getAggregate([
queryObject,
{
$project: {
name: '$metaInformation.name',
externalId: '$metaInformation.externalId',
addressLine1: '$metaInformation.addressLine1',
addressLine2: '$metaInformation.addressLine2',
entityType: 1,
},
},
{
$facet: {
totalCount: [{ $count: 'count' }],
data: [{ $skip: pageSize * (pageNo - 1) }, { $limit: pageSize }],
},
},
{
$project: {
data: 1,
count: {
$arrayElemAt: ['$totalCount.count', 0],
},
},
},
])

finalEntityDocuments.push(...entityDocuments)
} else {
let entityDocuments = await entitiesQueries.getAggregate([
queryObject,
{
$project: {
// name: '$translations.hi.name',
name: `$translations.${language}.name`,
externalId: '$metaInformation.externalId',
addressLine1: '$metaInformation.addressLine1',
addressLine2: '$metaInformation.addressLine2',
entityType: 1,
},
// check the language criteria is set to english or not
const isEnglish = !language || language === CONSTANTS.common.ENGLISH_LANGUGE_CODE
// construct the name expression based on language
const nameExpr = isEnglish ? '$metaInformation.name' : `$translations.${language}.name`
// create a query pipeline
let pipeline = [
queryObject,
{
$project: {
name: nameExpr,
externalId: '$metaInformation.externalId',
addressLine1: '$metaInformation.addressLine1',
addressLine2: '$metaInformation.addressLine2',
entityType: 1,
},
},
]
// check if sort is necessary
// added here because $sort is not allowed after $facet
if (sortOrder && sortKey) {
// Define sort order
sortOrder = sortOrder.toLowerCase() === 'desc' ? -1 : 1

// Create sort object dynamically
pipeline.push({ $sort: { [sortKey]: sortOrder } })
}
// append the remaining to pipeline
pipeline = [
...pipeline,
...[
{
$facet: {
totalCount: [{ $count: 'count' }],
Expand All @@ -727,15 +743,13 @@ module.exports = class UserProjectsHelper {
{
$project: {
data: 1,
count: {
$arrayElemAt: ['$totalCount.count', 0],
},
count: { $arrayElemAt: ['$totalCount.count', 0] },
},
},
])

finalEntityDocuments.push(...entityDocuments)
}
],
]
const entityDocuments = await entitiesQueries.getAggregate(pipeline)
finalEntityDocuments.push(...entityDocuments)

return resolve(finalEntityDocuments)
} catch (error) {
Expand Down
23 changes: 23 additions & 0 deletions src/module/entities/validator/v1.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,29 @@ module.exports = (req) => {
req.checkQuery('type').exists().withMessage('required type')
req.checkParams('_id').exists().withMessage('required _id')
req.checkParams('_id').exists().isMongoId().withMessage('Invalid Entity ID')

// Validate dependent sort query params: if one is present the other must be present
if (req.query && (req.query.sortOrder !== undefined || req.query.sortKey !== undefined)) {
// sortOrder must be present and either 'asc' or 'desc' (case-insensitive)
req.checkQuery('sortOrder')
.exists()
.withMessage('required sortOrder')
.custom((value) => {
if (typeof value !== 'string') return false
const v = value.toLowerCase()
return v === 'asc' || v === 'desc'
})
.withMessage("sortOrder must be one of 'asc' or 'desc'")

// sortKey must be present and one of 'name' or 'externalId'
req.checkQuery('sortKey')
.exists()
.withMessage('required sortKey')
.custom((value) => {
return value === 'name' || value === 'externalId'
})
.withMessage("sortKey must be one of 'name' or 'externalId'")
}
},
targetedRoles: function () {
req.checkParams('_id').exists().withMessage('The entity ID (_id) is required.')
Expand Down