* Shared `status`/`probe_key` filter evaluation for BOTH fake PB clients * (`makeFakePb` + `makePagingPb`). A clause on a field OR OPERATOR the fakes * can't honor THROWS loudly — matching the fakes' own unsupported-method * philosophy — so a future test exercising an unmodeled filter shape can
(row: FilterableRow, filter?: string)
| 189 | * these filters legitimately carries operator characters. |
| 190 | */ |
| 191 | function rowMatchesFilter(row: FilterableRow, filter?: string): boolean { |
| 192 | if (!filter) return true; |
| 193 | for (const [, field, op] of filter.matchAll( |
| 194 | /([A-Za-z_][\w.]*)\s*(\?~|\?=|!~|!=|<=|>=|<|>|~|=)/g, |
| 195 | )) { |
| 196 | if (field !== "status" && field !== "probe_key" && field !== "id") { |
| 197 | throw new Error( |
| 198 | `fake-pb: filter clause on unsupported field "${field}" — only status/probe_key/id are honored (filter: ${filter})`, |
| 199 | ); |
| 200 | } |
| 201 | if (field === "status" && op !== "=") { |
| 202 | throw new Error( |
| 203 | `fake-pb: status clause with unsupported operator "${op}" — only \`=\` is honored (filter: ${filter})`, |
| 204 | ); |
| 205 | } |
| 206 | if (field === "probe_key" && !["=", "!=", "~", "!~"].includes(op)) { |
| 207 | throw new Error( |
| 208 | `fake-pb: probe_key clause with unsupported operator "${op}" (filter: ${filter})`, |
| 209 | ); |
| 210 | } |
| 211 | // `id` is honored for the NEGATIVE equality only (the discovery |
| 212 | // by-row-id exclusion for clause-unsafe families); anything else throws |
| 213 | // per the fakes' philosophy. |
| 214 | if (field === "id" && op !== "!=") { |
| 215 | throw new Error( |
| 216 | `fake-pb: id clause with unsupported operator "${op}" — only \`!=\` is honored (filter: ${filter})`, |
| 217 | ); |
| 218 | } |
| 219 | } |
| 220 | // BOOLEAN-CONNECTIVE GUARD: the evaluation below ORs all POSITIVE clauses |
| 221 | // per field (faithful to the production inclusion groups, which are |
| 222 | // `(probe_key ~ x || probe_key = y)` / `(status = a || status = b)`) and |
| 223 | // ANDs negatives. Two positive clauses for ONE field joined WITHOUT a |
| 224 | // `||` between them are ANDed in the real grammar — a shape this OR-model |
| 225 | // would evaluate wrong, so it must throw rather than pass vacuously. |
| 226 | // |
| 227 | // KNOWN LIMITATION (interleaved `||`, G1h): the guard only checks that the |
| 228 | // RAW TEXT between two same-field positives contains a `||` — it is blind |
| 229 | // to grouping/precedence. A filter like |
| 230 | // `probe_key = "a" || status = "x" && probe_key = "b"` interleaves a |
| 231 | // different field between the two probe_key positives; the separator |
| 232 | // contains `||`, so the guard passes, yet the OR-model flattens what the |
| 233 | // real grammar binds as `a || (x && b)`. No production builder emits such |
| 234 | // a shape (inclusion groups are homogeneous parenthesized ORs); a future |
| 235 | // test that does must extend the matcher, not trust it. |
| 236 | const assertPositivesOrJoined = (field: string, re: RegExp): void => { |
| 237 | const ms = [...filter.matchAll(re)]; |
| 238 | for (let i = 1; i < ms.length; i++) { |
| 239 | const prev = ms[i - 1]; |
| 240 | const sep = filter.slice((prev.index ?? 0) + prev[0].length, ms[i].index); |
| 241 | if (!sep.includes("||")) { |
| 242 | throw new Error( |
| 243 | `fake-pb: multiple positive ${field} clauses ANDed — the OR-model cannot honor this shape (filter: ${filter})`, |
| 244 | ); |
| 245 | } |
| 246 | } |
| 247 | }; |
| 248 | // `(?:~|=)` requires the operator DIRECTLY after the field (`!~`/`!=` |
no test coverage detected
searching dependent graphs…