Skip to content

feat(rpc,entity): add context-aware filter lookup support - #111

Merged
moshloop merged 4 commits into
mainfrom
chore/commit-taskui-embed-bundle
Jun 7, 2026
Merged

feat(rpc,entity): add context-aware filter lookup support#111
moshloop merged 4 commits into
mainfrom
chore/commit-taskui-embed-bundle

Conversation

@moshloop

@moshloop moshloop commented Jun 5, 2026

Copy link
Copy Markdown
Member

What

  • Introduce ContextLookupFunc and related interfaces (ContextFilter, ContextSearchableFilter) to enable filters to resolve request-scoped state
  • Add contextLookupFuncRegistry to track context-aware lookups
  • Implement GetContextLookupFunc() to retrieve registered context lookups
  • Add AddCommandWithContext() for commands receiving request context
  • Refactor buildLookupFunc into resolveLookup() to support both context and non-context paths
  • Update EntityOperation and BulkActionInfo to include ContextLookupFunc field
  • Update RPC converter and executor to prefer ContextLookupFunc over LookupFunc

Why

  • Filters can now access request-scoped state (e.g., per-request database handles) during option resolution instead of relying on process globals

Summary by CodeRabbit

  • New Features

    • Pagination support for list endpoints now includes limit, offset, and total count metadata in responses.
    • Added HTTP response headers (X-Total-Count, X-Page-Limit, X-Page-Offset) for paginated list operations.
    • Improved filter resolution with context-aware lookup capabilities.
  • Chores

    • Updated project dependencies.

…-scoped state

Introduce ContextLookupFunc and related interfaces to enable filters to resolve request-scoped state (e.g., per-request database handles) instead of process globals.

New types:
- ContextLookupFunc: context-aware variant of filter lookup closure
- ContextFilter: optional interface for filters needing request context
- ContextSearchableFilter: context-aware variant of SearchableFilter

Changes:
- Add contextLookupFuncRegistry to track context-aware lookups
- Implement GetContextLookupFunc() to retrieve registered context lookups
- Add AddCommandWithContext() for commands receiving request context
- Refactor buildLookupFunc into resolveLookup() to support both context and non-context paths
- Update EntityOperation and BulkActionInfo to include ContextLookupFunc field
- Implement liftedFilter methods for context-aware option resolution
- Update RPC converter and executor to prefer ContextLookupFunc over LookupFunc
- Add hasLookup() helper to check for either lookup variant

Filters implementing ContextFilter/ContextSearchableFilter can now access request context during option resolution, enabling dynamic filtering based on per-request state.
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@moshloop, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 38 minutes and 32 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1747c51e-e081-45e1-8f38-d4067e9aeacc

📥 Commits

Reviewing files that changed from the base of the PR and between 10cbbfd and 391af4a.

📒 Files selected for processing (5)
  • Makefile
  • e2e_integration_test.go
  • entity.go
  • rpc/serve.go
  • task/group.go

Walkthrough

This PR extends entity command generation with context-aware filter lookups and pagination support. New PageInfo, Paged, and PagedResult[T] types define pagination contracts; ContextLookupFunc enables filters to resolve options using request context. Entity configuration gains ListPaged/ListPagedWithContext methods; RegisterEntity wires paged list variants and propagates context metadata. The entity root command is promoted to act as the canonical list endpoint. RPC operations carry context lookup and paged flags; OpenAPI schemas wrap paginated responses with data/page structure and headers; HTTP response handling dispatches through context-aware lookups and formats pagination headers.

Changes

Context-aware Pagination and Entity Filtering

Layer / File(s) Summary
Pagination Primitives and Context-aware Types
pagination.go, response_meta.go, rpc/types.go
Introduces PageInfo, Paged, PagedResult[T] types and NewPagedResult constructor; adds Paged field to ResponseOpenAPIMeta; defines ContextLookupFunc type for request-scoped filter option resolution.
Cobra Command Context Support
cobra_command.go
Adds contextLookupFuncRegistry to store per-command context-aware filter lookups; implements GetContextLookupFunc accessor; exports AddCommandWithContext to register commands that receive context.Context during execution.
Entity Configuration and Filter Interfaces
entity_builder.go, entity.go
Extends EntityBuilder with ListWithContext, ListPaged, ListPagedWithContext fluent methods; defines ContextFilter and ContextSearchableFilter interfaces; updates EntityOperation and BulkActionInfo structs with ContextLookupFunc and ResponsePaged fields; adds ListPaged/ListPagedWithContext to Entity config.
Entity Operation Registration and Wiring
entity.go
Expands RegisterEntity to handle paged list variants via ListPagedWithContext/ListPaged; updates bulk action and admin list operations to register context lookup metadata; propagates ResponsePaged and context lookup through list/ID/body command metadata; extends LiftFilters to forward OptionsWithContext/OptionsWithQueryAndContext.
Entity Root Promotion and Lookup Resolution
entity.go
Implements promoteListToEntityRoot to copy list subcommand execution/flags onto entity root; refactors lookup generation into context-aware buildLookupFuncWithContext; introduces resolveLookup to route filter option fetching through context-aware or non-context variants with support for targeted server-side search.
RPC Operation Integration
rpc/converter.go, rpc/executor.go, rpc/types.go
Extends RPCOperation with ContextLookupFunc and ResponsePaged fields; updates ConvertCommand to default Verb/Scope to list/collection for entity operations and populate context lookup and paged flags from metadata; changes lookup candidate filter to use hasLookup helper.
OpenAPI Schema and Pagination Headers
rpc/openapi.go
Generates paged response schemas wrapping data/page structure; adds responseHeadersForOperation and pageInfoSchema helpers to produce X-Total-Count, X-Page-Limit, X-Page-Offset headers in OpenAPI spec; fixes clickySurfaceBaseKey to always pluralize entity name.
HTTP Response Handling and Pagination
rpc/serve.go
Routes lookup endpoints through hasLookup check; dispatches to ContextLookupFunc when available, otherwise falls back to LookupFunc; detects Paged responses and sets pagination headers; conditionally serializes PageRows() for non-JSON formats via shouldFormatPagedRows helper.
Test Coverage for Paged Lists and Entity Root
rpc/entities_test.go
Adds TestEntityPagedList_ResponseEnvelopeAndHeaders to validate paged response envelope and pagination header correctness; adds TestEntityRoot_RunnableListShortcut_OmitsGlobalFlags to verify entity root acts as canonical list endpoint while excluding global persistent flags from parameters.

Dependency Updates

Layer / File(s) Summary
Go Module Dependency Updates
examples/uber_demo/go.mod
Bumped direct dependencies (github.com/flanksource/commons to v1.51.3, golang.org/x/term to v0.41.0); updated large batch of indirect dependencies including github.com/cert-manager/cert-manager, github.com/flanksource/gomplate/v3, go.opentelemetry.io/otel, k8s.io/*, protobuf/genproto, and multiple golang.org/x/* packages.

Sequence Diagram

sequenceDiagram
  participant Client as HTTP Client
  participant Serve as rpc/serve
  participant RPC as RPC Executor
  participant Entity as Entity Handler
  participant Filter as Filter
  Client->>Serve: GET /api/v1/resource?limit=10&offset=0
  Serve->>RPC: resolve operation
  RPC->>RPC: check hasLookup(op)
  alt ContextLookupFunc available
    RPC->>Filter: ContextLookupFunc(ctx, flags)
  else fallback
    RPC->>Filter: LookupFunc(flags)
  end
  Filter-->>Entity: options
  Entity->>Entity: ListPagedWithContext(ctx, opts)
  Entity-->>Entity: PagedResult{Data, Page}
  Serve->>Serve: detect Paged result
  Serve->>Serve: set X-Total-Count header
  Serve-->>Client: {data: [...], page: {limit, offset, total}}
Loading

Possibly related PRs

  • flanksource/clicky#108: Modifies entity operation command annotation with additional optional ID parameter, sharing the same CLI metadata wiring patterns.
  • flanksource/clicky#101: Updates response metadata plumbing (ResponseOpenAPIMeta, RPC converter/types) that this PR extends with paged and context lookup fields.
  • flanksource/clicky#105: Introduces PrettyShort rendering interface used to format paginated response rows.

Suggested labels

released

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% 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(rpc,entity): add context-aware filter lookup support' directly describes the main feature added: context-aware filter lookup infrastructure across RPC and entity subsystems.
Description check ✅ Passed The PR description provides a comprehensive 'What' and 'Why' section explaining the feature, but the formal checklist sections from the template are not completed.
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.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/commit-taskui-embed-bundle
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch chore/commit-taskui-embed-bundle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Gavel summary

Source Pass Fail Skip Duration
(unknown) 0 1 0 -
github.com/flanksource/clicky 45 2 0 3.0s
ai 9 0 0 575.472µs
api 125 0 0 28ms
clicky 98 0 0 11.3s
examples/enitity 1 0 0 -
exec 68 0 0 3.0s
flags 20 0 0 809.588µs
formatters 26 0 0 2ms
github.com/flanksource/clicky/ai 10 0 0 10ms
github.com/flanksource/clicky/api 217 0 0 240ms
github.com/flanksource/clicky/api/tailwind 427 0 0 10ms
github.com/flanksource/clicky/exec 3 0 0 310ms
github.com/flanksource/clicky/flags 26 0 0 10ms
github.com/flanksource/clicky/formatters 35 0 0 -
github.com/flanksource/clicky/formatters/http 38 0 0 -
github.com/flanksource/clicky/formatters/pdf 0 0 1 -
github.com/flanksource/clicky/formatters/tests 202 0 1 1m2s
github.com/flanksource/clicky/internal/gumchoose 2 0 0 -
github.com/flanksource/clicky/lint 4 0 0 -
github.com/flanksource/clicky/mcp 34 0 0 40ms
github.com/flanksource/clicky/middleware 31 0 0 -
github.com/flanksource/clicky/rpc 183 0 1 10ms
github.com/flanksource/clicky/task 75 0 0 9.3s
lint 6 0 0 6.9s
metrics 7 0 0 1ms
middleware 38 0 0 6ms
tests 11 0 21 22ms
text 78 0 0 305ms
valkey 4 0 0 8ms

Totals: 1823 passed · 3 failed · 24 skipped · 1m36s

Failing tests

ginkgo Execution

✓ test-cancellation 10 of 10 100ms     
✓ test-rapid 20 of 20 100ms     
✓ test-no-double-close 3 of 3 100ms     
✓ test-goroutine-lifecycle 10 of 10 100ms     
... (46 more lines truncated)```

#### github.com/flanksource/clicky — TestClicky

go: downloading github.com/charmbracelet/bubbletea v1.3.10
go: downloading github.com/charmbracelet/huh v1.0.0
go: downloading github.com/flanksource/commons v1.51.3
go: downloading github.com/samber/lo v1.53.0
... (93 more lines truncated)


#### github.com/flanksource/clicky — TestBuildLookupFunc_StripsReservedParamsFromOpts

go: downloading github.com/charmbracelet/bubbletea v1.3.10
go: downloading github.com/charmbracelet/huh v1.0.0
go: downloading github.com/flanksource/commons v1.51.3
go: downloading github.com/samber/lo v1.53.0
... (93 more lines truncated)


[View full results](https://github.com/flanksource/clicky/actions/runs/27101376398/artifacts/7466940604)

Introduce PagedResult type and pagination metadata to support list operations that return total counts and paging information. Add ListPaged and ListPagedWithContext methods to EntityBuilder for declaring paginated list handlers. Implement promoteListToEntityRoot to make the bare entity command runnable as its own list operation, exposed as GET /api/v1/<entity>. Update RPC converter and OpenAPI generator to handle paged responses with X-Total-Count, X-Page-Limit, and X-Page-Offset headers. Ensure only ListOpts filter flags are promoted to entity root, preventing global persistent flags from leaking into query parameters.

BREAKING CHANGE: runEntityOp now extracts paged results via PageRows() interface method before formatting, changing how paged responses are serialized in RPC responses.
@socket-security

socket-security Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​marked@​15.0.121001001009880

View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
entity.go (1)

785-805: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Admin list registration skips new context/paged list handlers.

Line 785 only checks admin.List != nil, so admin entities configured with ListWithContext, ListPaged, or ListPagedWithContext alone won’t register a list operation. Mirror the main list switch here so admin behavior matches the new API surface.

Suggested fix sketch
- if admin.List != nil {
-   adminInfo.Operations = append(adminInfo.Operations, EntityOperation{
-     Verb: "list",
-     DataFunc: func(flagMap map[string]string, args []string) (any, error) { ... },
-     ...
-   })
- }
+ if admin.ListPagedWithContext != nil || admin.ListPaged != nil || admin.ListWithContext != nil || admin.List != nil {
+   op := EntityOperation{
+     Verb:              "list",
+     LookupFunc:        buildLookupFunc[ListOpts](admin.Filters),
+     ContextLookupFunc: buildLookupFuncWithContext[ListOpts](admin.Filters),
+     BindCompletions:   buildFilterCompletionBinder[ListOpts](admin.Filters),
+     ResponseType:      reflect.TypeOf((*T)(nil)).Elem(),
+     ResponseArray:     true,
+     ResponseEntityID:  true,
+   }
+   // same precedence as primary entity list:
+   // ListPagedWithContext > ListPaged > ListWithContext > List
+   // set op.ResponsePaged + DataFunc/ContextDataFunc accordingly
+   adminInfo.Operations = append(adminInfo.Operations, op)
+ }
🤖 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 `@entity.go` around lines 785 - 805, The admin registration currently only
checks admin.List when adding the "list" EntityOperation, so entities that
implement ListWithContext, ListPaged, or ListPagedWithContext are skipped;
update the block that appends to adminInfo.Operations to mirror the main list
switch by checking all variants (admin.List, admin.ListWithContext,
admin.ListPaged, admin.ListPagedWithContext), wiring the appropriate DataFunc
(and preserving the existing use of resolveEntityOpts, withEntityIDs, and error
handling) and keeping
LookupFunc/ContextLookupFunc/BindCompletions/ResponseType/ResponseArray/ResponseEntityID
consistent (use buildLookupFunc and buildLookupFuncWithContext as needed) so any
of the four list handlers will register a "list" operation on adminInfo.
🧹 Nitpick comments (1)
rpc/entities_test.go (1)

113-168: ⚡ Quick win

Add a application/json+clicky pagination assertion.

This test currently validates only application/json. Adding one clicky-json request/assertion would lock coverage for the structured paged envelope path and prevent format-specific regressions.

🤖 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 `@rpc/entities_test.go` around lines 113 - 168,
TestEntityPagedList_ResponseEnvelopeAndHeaders only exercises
"application/json"; add a second request that uses the clicky structured paged
envelope MIME to lock that code path. Duplicate the httptest request (create
req2/rr2), set req2.Header.Set("Accept", "application/json+clicky"), call
mux.ServeHTTP(rr2, req2), then assert rr2.Code == http.StatusOK, the same
pagination headers ("X-Total-Count", "X-Page-Limit", "X-Page-Offset") and
unmarshal rr2.Body into the same payload struct to assert payload.Data length
and payload.Page fields (Limit/Offset/Total) match expected values; use variable
names like req2 and rr2 to avoid clobbering the original test flow.
🤖 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 `@entity.go`:
- Around line 1484-1492: The code mutates the caller-owned flagMap by deleting
lookupFilterKeyParam and lookupQueryParam before calling buildOpts[T], which can
leak side-effects; to fix, make a shallow copy of flagMap (e.g., new map
variable) and perform the delete operations on that copy, then pass the copied
map into buildOpts[T] while preserving the original flagMap and keeping
searchKey/searchQuery extraction logic intact.

In `@rpc/serve.go`:
- Around line 752-758: The function shouldFormatPagedRows currently treats
formats "json", "yaml", and "yml" as non-formattable but omits the clicky JSON
variant; update shouldFormatPagedRows to also treat "clicky-json" (and therefore
requests with MIME "application/json+clicky") as false so responses use the
paged envelope (preserving data/page metadata) instead of being flattened by
PageRows().

---

Outside diff comments:
In `@entity.go`:
- Around line 785-805: The admin registration currently only checks admin.List
when adding the "list" EntityOperation, so entities that implement
ListWithContext, ListPaged, or ListPagedWithContext are skipped; update the
block that appends to adminInfo.Operations to mirror the main list switch by
checking all variants (admin.List, admin.ListWithContext, admin.ListPaged,
admin.ListPagedWithContext), wiring the appropriate DataFunc (and preserving the
existing use of resolveEntityOpts, withEntityIDs, and error handling) and
keeping
LookupFunc/ContextLookupFunc/BindCompletions/ResponseType/ResponseArray/ResponseEntityID
consistent (use buildLookupFunc and buildLookupFuncWithContext as needed) so any
of the four list handlers will register a "list" operation on adminInfo.

---

Nitpick comments:
In `@rpc/entities_test.go`:
- Around line 113-168: TestEntityPagedList_ResponseEnvelopeAndHeaders only
exercises "application/json"; add a second request that uses the clicky
structured paged envelope MIME to lock that code path. Duplicate the httptest
request (create req2/rr2), set req2.Header.Set("Accept",
"application/json+clicky"), call mux.ServeHTTP(rr2, req2), then assert rr2.Code
== http.StatusOK, the same pagination headers ("X-Total-Count", "X-Page-Limit",
"X-Page-Offset") and unmarshal rr2.Body into the same payload struct to assert
payload.Data length and payload.Page fields (Limit/Offset/Total) match expected
values; use variable names like req2 and rr2 to avoid clobbering the original
test flow.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: be00eb1d-3227-4b69-a92c-e76887a0338f

📥 Commits

Reviewing files that changed from the base of the PR and between 1dd7af6 and 10cbbfd.

⛔ Files ignored due to path filters (2)
  • examples/go.sum is excluded by !**/*.sum
  • examples/uber_demo/go.sum is excluded by !**/*.sum
📒 Files selected for processing (12)
  • cobra_command.go
  • entity.go
  • entity_builder.go
  • examples/uber_demo/go.mod
  • pagination.go
  • response_meta.go
  • rpc/converter.go
  • rpc/entities_test.go
  • rpc/executor.go
  • rpc/openapi.go
  • rpc/serve.go
  • rpc/types.go

Comment thread entity.go
Comment thread rpc/serve.go
moshloop added 2 commits June 7, 2026 21:30
Extend the fmt target to run 'go mod tidy' across all Go module directories (., valkey, examples, examples/uber_demo) in addition to code formatting. This ensures dependencies are kept in sync whenever code formatting is performed.

Also clean up unused dependencies in examples/go.sum.
- resolveLookup: copy flagMap before stripping reserved lookup params so
  the caller-owned map is not mutated
- shouldFormatPagedRows: preserve paged envelope for clicky-json responses
  so application/json+clicky keeps data/page metadata
- lint e2e: set GOFLAGS=-mod=mod for fixture modules so package loading
  populates go.sum instead of failing on missing transitive entries
@moshloop
moshloop merged commit 28bd967 into main Jun 7, 2026
12 of 13 checks passed
@moshloop
moshloop deleted the chore/commit-taskui-embed-bundle branch June 7, 2026 18:49
@flankbot

flankbot commented Jun 7, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.21.15

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants