import { ExtendedFindConfig, FindConfig } from "@medusajs/types" import { And, FindManyOptions, FindOperator, FindOptionsOrder, FindOptionsRelations, FindOptionsSelect, FindOptionsWhere, ILike, In, IsNull, LessThan, LessThanOrEqual, MoreThan, MoreThanOrEqual, } from "typeorm" import { buildOrder, buildRelations, buildSelects } from "@medusajs/utils" const operatorsMap = { lt: (value) => LessThan(value), gt: (value) => MoreThan(value), lte: (value) => LessThanOrEqual(value), gte: (value) => MoreThanOrEqual(value), contains: (value) => ILike(`%${value}%`), starts_with: (value) => ILike(`${value}%`), ends_with: (value) => ILike(`%${value}`), } /** * Used to build TypeORM queries. * @param selector The selector * @param config The config * @return The QueryBuilderConfig */ export function buildQuery( selector: TWhereKeys, config: FindConfig = {} ) { const query: ExtendedFindConfig = { where: buildWhere(selector), } if ("deleted_at" in selector || config.withDeleted) { query.withDeleted = true } if ("skip" in config) { ;(query as FindManyOptions).skip = config.skip } if ("take" in config) { ;(query as FindManyOptions).take = config.take } if (config.relations) { query.relations = buildRelations( config.relations ) as FindOptionsRelations } if (config.select) { query.select = buildSelects( config.select as string[] ) as FindOptionsSelect } if (config.order) { query.order = buildOrder(config.order) as FindOptionsOrder } return query } /** * @param constraints * * @example * const q = buildWhere( * { * id: "1234", * test1: ["123", "12", "1"], * test2: Not("this"), * date: { gt: date }, * amount: { gt: 10 }, * }, *) * * // Output * { * id: "1234", * test1: In(["123", "12", "1"]), * test2: Not("this"), * date: MoreThan(date), * amount: MoreThan(10) * } */ function buildWhere( constraints: TWhereKeys ): FindOptionsWhere { const where: FindOptionsWhere = {} for (const [key, value] of Object.entries(constraints)) { if (value === undefined) { continue } if (value === null) { where[key] = IsNull() continue } if (value instanceof FindOperator) { where[key] = value continue } if (Array.isArray(value)) { where[key] = In(value) continue } if (typeof value === "object") { Object.entries(value).forEach(([objectKey, objectValue]) => { where[key] = where[key] || [] if (operatorsMap[objectKey]) { where[key].push(operatorsMap[objectKey](objectValue)) } else { if (objectValue != undefined && typeof objectValue === "object") { where[key] = buildWhere(objectValue) return } where[key] = value } return }) if (!Array.isArray(where[key])) { continue } if (where[key].length === 1) { where[key] = where[key][0] } else { where[key] = And(...where[key]) } continue } where[key] = value } return where }