Source: core/get_traceability_matrix.js

/*
 * This file is part of PKM (Persistent Knowledge Monitor).
 * Copyright (c) 2020 Capgemini Group, Commissariat à l'énergie atomique et aux énergies alternatives,
 *                    OW2, Sysgo AG, Technikon, Tree Technology, Universitat Politècnica de València.
 * 
 * PKM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation.
 * 
 * PKM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with PKM.  If not, see <https://www.gnu.org/licenses/>.
 */

/**
 * Get Traceability Matrix Documents
 * 
 * @memberof PKM
 * @instance
 * @param {string} dbName - database name
 * @param {string} [query] - query
 * @param {Object} [options] - options
 * 
 * @return {Promise.<Array<Object> >} a promise
 */
function get_traceability_matrix(dbName, query = {}, options = {})
{
	return new Promise(async function(resolve, reject)
	{
		const debug = this.debug;
		const collection_name = 'TraceabilityMatrix';
		this.get_collection(dbName, collection_name).then(async (documents_collection) =>
		{
			let find_options = Object.assign({}, options);
			delete delete find_options.rowRole;
			if(options.skip !== undefined) delete find_options.skip;
			if(options.limit !== undefined) delete find_options.limit;
			
			let transposed_matrix;
			switch(options.rowRole)
			{
				case 'target':
					transposed_matrix = true;
					break;
				case 'source':
					transposed_matrix = false;
					break;
				default:
					reject(this.BadRequest('rowRole shall be target or source'));
			}
			
			// ask MongoDB to sort cells in ascending order
			find_options.sort = transposed_matrix ? { tgt_path : 1, tgt_access : 1, src_path : 1, src_access : 1 }
																						: { src_path : 1, src_access : 1, tgt_path : 1, tgt_access : 1 };
			
			let document_cursor = documents_collection.find(query, find_options);
			
			let documents = [];
			let row = 0;
			let col = 0;
			let last_document;
			let error;
			
			// scan cells
			while(await document_cursor.hasNext().catch((err) => { error = err }))
			{
				// get cell
				const document = await document_cursor.next().catch((err) => { error = err });
				
				if(error !== undefined) break;
				
				// detect row change, and compute row and column numbers
				if(last_document !== undefined)
				{
					if((transposed_matrix && ((document.tgt_path != last_document.tgt_path) || (document.tgt_access != last_document.tgt_access))) ||
						(!transposed_matrix && ((document.src_path != last_document.src_path) || (document.src_access != last_document.src_access))))
					{
						++row;
						col = 0;
					}
					else
					{
						++col;
					}
				}
				
				// stop scanning cells as soon as enough cells have been collected
				if((options.toRow !== undefined) && ((row > options.toRow) || ((options.toColumn !== undefined) && (row == options.toRow) && (col > options.toColumn))))
				{
					break;
				}
				
				// filter cells
				if(((options.fromRow === undefined) || (row >= options.fromRow)) &&
						((options.fromColumn === undefined) || (col >=  options.fromColumn)) &&
						((options.toColumn === undefined) || (col <= options.toColumn)))
				{
					// add cell
					
					// For debugging, uncomment lines below
					// document.row = row;
					// document.col = col;
					// document.transposed_matrix = transposed_matrix;
					documents.push(this.fix_document(document, collection_name));
				}
				
				last_document = document;
			}
			
			if(error !== undefined)
			{
				reject(this.Error(error));
			}
			else
			{
				resolve(documents);
			}
		}).catch((err) =>
		{
			reject(this.Error(err));
		});
	}.bind(this));
}

exports.get_traceability_matrix = get_traceability_matrix;