const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; module.exports = Self => { Self.remoteMethod('getLeaves', { description: 'Returns the first shipped and landed possible for params', accepts: [{ arg: 'parentFk', type: 'Number', default: 1, required: false, }, { arg: 'filter', type: 'Object', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', http: {source: 'query'} }], returns: { type: ['object'], root: true }, http: { path: `/getLeaves`, verb: 'GET' } }); Self.getLeaves = async(parentFk = 1, filter) => { let conn = Self.dataSource.connector; let stmt = new ParameterizedSQL( `SELECT child.id, child.name, child.lft, child.rgt, child.depth, child.sons FROM department parent JOIN department child ON child.lft > parent.lft AND child.rgt < parent.rgt AND child.depth = parent.depth + 1 WHERE parent.id = ?`, [parentFk]); // Get nodes from depth greather than Origin stmt.merge(conn.makeSuffix(filter)); const nodes = await Self.rawStmt(stmt); if (nodes.length == 0) return nodes; // Get parent nodes const minorDepth = nodes.reduce((a, b) => { return b < a ? b : a; }).depth; const parentNodes = nodes.filter(element => { return element.depth === minorDepth; }); const leaves = Object.assign([], parentNodes); nestLeaves(leaves); function nestLeaves(elements) { elements.forEach(element => { let childs = Object.assign([], getLeaves(element)); if (childs.length > 0) { element.childs = childs; nestLeaves(element.childs); } }); } function getLeaves(parent) { let elements = nodes.filter(element => { return element.lft > parent.lft && element.rgt < parent.rgt && element.depth === parent.depth + 1; }); return elements; } return leaves; }; };