Files
pokemon-inventory/apps/api/src/modules/search/domain/search-query.js
T
fragginwagon b036092775
Quality / test (push) Canceled after 0s
feat: expand catalog sorting
2026-09-10 02:39:42 -04:00

93 lines
2.3 KiB
JavaScript

function requiredString(value, fieldName) {
if (typeof value !== "string") {
throw new Error(`${fieldName} must be a string.`);
}
return value;
}
export function normalizeSearchQuery(value) {
return requiredString(value, "Search query")
.trim()
.normalize("NFKC")
.replace(/[^\p{L}\p{N}\s]+/gu, " ")
.replace(/\s+/g, " ")
.toLowerCase();
}
export function createSearchQuery({
query = "",
category,
conditionId,
minPriceMinor,
maxPriceMinor,
page = 1,
limit = 20,
includeSold = false,
sort = "recent",
}) {
const text = normalizeSearchQuery(query);
if (!Number.isInteger(page) || page < 1) {
throw new Error("page must be >= 1");
}
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
throw new Error("limit must be between 1 and 100");
}
if (
typeof minPriceMinor !== "undefined" &&
(!Number.isInteger(minPriceMinor) || minPriceMinor < 0)
) {
throw new Error("minPriceMinor must be a non-negative integer");
}
if (
typeof maxPriceMinor !== "undefined" &&
(!Number.isInteger(maxPriceMinor) || maxPriceMinor < 0)
) {
throw new Error("maxPriceMinor must be a non-negative integer");
}
if (
typeof minPriceMinor !== "undefined" &&
typeof maxPriceMinor !== "undefined" &&
minPriceMinor > maxPriceMinor
) {
throw new Error("minPriceMinor must be <= maxPriceMinor");
}
if (!["recent", "updated", "name_asc", "name_desc", "price_low", "price_high"].includes(sort)) {
throw new Error("sort must be recent, updated, name_asc, name_desc, price_low, or price_high");
}
return {
text,
...(typeof category === "string" && category.trim().length > 0
? { category: category.trim() }
: {}),
...(typeof conditionId === "string" && conditionId.trim().length > 0
? { conditionId: conditionId.trim() }
: {}),
...(typeof minPriceMinor === "number" ? { minPriceMinor } : {}),
...(typeof maxPriceMinor === "number" ? { maxPriceMinor } : {}),
page,
limit,
includeSold,
...(sort !== "recent" ? { sort } : {}),
};
}
export function buildSearchFilters({
includeSold = false,
status = "AVAILABLE",
sort = ["recently_added"],
}) {
return {
status: includeSold ? "ALL" : status,
includeSold,
sort,
};
}