9101: Added new filters for motifs (#193)

This commit is contained in:
Erik Tiekstra
2026-05-04 09:55:51 +02:00
committed by GitHub
parent bbb750e5f4
commit c996cf53e0
3 changed files with 85 additions and 74 deletions
+59 -63
View File
@@ -3,7 +3,18 @@ import { ScopeAccess, Scopes } from '../cognito/access-control';
import { Category, CategoryLocaleData } from '../types/category-types'; import { Category, CategoryLocaleData } from '../types/category-types';
import { DataSourceOptions } from '../types/types'; import { DataSourceOptions } from '../types/types';
import { BaseSQLDataSource } from './BaseSQLDataSource'; import { BaseSQLDataSource } from './BaseSQLDataSource';
import { createQuestionMarksFromList, MINUTE } from './utils'; import { createQuestionMarksFromList, HOUR, MINUTE } from './utils';
const ROOMS_PARENT_ID = 270;
const COLORS_PARENT_ID = 1665;
const STYLES_PARENT_ID = 1814;
const PATTERNS_PARENT_ID = 1414;
const KNOWN_FACET_PARENT_IDS = [
ROOMS_PARENT_ID,
COLORS_PARENT_ID,
STYLES_PARENT_ID,
PATTERNS_PARENT_ID,
];
export class CategoryAPI extends BaseSQLDataSource { export class CategoryAPI extends BaseSQLDataSource {
private categoryLoader: DataLoader<number, Category>; private categoryLoader: DataLoader<number, Category>;
@@ -86,108 +97,93 @@ WHERE product_category.product_id = ?
return res; return res;
} }
async getMotifRootIds(): Promise<number[]> {
const { rows } = await this.cachedRaw(
/* sql */ `
SELECT id
FROM v_categorytree_v2
WHERE depth = 1
AND id NOT IN (${createQuestionMarksFromList(KNOWN_FACET_PARENT_IDS)})
`,
KNOWN_FACET_PARENT_IDS,
)
// @ts-ignore
.cache(HOUR);
return rows.map((row) => row.id);
}
async getCategoryBasedFacets(productId: number): Promise<{ async getCategoryBasedFacets(productId: number): Promise<{
room: string[]; room: string[];
color: string[]; color: string[];
style: string[]; style: string[];
pattern: string[]; pattern: string[];
motif: string[];
}> { }> {
ScopeAccess.validate(this.user).some([ ScopeAccess.validate(this.user).some([
Scopes.CATEGORIES_READ, Scopes.CATEGORIES_READ,
Scopes.CATEGORIES_PUBLIC_READ, Scopes.CATEGORIES_PUBLIC_READ,
]); ]);
const ROOMS_PARENT_ID = 270; const motifRootIds = await this.getMotifRootIds();
const COLORS_PARENT_ID = 1665; const allFacetParentIds = [...KNOWN_FACET_PARENT_IDS, ...motifRootIds];
const STYLES_PARENT_ID = 1814;
const PATTERNS_PARENT_ID = 1414;
const { rows } = await this.cachedRaw( const { rows } = await this.cachedRaw(
` /* sql */ `
WITH rooms AS ( WITH facet_parents AS (
SELECT lft, rgt FROM categories_v2_lft_rgt WHERE id = ? SELECT id, lft, rgt, name,
), CASE
colors AS ( WHEN id = ? THEN 'room'
SELECT lft, rgt FROM categories_v2_lft_rgt WHERE id = ? WHEN id = ? THEN 'color'
), WHEN id = ? THEN 'style'
styles AS ( WHEN id = ? THEN 'pattern'
SELECT lft, rgt FROM categories_v2_lft_rgt WHERE id = ? ELSE 'motif'
), END AS facet
patterns AS ( FROM categories_v2_lft_rgt
SELECT lft, rgt FROM categories_v2_lft_rgt WHERE id = ? WHERE id IN (${createQuestionMarksFromList(allFacetParentIds)})
) )
SELECT SELECT
array_remove( array_agg(DISTINCT c.name) FILTER (WHERE fp.facet = 'room') AS room,
array_agg( array_agg(DISTINCT c.name) FILTER (WHERE fp.facet = 'color') AS color,
DISTINCT CASE array_agg(DISTINCT c.name) FILTER (WHERE fp.facet = 'style') AS style,
WHEN c.lft > rooms.lft AND c.rgt < rooms.rgt THEN c.name array_agg(DISTINCT c.name) FILTER (WHERE fp.facet = 'pattern') AS pattern,
END array_agg(DISTINCT fp.name) FILTER (WHERE fp.facet = 'motif') AS motif
),
NULL
) AS room,
array_remove(
array_agg(
DISTINCT CASE
WHEN c.lft > colors.lft AND c.rgt < colors.rgt THEN c.name
END
),
NULL
) AS color,
array_remove(
array_agg(
DISTINCT CASE
WHEN c.lft > styles.lft AND c.rgt < styles.rgt THEN c.name
END
),
NULL
) AS style,
array_remove(
array_agg(
DISTINCT CASE
WHEN c.lft > patterns.lft AND c.rgt < patterns.rgt THEN c.name
END
),
NULL
) AS pattern
FROM product_category pc FROM product_category pc
JOIN categories_v2_lft_rgt c ON c.id = pc.category_id JOIN categories_v2_lft_rgt c ON c.id = pc.category_id
CROSS JOIN rooms JOIN facet_parents fp ON c.lft > fp.lft AND c.rgt < fp.rgt
CROSS JOIN colors
CROSS JOIN styles
CROSS JOIN patterns
WHERE pc.product_id = ? WHERE pc.product_id = ?
AND (
(c.lft > rooms.lft AND c.rgt < rooms.rgt)
OR
(c.lft > colors.lft AND c.rgt < colors.rgt)
OR
(c.lft > styles.lft AND c.rgt < styles.rgt)
OR
(c.lft > patterns.lft AND c.rgt < patterns.rgt)
)
`, `,
[ [
ROOMS_PARENT_ID, ROOMS_PARENT_ID,
COLORS_PARENT_ID, COLORS_PARENT_ID,
STYLES_PARENT_ID, STYLES_PARENT_ID,
PATTERNS_PARENT_ID, PATTERNS_PARENT_ID,
...allFacetParentIds,
productId, productId,
], ],
) )
// @ts-ignore // @ts-ignore
.cache(MINUTE * 5); .cache(MINUTE * 5);
const facetRow = rows[0] ?? { room: [], color: [], style: [], pattern: [] }; const facetRow = rows[0] ?? {
room: [],
color: [],
style: [],
pattern: [],
motif: [],
};
const roomCategories: string[] = facetRow.room ?? []; const roomCategories: string[] = facetRow.room ?? [];
const colorCategories: string[] = facetRow.color ?? []; const colorCategories: string[] = facetRow.color ?? [];
const styleCategories: string[] = facetRow.style ?? []; const styleCategories: string[] = facetRow.style ?? [];
const patternCategories: string[] = facetRow.pattern ?? []; const patternCategories: string[] = facetRow.pattern ?? [];
const motifCategories: string[] = facetRow.motif ?? [];
return { return {
room: roomCategories, room: roomCategories,
color: colorCategories, color: colorCategories,
style: styleCategories, style: styleCategories,
pattern: patternCategories, pattern: patternCategories,
motif: motifCategories,
}; };
} }
+4
View File
@@ -8,6 +8,7 @@ import {
type InputType = string | undefined | null; type InputType = string | undefined | null;
export const MINUTE = 60; export const MINUTE = 60;
export const HOUR = 3600;
function isNumeric(n: InputType) { function isNumeric(n: InputType) {
return !isNaN(parseFloat(n)); return !isNaN(parseFloat(n));
@@ -82,6 +83,9 @@ export const createQuestionMarksFromList = (arr: unknown[]): string => {
return '?,'.repeat(arr.length).slice(0, -1); return '?,'.repeat(arr.length).slice(0, -1);
}; };
export const sanitizeFacetValues = (values: string[]): string[] =>
values.map((v) => v.toLowerCase().replace(/,/g, ''));
export const isRepeatingPattern = (product: Product): boolean => { export const isRepeatingPattern = (product: Product): boolean => {
const found = product.printProducts.find( const found = product.printProducts.find(
(pr) => pr.groupId === ProductGroup.WALLPAPER, (pr) => pr.groupId === ProductGroup.WALLPAPER,
+22 -11
View File
@@ -21,7 +21,11 @@ import { DesignerAPI } from '../datasources/designer-api';
import { PrintProductDefaultsAPI } from '../datasources/printproduct-defaults-api'; import { PrintProductDefaultsAPI } from '../datasources/printproduct-defaults-api';
import { PrintProductDefaults } from '../types/printproduct-defaults-types'; import { PrintProductDefaults } from '../types/printproduct-defaults-types';
import { GraphQLError } from 'graphql'; import { GraphQLError } from 'graphql';
import { getOrientationString, isRepeatingPattern } from '../datasources/utils'; import {
getOrientationString,
isRepeatingPattern,
sanitizeFacetValues,
} from '../datasources/utils';
import { sendMessage } from '../aws/sqs'; import { sendMessage } from '../aws/sqs';
import { sendProductUpdatedEvent } from '../bernard/client'; import { sendProductUpdatedEvent } from '../bernard/client';
@@ -117,16 +121,13 @@ const Product = {
}), }),
]); ]);
const patterns = product.printProducts.some( const patterns = isRepeating ? categoryBasedFacets.pattern : [];
(pp) => pp.groupId === ProductGroup.WALLPAPER, const motifs = isRepeating ? [] : categoryBasedFacets.motif;
)
? categoryBasedFacets.pattern
: [];
return [ return [
{ {
attribute: 'color', attribute: 'color',
values: [...colors], values: sanitizeFacetValues([...colors]),
}, },
{ {
attribute: 'orientation', attribute: 'orientation',
@@ -141,10 +142,20 @@ const Product = {
return value.toLowerCase(); return value.toLowerCase();
}), }),
}, },
{ attribute: 'type', values: types }, { attribute: 'type', values: sanitizeFacetValues(types) },
{ attribute: 'room', values: categoryBasedFacets.room }, {
{ attribute: 'style', values: categoryBasedFacets.style }, attribute: 'room',
{ attribute: 'pattern', values: patterns }, values: sanitizeFacetValues(categoryBasedFacets.room),
},
{
attribute: 'style',
values: sanitizeFacetValues(categoryBasedFacets.style),
},
{ attribute: 'pattern', values: sanitizeFacetValues(patterns) },
{
attribute: 'motif',
values: sanitizeFacetValues(motifs),
},
]; ];
}, },
}; };