fix: exact redirects with a trailing slash or an upper-case query fire at runtime (CR-03)
The resolver fetched exact rules with lower(source) IN keys, while the keys drop one trailing slash and keep the query as written, so a source stored as /old/ or /list?Page=2 was never read. A new migration adds the stored generated column source_key (the SQL form of exactKey) with an index for exact rules, and the fetch compares it.
This commit is contained in:
42
updates/202610280001_add_golem15_seo_redirects_source_key.go
Normal file
42
updates/202610280001_add_golem15_seo_redirects_source_key.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package updates
|
||||
|
||||
import (
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// redirectSourceKey is the SQL form of classes.exactKey: the source's path
|
||||
// lowercased without one trailing slash (the root stays "/"), then its
|
||||
// query as written. The resolver fetches exact rules by this key, so a
|
||||
// source stored as "/old/" or "/list?Page=2" is found for every request the
|
||||
// in-memory matcher accepts.
|
||||
const redirectSourceKey = `(CASE
|
||||
WHEN length(split_part(source, '?', 1)) > 1 AND right(split_part(source, '?', 1), 1) = '/'
|
||||
THEN lower(left(split_part(source, '?', 1), -1))
|
||||
ELSE lower(split_part(source, '?', 1))
|
||||
END) || (CASE WHEN strpos(source, '?') > 0 THEN substr(source, strpos(source, '?')) ELSE '' END)`
|
||||
|
||||
// addRedirectSourceKey adds golem15_seo_redirects.source_key, a stored
|
||||
// generated column holding the exact-match lookup key, and indexes it for
|
||||
// exact rules. Every write path fills it, because Postgres computes it.
|
||||
var addRedirectSourceKey = []*gormigrate.Migration{
|
||||
{
|
||||
ID: "202610280001_add_golem15_seo_redirects_source_key",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Exec(`ALTER TABLE golem15_seo_redirects ADD COLUMN source_key TEXT GENERATED ALWAYS AS (` + redirectSourceKey + `) STORED`).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Exec(`CREATE INDEX golem15_seo_redirects_source_key ON golem15_seo_redirects (source_key) WHERE match = 'exact'`).Error
|
||||
},
|
||||
Rollback: func(tx *gorm.DB) error {
|
||||
if err := tx.Exec(`DROP INDEX IF EXISTS golem15_seo_redirects_source_key`).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Exec(`ALTER TABLE golem15_seo_redirects DROP COLUMN IF EXISTS source_key`).Error
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(addRedirectSourceKey...)
|
||||
}
|
||||
Reference in New Issue
Block a user