Data binding and zero-copy access
A view binds one data source to one ontology class. Reads go to the source at request time, with your governance applied before any row is returned. You get current data without building a copy of it.
Views#
A view declares where the data is, which class it represents, how its fields map to class attributes, which policy scopes it, and how much to trust it.
refName: policy-admin-view ontologyClass: Policy sourceKind: sql # sql | rest | google_sheets | query_gateway connectionRef: policy-admin-db locator: policies # table, endpoint or range mappingRef: policy-admin-mapping # source column -> class attribute policyRef: policy-region-filter # row rules in ontology-attribute terms trustTier: authoritative # used when sources overlap
Policies are written against class attributes (region), not source columns (rgn_cd). One policy therefore governs every source bound to the class.
Reading through a view#
GET /v1/system/view-gateway/policy-admin-view/resolve?filter=status:ACTIVE
Each read goes through these steps:
- The caller must hold an explicit allow for the class. Anything else is a deny.
- The view's policy clauses are combined with the caller's filter. An unresolved policy variable fails closed.
- The filter is translated from ontology attributes back to source columns and, for SQL, pushed down as a parameterized
WHERE. Only governed rows leave the source. - Rows are mapped to class attributes and returned.
Zero-copy: what you get#
- No extract-and-load copy. A virtual view stores only its definition, never the rows.
- Fresh by construction. The answer reflects the source at the moment of the read.
- Governance at the boundary. Authorization is decided per class before the source is touched, and SQL row policies execute inside the source.
- A smaller exposure surface. There is no second store of the data to secure, retain or delete.
Views can also be materialized for sources that are too slow or too limited for live reads. A materialized view is a copy with a refresh; choose it deliberately and treat it as a data store.
Connectors#
| Connector | Filter pushdown | Notes |
|---|---|---|
| SQL (JDBC) | Yes: parameterized WHERE | Filters using negation, regular expressions or text search are rejected rather than applied partially. |
| REST | No | See the known issue below. |
| Spreadsheet | No; filtered reads are rejected | Up to 500 rows per read. |
| Platform query gateway | No; filtered reads are rejected | The platform applies its own realm, row and field security. Default 500 rows, maximum 2,000. |
Further connectors (document stores, streams, object storage, warehouses) and pushdown of projection, sorting, limits and joins are Planned.
Known issues
- REST views do not apply row policies. The REST connector currently ignores both the governed filter and your filter and returns what the endpoint returns. Scope the REST endpoint itself, or do not bind REST sources to classes with row policies, until this is fixed.
- No column masking in views. Field-level redaction is not yet applied to view reads. Map only the columns a class needs.
- No paging on SQL and REST reads. Always pass a selective filter.
Joining across sources#
When two classes live in different sources, a relation between them with join keys lets the gateway join them at read time:
placedBy: domain: Order range: Customer functional: true joinFromField: customerId # on Order joinToField: id # on Customer
The join is a left-outer join in the gateway: each order gets its customer nested under placedBy. A missing join key fails closed. For a to-one relation the gateway takes the first match; if the same entity comes from several sources with different values, use fusion instead (Resolving overlapping sources).