Source: core/find_in_doc.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/>.
 */

/**
 * Find in Documentation
 * 
 * @memberof PKM
 * @instance
 * @param {string} dbName - database name
 * @param {Object} [query] - query
 * @param {Object} [options] - options
 * 
 * @return {Promise<Array.<Object>>} a promise
 */
function find_in_doc(dbName, query = {}, options = {})
{
	return new Promise(function(resolve, reject)
	{
		const member_keys = [ 'invariant', 'field', 'method', 'type', 'macro', 'constant' ];
		
		let get_doc_query = {};
		let get_doc_options;
		let search_query = {};
		let querying_member = false;
		
		const query_is_empty = Object.keys(query).length == 0;
		
		if(query.id !== undefined)
		{
			search_query.id = query.id;
		}
		
		if((query.id === undefined) &&
		   ((query.doc !== undefined) ||
		    (query.filename !== undefined) ||
		    (query.unit !== undefined) ||
		    (query.class !== undefined) ||
		    (query.invariant !== undefined) ||
		    (query.field !== undefined) ||
		    (query.method !== undefined) ||
		    (query.type !== undefined) ||
		    (query.macro !== undefined) ||
		    (query.member !== undefined)))
		{
			get_doc_options = Object.assign({}, options);
			if(get_doc_options.skip !== undefined) delete get_doc_options.skip;
			if(get_doc_options.limit !== undefined) delete get_doc_options.limit;
			
			get_doc_query.$and = [];
			
			if((query.doc !== undefined) || (query.filename !== undefined))
			{
				let get_doc_id_query = [];
				if((query.doc !== undefined) && query.doc.startsWith('/') && query.doc.endsWith('/'))
				{
					get_doc_id_query.push({ name : { $regex : query.doc.slice(1, query.doc.length - 1) } });
				}
				else
				{
					get_doc_id_query.push({ name : query.doc });
				}
				if((query.filename !== undefined) && query.filename.startsWith('/') && query.filename.endsWith('/'))
				{
					get_doc_id_query.push({ sourceFile : { $regex : query.filename.slice(1, query.filename.length - 1) } });
				}
				else
				{
					get_doc_id_query.push({ sourceFile : query.filename });
				}
				get_doc_query.$and.push(get_doc_id_query);
			}
			if(query.unit !== undefined)
			{
				if(query.unit.startsWith('/') && query.unit.endsWith('/'))
				{
					get_doc_query.$and.push({ 'units.name' : { $regex : query.unit.slice(1, query.unit.length - 1) } });
					search_query.unit = new RegExp(query.unit.slice(1, query.unit.length - 1));
				}
				else
				{
					get_doc_query.$and.push({ 'units.name' : query.unit });
					search_query.unit = query.unit;
				}
			}
			if(query.class !== undefined)
			{
				if(query.class.startsWith('/') && query.class.endsWith('/'))
				{
					get_doc_query.$and.push({ 'units.classes.name' : { $regex : query.class.slice(1, query.class.length - 1) } });
					search_query.class = new RegExp(query.class.slice(1, query.class.length - 1));
				}
				else
				{
					get_doc_query.$and.push({ 'units.classes.name' : query.class });
					search_query.class = query.class;
				}
			}
			if((query.invariant !== undefined) ||
			   (query.field !== undefined) ||
			   (query.method !== undefined) ||
			   (query.type !== undefined) ||
			   (query.macro !== undefined) ||
			   (query.member !== undefined))
			{
				querying_member = true;
				get_doc_member_query = [];
				member_keys.forEach((key) =>
				{
					if((query[key] !== undefined) || (query.member !== undefined))
					{
						let q = {};
						if(query.member !== undefined)
						{
							if(query.member.startsWith('/') && query.member.endsWith('/'))
							{
								q['units.classes.' + key + 's.name'] = { $regex : query.member.slice(1, query.member.length - 1) };
								search_query[key] = new RegExp(query.member.slice(1, query.member.length - 1));
							}
							else
							{
								q['units.classes.' + key + 's.name'] = query.member;
								search_query[key] = query.member;
							}
						}
						else if(query[key].startsWith('/') && query[key].endsWith('/'))
						{
							q['units.classes.' + key + 's.name'] = { $regex : query[key].slice(1, query[key].length - 1) };
							search_query[key] = new RegExp(query[key].slice(1, query[key].length - 1));
						}
						else
						{
							q['units.classes.' + key + 's.name'] = query[key];
							search_query[key] = query[key];
						}
						get_doc_member_query.push(q);
					}
				});
				get_doc_query.$and.push({ $or : get_doc_member_query });
			}
		}
		else
		{
			get_doc_options = options;
		}
		
		this.get_documents(dbName, 'Documentation', get_doc_query, get_doc_options).then((doc_documents) =>
		{
			if((search_query.id !== undefined) ||
			   (search_query.unit !== undefined) ||
			   (search_query.class !== undefined) ||
			   querying_member)
			{
				let result = [];
			
				doc_documents.forEach((doc_document) =>
				{
					if(Array.isArray(doc_document.units))
					{
						doc_document.units.forEach((unit) =>
						{
							if((search_query.id !== undefined) || 
							   (search_query.unit === undefined) ||                                               // match all
							   ((typeof search_query.unit === 'string') && (search_query.unit === unit.name)) ||  // match bare string
							   ((search_query.unit instanceof RegExp) && search_query.unit.test(unit.name)))      // match regular expression
							{
								if((search_query.id !== undefined) || (search_query.class !== undefined) || querying_member)
								{
									if(Array.isArray(unit.classes))
									{
										unit.classes.forEach((cls) =>
										{
											if((search_query.id !== undefined) ||
											   (search_query.class === undefined) ||
											   ((typeof search_query.class === 'string') && (search_query.class === cls.name)) ||  // match all
											   ((search_query.class instanceof RegExp) && search_query.class.test(cls.name)))      // match bare string
											{                                                                                      // match regular expression
												if(querying_member)
												{
													member_keys.forEach((key) =>
													{
														if(search_query[key] !== undefined)
														{
															const members = cls[key + 's'];
															
															if(Array.isArray(members))
															{
																members.forEach((member) =>
																{
																	if(((search_query.id === undefined) || (search_query.id === member.id)) &&              // match id
																	   (((typeof search_query[key] === 'string') && (search_query[key] === member.name)) || // match bare string
																	   ((search_query[key] instanceof RegExp) && search_query[key].test(member.name))))     // match regular expression
																	{
																		member.type = 'DocClass' + key.substring(0,1).toUpperCase() + key.substring(1);
																		result.push(member);
																	}
																});
															}
														}
													});
												}
												else if((search_query.id === undefined) || (search_query.id === cls.id))
												{
													cls.type = 'DocClass';
													result.push(cls);
												}
											}
										});
									}
								}
								else if((search_query.id === undefined) || (search_query.id === unit.id))
								{
									unit.type = 'DocUnit';
									result.push(unit);
								}
							}
						});
					}
				});
				
				if(result.length || query_is_empty)
				{
					if((options.skip !== undefined) || (options.limit !== undefined))
					{
						let start = options.skip || 0;
						let end = start + (options.limit ? options.limit : result.length);
						resolve(result.slice(start, end));
					}
					else
					{
						resolve(result);
					}
				}
				else
				{
					reject(this.NotFound());
				}
			}
			else if(search_query.id === undefined)
			{
				resolve(doc_documents);
			}
		}).catch((err) =>
		{
			reject(this.Error(err));
		});
	}.bind(this));
}

exports.find_in_doc = find_in_doc;