1
0
mirror of https://github.com/tcgdex/cards-database.git synced 2025-04-25 20:32:11 +00:00

fix: Invalid card when searching using the set and localid (#472)

This commit is contained in:
Florian Bouillon 2024-01-08 00:40:31 +01:00 committed by GitHub
parent 8684fb14e4
commit 33007d83bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 53 additions and 17 deletions

View File

@ -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
}

View File

@ -4,7 +4,7 @@
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"compile": "bun compiler/index.ts", "compile": "bun compiler/index.ts",
"dev": "bun --watch --hot src/index.ts", "dev": "bun --watch src/index.ts",
"validate": "tsc --noEmit --project ./tsconfig.json", "validate": "tsc --noEmit --project ./tsconfig.json",
"start": "bun src/index.ts" "start": "bun src/index.ts"
}, },

View File

@ -69,7 +69,7 @@ export default class Card implements LocalCard {
} }
public static findOne(lang: SupportedLanguages, query: Query<SDKCard>) { public static findOne(lang: SupportedLanguages, query: Query<SDKCard>) {
const res = handleValidation(this.getAll(lang), query) const res = handleSort(handleValidation(this.getAll(lang), query), query)
if (res.length === 0) { if (res.length === 0) {
return undefined return undefined
} }

View File

@ -30,8 +30,8 @@ const endpointToField: Record<string, keyof SDKCard> = {
} }
server server
// Midleware that handle caching // Midleware that handle caching only in production and on GET requests
.use(apicache.middleware('1 day', (req: Request) => req.method === 'GET', {})) .use(apicache.middleware('1 day', (req: Request) => process.env.NODE_ENV === 'production' && req.method === 'GET', {}))
// .get('/cache/performance', (req, res) => { // .get('/cache/performance', (req, res) => {
// res.json(apicache.getPerformance()) // res.json(apicache.getPerformance())
@ -186,23 +186,23 @@ server
let result: any | undefined let result: any | undefined
switch (endpoint) { switch (endpoint) {
case 'cards': case 'cards':
result = Card.findOne(lang, { filters: { id }})?.full() result = Card.findOne(lang, { filters: { id }, strict: true })?.full()
if (!result) { if (!result) {
result = Card.findOne(lang, { filters: { name: id }})?.full() result = Card.findOne(lang, { filters: { name: id }, strict: true })?.full()
} }
break break
case 'sets': case 'sets':
result = Set.findOne(lang, { filters: { id }})?.full() result = Set.findOne(lang, { filters: { id }, strict: true })?.full()
if (!result) { if (!result) {
result = Set.findOne(lang, {filters: { name: id }})?.full() result = Set.findOne(lang, {filters: { name: id }, strict: true })?.full()
} }
break break
case 'series': case 'series':
result = Serie.findOne(lang, { filters: { id }})?.full() result = Serie.findOne(lang, { filters: { id }, strict: true })?.full()
if (!result) { if (!result) {
result = Serie.findOne(lang, { filters: { name: id }})?.full() result = Serie.findOne(lang, { filters: { name: id }, strict: true })?.full()
} }
break break
default: default:
@ -242,7 +242,7 @@ server
switch (endpoint) { switch (endpoint) {
case 'sets': case 'sets':
result = Card result = Card
.findOne(lang, { filters: { localId: subid, set: id }})?.full() .findOne(lang, { filters: { localId: subid, set: id }, strict: true})?.full()
break break
} }
if (!result) { if (!result) {

View File

@ -28,6 +28,10 @@ export interface Query<T extends {} = {}> {
*/ */
filters?: Partial<{ [Key in keyof T]: T[Key] extends object ? string | number | Array<string | number> : T[Key] | Array<T[Key]> }> filters?: Partial<{ [Key in keyof T]: T[Key] extends object ? string | number | Array<string | number> : T[Key] | Array<T[Key]> }>
/**
* instead of filtering text search it will search using the full string
*/
strict?: boolean
/** /**
* data sorting * data sorting
* *

View File

@ -59,9 +59,15 @@ export function betterSorter(a: string, b: string) {
* *
* @param validator the validation object * @param validator the validation object
* @param value the value to validate * @param value the value to validate
* @param strict change how the results are fetched
* @returns `true` if valid else `false` * @returns `true` if valid else `false`
*/ */
export function validateItem(validator: any | Array<any>, value: any): boolean { export function validateItem(validator: any | Array<any>, value: any, strict: boolean = false): boolean {
// convert to number is possible
if (/^\d+$/.test(validator)) {
validator = parseInt(validator)
}
if (typeof value === 'object') { if (typeof value === 'object') {
// invert signal so that an early exit mean that a match was found! // invert signal so that an early exit mean that a match was found!
return !objectLoop(value, (v) => { return !objectLoop(value, (v) => {
@ -69,14 +75,14 @@ export function validateItem(validator: any | Array<any>, value: any): boolean {
if (typeof v === 'object') return true if (typeof v === 'object') return true
// check for each childs until one match // check for each childs until one match
return !validateItem(validator, v) return !validateItem(validator, v, strict)
}) })
} }
// loop to validate for an array // loop to validate for an array
if (Array.isArray(validator)) { if (Array.isArray(validator)) {
for (const sub of validator) { for (const sub of validator) {
const res = validateItem(sub, value) const res = validateItem(sub, value, strict)
if (res) { if (res) {
return true return true
} }
@ -84,8 +90,12 @@ export function validateItem(validator: any | Array<any>, value: any): boolean {
return false return false
} }
if (typeof validator === 'string') { if (typeof validator === 'string') {
// run a string validation // run a strict string validation
return value.toString().toLowerCase().includes(validator.toLowerCase()) if (strict) {
return value.toString().toLowerCase() === validator.toLowerCase()
} else {
return value.toString().toLowerCase().includes(validator.toLowerCase())
}
} else if (typeof validator === 'number') { } else if (typeof validator === 'number') {
// run a number validation // run a number validation
if (typeof value === 'number') { if (typeof value === 'number') {
@ -197,6 +207,6 @@ export function handleValidation(data: Array<any>, query: Query) {
} }
return data.filter((v) => objectLoop(filters, (valueToValidate, key) => { return data.filter((v) => objectLoop(filters, (valueToValidate, key) => {
return validateItem(valueToValidate, v[key]) return validateItem(valueToValidate, v[key], query.strict)
})) }))
} }