UNPKG

@storecraft/database-sql-base

Version:

Official SQL Database driver for storecraft

211 lines (189 loc) 5.61 kB
/** * @import { * DiscountType, Filter_p_in_price_range, Filter_p_not_in_collections, * Filter_p_in_collections, Filter_p_not_in_tags, Filter_p_in_tags, * Filter_p_in_products, Filter_p_not_in_products * } from '@storecraft/core/api' * @import { Database } from '../types.sql.tables.js' * @import { ExpressionBuilder, BinaryOperator } from 'kysely' */ import { enums } from "@storecraft/core/api"; import { assert } from "console"; /** @param {DiscountType} d */ export const is_order_discount = d => { return ( (d.info.details.type===enums.DiscountMetaEnum.order.type) || // @ts-ignore (d.info.details.meta?.type===enums.DiscountMetaEnum.order.type) ); } /** @param {DiscountType} d */ export const is_automatic_discount = d => { return (d.application.id===enums.DiscountApplicationEnum.Auto.id); } const extract_abs_number = v => { return v && !isNaN(v) && v!==Infinity && Math.abs(v); } /** * @param {ExpressionBuilder<Database, 'products'>} eb * @param {keyof Pick<Database, 'entity_to_tags_projections' | 'products_to_collections'>} table * @param {string[]} value */ const eb_in = (eb, table, value) => { return eb.exists( eb => eb .selectFrom(table) .select('id') .where( eb => eb.and( [ eb.or( [ eb(`${table}.entity_id`, '=', eb.ref('products.id')), eb(`${table}.entity_handle`, '=', eb.ref('products.handle')), ] ), eb(`${table}.value`, 'in', value) ] ) ) ) } /** * @description create a filter conjunctions clauses from discount * for filtering. * @param {ExpressionBuilder<Database, 'products'>} eb * @param {DiscountType} d */ export const discount_to_conjunctions = (eb, d) => { // discount has to be product discount + automatic + active + has filters const is_good = ( !is_order_discount(d) && is_automatic_discount(d) && d.active && d?.info?.filters?.length ); assert( is_good, `discount_to_conjunctions: discount is not a product discount` ); const conjunctions = []; const filters = d.info.filters; for(const filter of filters) { const op = filter.op ?? filter.meta.op; switch (op) { case enums.FilterMetaEnum.p_all.op: // do nothing break; case enums.FilterMetaEnum.p_in_products.op: { const cast_filter = /** @type {Filter_p_in_products} */ ( filter ); const value = cast_filter?.value ?? []; conjunctions.push( eb( 'products.handle', 'in', value.map(item => item.handle).filter(Boolean) ) ); } break; case enums.FilterMetaEnum.p_not_in_products.op: { const cast_filter = /** @type {Filter_p_not_in_products} */ ( filter ); const value = cast_filter?.value ?? []; conjunctions.push( eb( 'products.handle', 'not in', value.map(item => item.handle).filter(Boolean) ) ); } break; case enums.FilterMetaEnum.p_in_tags.op: { const cast_filter = /** @type {Filter_p_in_tags} */ ( filter ); const value = cast_filter?.value ?? []; conjunctions.push( eb_in( eb, 'entity_to_tags_projections', value ) ); } break; case enums.FilterMetaEnum.p_not_in_tags.op: { const cast_filter = /** @type {Filter_p_not_in_tags} */ ( filter ); const value = cast_filter?.value ?? []; conjunctions.push( eb.not( eb_in( eb, 'entity_to_tags_projections', value ) ) ); } break; case enums.FilterMetaEnum.p_in_collections.op: { const cast_filter = /** @type {Filter_p_in_collections} */ ( filter ); const value = cast_filter?.value ?? []; // PROBLEM: we only have ids, but use handles in the filters conjunctions.push( eb_in( eb, 'products_to_collections', value.map(c => c.id) ) ); } break; case enums.FilterMetaEnum.p_not_in_collections.op: { const cast_filter = /** @type {Filter_p_not_in_collections} */ ( filter ); const value = cast_filter?.value ?? []; conjunctions.push( eb.not( eb_in( eb, 'products_to_collections', value.map(c => c.id) ) ) ); } break; case enums.FilterMetaEnum.p_in_price_range.op: { const cast_filter = /** @type {Filter_p_in_price_range} */ ( filter ); const value = /** @type {Filter_p_in_price_range["value"]} */({ from: 0, to: Number.POSITIVE_INFINITY, ...(cast_filter?.value ?? {}), }); const from = extract_abs_number(value.from); const to = extract_abs_number(value.to); const conj = { price: { $and: [] } }; if(from) conjunctions.push(eb('price', '>=', from)); if(to) conjunctions.push(eb('price', '<', to)); } break; default: break; } } return conjunctions; }