docs(developer-guide): show the pre-edit hook result, fix the re-read drop list #17

Merged
allan merged 2 commits from docs/pre-edit-hook-images into main 2026-10-15 17:57:19 +00:00
3 changed files with 10 additions and 2 deletions
Showing only changes of commit 0de0fbde4a - Show all commits

No files matched your search

+10 -2
View File
@@ -100,7 +100,7 @@ The hook below is registered in `MPE_TABLES.PRE_EDIT_HOOK` for a table with a da
run; run;
/* re-read the table, so the grid shows both quarters */ /* re-read the table, so the grid shows both quarters */
data work.out (drop=&var_txfrom &var_txto &var_processed); data work.out (drop=&var_txfrom &var_txto &var_processed &drop_rk);
_____DELETE__THIS__RECORD_____="No"; _____DELETE__THIS__RECORD_____="No";
set &orig_libds; set &orig_libds;
where %inc newfilt; where %inc newfilt;
@@ -125,9 +125,17 @@ The hook below is registered in `MPE_TABLES.PRE_EDIT_HOOK` for a table with a da
- **The user's clause.** `work.QUERY` is the filter's clauses as structured rows, and `%mp_filtergenerate` turns them back into a WHERE clause. This is the user's filter on its own, with no Row Level Security or validity clause mixed in. - **The user's clause.** `work.QUERY` is the filter's clauses as structured rows, and `%mp_filtergenerate` turns them back into a WHERE clause. This is the user's filter on its own, with no Row Level Security or validity clause mixed in.
- **Data Controller's clause.** Calling `%mpe_filtermaster` with `filter_rk=-1` produces the part of the filter that is not the user's: the current-record validity clause and any Row Level Security, or `1=1` when there is neither. - **Data Controller's clause.** Calling `%mpe_filtermaster` with `filter_rk=-1` produces the part of the filter that is not the user's: the current-record validity clause and any Row Level Security, or `1=1` when there is neither.
- **The combined filter.** The two clauses are combined as `( user OR previous-quarter ) AND ( validity + RLS )`, so the previous quarter is added to the user's selection without widening anything the user is not entitled to see. - **The combined filter.** The two clauses are combined as `( user OR previous-quarter ) AND ( validity + RLS )`, so the previous quarter is added to the user's selection without widening anything the user is not entitled to see.
- **The rows.** `work.OUT` is rebuilt with the combined filter, mirroring the data step `getdata` uses itself - including dropping the transaction and processing columns it drops. - **The rows.** `work.OUT` is rebuilt with the combined filter, using the same drop list as the data step `getdata` runs itself - the transaction and processing columns, plus `&drop_rk`, the surrogate key that `getdata` hides when a table is registered with `RK_UNDERLYING`. On a bitemporal table `getdata` also deduplicates to the latest record per primary key (`by &pk &var_busfrom`); add that step too, or the re-read returns every temporal version rather than the current one.
- **The returned text.** `filtref` is overwritten with the combined filter, so the clause the editor shows is the one that was actually applied. - **The returned text.** `filtref` is overwritten with the combined filter, so the clause the editor shows is the one that was actually applied.
### What it looks like
The captures below are the editor for a table with an `ORDER_DATE` column, opened with a filter for the current quarter. In the first, no hook is configured, so the filter is the user's own and the grid holds one quarter of rows. In the second, the hook has run: the filter above the grid carries both quarters, and the rows have grown to match.
![The editor with the user's own filter, one quarter of rows](/img/pre-edit-hook-before.png)
![The same editor after the hook widened the filter to the previous quarter](/img/pre-edit-hook-after.png)
## Row Level Security ## Row Level Security
The user's clause and Data Controller's clause have to be kept apart, because Row Level Security lives in the second one. Combining them as `( user OR previous-quarter ) AND ( validity + RLS )` keeps RLS applied to both branches. Wrapping the whole existing filter instead - `( existing OR previous-quarter )` - would let the previous-quarter rows through without their RLS condition, so do not take that shortcut. The user's clause and Data Controller's clause have to be kept apart, because Row Level Security lives in the second one. Combining them as `( user OR previous-quarter ) AND ( validity + RLS )` keeps RLS applied to both branches. Wrapping the whole existing filter instead - `( existing OR previous-quarter )` - would let the previous-quarter rows through without their RLS condition, so do not take that shortcut.
Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB