Add GLOB match type to replace PREFIX for tracker patterns

Introduces a wildcard-based match type that supports prefix, suffix,
and sandwich patterns (e.g. ph_phc_*_posthog). The SQL matching uses
starts_with/ends_with on the parts split at '*', avoiding LIKE and
its underscore escaping issues. Existing PREFIX rows are migrated to
GLOB with a trailing '*'.

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-05-06 20:24:34 +04:00
parent 31bfbefc45
commit 70d86d68af
4 changed files with 50 additions and 11 deletions

View File

@@ -0,0 +1,15 @@
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above
-- copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
ALTER TYPE cookie_pattern_match_type ADD VALUE IF NOT EXISTS 'GLOB';

View File

@@ -0,0 +1,18 @@
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above
-- copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
UPDATE tracker_patterns
SET pattern = pattern || '*',
match_type = 'GLOB'
WHERE match_type = 'PREFIX';

View File

@@ -239,26 +239,28 @@ WHERE
AND cookie_banner_id = @cookie_banner_id
AND tracker_type = @tracker_type
AND (
(match_type = @match_type_prefix AND starts_with(@identifier, pattern))
(match_type = @match_type_glob
AND starts_with(@identifier, split_part(pattern, '*', 1))
AND ends_with(@identifier, split_part(pattern, '*', 2))
AND length(@identifier) >= length(pattern) - 1)
OR (match_type = @match_type_exact AND pattern = @identifier)
)
ORDER BY
CASE WHEN match_type = @match_type_exact AND pattern = @identifier THEN 0
WHEN match_type = @match_type_prefix THEN 1
ELSE 2
ELSE 1
END,
LENGTH(pattern) DESC
length(pattern) - 1 DESC
LIMIT 1;
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"cookie_banner_id": cookieBannerID,
"tracker_type": trackerType,
"identifier": identifier,
"match_type_prefix": TrackerPatternMatchTypePrefix,
"match_type_exact": TrackerPatternMatchTypeExact,
"cookie_banner_id": cookieBannerID,
"tracker_type": trackerType,
"identifier": identifier,
"match_type_glob": TrackerPatternMatchTypeGlob,
"match_type_exact": TrackerPatternMatchTypeExact,
}
maps.Copy(args, scope.SQLArguments())

View File

@@ -24,12 +24,13 @@ type TrackerPatternMatchType string
const (
TrackerPatternMatchTypeExact TrackerPatternMatchType = "EXACT"
TrackerPatternMatchTypePrefix TrackerPatternMatchType = "PREFIX"
TrackerPatternMatchTypeGlob TrackerPatternMatchType = "GLOB"
)
func TrackerPatternMatchTypes() []TrackerPatternMatchType {
return []TrackerPatternMatchType{
TrackerPatternMatchTypeExact,
TrackerPatternMatchTypePrefix,
TrackerPatternMatchTypeGlob,
}
}
@@ -53,6 +54,8 @@ func (m *TrackerPatternMatchType) Scan(value any) error {
*m = TrackerPatternMatchTypeExact
case TrackerPatternMatchTypePrefix:
*m = TrackerPatternMatchTypePrefix
case TrackerPatternMatchTypeGlob:
*m = TrackerPatternMatchTypeGlob
default:
return fmt.Errorf("invalid TrackerPatternMatchType value: %q", v)
}
@@ -62,7 +65,8 @@ func (m *TrackerPatternMatchType) Scan(value any) error {
func (m TrackerPatternMatchType) Value() (driver.Value, error) {
switch m {
case TrackerPatternMatchTypeExact,
TrackerPatternMatchTypePrefix:
TrackerPatternMatchTypePrefix,
TrackerPatternMatchTypeGlob:
return string(m), nil
default:
return nil, fmt.Errorf("invalid TrackerPatternMatchType: %s", m)