Package su.onno.ui

Class CatalogQueryService

java.lang.Object
su.onno.ui.CatalogQueryService

public class CatalogQueryService extends Object
Read-side queries for catalogs, shared by the REST API and the DivKit emitters so the SQL and ref-resolution live in one place. Pure data access — access control stays with the callers.
  • Constructor Details

    • CatalogQueryService

      public CatalogQueryService(MetadataRegistry registry, org.jdbi.v3.core.Jdbi jdbi)
  • Method Details

    • require

      public CatalogDescriptor require(String name)
    • forClass

      public CatalogDescriptor forClass(Class<?> clazz)
      The catalog descriptor for a domain class, or null if it isn't a registered catalog.
    • search

      public List<Map<String,Object>> search(CatalogDescriptor desc, String query, int limit)
      Server-side typeahead for ref pickers: case-insensitive match across the same text columns the paged list search covers — code, description, and every (non-secret) String attribute — so a record is findable by a secondary attribute like a phone, not just its name (issue #184). Capped at limit, so a 2000-row catalog never ships whole to the client.
    • search

      public List<Map<String,Object>> search(CatalogDescriptor desc, String query, int limit, String filter)
      As search(CatalogDescriptor, String, int), additionally narrowed by a WidgetFilter predicate — the cascading ref picker sends its resolved refFilter here (e.g. "supplier = <uuid>"), so only compatible records are offered. Ref/enum columns bind as typed uuids (PG-strict); a null/blank/invalid predicate is simply no filter.
    • newDraft

      public Map<String,Object> newDraft(CatalogDescriptor desc)
      The seed row for a new catalog form: a fresh instance's field-initializer defaults in the same column-keyed, ref-resolved shape get(su.onno.metadata.CatalogDescriptor, java.util.UUID) returns for an existing record, so the New form pre-fills declared defaults instead of opening blank (issue #181).
    • newDraft

      public Map<String,Object> newDraft(CatalogDescriptor desc, Map<String,String> prefill)
      As newDraft(CatalogDescriptor), but overlays caller-supplied initial values (from the New-form navigation query, keyed by attribute field name) onto the seed row before ref/enum resolution — so a deep link like …/new?field=value pre-fills those fields.
    • count

      public long count(CatalogDescriptor desc)
    • aggregate

      public BigDecimal aggregate(CatalogDescriptor desc, String metric, String field, String filter)
      A single aggregate value for a count/metric card — count of rows, or sum|avg|min|max of one numeric column — restricted to live records and narrowed by an optional safe filter predicate (see WidgetFilter).
    • aggregateBuckets

      public Map<String,Object> aggregateBuckets(CatalogDescriptor desc, WidgetBuckets.Request request)
      Grouped aggregate buckets for a chart/stat widget — a server-side GROUP BY returning O(buckets) rows instead of the whole table (#199). See WidgetBuckets.
    • keysetPage

      public KeysetPage keysetPage(CatalogDescriptor desc, String cursorToken, int limit, String sortColumn, boolean descending, String search, List<String> eq, List<String> in, List<String> like, List<String> prefix, List<String> ge, List<String> le, String widgetFilter)
      One keyset-paginated window — the constant-time default for the list grid. Seeks past cursorToken (null/blank for the first window) instead of counting past an offset, so page 1 and page 10 000 cost the same. Applies server-side sort/search/filters, fetches one extra row to report hasMore without a COUNT, and mints the next cursor from the last row. A cursor minted for a different sort is ignored (paging restarts), and a sort by a column the framework doesn't keep populated uses the NULL-safe seek shape.
    • estimateCount

      public Long estimateCount(CatalogDescriptor desc, boolean filtered)
      A cheap live-row estimate for the scroll-height hint, or null when none is available. Uses PostgreSQL planner statistics (pg_class.reltuples) so it never scans the table; returns null on H2 or whenever a search/filter is active (the estimate can't reflect a predicate). Callers wanting an exact figure use count(su.onno.metadata.CatalogDescriptor) instead.
    • rowsByIds

      public List<Map<String,Object>> rowsByIds(CatalogDescriptor desc, List<UUID> ids)
      Fetch specific live rows by id, decorated like keyset rows (refs resolved, secrets redacted) so a client can refresh just the rows that changed without re-paging the whole window. Drives the list island's surgical single-row live patch. Returns only the rows that still exist and aren't deletion-marked, in no particular order; an empty/blank input yields an empty list.
    • count

      public long count(CatalogDescriptor desc, String search, List<String> eq, List<String> in, List<String> like, List<String> prefix, List<String> ge, List<String> le, String widgetFilter)
      Total live rows matching the search (+ declarative filters + widget filter) — for the virtual scroller.
    • groups

      public ListGroups.GroupResult groups(CatalogDescriptor desc, String groupColumn, String granularity, String search, List<String> eq, List<String> in, List<String> like, List<String> prefix, List<String> ge, List<String> le, String widgetFilter, List<ListGroups.Agg> aggregates)
      Group a catalog list by groupColumn (a validated sortable column): one header per distinct value, or — for a date/time column — per granularity bucket, over the same WHERE (search + declarative + widget filters) as the flat list. Each header carries its row count, the requested aggregates, and the expand filter the client replays on the normal feed to load that group's rows. Headers are capped at ListGroups.MAX_GROUPS.
    • sortableColumns

      public Set<String> sortableColumns(CatalogDescriptor desc)
      Column names that may be sorted on: the system columns + every attribute column.
    • children

      public List<Map<String,Object>> children(CatalogDescriptor desc, UUID parent)
    • tree

      public List<Map<String,Object>> tree(CatalogDescriptor desc)
    • relatedRows

      public List<Map<String,Object>> relatedRows(CatalogDescriptor desc, String viaColumn, UUID parentId)
      Live rows of a join catalog whose viaColumn ref points at parentId — the read side of a related-list panel (see RelatedList). Ordered by code so the inline roster is stable. Refs are resolved (so the display ref shows its description) and secrets redacted, exactly like the standalone catalog list. viaColumn must be a real column on desc (the caller resolves it from the join catalog's metadata, never from user input) so this stays injection-safe.
    • get

      public Map<String,Object> get(CatalogDescriptor desc, UUID id)