Skip to content

feat(assets): add job_ids filter to GET /api/assets#13998

Open
mattmillerai wants to merge 5 commits into
masterfrom
matt/be-891-local-add-job_ids-filter-param-to-get-apiassets
Open

feat(assets): add job_ids filter to GET /api/assets#13998
mattmillerai wants to merge 5 commits into
masterfrom
matt/be-891-local-add-job_ids-filter-param-to-get-apiassets

Conversation

@mattmillerai
Copy link
Copy Markdown
Contributor

@mattmillerai mattmillerai commented May 20, 2026

Summary

  • Adds job_ids query param to GET /api/assets on the Python local server, mirroring the existing cloud behavior.
  • Accepts a comma-separated string or repeated query params; entries must parse as UUIDs (canonicalized to lowercase hyphenated form, deduplicated).
  • Combinable with existing filters (include_tags, exclude_tags, name_contains, metadata_filter, etc.).
  • No migration: the AssetReference.job_id column already exists.

OpenAPI

Drops the [cloud-only] description prefix and the x-runtime: [cloud] tag from the job_ids parameter — per the field-drift convention, an absent runtime tag means both local and cloud populate/accept the field.

Test plan

  • pytest tests-unit/assets_test/queries -x -q (133 passed) — includes two new tests covering single-job filter, multi-job IN, unknown-job (empty result), empty/None passthrough, and combination with name_contains.
  • Smoke-tested ListAssetsQuery.job_ids validator: CSV input, list input, mixed CSV-in-list, dedup, default-empty, and invalid-UUID rejection (raises ValidationError).
  • Reviewer: confirm the OpenAPI convention call (dropping x-runtime: [cloud]) matches the project's expectation for now-bi-runtime fields.

HTTP smoke test

Ran local ComfyUI from this branch with --enable-assets, seeded three AssetReference rows directly: smoke-job-a.png (JOB_A=11111111-1111-1111-1111-111111111111), smoke-job-b.png (JOB_B=22222222-2222-2222-2222-222222222222), and smoke-no-job.png (no job). Hit the live HTTP endpoint with eight query variants:

# Query Expected Result
1 ?job_ids={A} only smoke-job-a.png total=1, [smoke-job-a.png]
2 ?job_ids={A},{B} (comma-separated) a + b total=2, [a, b]
3 ?job_ids={A}&job_ids={B} (repeated) a + b total=2, [a, b]
4 ?job_ids={ghost UUID} empty total=0
5 no filter all three smoke rows present alongside scanner rows total=15, all three present
6 ?job_ids=not-a-uuid 4xx HTTP 400, code: INVALID_QUERY, structured details.errors[*].loc=["job_ids"]
7 ?job_ids={A},{B}&name_contains=job-a just smoke-job-a.png total=1, [smoke-job-a.png]
8 UUID matching the canonical form finds smoke-job-a.png total=1, [smoke-job-a.png]

Net: single, multi, comma-separated, repeated, unknown, invalid, and combined-filter cases all behave correctly. Validation error surfaces a clean structured 400. No regression on the no-filter path.

Mirrors the existing cloud `job_ids` query param on the local Python server:
clients can pass a comma-separated list (or repeated query params) of UUIDs
to filter assets by their associated job.

The `AssetReference.job_id` column already exists, so no migration is
needed — this just plumbs the filter through schema → service → query.

Marks the parameter as available in both runtimes by dropping the
`[cloud-only]` description prefix and the `x-runtime: [cloud]` tag from
the OpenAPI spec, per the OSS field-drift convention (absent runtime tag
= populated by both local and cloud).
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a validated job_ids query field to the asset-listing request model, threads the canonicalized UUID list through list_assets_page into list_references_page, applies AssetReference.job_id IN job_ids to both paginated and total-count DB queries when provided, updates the OpenAPI GET /api/assets parameter to an array of UUIDs, and adds unit tests for single/multi/empty/combined-filter behaviors.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(assets): add job_ids filter to GET /api/assets' accurately and concisely summarizes the main change—adding a job_ids filter parameter to the assets endpoint.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering the feature details, OpenAPI updates, test coverage, and HTTP smoke test results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

From cursor-reviews on the parent commit:

- OpenAPI: declare job_ids as `type: array, items: string format: uuid`
  with `style: form, explode: true` so it matches the documented
  contract (and matches sibling include_tags/exclude_tags shape).
  Description now states both accepted shapes explicitly.
