docs: function buildQueryTree(
  	dbDriver, recordTypes, propsTree, anchorNode, clauses, singleAxis) {
  
  	// get and validate top records specification data
  	const recordTypeDesc = recordTypes.getRecordTypeDesc(
  		propsTree.desc.refTarget);
  	const topIdPropName = recordTypeDesc.idPropertyName;
  	const topIdColumn = recordTypeDesc.getPropertyDesc(topIdPropName).column;
  
  	// create top query tree node
  	const topNode = (
  		anchorNode ?
  			anchorNode.createChildNode(
  				propsTree, recordTypeDesc.table, topIdColumn,
  				false, false,
  				topIdColumn, topIdColumn) :
  			new QueryTreeNode(
  				dbDriver, recordTypes, new Map(), new Map(), new Map(),
  				singleAxis, propsTree, true, recordTypeDesc.table, 'z',
  				topIdColumn)
  	);
  	topNode.rootPropNode = propsTree;
  
  	// add top record id property to have it in front of the select list
  	const idPropSql = topNode.tableAlias + '.' + topIdColumn;
  	topNode.addSelect(makeSelector(idPropSql, topIdPropName));
  	topNode.addPropSql(topIdPropName, idPropSql);
  	topNode.addPropValueColumn(
  		topIdPropName, topNode.table, topNode.tableAlias, topIdColumn);
  
  	// add the rest of selected properties
  	if (propsTree.hasChildren()) {
  		const topMarkupCtx = {
  			prefix: '',
  			nextChildMarkupDisc: 'a'.charCodeAt(0)
  		};
  		for (let p of propsTree.children)
  			if (!p.desc.isId()) // already included
  				topNode.addProperty(p, clauses, topMarkupCtx);
  	}
  
  	// return the query tree
  	return topNode;
  }