filter stuff

This commit is contained in:
Gauthier Roebroeck 2026-01-30 12:14:23 +08:00
parent b24bc27748
commit 81a463a741
4 changed files with 119 additions and 0 deletions

View file

@ -0,0 +1,41 @@
import * as v from 'valibot'
import { useRouteQuery } from '@vueuse/router'
import { syncRef } from '@vueuse/core'
/**
* Reactive `route.query` with schema validation.
* If value is not valid, the `schema` default values are used.
*
* @param queryName the query parameter name
* @param schema valibot schema to validate against
*/
export function useRouteQuerySchema<T extends v.GenericSchema>(queryName: string, schema: T) {
const queryString = useRouteQuery(queryName, '{}')
const defaults = v.getDefaults(schema)
function getInitialValue(stringValue: string) {
try {
return v.parse(schema, JSON.parse(stringValue))
} catch {
return defaults
}
}
const data = ref(getInitialValue(String(queryString.value)))
syncRef(data, queryString, {
direction: 'ltr',
deep: true,
transform: {
ltr: (left) => {
if (JSON.stringify(left) !== JSON.stringify(defaults)) return JSON.stringify(left)
return undefined
},
},
})
return {
data: data as v.InferOutput<T>,
}
}

View file

@ -0,0 +1,22 @@
import type { SchemaFilterSeriesStatus } from '@/types/filter'
import type { InferOutput } from 'valibot'
export function schemaFilterSeriesStatusToConditions(
filter: MaybeRefOrGetter<InferOutput<typeof SchemaFilterSeriesStatus>>,
) {
const list = toValue(filter).v.map((it) => ({
seriesStatus: {
operator: it.i === 'e' ? 'isNot' : 'is',
value: it.v,
},
}))
if (toValue(filter).m === 'allOf')
return {
allOf: list,
}
else
return {
anyOf: list,
}
}

View file

@ -0,0 +1,32 @@
import { describe, expect, test } from 'vitest'
import * as v from 'valibot'
import { SchemaAnyAll } from '@/types/filter'
describe('schema any all', () => {
test('anyOf', () => {
const input = { m: 'anyOf' }
const result = v.parse(SchemaAnyAll, input)
expect(result).toStrictEqual(input)
})
test('allOf', () => {
const input = { m: 'allOf' }
const result = v.parse(SchemaAnyAll, input)
expect(result).toStrictEqual(input)
})
test('other value throws error', () => {
const input = { m: 'other' }
expect(() => v.parse(SchemaAnyAll, input)).toThrowError()
})
test('defaults to anyOf', () => {
const input = { m: 'anyOf' }
const defaults = v.getDefaults(SchemaAnyAll)
expect(defaults).toStrictEqual(input)
})
})

View file

@ -0,0 +1,24 @@
import * as v from 'valibot'
export type AnyAll = 'anyOf' | 'allOf'
export const SchemaAnyAll = v.object({
m: v.optional(v.picklist(['anyOf', 'allOf']), 'anyOf'),
})
const SchemaIncludeExclude = v.object({ i: v.optional(v.picklist(['i', 'e'])) })
const SchemaSeriesStatus = v.object({
...SchemaIncludeExclude.entries,
v: v.optional(v.picklist(['ENDED', 'ONGOING', 'ABANDONED', 'HIATUS'])),
})
export const SchemaFilterSeriesStatus = v.object({
...SchemaAnyAll.entries,
v: v.fallback(v.optional(v.array(SchemaSeriesStatus), []), []),
})
export const FilterSeriesGenre = v.object({
...SchemaAnyAll.entries,
value: v.array(v.string()),
})