@@ -419,3 +419,137 @@ Future<Response> _handlePost(
419
419
// Return 201 Created with the wrapped and serialized response
420
420
return Response .json (statusCode: HttpStatus .created, body: responseJson);
421
421
}
422
+
423
+ /*
424
+ Simplified Strict Filtering Rules (ALL FILTERS ARE ANDed if present):
425
+
426
+ 1. Headlines (`model=headline`):
427
+ - Filterable by any combination (ANDed) of:
428
+ - `categories` (plural, comma-separated IDs, matching `headline.category.id`)
429
+ - `sources` (plural, comma-separated IDs, matching `headline.source.id`)
430
+ - `q` (free-text query, searching `headline.title` only)
431
+ - *No other filters (like `countries`) are allowed for headlines.*
432
+
433
+ 2. Sources (`model=source`):
434
+ - Filterable by any combination (ANDed) of:
435
+ - `countries` (plural, comma-separated ISO codes, matching `source.headquarters.iso_code`)
436
+ - `sourceTypes` (plural, comma-separated enum strings, matching `source.sourceType`)
437
+ - `languages` (plural, comma-separated language codes, matching `source.language`)
438
+ - `q` (free-text query, searching `source.name` only)
439
+
440
+ 3. Categories (`model=category`):
441
+ - Filterable __only__ by:
442
+ - `q` (free-text query, searching `category.name` only)
443
+
444
+ 4. Countries (`model=country`):
445
+ - Filterable __only__ by:
446
+ - `q` (free-text query, searching `country.name` only)
447
+
448
+ ------
449
+
450
+ Explicitly Define Allowed Parameters per Model: When processing the request for a given `modelName`, the handler should have a predefined set of *allowed* query parameter keys for that specific model.
451
+
452
+ - Example for `modelName == 'headline'`:
453
+ - Allowed keys: `categories`, `sources`, `q` (plus standard ones like `limit`, `startAfterId`).
454
+ - Example for `modelName == 'source'`:
455
+ - Allowed keys: `countries`, `sourceTypes`, `languages`, `q` (plus standard ones).
456
+ - And so on for `category` and `country`.
457
+
458
+ ----------------- TESTED FILTERS ---------------
459
+
460
+ Model: `headline`
461
+
462
+ 1. Filter by single category:
463
+ - URL: `/api/v1/data?model=headline&categories=c1a2b3c4-d5e6-f789-0123-456789abcdef`
464
+ - Expected: Headlines with category ID `c1a2b3c4-d5e6-f789-0123-456789abcdef`.
465
+
466
+ 2. Filter by multiple comma-separated categories (client-side `_in` implies OR for values):
467
+ - URL: `/api/v1/data?model=headline&categories=c1a2b3c4-d5e6-f789-0123-456789abcdef,c2b3c4d5-e6f7-a890-1234-567890abcdef`
468
+ - Expected: Headlines whose category ID is *either* of the two provided.
469
+
470
+ 3. Filter by single source:
471
+ - URL: `/api/v1/data?model=headline&sources=s1a2b3c4-d5e6-f789-0123-456789abcdef`
472
+ - Expected: Headlines with source ID `s1a2b3c4-d5e6-f789-0123-456789abcdef`.
473
+
474
+ 4. Filter by multiple comma-separated sources (client-side `_in` implies OR for values):
475
+ - URL: `/api/v1/data?model=headline&sources=s1a2b3c4-d5e6-f789-0123-456789abcdef,s2b3c4d5-e6f7-a890-1234-567890abcdef`
476
+ - Expected: Headlines whose source ID is *either* of the two provided.
477
+
478
+ 5. Filter by a category AND a source:
479
+ - URL: `/api/v1/data?model=headline&categories=c1a2b3c4-d5e6-f789-0123-456789abcdef&sources=s1a2b3c4-d5e6-f789-0123-456789abcdef`
480
+ - Expected: Headlines matching *both* the category ID AND the source ID.
481
+
482
+ 6. Filter by text query `q` (title only):
483
+ - URL: `/api/v1/data?model=headline&q=Dart`
484
+ - Expected: Headlines where "Dart" (case-insensitive) appears in the title.
485
+
486
+ 7. Filter by `q` AND `categories` (q should take precedence, categories ignored):
487
+ - URL: `/api/v1/data?model=headline&q=Flutter&categories=c1a2b3c4-d5e6-f789-0123-456789abcdef`
488
+ - Expected: Headlines matching `q=Flutter` (in title), ignoring the category filter.
489
+
490
+ 8. Invalid parameter for headlines (e.g., `countries`):
491
+ - URL: `/api/v1/data?model=headline&countries=US`
492
+ - Expected: `400 Bad Request` with an error message about an invalid query parameter.
493
+
494
+ Model: `source`
495
+
496
+ 9. Filter by single country (ISO code):
497
+ - URL: `/api/v1/data?model=source&countries=GB`
498
+ - Expected: Sources headquartered in 'GB'.
499
+
500
+ 10. Filter by multiple comma-separated countries (client-side `_in` implies OR for values):
501
+ - URL: `/api/v1/data?model=source&countries=US,GB`
502
+ - Expected: Sources headquartered in 'US' OR 'GB'.
503
+
504
+ 11. Filter by single `sourceType`:
505
+ - URL: `/api/v1/data?model=source&sourceTypes=blog`
506
+ - Expected: Sources of type 'blog'.
507
+
508
+ 12. Filter by multiple comma-separated `sourceTypes` (client-side `_in` implies OR for values):
509
+ - URL: `/api/v1/data?model=source&sourceTypes=blog,specializedPublisher`
510
+ - Expected: Sources of type 'blog' OR 'specializedPublisher'.
511
+
512
+ 13. Filter by single `language`:
513
+ - URL: `/api/v1/data?model=source&languages=en`
514
+ - Expected: Sources in 'en' language.
515
+
516
+ 14. Filter by combination (countries AND sourceTypes AND languages):
517
+ - URL: `/api/v1/data?model=source&countries=GB&sourceTypes=nationalNewsOutlet&languages=en`
518
+ - Expected: Sources matching all three criteria.
519
+
520
+ 15. Filter by text query `q` for sources (name only):
521
+ - URL: `/api/v1/data?model=source&q=Ventures`
522
+ - Expected: Sources where "Ventures" appears in the name.
523
+
524
+ 16. Filter by `q` AND `countries` for sources (`q` takes precedence):
525
+ - URL: `/api/v1/data?model=source&q=Official&countries=US`
526
+ - Expected: Sources matching `q=Official` (in name), ignoring the country filter.
527
+
528
+ 17. Invalid parameter for sources (e.g., `categories`):
529
+ - URL: `/api/v1/data?model=source&categories=catId1`
530
+ - Expected: `400 Bad Request`.
531
+
532
+ Model: `category`
533
+
534
+ 18. Filter by text query `q` for categories (name only):
535
+ - URL: `/api/v1/data?model=category&q=Mobile`
536
+ - Expected: Categories where "Mobile" appears in name.
537
+
538
+ 19. Invalid parameter for categories (e.g., `sources`):
539
+ - URL: `/api/v1/data?model=category&sources=sourceId1`
540
+ - Expected: `400 Bad Request`.
541
+
542
+ Model: `country`
543
+
544
+ 20. Filter by text query `q` for countries (name only):
545
+ - URL: `/api/v1/data?model=country&q=United`
546
+ - Expected: Countries where "United" appears in the name.
547
+
548
+ 21. Filter by text query `q` for countries (name only, to match "US" if a country name contains "US"):
549
+ - URL: `/api/v1/data?model=country&q=US`
550
+ - Expected: Country with name containing "US". (Note: This test's expectation might need adjustment if no country name contains "US" but its isoCode is "US". The current `q` logic for country only searches name).
551
+
552
+ 22. Invalid parameter for countries (e.g., `categories`):
553
+ - URL: `/api/v1/data?model=country&categories=catId1`
554
+ - Expected: `400 Bad Request`.
555
+ */
0 commit comments