Skip to content

/identities sort completeness + /contestedResources filter support #791

Description

@litury

Two adjacent gaps surfaced while wiring the new frontend filter + sortable headers on /identities (feat/identities-filters branch). Bundling so backend gets one tracking item.

1. /identities orderBy is incomplete — filter exposes the columns, sort doesn't

The existing range filters in IdentitiesDAO.getIdentities already build WHERE clauses against total_data_contracts, total_documents, total_txs, total_transfers, balance (lines ~251‑280). So the columns are clearly accessible to the DAO — filter works, e.g. ?data_contracts_min=2 returns identities with ≥ 2 contracts.

But the ORDER BY switch at lines 231‑239 only branches on tx_count and balance:

const orderByOptions = [{ column: 'identity_id', order }]
if (orderBy === 'tx_count') orderByOptions.unshift({ column: 'total_txs', order })
if (orderBy === 'balance')  orderByOptions.unshift({ column: 'balance',  order })

Everything else (including documents_count and timestamp, which ARE in the paginationOptions.orderBy enum at packages/api/src/schemas.js#L28) silently falls through to identity_id ${order} — the request 200s but the rows aren't sorted by what the client asked for. data_contracts_count / transfers_count aren't even in the enum, so a request with those values 400s.

Net effect on the frontend list table: of 6 useful column headers (Identifier, Balance, Tx, Documents, Data Contracts, Timestamp), only two (Balance, Tx) actually sort correctly server‑side. Users can filter by Data Contracts via the existing filter pills but can't sort by it.

Suggested fix (10‑line change, zero new joins)

total_documents, total_data_contracts, total_transfers and blocks.timestamp are already selected by the existing query (lines 336‑337, line 361, line 366). Just teach the DAO orderBy switch to use them:

const sortColumns = {
  tx_count: 'total_txs',
  balance: 'balance',
  documents_count: 'total_documents',
  data_contracts_count: 'total_data_contracts',
  transfers_count: 'total_transfers',
  timestamp: 'timestamp'
}
const orderByOptions = [{ column: 'identity_id', order }]
if (sortColumns[orderBy]) orderByOptions.unshift({ column: sortColumns[orderBy], order })

And add data_contracts_count and transfers_count to the paginationOptions.orderBy enum at packages/api/src/schemas.js#L28. Symmetrical with what the filter side already does for those same columns.

2. /contestedResources has no filters

packages/api/src/routes.js#L270 wires the route to paginationOptions# only. Frontend can't filter the contested resources list at all today.

Proposed filter fields (mirror the /identities pattern)

  • status: enum 'pending' | 'finished' — matches the value in ContestedResource.js#L68
  • document_type_name: string — e.g. domain for DPNS contested names
  • data_contract_identifier: string (base58 id)
  • timestamp_min / timestamp_max: ISO 8601 — creation range

Optional, low priority: extend paginationOptions.orderBy enum with total_count_votes and end_timestamp so the frontend can sort contested resources by activity / time remaining.

Notes for implementation

ContestedResourcesDAO.js#L186 is non‑trivial — 6 nested CTEs with jsonb_each, jsonb_array_elements, ranking windows. The right place to apply WHERE clauses is probably the outer‑most from('ranked_documents') SELECT (~line 237) where data_contracts.identifier, documents.document_type_name, timestamp are all in scope. Worth a quick EXPLAIN ANALYZE before merge. status is computed from endTimestamp in the model, so server‑side filtering it likely needs WHERE end_timestamp ${'>' | '<='} NOW() rather than a stored column.

Frontend will mirror the just‑landed IdentitiesFilter once these fields are available.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendRelated to backend (API)enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions