feat(rules): add W015 join-function-on-column#33
Conversation
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Rule's solid. The negative lookahead stopping at the next clause keyword is exactly right, and the clean-JOIN-dirty-WHERE test is the one I'd have asked for. CI's only blocker is the CHANGELOG entry under [Unreleased] / ### Added. Same shape as the W023 line that just merged in #34. While you're rebasing, please also add a README rule-table row for W015 and bump the key-numbers (Rules, warnings sub-count, the intro paragraph). One sequencing note: I merged #34 first, so main is now at 35 rules / 25 warnings. The assertions in test_rules.py need 35 → 36 and 25 → 26, and test_25_warnings becomes test_26_warnings. The rev-pin warnings you saw in pr-sop output are now fixed on main too, so a fresh rebase will clear those. Good to merge once those are in. Thanks for the second one this week. |
Adds a new warning rule that catches function-wrapped columns in JOIN ... ON clauses, mirroring W003 which only checks the WHERE clause. Both patterns are equally index-hostile. Detects functions on either side of the equality predicate: - YEAR/MONTH/DAY/DATE on date columns - UPPER/LOWER/TRIM/CAST/CONVERT/SUBSTRING/COALESCE on text columns Closes Pawansingh3889#5.
Without bounding the inner '.*', a single-line query with a clean JOIN predicate and a dirty WHERE function (e.g. UPPER on a column) would trip W015 even though W003 already owns that case. The new regex anchors the function search to the ON predicate by refusing to cross WHERE / GROUP BY / ORDER BY / HAVING / a subsequent JOIN / UNION before finding the function. Adds a regression test covering the false-positive case.
19c65de to
ee7a469
Compare
|
Picked this back up — rebased on main, added the CHANGELOG entry, README rule-table row, and the key-numbers bump. CI is green. Squashing now. Thanks for the patience and for shipping the third one this month, much appreciated. |
Closes #5.
Adds W015 join-function-on-column. The rule mirrors W003 but checks JOIN ... ON predicates instead of WHERE clauses. Both patterns destroy index-based join performance the same way.
Implementation
sql_guard/rules/warnings.py: newJoinFunctionOnColumnrule. Same shape asFunctionOnIndexedColumn(W003), with one difference -- the regex anchors the function search to the ON predicate so it stops at the next clause keyword (WHERE / GROUP BY / ORDER BY / HAVING / next JOIN / UNION). Without that bound, single-line queries with a clean JOIN and a dirty WHERE would trip W015 even though W003 already owns that case.Function list matches W003: YEAR, MONTH, DAY, DATE, UPPER, LOWER, TRIM, CAST, CONVERT, SUBSTRING, COALESCE.
Wiring
sql_guard/rules/__init__.py: import + registration in ALL_RULES.tests/fixtures/warnings.sql: fixture entry exercising the rule.tests/test_new_rules.py: 5 unit tests -- happy path (UPPER, YEAR), passing case (materialized columns), W003-only case (function in WHERE), and the false-positive regression (clean JOIN + dirty WHERE on the same line).tests/test_rules.py: registry counts updated (34 -> 35 rules, 24 -> 25 warnings) and an integration test verifying W015 fires from the fixture.Verification
The
test_structural.pyfailure pre-exists onupstream/mainand is unrelated to this change.