Skip to content

feat(indexer): advanced multi-step search with cross-document references (#5022)#6215

Open
XananasX7 wants to merge 1 commit into
hashgraph:developfrom
XananasX7:feature/5022-advanced-search
Open

feat(indexer): advanced multi-step search with cross-document references (#5022)#6215
XananasX7 wants to merge 1 commit into
hashgraph:developfrom
XananasX7:feature/5022-advanced-search

Conversation

@XananasX7

Copy link
Copy Markdown

Summary

Implements the advanced Indexer search capability requested in #5022, covering sub-issues #5021 (finding suitable carbon credits) and #5019 (searching common project practices).

Closes #5022
Closes #5021
Closes #5019


Architecture

Layer Change
indexer-interfaces New AdvancedSearchParams, AdvancedSearchStep, SearchCondition, AdvancedSearchResult interfaces + 11 operators
indexer-common New IndexerMessageAPI.GET_ADVANCED_SEARCH_API enum value
indexer-api-gateway New POST /search/advanced endpoint with Swagger docs + class-validator DTOs
indexer-service New AdvancedSearchService — multi-step MongoDB query executor
indexer-frontend New AdvancedSearchViewComponent at /search/advanced; link from basic search page

Operators

eq, neq, contains (case-insensitive), regex, gt, gte, lt, lte, between, in, not_in


Multi-step cross-referencing

Intermediate steps carry field values forward via carryFields. Subsequent steps reference them with $step{n}.fieldPath syntax in any condition value. When a prior step returns multiple values, single-value eq auto-upgrades to in.


URL bookmarking

Each search result includes a searchToken (base64-encoded params). The frontend writes it to ?token= so searches can be bookmarked and shared — pasting the URL restores the full form state.


Use-case examples

#5019 — Common project practices

{
  "steps": [
    { "type": "Policy", "conditions": [{ "field": "analytics.textSearch", "operator": "contains", "value": "ACM0007" }], "carryFields": ["analytics.policyId"] },
    { "type": "VC-Document", "conditions": [{ "field": "analytics.policyId", "operator": "eq", "value": "$step0.analytics.policyId" }, { "field": "options.credentialSubject.decision", "operator": "eq", "value": "(c) Use default values" }] }
  ],
  "pageIndex": 0, "pageSize": 10
}

#5021 — Find suitable carbon credits

{
  "steps": [
    { "type": "VC-Document", "conditions": [{ "field": "analytics.schemaName", "operator": "contains", "value": "Monitoring Report" }], "carryFields": ["options.credentialSubject.projectId"] },
    { "type": "VC-Document", "conditions": [{ "field": "options.credentialSubject.projectId", "operator": "eq", "value": "$step0.options.credentialSubject.projectId" }] }
  ],
  "pageIndex": 0, "pageSize": 10
}

@XananasX7 XananasX7 requested review from a team as code owners June 15, 2026 13:22
…ces (hashgraph#5022, hashgraph#5021, hashgraph#5019)

Implements the advanced Indexer search capability requested in hashgraph#5022,
which also satisfies the use-cases from hashgraph#5021 (finding suitable carbon
credits) and hashgraph#5019 (searching for common project practices).

## What changed

### New interfaces — indexer-interfaces/
AdvancedSearchParams, AdvancedSearchStep, SearchCondition,
AdvancedSearchResult, AdvancedSearchResultItem, ConditionOperator
(advanced-search.interface.ts)

### New message API enum
IndexerMessageAPI.GET_ADVANCED_SEARCH_API

### New DTOs — indexer-api-gateway/src/dto/advanced-search.dto.ts
Full class-validator/class-transformer annotated DTOs with Swagger docs
for all request and response shapes.

### New API endpoint — POST /search/advanced
Returns AdvancedSearchResultDTO with:
- paginated result items with configurable display columns
- serialised base64 'searchToken' for URL bookmark/share

### New backend service — indexer-service/src/api/advanced-search.service.ts
Multi-step query executor:
- Builds MongoDB filter from conditions using MikroORM EntityManager
- Operators: eq, neq, contains (case-insensitive regex), regex, gt,
  gte, lt, lte, between, in, not_in
- Type filter applied automatically per step
- Cross-step references: {n}.fieldPath resolved from prior step
  carry-values; auto-upgrades 'eq' to 'in' for multi-value results
- Intermediate steps capped at 1000 docs for memory safety
- In-memory groupBy support after final DB fetch
- searchToken = base64(JSON.stringify(params)) for bookmark support

### New Angular component — indexer-frontend/.../search/advanced/
AdvancedSearchViewComponent (standalone):
- Reactive form for N search steps, each with M conditions
- All 11 operators with appropriate input modes (range, list, single value)
- Carry-forward field configuration for multi-step cross-referencing
- Configurable result grid columns (add/remove)
- URL persistence: token + pageIndex/pageSize written to queryParams
- Restore-from-URL: pasting a bookmarked URL restores full form state
- 'Copy Link' button for sharing
- Navigates to detail pages on row open (same logic as basic search)

### Basic search view
Added 'Advanced search ›' link to navigate to /search/advanced

### Route
Added { path: 'search/advanced', component: AdvancedSearchViewComponent }

## Use-cases covered (per hashgraph#5022 acceptance criteria)

### hashgraph#5019 — Search for common project practices
Step 1: type=Policy, conditions=[{ field:'analytics.textSearch', operator:'contains', value:'ACM0007' }], carryFields:['analytics.policyId']
Step 2: type=VC-Document, conditions=[{ field:'analytics.policyId', operator:'eq', value:'$step0.analytics.policyId'}, {field:'options.credentialSubject.decisionField', operator:'eq', value:'(c) Use default values'}]

### hashgraph#5021 — Find suitable carbon credits
Step 1: type=VC-Document, conditions=[{ field:'type', op:'eq', value:'Monitoring Report'}, {field:'analytics.schemaName', op:'contains', value:'Monitoring'}], carryFields:['options.credentialSubject.projectId']
Step 2: type=VC-Document (minting), conditions=[{field:'options.credentialSubject.projectId', op:'eq', value:'$step0.options.credentialSubject.projectId'}]

### Generic support
- Range conditions (e.g. totalIssuance > 10000)
- Set conditions (find all where policyId IN [...])
- Regex pattern matching on any field
- Arithmetic on values (supported via GT/LT/BETWEEN on numeric fields)
- Result grid sorted and grouped by any field

Closes hashgraph#5022
Partially addresses hashgraph#5021
Partially addresses hashgraph#5019

Signed-off-by: XananasX7 <xananasX7@users.noreply.github.com>
@XananasX7 XananasX7 force-pushed the feature/5022-advanced-search branch from 9e46168 to 97870d9 Compare June 16, 2026 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant