Skip to content

Commit bbab9a3

Browse files
authored
Merge pull request #2933 from rommapp/none-filter-support
Add NONE support for filter logic operators
2 parents 12c1572 + b49522e commit bbab9a3

7 files changed

Lines changed: 148 additions & 97 deletions

File tree

backend/endpoints/rom.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -351,55 +351,55 @@ def get_roms(
351351
genres_logic: Annotated[
352352
str,
353353
Query(
354-
description="Logic operator for genres filter: 'any' (OR) or 'all' (AND).",
354+
description="Logic operator for genres filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
355355
),
356356
] = "any",
357357
franchises_logic: Annotated[
358358
str,
359359
Query(
360-
description="Logic operator for franchises filter: 'any' (OR) or 'all' (AND).",
360+
description="Logic operator for franchises filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
361361
),
362362
] = "any",
363363
collections_logic: Annotated[
364364
str,
365365
Query(
366-
description="Logic operator for collections filter: 'any' (OR) or 'all' (AND).",
366+
description="Logic operator for collections filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
367367
),
368368
] = "any",
369369
companies_logic: Annotated[
370370
str,
371371
Query(
372-
description="Logic operator for companies filter: 'any' (OR) or 'all' (AND).",
372+
description="Logic operator for companies filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
373373
),
374374
] = "any",
375375
age_ratings_logic: Annotated[
376376
str,
377377
Query(
378-
description="Logic operator for age ratings filter: 'any' (OR) or 'all' (AND).",
378+
description="Logic operator for age ratings filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
379379
),
380380
] = "any",
381381
regions_logic: Annotated[
382382
str,
383383
Query(
384-
description="Logic operator for regions filter: 'any' (OR) or 'all' (AND).",
384+
description="Logic operator for regions filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
385385
),
386386
] = "any",
387387
languages_logic: Annotated[
388388
str,
389389
Query(
390-
description="Logic operator for languages filter: 'any' (OR) or 'all' (AND).",
390+
description="Logic operator for languages filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
391391
),
392392
] = "any",
393393
statuses_logic: Annotated[
394394
str,
395395
Query(
396-
description="Logic operator for statuses filter: 'any' (OR) or 'all' (AND).",
396+
description="Logic operator for statuses filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
397397
),
398398
] = "any",
399399
player_counts_logic: Annotated[
400400
str,
401401
Query(
402-
description="Logic operator for player counts filter: 'any' (OR) or 'all' (AND).",
402+
description="Logic operator for player counts filter: 'any' (OR), 'all' (AND) or 'none' (NOT).",
403403
),
404404
] = "any",
405405
order_by: Annotated[

backend/handler/database/roms_handler.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,11 @@ def _filter_by_genres(
372372
session: Session,
373373
values: Sequence[str],
374374
match_all: bool = False,
375+
match_none: bool = False,
375376
) -> Query:
376377
op = json_array_contains_all if match_all else json_array_contains_any
377-
return query.filter(op(RomMetadata.genres, values, session=session))
378+
condition = op(RomMetadata.genres, values, session=session)
379+
return query.filter(~condition) if match_none else query.filter(condition)
378380

379381
def _filter_by_franchises(
380382
self,
@@ -383,9 +385,11 @@ def _filter_by_franchises(
383385
session: Session,
384386
values: Sequence[str],
385387
match_all: bool = False,
388+
match_none: bool = False,
386389
) -> Query:
387390
op = json_array_contains_all if match_all else json_array_contains_any
388-
return query.filter(op(RomMetadata.franchises, values, session=session))
391+
condition = op(RomMetadata.franchises, values, session=session)
392+
return query.filter(~condition) if match_none else query.filter(condition)
389393

390394
def _filter_by_collections(
391395
self,
@@ -394,9 +398,11 @@ def _filter_by_collections(
394398
session: Session,
395399
values: Sequence[str],
396400
match_all: bool = False,
401+
match_none: bool = False,
397402
) -> Query:
398403
op = json_array_contains_all if match_all else json_array_contains_any
399-
return query.filter(op(RomMetadata.collections, values, session=session))
404+
condition = op(RomMetadata.collections, values, session=session)
405+
return query.filter(~condition) if match_none else query.filter(condition)
400406

401407
def _filter_by_companies(
402408
self,
@@ -405,9 +411,11 @@ def _filter_by_companies(
405411
session: Session,
406412
values: Sequence[str],
407413
match_all: bool = False,
414+
match_none: bool = False,
408415
) -> Query:
409416
op = json_array_contains_all if match_all else json_array_contains_any
410-
return query.filter(op(RomMetadata.companies, values, session=session))
417+
condition = op(RomMetadata.companies, values, session=session)
418+
return query.filter(~condition) if match_none else query.filter(condition)
411419

412420
def _filter_by_age_ratings(
413421
self,
@@ -416,9 +424,11 @@ def _filter_by_age_ratings(
416424
session: Session,
417425
values: Sequence[str],
418426
match_all: bool = False,
427+
match_none: bool = False,
419428
) -> Query:
420429
op = json_array_contains_all if match_all else json_array_contains_any
421-
return query.filter(op(RomMetadata.age_ratings, values, session=session))
430+
condition = op(RomMetadata.age_ratings, values, session=session)
431+
return query.filter(~condition) if match_none else query.filter(condition)
422432

423433
def _filter_by_status(self, query: Query, statuses: Sequence[str]):
424434
"""Filter by one or more user statuses using OR logic."""
@@ -449,9 +459,11 @@ def _filter_by_regions(
449459
session: Session,
450460
values: Sequence[str],
451461
match_all: bool = False,
462+
match_none: bool = False,
452463
) -> Query:
453464
op = json_array_contains_all if match_all else json_array_contains_any
454-
return query.filter(op(Rom.regions, values, session=session))
465+
condition = op(Rom.regions, values, session=session)
466+
return query.filter(~condition) if match_none else query.filter(condition)
455467

456468
def _filter_by_languages(
457469
self,
@@ -460,9 +472,11 @@ def _filter_by_languages(
460472
session: Session,
461473
values: Sequence[str],
462474
match_all: bool = False,
475+
match_none: bool = False,
463476
) -> Query:
464477
op = json_array_contains_all if match_all else json_array_contains_any
465-
return query.filter(op(Rom.languages, values, session=session))
478+
condition = op(Rom.languages, values, session=session)
479+
return query.filter(~condition) if match_none else query.filter(condition)
466480

467481
def _filter_by_player_counts(
468482
self,
@@ -471,8 +485,12 @@ def _filter_by_player_counts(
471485
session: Session,
472486
values: Sequence[str],
473487
match_all: bool = False,
488+
match_none: bool = False,
474489
) -> Query:
475-
return query.filter(RomMetadata.player_count.in_(values))
490+
condition = RomMetadata.player_count.in_(values)
491+
if match_none:
492+
return query.filter(not_(condition))
493+
return query.filter(condition)
476494

477495
@begin_session
478496
def filter_roms(
@@ -695,7 +713,11 @@ def filter_roms(
695713
for values, logic, filter_func in filters_to_apply:
696714
if values:
697715
query = filter_func(
698-
query, session=session, values=values, match_all=(logic == "all")
716+
query,
717+
session=session,
718+
values=values,
719+
match_all=(logic == "all"),
720+
match_none=(logic == "none"),
699721
)
700722

701723
# The RomUser table is already joined if user_id is set

0 commit comments

Comments
 (0)