113 lines
2.9 KiB
JavaScript
113 lines
2.9 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,
|
|
setName,
|
|
eventName,
|
|
tag,
|
|
status,
|
|
newlyAdded = false,
|
|
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 (status && !["AVAILABLE", "PENDING", "SOLD", "ALL"].includes(status)) {
|
|
throw new Error("status must be AVAILABLE, PENDING, SOLD, or ALL");
|
|
}
|
|
|
|
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 setName === "string" && setName.trim().length > 0
|
|
? { setName: setName.trim() }
|
|
: {}),
|
|
...(typeof eventName === "string" && eventName.trim().length > 0
|
|
? { eventName: eventName.trim() }
|
|
: {}),
|
|
...(typeof tag === "string" && tag.trim().length > 0
|
|
? { tag: tag.trim().toLowerCase() }
|
|
: {}),
|
|
...(typeof minPriceMinor === "number" ? { minPriceMinor } : {}),
|
|
...(typeof maxPriceMinor === "number" ? { maxPriceMinor } : {}),
|
|
page,
|
|
limit,
|
|
includeSold,
|
|
...(status ? { status } : {}),
|
|
...(newlyAdded ? { newlyAdded: true } : {}),
|
|
...(sort !== "recent" ? { sort } : {}),
|
|
};
|
|
}
|
|
|
|
export function buildSearchFilters({
|
|
includeSold = false,
|
|
status = "AVAILABLE",
|
|
sort = ["recently_added"],
|
|
}) {
|
|
return {
|
|
status: includeSold ? "ALL" : status,
|
|
includeSold,
|
|
sort,
|
|
};
|
|
}
|