diff --git a/.bruno/fixes/invalid sorting.bru b/.bruno/fixes/466-invalid-sorting.bru similarity index 100% rename from .bruno/fixes/invalid sorting.bru rename to .bruno/fixes/466-invalid-sorting.bru diff --git a/.bruno/fixes/471-invalid-set-sorting.bru b/.bruno/fixes/471-invalid-set-sorting.bru new file mode 100644 index 000000000..1e1575d04 --- /dev/null +++ b/.bruno/fixes/471-invalid-set-sorting.bru @@ -0,0 +1,22 @@ +meta { + name: 471-invalid-set-sorting + type: http + seq: 2 +} + +get { + url: {{BASE_URL}}/v2/en/sets/swsh12/10 + body: none + auth: none +} + +assert { + res.body.id: eq swsh12-010 + res.status: eq 200 +} + +docs { + Validate the issue seen in + + https://github.com/tcgdex/cards-database/issues/471 +} diff --git a/server/package.json b/server/package.json index 4690d7a28..e847b132f 100644 --- a/server/package.json +++ b/server/package.json @@ -4,7 +4,7 @@ "main": "dist/index.js", "scripts": { "compile": "bun compiler/index.ts", - "dev": "bun --watch --hot src/index.ts", + "dev": "bun --watch src/index.ts", "validate": "tsc --noEmit --project ./tsconfig.json", "start": "bun src/index.ts" }, diff --git a/server/src/V2/Components/Card.ts b/server/src/V2/Components/Card.ts index 55fbf171e..5579f2839 100644 --- a/server/src/V2/Components/Card.ts +++ b/server/src/V2/Components/Card.ts @@ -69,7 +69,7 @@ export default class Card implements LocalCard { } public static findOne(lang: SupportedLanguages, query: Query) { - const res = handleValidation(this.getAll(lang), query) + const res = handleSort(handleValidation(this.getAll(lang), query), query) if (res.length === 0) { return undefined } diff --git a/server/src/V2/endpoints/jsonEndpoints.ts b/server/src/V2/endpoints/jsonEndpoints.ts index ba626137f..9947a1897 100644 --- a/server/src/V2/endpoints/jsonEndpoints.ts +++ b/server/src/V2/endpoints/jsonEndpoints.ts @@ -30,8 +30,8 @@ const endpointToField: Record = { } server - // Midleware that handle caching - .use(apicache.middleware('1 day', (req: Request) => req.method === 'GET', {})) + // Midleware that handle caching only in production and on GET requests + .use(apicache.middleware('1 day', (req: Request) => process.env.NODE_ENV === 'production' && req.method === 'GET', {})) // .get('/cache/performance', (req, res) => { // res.json(apicache.getPerformance()) @@ -186,23 +186,23 @@ server let result: any | undefined switch (endpoint) { case 'cards': - result = Card.findOne(lang, { filters: { id }})?.full() + result = Card.findOne(lang, { filters: { id }, strict: true })?.full() if (!result) { - result = Card.findOne(lang, { filters: { name: id }})?.full() + result = Card.findOne(lang, { filters: { name: id }, strict: true })?.full() } break case 'sets': - result = Set.findOne(lang, { filters: { id }})?.full() + result = Set.findOne(lang, { filters: { id }, strict: true })?.full() if (!result) { - result = Set.findOne(lang, {filters: { name: id }})?.full() + result = Set.findOne(lang, {filters: { name: id }, strict: true })?.full() } break case 'series': - result = Serie.findOne(lang, { filters: { id }})?.full() + result = Serie.findOne(lang, { filters: { id }, strict: true })?.full() if (!result) { - result = Serie.findOne(lang, { filters: { name: id }})?.full() + result = Serie.findOne(lang, { filters: { name: id }, strict: true })?.full() } break default: @@ -242,7 +242,7 @@ server switch (endpoint) { case 'sets': result = Card - .findOne(lang, { filters: { localId: subid, set: id }})?.full() + .findOne(lang, { filters: { localId: subid, set: id }, strict: true})?.full() break } if (!result) { diff --git a/server/src/interfaces.d.ts b/server/src/interfaces.d.ts index c3f075c81..922f7f71c 100644 --- a/server/src/interfaces.d.ts +++ b/server/src/interfaces.d.ts @@ -28,6 +28,10 @@ export interface Query { */ filters?: Partial<{ [Key in keyof T]: T[Key] extends object ? string | number | Array : T[Key] | Array }> + /** + * instead of filtering text search it will search using the full string + */ + strict?: boolean /** * data sorting * diff --git a/server/src/util.ts b/server/src/util.ts index f9927019e..8c7a62bf9 100644 --- a/server/src/util.ts +++ b/server/src/util.ts @@ -59,9 +59,15 @@ export function betterSorter(a: string, b: string) { * * @param validator the validation object * @param value the value to validate + * @param strict change how the results are fetched * @returns `true` if valid else `false` */ -export function validateItem(validator: any | Array, value: any): boolean { +export function validateItem(validator: any | Array, value: any, strict: boolean = false): boolean { + // convert to number is possible + if (/^\d+$/.test(validator)) { + validator = parseInt(validator) + } + if (typeof value === 'object') { // invert signal so that an early exit mean that a match was found! return !objectLoop(value, (v) => { @@ -69,14 +75,14 @@ export function validateItem(validator: any | Array, value: any): boolean { if (typeof v === 'object') return true // check for each childs until one match - return !validateItem(validator, v) + return !validateItem(validator, v, strict) }) } // loop to validate for an array if (Array.isArray(validator)) { for (const sub of validator) { - const res = validateItem(sub, value) + const res = validateItem(sub, value, strict) if (res) { return true } @@ -84,8 +90,12 @@ export function validateItem(validator: any | Array, value: any): boolean { return false } if (typeof validator === 'string') { - // run a string validation - return value.toString().toLowerCase().includes(validator.toLowerCase()) + // run a strict string validation + if (strict) { + return value.toString().toLowerCase() === validator.toLowerCase() + } else { + return value.toString().toLowerCase().includes(validator.toLowerCase()) + } } else if (typeof validator === 'number') { // run a number validation if (typeof value === 'number') { @@ -197,6 +207,6 @@ export function handleValidation(data: Array, query: Query) { } return data.filter((v) => objectLoop(filters, (valueToValidate, key) => { - return validateItem(valueToValidate, v[key]) + return validateItem(valueToValidate, v[key], query.strict) })) }