- Schema: cap `job_ids` at 500 entries (max_length on the Pydantic
  field) so a client can't splice an unbounded list into the IN clauses.
- Schema: drop `AttributeError` from the except — `raw` only contains
  `str` items by construction, so `uuid.UUID(<str>)` raises `ValueError`
  exclusively; the second clause was dead code.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@openapi.yaml`:
- Around line 1562-1568: The OpenAPI schema for the job_ids query parameter in
ListAssetsQuery lacks the server-side cap; update the array schema for parameter
"job_ids" (the ListAssetsQuery / job_ids items block) to include maxItems: 500
so generated clients/docs reflect the runtime limit—add a top-level "maxItems:
500" property under the array definition that currently has "type: array" /
"items: { type: string, format: uuid }".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 82e239f0-0540-4274-9925-967852ac96da

📥 Commits

Reviewing files that changed from the base of the PR and between fbaae9b and cdc6170.

📒 Files selected for processing (2)
  • app/assets/api/schemas_in.py
  • openapi.yaml

Comment thread openapi.yaml
CodeRabbit catch on PR #13998: the Pydantic schema caps `job_ids` at
500 entries, but the OpenAPI parameter omitted `maxItems`, so generated
clients and docs wouldn't reflect the runtime limit.
Aligns with the parallel hardening from draft PR #13848 (now closed as
a duplicate). The validator now:

- Raises ValueError on non-string list items (was: silently dropped).
- Raises ValueError on non-string / non-list top-level values like dict
  or int (was: silently passed through to Pydantic's downstream coercion).

Adds tests-unit/assets_test/queries/test_list_assets_query.py covering
the validator end-to-end: CSV canonicalization, dedup order, default
empty, invalid UUID, non-string list item, non-string non-list value,
and the max_length=500 boundary.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests-unit/assets_test/queries/test_list_assets_query.py (1)

10-60: ⚡ Quick win

Consider adding a test for mixed CSV-in-list input.

The validator supports CSV within list items (e.g., ["uuid1,uuid2", "uuid3"]), which corresponds to the HTTP query string ?job_ids=uuid1,uuid2&job_ids=uuid3. This behavior is implemented in line 102 of the validator but isn't explicitly tested.

🧪 Suggested test to add
def test_mixed_csv_in_list(self):
    a = "11111111-1111-1111-1111-111111111111"
    b = "22222222-2222-2222-2222-222222222222"
    c = "33333333-3333-3333-3333-333333333333"
    # Simulates ?job_ids=uuid1,uuid2&job_ids=uuid3
    q = ListAssetsQuery.model_validate({"job_ids": [f"{a},{b}", c]})
    assert q.job_ids == [a, b, c]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests-unit/assets_test/queries/test_list_assets_query.py` around lines 10 -
60, Add a unit test to cover CSV-in-list behavior by creating a new test method
(e.g., test_mixed_csv_in_list) in TestJobIdsValidator that calls
ListAssetsQuery.model_validate with {"job_ids": [f"{a},{b}", c]} using three
UUID strings and asserts the resulting q.job_ids equals [a, b, c]; this verifies
the validator (ListAssetsQuery.model_validate) expands CSV entries inside list
items (the behavior implemented around line 102) and preserves
order/deduplication/canonicalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests-unit/assets_test/queries/test_list_assets_query.py`:
- Around line 10-60: Add a unit test to cover CSV-in-list behavior by creating a
new test method (e.g., test_mixed_csv_in_list) in TestJobIdsValidator that calls
ListAssetsQuery.model_validate with {"job_ids": [f"{a},{b}", c]} using three
UUID strings and asserts the resulting q.job_ids equals [a, b, c]; this verifies
the validator (ListAssetsQuery.model_validate) expands CSV entries inside list
items (the behavior implemented around line 102) and preserves
order/deduplication/canonicalization.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 17f8a6f3-0f54-422e-b2ba-67fd185015b8

📥 Commits

Reviewing files that changed from the base of the PR and between f1adcaa and 51487d7.

📒 Files selected for processing (2)
  • app/assets/api/schemas_in.py
  • tests-unit/assets_test/queries/test_list_assets_query.py

@mattmillerai mattmillerai added the Core Core team dependency label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Core Core team dependency

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants