{"version":3,"sources":["../LuV.LUMAS.Services/scripts/spext/services/spSearchResultParser.ts"],"names":["SearchResultParser","prototype","parse","data","selectedProperties","this","extractData","relevantResults","PrimaryQueryResult","RelevantResults","transformSearchResult","d","postquery","query","_this","results","map","getSelectPropertiesMap","rows","Table","Rows","length","_","forEach","row","result","resultWithPrios","push","cells","Cells","Array","isArray","cell","key","element","Key","prio","resultCell","formatValue","Value","ValueType","v","k","reduce","before","$log","log","options","spSearchOptions_1","SearchOptions","setSelectPropertiesMap","getSelectPropertiesManagedMap","isEmpty","parseTaxonomyValue","input","m","_regExTax","exec","Label","value","type","values","_regExDate","test","Date","indexOf","Url","split","Title","lowerKey","toLocaleLowerCase","keyLength","owsUserIndex","meta","Email","ID","Login","owsBoolIndex","parseBoolean","parseInt","parseFloat","date_1","parsers_1","default","humanizeDate","str","parseRefiners","refiners","RefinementResults","Refiners","ex","refiner","Name","Entries","RefinementToken","replace","formatRefinerName","RefinementName","RefinementCount","name","isString","window","console","exports"],"mappings":"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","file":"spSearchResultParser.js","sourcesContent":["import * as _ from 'lodash';\r\nimport parsers from '../helpers/parsers';\r\nimport { PriorityElement, SearchOptions } from './spSearchOptions';\r\n\r\ninterface ITaxValue {\r\n GP0: string,\r\n GPP: string,\r\n L0: string,\r\n Label: string,\r\n}\r\n\r\ninterface ITaxValues extends Array {\r\n GTSet: string,\r\n}\r\n\r\ninterface IRefinerValues {\r\n [name: string]: { [value: string]: string }\r\n}\r\n\r\nexport class SearchResultParser {\r\n private static _regExDate = /\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,7})?Z/;\r\n private static _regExTax = /(?:;|^)(GTSet|GP0|GPP|L0)\\|#0?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\|([^;\\n]+))?/gm;\r\n public constructor(private $log: ng.ILogService) {\r\n if (!$log) {\r\n this.$log = window.console;\r\n }\r\n }\r\n\r\n /**\r\n * parse the result of a search query in to better readable result with appropriate types\r\n * Parameters:\r\n * data = Result from postquery or query rest call\r\n * selectedProperties = array property for mapping like display templates\r\n * example: ['DocId',{'title':'Title'},{'url':['Path','OriginalPath']},{'startDate':['EventDateOWSDATE','StartDateOWSDate'],'endDate':['EndDateOWSDATE']}]\r\n */\r\n public parse(data: any, selectedProperties: Array) {\r\n data = this.extractData(data);\r\n if (!data) {\r\n //no data, no result\r\n return [];\r\n }\r\n const relevantResults = data.PrimaryQueryResult.RelevantResults;\r\n return this.transformSearchResult(relevantResults, selectedProperties);\r\n }\r\n\r\n /**\r\n * finds the real data, cloaked behind verbose 'd' or postquery/query\r\n */\r\n private extractData(data: any) {\r\n if (!data) {\r\n //no data, no result\r\n return null;\r\n }\r\n if (data.d) {\r\n //verbose is active\r\n data = data.d;\r\n }\r\n if (data.postquery) {\r\n //data from postquery\r\n data = data.postquery;\r\n }\r\n if (data.query) {\r\n //data from get query\r\n data = data.query;\r\n }\r\n if (!data.PrimaryQueryResult) {\r\n return null;\r\n }\r\n return data;\r\n }\r\n\r\n /**\r\n * transforms over the top postquery result into simple objects\r\n */\r\n private transformSearchResult(relevantResults: any, selectedProperties: Array) {\r\n const results = [];\r\n const map = this.getSelectPropertiesMap(selectedProperties);\r\n let rows = relevantResults.Table.Rows;\r\n\r\n // in sp 2013 rows have a results array\r\n if(rows.results) {\r\n // set rows to the first element in results will cure this method\r\n rows = rows.results;\r\n }\r\n\r\n if(rows.length <= 0) {\r\n return results;\r\n }\r\n\r\n _.forEach(rows, (row) => {\r\n const result = {};\r\n const resultWithPrios = {};\r\n results.push(result);\r\n const formatedCells = {};\r\n let cells = row.Cells;\r\n if (Array.isArray(row) && row.length > 0) {\r\n cells = row[0].Cells;\r\n }\r\n\r\n // in sp 2013 rows have a results array\r\n if(cells.results && cells.results.length > 0) {\r\n // set rows to the first element in results will cure this method\r\n cells = cells.results;\r\n }\r\n\r\n _.forEach(cells, (cell) => {\r\n let element = map[cell.Key] as PriorityElement;\r\n let key;\r\n let prio = -1;\r\n if (element) {\r\n prio = element.prio;\r\n key = element.key;\r\n }\r\n if (!key) {\r\n key = cell.Key;\r\n }\r\n if (prio > -1) {\r\n //if multiple managed propertie were configured for one result, the prio will start at 0\r\n let resultCell = resultWithPrios[key] || [];\r\n resultCell[prio] = this.formatValue(cell.Key, cell.Value, cell.ValueType);\r\n resultWithPrios[key] = resultCell;\r\n } else {\r\n result[key] = this.formatValue(cell.Key, cell.Value, cell.ValueType);\r\n }\r\n });\r\n _.forEach(resultWithPrios, (v: Array, k: string) => {\r\n //select the first value with the highest prio\r\n result[k] = _.reduce(v, (before, v) => { return before || v; }, null);\r\n });\r\n });\r\n this.$log.log('SearchResultParser', results);\r\n return results;\r\n }\r\n\r\n /**\r\n * map for managedproperties as key & templatekey as value\r\n */\r\n private getSelectPropertiesMap(selectedProperties: Array): { [key: string]: PriorityElement } {\r\n const options = new SearchOptions();\r\n options.setSelectPropertiesMap(selectedProperties);\r\n const result = options.getSelectPropertiesManagedMap();\r\n if (_.isEmpty(result)) {\r\n return null;\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * parses the taxvalue string in to an array with additional property GTSet\r\n */\r\n private parseTaxonomyValue(input: string): ITaxValues {\r\n const results = [];\r\n let result;\r\n let m = SearchResultParser._regExTax.exec(input);\r\n while (m) {\r\n if (m[1] == 'GP0') {\r\n result = { Label: null };\r\n results.push(result);\r\n }\r\n //GTSet only occures in first token, is if of Termset, therefor a property of the array\r\n if (m[1] == 'GTSet') {\r\n results[m[1]] = m[2];\r\n }\r\n else {\r\n result[m[1]] = m[2];\r\n }\r\n if (m[3]) {\r\n result.Label = m[3];\r\n }\r\n m = SearchResultParser._regExTax.exec(input);\r\n }\r\n return results;\r\n }\r\n\r\n /**\r\n * parses the value with the help of its structure, key and type\r\n * returns the best 'guess', because the search returns strange things sometimes\r\n */\r\n private formatValue(key: string, value: string, type: string): any {\r\n switch (type) {\r\n case 'Edm.String':\r\n if (value) {\r\n let values;\r\n //some Strings are Dates, recognize by pattern\r\n if (value[value.length - 1] == 'Z' && SearchResultParser._regExDate.test(value)) {\r\n return new Date(value);\r\n }\r\n //some Strings are Urls\r\n if (value.indexOf('http') === 0 && value.indexOf(', ') > 4) {\r\n values = value.split(', ');\r\n return { Url: values[0], Title: values[1] };\r\n }\r\n const lowerKey = key.toLocaleLowerCase();\r\n const keyLength = key.length;\r\n //some Strings are User\r\n const owsUserIndex = lowerKey.indexOf('owsuser');\r\n if (owsUserIndex > -1 && owsUserIndex === keyLength - 7) {\r\n values = value.split(' | ');\r\n const meta = values[2].split(' ');\r\n return { Email: values[0], Title: values[1], ID: meta[0], Login: meta[1] };\r\n }\r\n //some Strings are Terms\r\n if (lowerKey.indexOf('owstaxid') === 0 || SearchResultParser._regExTax.test(value)) {\r\n return this.parseTaxonomyValue(value);\r\n }\r\n //some String are Boolean\r\n const owsBoolIndex = lowerKey.indexOf('owsbool');\r\n if (owsBoolIndex > -1 && owsBoolIndex === keyLength - 7) {\r\n return this.parseBoolean(value);\r\n }\r\n }\r\n return value;\r\n case 'Edm.Guid':\r\n return value;\r\n case 'Edm.Int32':\r\n case 'Edm.Int64':\r\n return parseInt(value);\r\n case 'Edm.Double':\r\n return parseFloat(value);\r\n case 'Edm.DateTime':\r\n if (value) {\r\n let date = new Date(value);\r\n parsers.humanizeDate(date, (str) => { date['humanized'] = str; });\r\n return date;\r\n }\r\n return null;\r\n case 'Edm.Boolean':\r\n return this.parseBoolean(value);\r\n case 'Null':\r\n return null;\r\n default:\r\n throw 'Unknown value type: ' + type;\r\n }\r\n }\r\n\r\n /**\r\n * parse string of boolean (false,true,0,1) into real boolean\r\n */\r\n private parseBoolean(value: string): boolean {\r\n if (value === 'false' || value === '0') {\r\n return false;\r\n } else if (value === 'true' || value === '1') {\r\n return true;\r\n }\r\n throw 'Unknown boolean value: ' + value;\r\n }\r\n\r\n /**\r\n * parses the Refiners from a search result\r\n */\r\n public parseRefiners(data: any): IRefinerValues {\r\n data = this.extractData(data);\r\n const result = {};\r\n let refiners;\r\n try {\r\n refiners = data.PrimaryQueryResult.RefinementResults.Refiners;\r\n }\r\n catch (ex) {\r\n return result;\r\n }\r\n _.forEach(refiners, (v) => {\r\n const refiner = {};\r\n result[v.Name] = refiner;\r\n _.forEach(v.Entries, (v) => {\r\n refiner[v.RefinementToken.replace(/(^\"|\"$)/g, '')] = this.formatRefinerName(v.RefinementName) + ' (' + v.RefinementCount + ')';\r\n });\r\n });\r\n return result;\r\n };\r\n\r\n //TODO MK: must be tested!\r\n private formatRefinerName(name: string): string {\r\n if (!name || !_.isString(name)) {\r\n return name;\r\n }\r\n if (name.indexOf('L0|#') > -1) {\r\n const taxValues = this.parseTaxonomyValue(name);\r\n return taxValues[0].Label;\r\n }\r\n return name;\r\n }\r\n}\r\n\r\n"]}