diff options
author | Wolfgang Müller | 2025-02-20 13:40:40 +0100 |
---|---|---|
committer | Wolfgang Müller | 2025-02-20 19:48:37 +0100 |
commit | 9c460c6db7e6a4e7f8ed3e8d93032c7ef070efee (patch) | |
tree | 69146def4fbc08f7fa4ad3bb37035a53d283b48a /frontend | |
parent | f90f3604cf161a82336ed1f81967933adedfeb96 (diff) | |
download | hircine-9c460c6db7e6a4e7f8ed3e8d93032c7ef070efee.tar.gz |
Add filter for association counts
This will replace the old 'empty' filter on comic associations and
introduce a generic way of matching against association counts, along
with support for different operators like 'greater than' or 'lower
than'.
Models that did not previously have a way of matching against their
associates (like filtering for Artists that have N comics associated
with them) now gain that functionality.
For now the frontend keeps the simpler approach of allowing the user to
only filter for empty associations, but we nonetheless need to adjust
the 'empty' field to instead be linked to the new 'count' field.
Diffstat (limited to 'frontend')
-rw-r--r-- | frontend/src/gql/graphql.ts | 25 | ||||
-rw-r--r-- | frontend/src/lib/Enums.ts | 7 | ||||
-rw-r--r-- | frontend/src/lib/Filter.svelte.ts | 25 |
3 files changed, 49 insertions, 8 deletions
diff --git a/frontend/src/gql/graphql.ts b/frontend/src/gql/graphql.ts index bd001f3..63f2c55 100644 --- a/frontend/src/gql/graphql.ts +++ b/frontend/src/gql/graphql.ts @@ -122,6 +122,7 @@ export type Artist = { }; export type ArtistFilter = { + comics?: InputMaybe<BasicCountFilter>; name?: InputMaybe<StringFilter>; }; @@ -164,10 +165,14 @@ export type ArtistsUpsertInput = { export type AssociationFilter = { all?: InputMaybe<Array<Scalars['Int']['input']>>; any?: InputMaybe<Array<Scalars['Int']['input']>>; - empty?: InputMaybe<Scalars['Boolean']['input']>; + count?: InputMaybe<CountFilter>; exact?: InputMaybe<Array<Scalars['Int']['input']>>; }; +export type BasicCountFilter = { + count: CountFilter; +}; + export enum Category { Artbook = 'ARTBOOK', Comic = 'COMIC', @@ -203,6 +208,7 @@ export type Character = { }; export type CharacterFilter = { + comics?: InputMaybe<BasicCountFilter>; name?: InputMaybe<StringFilter>; }; @@ -249,6 +255,7 @@ export type Circle = { }; export type CircleFilter = { + comics?: InputMaybe<BasicCountFilter>; name?: InputMaybe<StringFilter>; }; @@ -396,6 +403,11 @@ export type ComicTotals = { worlds: Scalars['Int']['output']; }; +export type CountFilter = { + operator?: InputMaybe<Operator>; + value: Scalars['Int']['input']; +}; + export type CoverInput = { id: Scalars['Int']['input']; }; @@ -862,6 +874,7 @@ export type Namespace = { export type NamespaceFilter = { name?: InputMaybe<StringFilter>; + tags?: InputMaybe<BasicCountFilter>; }; export type NamespaceFilterInput = { @@ -905,6 +918,12 @@ export enum OnMissing { Ignore = 'IGNORE' } +export enum Operator { + Equal = 'EQUAL', + GreaterThan = 'GREATER_THAN', + LowerThan = 'LOWER_THAN' +} + export type Page = { __typename?: 'Page'; comicId?: Maybe<Scalars['Int']['output']>; @@ -1153,11 +1172,12 @@ export type Tag = { export type TagAssociationFilter = { all?: InputMaybe<Array<Scalars['String']['input']>>; any?: InputMaybe<Array<Scalars['String']['input']>>; - empty?: InputMaybe<Scalars['Boolean']['input']>; + count?: InputMaybe<CountFilter>; exact?: InputMaybe<Array<Scalars['String']['input']>>; }; export type TagFilter = { + comics?: InputMaybe<BasicCountFilter>; name?: InputMaybe<StringFilter>; namespaces?: InputMaybe<AssociationFilter>; }; @@ -1324,6 +1344,7 @@ export type World = { }; export type WorldFilter = { + comics?: InputMaybe<BasicCountFilter>; name?: InputMaybe<StringFilter>; }; diff --git a/frontend/src/lib/Enums.ts b/frontend/src/lib/Enums.ts index 3264de4..db9fb86 100644 --- a/frontend/src/lib/Enums.ts +++ b/frontend/src/lib/Enums.ts @@ -10,6 +10,7 @@ import { Language, Layout, NamespaceSort, + Operator, Rating, TagSort, UpdateMode, @@ -125,6 +126,12 @@ export const UpdateModeLabel: Record<UpdateMode, string> = { [UpdateMode.Replace]: 'Replace' }; +export const OperatorLabel: Record<Operator, string> = { + [Operator.Equal]: 'Equal', + [Operator.GreaterThan]: 'Greater than', + [Operator.LowerThan]: 'Lower than,' +}; + export const LanguageLabel: Record<Language, string> = { [Language.Ab]: 'Abkhazian', [Language.Aa]: 'Afar', diff --git a/frontend/src/lib/Filter.svelte.ts b/frontend/src/lib/Filter.svelte.ts index 6183f06..e73f497 100644 --- a/frontend/src/lib/Filter.svelte.ts +++ b/frontend/src/lib/Filter.svelte.ts @@ -1,4 +1,5 @@ import { + Operator, type ArchiveFilter, type ArchiveFilterInput, type ComicFilter, @@ -30,7 +31,7 @@ type AssocFilter<T, K extends Key> = Filter< any?: T[] | null; all?: T[] | null; exact?: T[] | null; - empty?: boolean | null; + count?: { value: number; operator?: Operator | null } | null; }, K >; @@ -62,10 +63,6 @@ class ComplexMember<K extends Key> { if (this.values.length > 0) { filter[this.key] = { [this.mode]: this.values }; } - - if (this.empty) { - filter[this.key] = { ...filter[this.key], empty: this.empty }; - } } } @@ -80,7 +77,9 @@ export class Association<K extends Key> extends ComplexMember<K> { } const prop = filter[key]; - this.empty = prop?.empty; + this.empty = + prop?.count?.value === 0 && + (prop.count.operator === undefined || prop.count.operator === Operator.Equal); if (prop?.all && prop.all.length > 0) { this.mode = 'all'; @@ -93,6 +92,13 @@ export class Association<K extends Key> extends ComplexMember<K> { this.values = prop.exact; } } + + integrate(filter: AssocFilter<unknown, K>) { + super.integrate(filter); + if (this.empty) { + filter[this.key] = { ...filter[this.key], count: { value: 0, operator: Operator.Equal } }; + } + } } export class Enum<K extends Key> extends ComplexMember<K> { @@ -112,6 +118,13 @@ export class Enum<K extends Key> extends ComplexMember<K> { this.values = prop.any; } } + + integrate(filter: EnumFilter<K>) { + super.integrate(filter); + if (this.empty) { + filter[this.key] = { ...filter[this.key], empty: this.empty }; + } + } } class Bool<K extends Key> { |