1
0
mirror of https://github.com/tcgdex/cards-database.git synced 2025-04-25 12:22:14 +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",
"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"
},

View File

@ -69,7 +69,7 @@ export default class Card implements LocalCard {
}
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) {
return undefined
}

View File

@ -30,8 +30,8 @@ const endpointToField: Record<string, keyof SDKCard> = {
}
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) {

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]> }>
/**
* instead of filtering text search it will search using the full string
*/
strict?: boolean
/**
* data sorting
*

View File

@ -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<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') {
// 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<any>, 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<any>, 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<any>, query: Query) {
}
return data.filter((v) => objectLoop(filters, (valueToValidate, key) => {
return validateItem(valueToValidate, v[key])
return validateItem(valueToValidate, v[key], query.strict)
}))
}