@searchkit/api
Advanced tools
Comparing version 4.0.0-next.0 to 4.0.0-next.1
@@ -13,3 +13,3 @@ import { MultipleQueriesQuery } from '@algolia/client-search'; | ||
field?: string; | ||
type?: "numeric" | "string" | "date"; | ||
type?: 'numeric' | 'string' | 'date'; | ||
}; | ||
@@ -31,12 +31,12 @@ interface ClientConfigConnection { | ||
interface QueryStringRuleCondition { | ||
context: "query"; | ||
match_type: "prefix" | "contains" | "exact"; | ||
context: 'query'; | ||
match_type: 'prefix' | 'contains' | 'exact'; | ||
value: string; | ||
} | ||
interface PinnedResultAction { | ||
action: "PinnedResult"; | ||
action: 'PinnedResult'; | ||
documentIds: string[]; | ||
} | ||
interface QueryAttributeBoostAction { | ||
action: "QueryAttributeBoost"; | ||
action: 'QueryAttributeBoost'; | ||
attribute: string; | ||
@@ -47,6 +47,14 @@ value?: string; | ||
interface QueryRewriteAction { | ||
action: "QueryRewrite"; | ||
action: 'QueryRewrite'; | ||
query: string; | ||
} | ||
type QueryRuleAction = PinnedResultAction | QueryAttributeBoostAction | QueryRewriteAction; | ||
interface RenderUserDataAction { | ||
action: 'RenderUserData'; | ||
userData: string; | ||
} | ||
interface RenderFacetsOrderAction { | ||
action: 'RenderFacetsOrder'; | ||
facetAttributesOrder: string[]; | ||
} | ||
type QueryRuleAction = PinnedResultAction | QueryAttributeBoostAction | QueryRewriteAction | RenderUserDataAction | RenderFacetsOrderAction; | ||
type QueryRuleCondition = QueryStringRuleCondition; | ||
@@ -85,2 +93,3 @@ interface QueryRule { | ||
} | { | ||
userData?: unknown[] | undefined; | ||
hits: { | ||
@@ -95,3 +104,3 @@ _highlightResult: Record<string, any>; | ||
facets: { | ||
order: string[] | undefined; | ||
order: string[]; | ||
}; | ||
@@ -125,2 +134,3 @@ values: Record<string, { | ||
} | { | ||
userData?: unknown[] | undefined; | ||
hits: { | ||
@@ -135,3 +145,3 @@ _highlightResult: Record<string, any>; | ||
facets: { | ||
order: string[] | undefined; | ||
order: string[]; | ||
}; | ||
@@ -138,0 +148,0 @@ values: Record<string, { |
@@ -27,20 +27,2 @@ "use strict"; | ||
// src/queryRules.ts | ||
var getSatisfiedRules = (queryContext, rules) => { | ||
return rules.filter((rule) => { | ||
return rule.conditions.filter((condition) => { | ||
if (condition.context === "query" && condition.match_type === "exact") { | ||
return condition.value === queryContext.query; | ||
} | ||
if (condition.context === "query" && condition.match_type === "contains") { | ||
return queryContext.query.includes(condition.value); | ||
} | ||
if (condition.context === "query" && condition.match_type === "prefix") { | ||
return queryContext.query.startsWith(condition.value); | ||
} | ||
return false; | ||
}).length > 0; | ||
}); | ||
}; | ||
// src/utils.ts | ||
@@ -52,15 +34,16 @@ var getFacetField = (facet_attributes, attribute) => { | ||
return attributeKey; | ||
} else { | ||
return ((_a = facet_attributes.find((a) => a.attribute === attributeKey)) == null ? void 0 : _a.field) || attributeKey; | ||
} | ||
return ((_a = facet_attributes.find((a) => a.attribute === attributeKey)) == null ? void 0 : _a.field) || attributeKey; | ||
}; | ||
var getFacetAttribute = (facet_attributes, attribute) => { | ||
var getFacetByAttribute = (facet_attributes, attribute) => { | ||
var _a; | ||
const attributeKey = typeof attribute === "string" ? attribute : attribute.attribute; | ||
const attributeKey = getFacetAttribute(attribute); | ||
if (facet_attributes.includes(attributeKey)) { | ||
return attributeKey; | ||
} else { | ||
return ((_a = facet_attributes.find((a) => a.attribute === attributeKey)) == null ? void 0 : _a.attribute) || attributeKey; | ||
} | ||
return ((_a = facet_attributes.find((a) => a.attribute === attributeKey)) == null ? void 0 : _a.attribute) || attributeKey; | ||
}; | ||
var getFacetAttribute = (facetAttribute) => { | ||
return typeof facetAttribute === "string" ? facetAttribute : facetAttribute.attribute; | ||
}; | ||
var getFacetFieldType = (facet_attributes, attribute) => { | ||
@@ -71,5 +54,4 @@ var _a; | ||
return "string"; | ||
} else { | ||
return ((_a = facet_attributes.find((a) => (a == null ? void 0 : a.attribute) === attributeKey)) == null ? void 0 : _a.type) || "string"; | ||
} | ||
return ((_a = facet_attributes.find((a) => (a == null ? void 0 : a.attribute) === attributeKey)) == null ? void 0 : _a.type) || "string"; | ||
}; | ||
@@ -79,6 +61,3 @@ | ||
var createRegexQuery = (queryString) => { | ||
let query = queryString.replace( | ||
/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, | ||
"\\$&" | ||
); | ||
let query = queryString.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | ||
query = query.split("").map((char) => { | ||
@@ -103,5 +82,3 @@ if (/[a-z]/.test(char)) { | ||
return numericFilters.reduce((sum, filter) => { | ||
const [match, field, operator, value] = filter.match( | ||
/(\w+)(\=|\!\=|\>|\>\=|\<|\<\=)(\d+)/ | ||
); | ||
const [match, field, operator, value] = filter.match(/(\w+)(\=|\!\=|\>|\>\=|\<|\<\=)(\d+)/); | ||
if (!match) | ||
@@ -189,3 +166,3 @@ return sum; | ||
}; | ||
var getAggs = (request, config) => { | ||
var getAggs = (request, config, queryRuleActions) => { | ||
const { params = {}, type } = request; | ||
@@ -205,13 +182,13 @@ const { facets, maxValuesPerFacet, facetName, facetQuery } = params; | ||
} else if (Array.isArray(facets)) { | ||
const facetAttributes = facets[0] === "*" ? config.facet_attributes || [] : facets; | ||
let facetAttibutes = config.facet_attributes || []; | ||
if (queryRuleActions.facetAttributesOrder) { | ||
facetAttibutes = queryRuleActions.facetAttributesOrder.map((attribute) => { | ||
return getFacetByAttribute(config.facet_attributes || [], attribute); | ||
}); | ||
} | ||
const facetAttributes = facets[0] === "*" ? facetAttibutes : facets; | ||
return facetAttributes.reduce((sum, facet) => { | ||
const fieldType = getFacetFieldType( | ||
config.facet_attributes || [], | ||
facet | ||
); | ||
const fieldType = getFacetFieldType(config.facet_attributes || [], facet); | ||
const field = getFacetField(config.facet_attributes || [], facet); | ||
const attributeName = getFacetAttribute( | ||
config.facet_attributes || [], | ||
facet | ||
); | ||
const attributeName = getFacetByAttribute(config.facet_attributes || [], facet); | ||
if (fieldType === "numeric") { | ||
@@ -246,6 +223,3 @@ return { | ||
const field = getFacetField(config.facet_attributes || [], facets); | ||
const attributeName = getFacetAttribute( | ||
config.facet_attributes || [], | ||
facets | ||
); | ||
const attributeName = getFacetByAttribute(config.facet_attributes || [], facets); | ||
if (fieldType === "numeric") { | ||
@@ -276,34 +250,4 @@ return { | ||
}; | ||
function RelevanceQueryMatch(query, search_attributes, config) { | ||
if (Array.isArray(config.query_rules) && config.query_rules.length > 0) { | ||
const satisfiedRules = getSatisfiedRules( | ||
{ | ||
query | ||
}, | ||
config.query_rules | ||
); | ||
const actionQueries = satisfiedRules.reduce( | ||
(sum, rule) => { | ||
rule.actions.map((action) => { | ||
if (action.action === "PinnedResult") { | ||
sum.pinnedDocs.push(...action.documentIds); | ||
} else if (action.action === "QueryRewrite") { | ||
sum.query = action.query; | ||
} else if (action.action === "QueryAttributeBoost") { | ||
sum.boostFunctions.push({ | ||
filter: { | ||
match: { [action.attribute]: { query: action.value } } | ||
}, | ||
weight: action.boost | ||
}); | ||
} | ||
}); | ||
return sum; | ||
}, | ||
{ | ||
pinnedDocs: [], | ||
boostFunctions: [], | ||
query | ||
} | ||
); | ||
function RelevanceQueryMatch(query, search_attributes, queryRuleActions) { | ||
if (queryRuleActions) { | ||
return { | ||
@@ -313,6 +257,6 @@ function_score: { | ||
pinned: { | ||
ids: actionQueries.pinnedDocs, | ||
ids: queryRuleActions.pinnedDocs, | ||
organic: { | ||
combined_fields: { | ||
query: actionQueries.query, | ||
query: queryRuleActions.query, | ||
fields: search_attributes | ||
@@ -323,3 +267,3 @@ } | ||
}, | ||
functions: actionQueries.boostFunctions | ||
functions: queryRuleActions.boostFunctions | ||
} | ||
@@ -332,3 +276,3 @@ }; | ||
} | ||
var getQuery = (request, config, requestOptions) => { | ||
var getQuery = (request, config, queryRuleActions, requestOptions) => { | ||
var _a; | ||
@@ -346,3 +290,3 @@ const { params = {} } = request; | ||
filter: filters, | ||
must: typeof query === "string" && query !== "" ? (requestOptions == null ? void 0 : requestOptions.getQuery) ? requestOptions.getQuery(query, searchAttributes, config) : RelevanceQueryMatch(query, searchAttributes, config) : [] | ||
must: typeof query === "string" && query !== "" ? (requestOptions == null ? void 0 : requestOptions.getQuery) ? requestOptions.getQuery(query, searchAttributes, config) : RelevanceQueryMatch(query, searchAttributes, queryRuleActions) : [] | ||
} | ||
@@ -376,15 +320,16 @@ }; | ||
post_tags: [params.highlightPostTag || "</ais-highlight-0000000000>"], | ||
fields: ((_a = config.highlight_attributes) == null ? void 0 : _a.reduce((sum, field) => { | ||
return { | ||
fields: ((_a = config.highlight_attributes) == null ? void 0 : _a.reduce( | ||
(sum, field) => ({ | ||
...sum, | ||
[field]: {} | ||
}; | ||
}, {})) || {} | ||
}), | ||
{} | ||
)) || {} | ||
} | ||
}; | ||
}; | ||
function transformRequest(request, config, requestOptions) { | ||
function transformRequest(request, config, queryRuleActions, requestOptions) { | ||
const body = { | ||
aggs: getAggs(request, config), | ||
query: getQuery(request, config, requestOptions), | ||
aggs: getAggs(request, config, queryRuleActions), | ||
query: getQuery(request, config, queryRuleActions, requestOptions), | ||
...getResultsSize(request, config), | ||
@@ -397,53 +342,54 @@ ...getHitFields(request, config), | ||
// src/transformResponse.ts | ||
var import_querystring = require("querystring"); | ||
// src/highlightUtils.ts | ||
function highlightTerm(value, query) { | ||
const regex = new RegExp(query, "gi"); | ||
return value.replace(regex, (match) => { | ||
return `<ais-highlight-0000000000>${match}</ais-highlight-0000000000>`; | ||
}); | ||
return value.replace( | ||
regex, | ||
(match) => `<ais-highlight-0000000000>${match}</ais-highlight-0000000000>` | ||
); | ||
} | ||
function getHighlightFields2(hit) { | ||
const { _source = {}, highlight = {} } = hit; | ||
const hitHighlights = Object.keys(_source).reduce( | ||
(sum, fieldKey) => { | ||
const fieldValue = _source[fieldKey]; | ||
const highlightedMatch = highlight[fieldKey] || null; | ||
if (Array.isArray(fieldValue) && !highlightedMatch) { | ||
return { | ||
...sum, | ||
[fieldKey]: fieldValue.map((value) => ({ | ||
matchLevel: "none", | ||
matchedWords: [], | ||
value | ||
})) | ||
}; | ||
} else if (Array.isArray(highlightedMatch)) { | ||
return { | ||
...sum, | ||
[fieldKey]: highlightedMatch.map((highlightedMatch2) => { | ||
const matchWords = Array.from( | ||
highlightedMatch2.matchAll( | ||
/\<ais-highlight-0000000000\>(.*?)\<\/ais-highlight-0000000000\>/g | ||
) | ||
).map((match) => match[1]); | ||
return { | ||
fullyHighlighted: false, | ||
matchLevel: "full", | ||
matchedWords: matchWords, | ||
value: highlightedMatch2 | ||
}; | ||
}) | ||
}; | ||
} | ||
const hitHighlights = Object.keys(_source).reduce((sum, fieldKey) => { | ||
const fieldValue = _source[fieldKey]; | ||
const highlightedMatch = highlight[fieldKey] || null; | ||
if (Array.isArray(fieldValue) && !highlightedMatch) { | ||
return { | ||
...sum, | ||
[fieldKey]: { | ||
[fieldKey]: fieldValue.map((value) => ({ | ||
matchLevel: "none", | ||
matchedWords: [], | ||
value: fieldValue | ||
} | ||
value | ||
})) | ||
}; | ||
}, | ||
{} | ||
); | ||
} else if (Array.isArray(highlightedMatch)) { | ||
return { | ||
...sum, | ||
[fieldKey]: highlightedMatch.map((highlightedMatch2) => { | ||
const matchWords = Array.from( | ||
highlightedMatch2.matchAll( | ||
/\<ais-highlight-0000000000\>(.*?)\<\/ais-highlight-0000000000\>/g | ||
) | ||
).map((match) => match[1]); | ||
return { | ||
fullyHighlighted: false, | ||
matchLevel: "full", | ||
matchedWords: matchWords, | ||
value: highlightedMatch2 | ||
}; | ||
}) | ||
}; | ||
} | ||
return { | ||
...sum, | ||
[fieldKey]: { | ||
matchLevel: "none", | ||
matchedWords: [], | ||
value: fieldValue | ||
} | ||
}; | ||
}, {}); | ||
return hitHighlights; | ||
@@ -453,3 +399,2 @@ } | ||
// src/transformResponse.ts | ||
var import_querystring = require("querystring"); | ||
var getHits = (response, config) => { | ||
@@ -519,4 +464,7 @@ const { hits } = response; | ||
}; | ||
var getRenderingContent = (config) => { | ||
var getRenderingContent = (config, queryRuleActions) => { | ||
var _a, _b; | ||
const defaultOrder = (_a = config.facet_attributes) == null ? void 0 : _a.map( | ||
(facet) => typeof facet === "string" ? facet : facet.attribute | ||
); | ||
return { | ||
@@ -526,15 +474,19 @@ renderingContent: { | ||
facets: { | ||
order: (_a = config.facet_attributes) == null ? void 0 : _a.map((facet) => { | ||
return typeof facet === "string" ? facet : facet.attribute; | ||
}) | ||
order: queryRuleActions.facetAttributesOrder || defaultOrder || [] | ||
}, | ||
values: (_b = config.facet_attributes) == null ? void 0 : _b.reduce((sum, facet) => { | ||
const facetName = typeof facet === "string" ? facet : facet.attribute; | ||
return { | ||
...sum, | ||
[facetName]: { | ||
sortRemainingBy: "count" | ||
values: (_b = config.facet_attributes) == null ? void 0 : _b.reduce( | ||
(sum, facet) => { | ||
const facetName = typeof facet === "string" ? facet : facet.attribute; | ||
if (queryRuleActions.facetAttributesOrder && !queryRuleActions.facetAttributesOrder.includes(facetName)) { | ||
return sum; | ||
} | ||
}; | ||
}, {}) | ||
return { | ||
...sum, | ||
[facetName]: { | ||
sortRemainingBy: "count" | ||
} | ||
}; | ||
}, | ||
{} | ||
) | ||
} | ||
@@ -549,5 +501,3 @@ } | ||
const totalHits = typeof total === "number" ? total : total == null ? void 0 : total.value; | ||
const nbPages = Math.ceil( | ||
(typeof total === "number" ? total : (total == null ? void 0 : total.value) || 0) / hitsPerPage | ||
); | ||
const nbPages = Math.ceil((typeof total === "number" ? total : (total == null ? void 0 : total.value) || 0) / hitsPerPage); | ||
return { | ||
@@ -562,3 +512,3 @@ hitsPerPage, | ||
}; | ||
function transformResponse(response, instantsearchRequest, config) { | ||
function transformResponse(response, instantsearchRequest, config, queryRuleActions) { | ||
return { | ||
@@ -570,7 +520,8 @@ exhaustiveNbHits: true, | ||
...getPageDetails(response, instantsearchRequest, config), | ||
...getRenderingContent(config), | ||
...getRenderingContent(config, queryRuleActions), | ||
...getFacets(response, config), | ||
hits: getHits(response, config), | ||
index: instantsearchRequest.indexName, | ||
params: (0, import_querystring.stringify)(instantsearchRequest.params) | ||
params: (0, import_querystring.stringify)(instantsearchRequest.params), | ||
...queryRuleActions.userData.length > 0 ? { userData: queryRuleActions.userData } : {} | ||
}; | ||
@@ -581,12 +532,10 @@ } | ||
return { | ||
facetHits: aggregations[Object.keys(aggregations)[0]].buckets.map( | ||
(entry) => ({ | ||
value: entry.key, | ||
highlighted: highlightTerm( | ||
entry.key, | ||
instantsearchRequest.params.facetQuery || "" | ||
), | ||
count: entry.doc_count | ||
}) | ||
), | ||
facetHits: aggregations[Object.keys(aggregations)[0]].buckets.map((entry) => ({ | ||
value: entry.key, | ||
highlighted: highlightTerm( | ||
entry.key, | ||
instantsearchRequest.params.facetQuery || "" | ||
), | ||
count: entry.doc_count | ||
})), | ||
exhaustiveFacetsCount: true, | ||
@@ -625,2 +574,56 @@ processingTimeMS: response.took | ||
// src/queryRules.ts | ||
var getQueryRulesActionsFromRequest = (queryRules, request) => { | ||
var _a; | ||
const queryContext = { | ||
query: ((_a = request.params) == null ? void 0 : _a.query) || "" | ||
}; | ||
const satisfiedRules = getSatisfiedRules(queryContext, queryRules || []); | ||
const actions = satisfiedRules.reduce( | ||
(sum, rule) => { | ||
rule.actions.map((action) => { | ||
if (action.action === "PinnedResult") { | ||
sum.pinnedDocs.push(...action.documentIds); | ||
} else if (action.action === "QueryRewrite") { | ||
sum.query = action.query; | ||
} else if (action.action === "QueryAttributeBoost") { | ||
sum.boostFunctions.push({ | ||
filter: { | ||
match: { [action.attribute]: { query: action.value } } | ||
}, | ||
weight: action.boost | ||
}); | ||
} else if (action.action === "RenderUserData") { | ||
sum.userData.push(JSON.parse(action.userData)); | ||
} else if (action.action === "RenderFacetsOrder") { | ||
sum.facetAttributesOrder = action.facetAttributesOrder; | ||
} | ||
}); | ||
return sum; | ||
}, | ||
{ | ||
pinnedDocs: [], | ||
boostFunctions: [], | ||
query: queryContext.query, | ||
userData: [], | ||
facetAttributesOrder: void 0 | ||
} | ||
); | ||
return actions; | ||
}; | ||
var getSatisfiedRules = (queryContext, rules) => rules.filter( | ||
(rule) => rule.conditions.filter((condition) => { | ||
if (condition.context === "query" && condition.match_type === "exact") { | ||
return condition.value === queryContext.query; | ||
} | ||
if (condition.context === "query" && condition.match_type === "contains") { | ||
return queryContext.query.includes(condition.value); | ||
} | ||
if (condition.context === "query" && condition.match_type === "prefix") { | ||
return queryContext.query.startsWith(condition.value); | ||
} | ||
return false; | ||
}).length > 0 | ||
); | ||
// src/index.ts | ||
@@ -645,14 +648,15 @@ var Client = class { | ||
async handleInstantSearchRequests(instantsearchRequests, requestOptions) { | ||
const esRequests = instantsearchRequests.map( | ||
(request, i) => { | ||
return { | ||
body: transformRequest( | ||
request, | ||
this.config.search_settings, | ||
requestOptions | ||
), | ||
indexName: request.indexName | ||
}; | ||
} | ||
); | ||
const queryRules = this.config.search_settings.query_rules || []; | ||
const requestQueryRuleActions = instantsearchRequests.map((request) => { | ||
return getQueryRulesActionsFromRequest(queryRules, request); | ||
}); | ||
const esRequests = instantsearchRequests.map((request, i) => ({ | ||
body: transformRequest( | ||
request, | ||
this.config.search_settings, | ||
requestQueryRuleActions[i], | ||
requestOptions | ||
), | ||
indexName: request.indexName | ||
})); | ||
const esResponses = await this.performSearch(esRequests); | ||
@@ -667,3 +671,4 @@ const instantsearchResponses = esResponses.map((response, i) => { | ||
instantsearchRequests[i], | ||
this.config.search_settings | ||
this.config.search_settings, | ||
requestQueryRuleActions[i] | ||
); | ||
@@ -676,5 +681,3 @@ }); | ||
}; | ||
var createClient = (config) => { | ||
return new Client(config); | ||
}; | ||
var createClient = (config) => new Client(config); | ||
var src_default = createClient; | ||
@@ -681,0 +684,0 @@ // Annotate the CommonJS export names for ESM import in node: |
{ | ||
"name": "@searchkit/api", | ||
"version": "4.0.0-next.0", | ||
"version": "4.0.0-next.1", | ||
"main": "./dist/index.js", | ||
@@ -5,0 +5,0 @@ "description": "", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
121473
1440