| """routes_connected_tables.py β the SOURCE-NEUTRAL door to a connected grid (W31-T49, contract C4). |
| |
| `GET /api/v1/connected-tables/{table_key}/rows` β one window over any grid whose rows come from a |
| connector and are read THROUGH the per-tenant DuckDB mirror rather than copied into the tenant |
| document. Odoo's four locked databases and its two line grains today; Meta Ads' entity and Insights |
| grids when `meta_relational` registers its specs (R2). |
| |
| β WHY THIS FILE EXISTS. The read-through window shipped in wave 30 inside `routes_odoo_tables.py`, |
| Odoo-named down to the URL β `/api/v1/odoo-tables/{key}/rows`. R2 puts a SECOND connector on the |
| same mirror, and a Meta campaign served from a URL with `odoo` in it is a name that lies to every |
| reader of a network tab, a log line and a bug report. So the capability gets a name that describes |
| what it IS. |
| |
| ββ IT IS AN ALIAS, NOT A REIMPLEMENTATION, AND THAT IS THE WHOLE DESIGN. T49's `done-when` is |
| *"the Odoo path behaves byte-identically, proven by an NC"*. There are two ways to make that true: |
| write a second handler and test that the two agree, or have ONE handler behind two URLs. Only the |
| second is true BY CONSTRUCTION β the first is true on the day it is written and drifts the first |
| time somebody fixes a bug in one of them. Every request here lands in |
| `routes_odoo_tables.odoo_table_rows`, unchanged, so the two doors cannot disagree without a line |
| being deleted. [[one-question-two-normalizers]] |
| |
| β THE OLD URL STAYS, and that is not politeness to a client we control. `CustomerGrid`'s bridge, |
| saved views and anything an operator has in a browser tab all name it; retiring it in the same wave |
| that introduces the new one would turn a rename into an outage for a feature that is already |
| half-proven (D-174). The Odoo-named route is kept as a deliberate alias with a stated retirement |
| condition rather than as a leftover: it goes when nothing in `web/src` names it. |
| |
| β THE MOUNT IS THE POINT AND IT HAS BEEN MISSED BEFORE β three finished routers shipped 404-dead |
| behind green gates in wave 23, and wave 28 proved a MOUNTED router can still be uncallable |
| (`session.is_admin`, an attribute that does not exist, raising above the route's own `try`). So |
| `verify_meta` both enumerates `main.app.routes` for this path AND calls it. |
| """ |
| from fastapi import APIRouter, Depends, Query |
|
|
| from deps import Session, require_session |
|
|
| router = APIRouter(prefix="/api/v1") |
|
|
|
|
| @router.get("/connected-tables/{table_key}/rows") |
| def connected_table_rows(table_key: str, |
| offset: int = Query(default=0, ge=0), |
| limit: int = Query(default=0), |
| filters: str = Query(default=None), |
| filterConj: str = Query(default="and"), |
| sorts: str = Query(default=None), |
| search: str = Query(default=None), |
| session: Session = Depends(require_session)): |
| """ONE WINDOW over a connected grid β `{fields, rows, total, totalUnfiltered, offset, limit, |
| limits, identity, recordsMutable}`, whichever connector the rows come from. |
| |
| β EVERY GUARANTEE IS INHERITED, NOT RESTATED, because the body below is one call. `total` is a |
| `SELECT count(*)` and never `len(rows)`; the filter, sort and search resolve in SQL over the |
| whole table; anything that cannot be answered is reported in `limits` with a cause and a |
| recommendation (R6's second sentence); the permission wall is `_defn_or_refuse`; and the |
| cross-tenant mirror guard (D-169) refuses with `409 cross_tenant_store` before a cursor is |
| handed out. Documenting them again HERE would be a second statement of a contract that has one |
| home β and the day the two drifted, this file would be the one that lied. |
| """ |
| import routes_odoo_tables |
| return routes_odoo_tables.odoo_table_rows( |
| table_key, offset=offset, limit=limit, filters=filters, filterConj=filterConj, |
| sorts=sorts, search=search, session=session) |
|
|