|
|
@@ -1,4 +1,4 @@
|
|
|
-import { SearchInput, SearchResult } from '@vendure/common/lib/generated-types';
|
|
|
+import { LogicalOperator, SearchInput, SearchResult } from '@vendure/common/lib/generated-types';
|
|
|
import { ID } from '@vendure/common/lib/shared-types';
|
|
|
import { Brackets, Connection, SelectQueryBuilder } from 'typeorm';
|
|
|
|
|
|
@@ -81,7 +81,7 @@ export class PostgresSearchStrategy implements SearchStrategy {
|
|
|
.take(take)
|
|
|
.skip(skip)
|
|
|
.getRawMany()
|
|
|
- .then((res) => res.map((r) => mapToSearchResult(r, ctx.channel.currencyCode)));
|
|
|
+ .then(res => res.map(r => mapToSearchResult(r, ctx.channel.currencyCode)));
|
|
|
}
|
|
|
|
|
|
async getTotalCount(ctx: RequestContext, input: SearchInput, enabledOnly: boolean): Promise<number> {
|
|
|
@@ -101,7 +101,7 @@ export class PostgresSearchStrategy implements SearchStrategy {
|
|
|
.select('COUNT(*) as total')
|
|
|
.from(`(${innerQb.getQuery()})`, 'inner')
|
|
|
.setParameters(innerQb.getParameters());
|
|
|
- return totalItemsQb.getRawOne().then((res) => res.total);
|
|
|
+ return totalItemsQb.getRawOne().then(res => res.total);
|
|
|
}
|
|
|
|
|
|
private applyTermAndFilters(
|
|
|
@@ -110,7 +110,7 @@ export class PostgresSearchStrategy implements SearchStrategy {
|
|
|
input: SearchInput,
|
|
|
forceGroup: boolean = false,
|
|
|
): SelectQueryBuilder<SearchIndexItem> {
|
|
|
- const { term, facetValueIds, collectionId } = input;
|
|
|
+ const { term, facetValueIds, facetValueOperator, collectionId } = input;
|
|
|
// join multiple words with the logical AND operator
|
|
|
const termLogicalAnd = term ? term.trim().replace(/\s+/, ' & ') : '';
|
|
|
|
|
|
@@ -130,7 +130,7 @@ export class PostgresSearchStrategy implements SearchStrategy {
|
|
|
'score',
|
|
|
)
|
|
|
.andWhere(
|
|
|
- new Brackets((qb1) => {
|
|
|
+ new Brackets(qb1 => {
|
|
|
qb1.where('to_tsvector(si.sku) @@ to_tsquery(:term)')
|
|
|
.orWhere('to_tsvector(si.productName) @@ to_tsquery(:term)')
|
|
|
.orWhere('to_tsvector(si.productVariantName) @@ to_tsquery(:term)')
|
|
|
@@ -139,13 +139,21 @@ export class PostgresSearchStrategy implements SearchStrategy {
|
|
|
)
|
|
|
.setParameters({ term: termLogicalAnd });
|
|
|
}
|
|
|
- if (facetValueIds) {
|
|
|
- for (const id of facetValueIds) {
|
|
|
- const placeholder = '_' + id;
|
|
|
- qb.andWhere(`:${placeholder} = ANY (string_to_array(si.facetValueIds, ','))`, {
|
|
|
- [placeholder]: id,
|
|
|
- });
|
|
|
- }
|
|
|
+ if (facetValueIds?.length) {
|
|
|
+ qb.andWhere(
|
|
|
+ new Brackets(qb1 => {
|
|
|
+ for (const id of facetValueIds) {
|
|
|
+ const placeholder = '_' + id;
|
|
|
+ const clause = `:${placeholder} = ANY (string_to_array(si.facetValueIds, ','))`;
|
|
|
+ const params = { [placeholder]: id };
|
|
|
+ if (facetValueOperator === LogicalOperator.AND) {
|
|
|
+ qb1.andWhere(clause, params);
|
|
|
+ } else {
|
|
|
+ qb1.orWhere(clause, params);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ );
|
|
|
}
|
|
|
if (collectionId) {
|
|
|
qb.andWhere(`:collectionId = ANY (string_to_array(si.collectionIds, ','))`, { collectionId });
|
|
|
@@ -165,7 +173,7 @@ export class PostgresSearchStrategy implements SearchStrategy {
|
|
|
*/
|
|
|
private createPostgresSelect(groupByProduct: boolean): string {
|
|
|
return fieldsToSelect
|
|
|
- .map((col) => {
|
|
|
+ .map(col => {
|
|
|
const qualifiedName = `si.${col}`;
|
|
|
const alias = `si_${col}`;
|
|
|
if (groupByProduct && col !== 'productId') {
|