From 7e9ea456b6ca34082c67414a87ddcc8345aabae0 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Wed, 1 Apr 2026 13:15:17 -0400 Subject: [PATCH] =?UTF-8?q?Fix=20baseline=20request=20body=20in=20spec=20?= =?UTF-8?q?=E2=80=94=20unified=20filters=20array?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the redundant date_from/date_to/date_col fields from the request body. Period selection is now expressed as a filter condition in the filters array like any other condition. SQL pattern updated to match (single {{filter_clause}} token instead of date_range + filter split). Co-Authored-By: Claude Sonnet 4.6 --- pf_spec.md | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/pf_spec.md b/pf_spec.md index b36e929..501dc1f 100644 --- a/pf_spec.md +++ b/pf_spec.md @@ -223,26 +223,23 @@ Source registration, col_meta configuration, SQL generation, version creation, a **Baseline load request body:** ```json { - "date_from": "2024-01-01", - "date_to": "2024-12-31", - "date_col": "order_date", "date_offset": "1 year", "filters": [ - { "col": "order_status", "op": "IN", "values": ["OPEN", "PENDING"] }, - { "col": "ship_date", "op": "BETWEEN", "values": ["2025-04-01", "2025-05-31"] } + { "col": "order_date", "op": "BETWEEN", "values": ["2024-01-01", "2024-12-31"] }, + { "col": "order_status", "op": "IN", "values": ["OPEN", "PENDING"] } ], - "pf_user": "admin", - "note": "Open orders regardless of order date", - "replay": false + "pf_user": "admin", + "note": "FY2024 actuals + open orders projected to FY2025", + "replay": false } ``` -- `date_from` / `date_to` / `date_col` — removed; period selection is expressed as a filter condition in the `filters` array like any other condition -- `date_offset` — PostgreSQL interval string applied to the primary `role = 'date'` column when inserting (not to filter columns). Examples: `"1 year"`, `"6 months"`, `"2 years 3 months"`. Defaults to `"0 days"`. -- `filters` — zero or more additional filter conditions. Each has: - - `col` — must be `role = 'filter'` or `role = 'date'` in col_meta +- `date_offset` — PostgreSQL interval string applied to the primary `role = 'date'` column at insert time. Examples: `"1 year"`, `"6 months"`, `"2 years 3 months"`. Defaults to `"0 days"`. Applied to the stored date value only — filter columns are never shifted. +- `filters` — one or more filter conditions defining what rows to pull from the source table. Period selection (date range, season, fiscal year, etc.) is expressed here as a regular filter — there is no separate date range parameter. Each condition has: + - `col` — must be `role = 'date'` or `role = 'filter'` in col_meta - `op` — one of `=`, `!=`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL`, `IS NOT NULL` - - `values` — array of strings; two elements for `BETWEEN`, multiple for `IN`/`NOT IN`, omitted for `IS NULL`/`IS NOT NULL` + - `values` — array of strings; two elements for `BETWEEN`; multiple for `IN`/`NOT IN`; omitted for `IS NULL`/`IS NOT NULL` +- At least one filter is required. - Baseline loads are **additive** — existing `iter = 'baseline'` rows are not touched. Each load is its own log entry and is independently undoable. `replay` controls behavior when incremental rows exist (applies to Clear + reload, not individual segments): @@ -504,7 +501,6 @@ SELECT FROM {schema}.{tname} WHERE - {{date_range_clause}} {{filter_clause}} ``` @@ -512,10 +508,7 @@ Baseline loads are **additive** — no DELETE before INSERT. Each segment append Token details: - `{{date_offset}}` — PostgreSQL interval string (e.g. `1 year`); defaults to `0 days`; applied only to the primary `role = 'date'` column on insert -- `{{date_range_clause}}` — built from `date_from`/`date_to`/`date_col` by the route; omitted entirely (replaced with `TRUE`) if no dates provided -- `{{filter_clause}}` — zero or more `AND` conditions built from the `filters` array; each validated against col_meta (column must be `role = 'filter'` or `role = 'date'`); operators: `=`, `!=`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL`, `IS NOT NULL` - -Both clauses are built at request time (not baked into stored SQL) since they vary per segment load. +- `{{filter_clause}}` — one or more `AND` conditions built from the `filters` array at request time (not baked into stored SQL since conditions vary per segment). Each condition is validated against col_meta (column must be `role = 'date'` or `role = 'filter'`). Supported operators: `=`, `!=`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL`, `IS NOT NULL`. ### Clear Baseline