@@ -22,7 +22,12 @@ public function testNormalizeKeepsOnlyVersionedVisibilityFields(): void
2222 'is_current_run ' => 'yes ' ,
2323 'namespace ' => ' production ' ,
2424 'workflow_type ' => ' billing.invoice-sync ' ,
25+ 'workflow_type_contains ' => ' invoice ' ,
2526 'business_key ' => '' ,
27+ 'contains ' => [
28+ 'instance_id ' => ' visibility ' ,
29+ 'business_key ' => ' order ' ,
30+ ],
2631 'compatibility ' => 'build-a ' ,
2732 'declared_entry_mode ' => ' canonical ' ,
2833 'declared_contract_source ' => ' durable_history ' ,
@@ -62,6 +67,9 @@ public function testNormalizeKeepsOnlyVersionedVisibilityFields(): void
6267 'task_problem ' => true ,
6368 'archived ' => true ,
6469 'is_terminal ' => false ,
70+ 'instance_id_contains ' => 'visibility ' ,
71+ 'workflow_type_contains ' => 'invoice ' ,
72+ 'business_key_contains ' => 'order ' ,
6573 'labels ' => [
6674 'region ' => 'us-east ' ,
6775 'tenant ' => 'acme ' ,
@@ -91,6 +99,7 @@ public function testMergeLetsLaterFiltersRefineSavedViewLabels(): void
9199 'labels ' => [
92100 'region ' => 'eu-west ' ,
93101 ],
102+ 'workflow_type_contains ' => 'invoice ' ,
94103 ],
95104 );
96105
@@ -101,6 +110,7 @@ public function testMergeLetsLaterFiltersRefineSavedViewLabels(): void
101110 'repair_attention ' => true ,
102111 'continue_as_new_recommended ' => true ,
103112 'archived ' => true ,
113+ 'workflow_type_contains ' => 'invoice ' ,
104114 'labels ' => [
105115 'region ' => 'eu-west ' ,
106116 'tenant ' => 'acme ' ,
@@ -234,19 +244,100 @@ public function testApplyFiltersUseBooleanExactFields(): void
234244 $ this ->assertSame (['01JVISBOOLMATCH00000000001 ' ], $ ids );
235245 }
236246
247+ public function testApplyFiltersRunSummariesByContainsFields (): void
248+ {
249+ WorkflowRunSummary::create ([
250+ 'id ' => '01JVISC0NTAINMATCH0000001 ' ,
251+ 'workflow_instance_id ' => 'tenant-acme-order-12345 ' ,
252+ 'run_number ' => 1 ,
253+ 'is_current_run ' => true ,
254+ 'engine_source ' => 'v2 ' ,
255+ 'class ' => 'BillingWorkflow ' ,
256+ 'workflow_type ' => 'billing.invoice-sync ' ,
257+ 'business_key ' => 'order_12345 ' ,
258+ 'status ' => 'waiting ' ,
259+ 'status_bucket ' => 'running ' ,
260+ ]);
261+ WorkflowRunSummary::create ([
262+ 'id ' => '01JVISC0NTAINMISS00000001 ' ,
263+ 'workflow_instance_id ' => 'tenant-beta-invoice-999 ' ,
264+ 'run_number ' => 1 ,
265+ 'is_current_run ' => true ,
266+ 'engine_source ' => 'v2 ' ,
267+ 'class ' => 'BillingWorkflow ' ,
268+ 'workflow_type ' => 'billing.invoice-sync ' ,
269+ 'business_key ' => 'order-12345 ' ,
270+ 'status ' => 'waiting ' ,
271+ 'status_bucket ' => 'running ' ,
272+ ]);
273+
274+ $ ids = VisibilityFilters::apply (WorkflowRunSummary::query (), [
275+ 'instance_id_contains ' => 'acme-order ' ,
276+ 'run_id_contains ' => 'MATCH ' ,
277+ 'workflow_type_contains ' => 'invoice ' ,
278+ 'business_key_contains ' => 'order_ ' ,
279+ ])->pluck ('id ' )
280+ ->all ();
281+
282+ $ this ->assertSame (['01JVISC0NTAINMATCH0000001 ' ], $ ids );
283+ }
284+
285+ public function testContainsFiltersEscapeSqlWildcards (): void
286+ {
287+ WorkflowRunSummary::create ([
288+ 'id ' => '01JVISC0NTAINESCAPEMATCH01 ' ,
289+ 'workflow_instance_id ' => 'tenant-order-A_01 ' ,
290+ 'run_number ' => 1 ,
291+ 'is_current_run ' => true ,
292+ 'engine_source ' => 'v2 ' ,
293+ 'class ' => 'BillingWorkflow ' ,
294+ 'workflow_type ' => 'billing.invoice-sync ' ,
295+ 'business_key ' => 'order-123 ' ,
296+ 'status ' => 'waiting ' ,
297+ 'status_bucket ' => 'running ' ,
298+ ]);
299+ WorkflowRunSummary::create ([
300+ 'id ' => '01JVISC0NTAINESCAPEMISS01 ' ,
301+ 'workflow_instance_id ' => 'tenant-order-AB01 ' ,
302+ 'run_number ' => 1 ,
303+ 'is_current_run ' => true ,
304+ 'engine_source ' => 'v2 ' ,
305+ 'class ' => 'BillingWorkflow ' ,
306+ 'workflow_type ' => 'billing.invoice-sync ' ,
307+ 'business_key ' => 'order-456 ' ,
308+ 'status ' => 'waiting ' ,
309+ 'status_bucket ' => 'running ' ,
310+ ]);
311+
312+ $ ids = VisibilityFilters::apply (WorkflowRunSummary::query (), [
313+ 'instance_id_contains ' => 'A_01 ' ,
314+ ])->pluck ('id ' )
315+ ->all ();
316+
317+ $ this ->assertSame (['01JVISC0NTAINESCAPEMATCH01 ' ], $ ids );
318+ }
319+
237320 public function testDefinitionDescribesExactVisibilityContract (): void
238321 {
239322 $ definition = VisibilityFilters::definition ();
240323
241324 $ this ->assertSame (VisibilityFilters::VERSION , $ definition ['version ' ]);
242- $ this ->assertSame ([1 , 2 , 3 , 4 , VisibilityFilters::VERSION ], $ definition ['supported_versions ' ]);
325+ $ this ->assertSame ([1 , 2 , 3 , 4 , 5 , VisibilityFilters::VERSION ], $ definition ['supported_versions ' ]);
243326 $ this ->assertSame ('Instance ID ' , $ definition ['fields ' ]['instance_id ' ]['label ' ]);
244327 $ this ->assertSame ('string ' , $ definition ['fields ' ]['instance_id ' ]['type ' ]);
245328 $ this ->assertSame ('text ' , $ definition ['fields ' ]['instance_id ' ]['input ' ]);
246329 $ this ->assertTrue ($ definition ['fields ' ]['instance_id ' ]['filterable ' ]);
247330 $ this ->assertTrue ($ definition ['fields ' ]['instance_id ' ]['saved_view_compatible ' ]);
248331 $ this ->assertSame (0 , $ definition ['fields ' ]['instance_id ' ]['order ' ]);
249332 $ this ->assertSame ('string ' , $ definition ['fields ' ]['run_id ' ]['type ' ]);
333+ $ this ->assertSame ('contains ' , $ definition ['fields ' ]['instance_id_contains ' ]['operator ' ]);
334+ $ this ->assertSame ('instance_id ' , $ definition ['fields ' ]['instance_id_contains ' ]['contains_field ' ]);
335+ $ this ->assertSame ('instance_id_contains ' , $ definition ['fields ' ]['instance_id_contains ' ]['query_parameter ' ]);
336+ $ this ->assertTrue ($ definition ['fields ' ]['workflow_type_contains ' ]['saved_view_compatible ' ]);
337+ $ this ->assertSame (
338+ 'Substring match against workflow type names for fragment lookup. ' ,
339+ $ definition ['fields ' ]['workflow_type_contains ' ]['help ' ],
340+ );
250341 $ this ->assertSame ('Namespace ' , $ definition ['fields ' ]['namespace ' ]['label ' ]);
251342 $ this ->assertSame ('string ' , $ definition ['fields ' ]['namespace ' ]['type ' ]);
252343 $ this ->assertSame ('text ' , $ definition ['fields ' ]['namespace ' ]['input ' ]);
@@ -403,7 +494,7 @@ public function testVersionMetadataMarksUnsupportedSavedViewContractsExplicitly(
403494 $ this ->assertSame (VisibilityFilters::VERSION , $ supported ['version ' ]);
404495 $ this ->assertSame (VisibilityFilters::VERSION , $ supported ['current_version ' ]);
405496 $ this ->assertSame (VisibilityFilters::MINIMUM_SUPPORTED_VERSION , $ supported ['minimum_supported_version ' ]);
406- $ this ->assertSame ([1 , 2 , 3 , 4 , VisibilityFilters::VERSION ], $ supported ['supported_versions ' ]);
497+ $ this ->assertSame ([1 , 2 , 3 , 4 , 5 , VisibilityFilters::VERSION ], $ supported ['supported_versions ' ]);
407498 $ this ->assertTrue ($ supported ['supported ' ]);
408499 $ this ->assertFalse ($ supported ['deprecated ' ]);
409500 $ this ->assertSame ('supported ' , $ supported ['status ' ]);
@@ -412,12 +503,12 @@ public function testVersionMetadataMarksUnsupportedSavedViewContractsExplicitly(
412503 $ this ->assertSame (99 , $ unsupported ['version ' ]);
413504 $ this ->assertSame (VisibilityFilters::VERSION , $ unsupported ['current_version ' ]);
414505 $ this ->assertSame (VisibilityFilters::MINIMUM_SUPPORTED_VERSION , $ unsupported ['minimum_supported_version ' ]);
415- $ this ->assertSame ([1 , 2 , 3 , 4 , VisibilityFilters::VERSION ], $ unsupported ['supported_versions ' ]);
506+ $ this ->assertSame ([1 , 2 , 3 , 4 , 5 , VisibilityFilters::VERSION ], $ unsupported ['supported_versions ' ]);
416507 $ this ->assertFalse ($ unsupported ['supported ' ]);
417508 $ this ->assertFalse ($ unsupported ['deprecated ' ]);
418509 $ this ->assertSame ('unsupported ' , $ unsupported ['status ' ]);
419510 $ this ->assertSame (
420- 'This saved view uses visibility filter version 99, but this Waterline build supports version 1, 2, 3, 4, 5. ' ,
511+ 'This saved view uses visibility filter version 99, but this Waterline build supports version 1, 2, 3, 4, 5, 6 . ' ,
421512 $ unsupported ['message ' ],
422513 );
423514 }
@@ -432,7 +523,7 @@ public function testVersionMetadataMarksDeprecatedVersionsExplicitly(): void
432523 $ this ->assertTrue ($ deprecated ['deprecated ' ]);
433524 $ this ->assertSame ('deprecated ' , $ deprecated ['status ' ]);
434525 $ this ->assertSame (
435- 'This saved view uses deprecated visibility filter version 1. Consider updating it to the current version 5 . ' ,
526+ 'This saved view uses deprecated visibility filter version 1. Consider updating it to the current version 6 . ' ,
436527 $ deprecated ['message ' ],
437528 );
438529
@@ -454,7 +545,7 @@ public function testVersionEvolutionPolicyExposesStableContract(): void
454545
455546 $ this ->assertSame (VisibilityFilters::VERSION , $ policy ['current_version ' ]);
456547 $ this ->assertSame (VisibilityFilters::MINIMUM_SUPPORTED_VERSION , $ policy ['minimum_supported_version ' ]);
457- $ this ->assertSame ([1 , 2 , 3 , 4 , VisibilityFilters::VERSION ], $ policy ['supported_versions ' ]);
548+ $ this ->assertSame ([1 , 2 , 3 , 4 , 5 , VisibilityFilters::VERSION ], $ policy ['supported_versions ' ]);
458549 $ this ->assertSame ([1 , 2 ], $ policy ['deprecated_versions ' ]);
459550 $ this ->assertSame ('system: ' , $ policy ['reserved_view_id_prefix ' ]);
460551 $ this ->assertIsString ($ policy ['upgrade_policy ' ]);
0 commit comments