Skip to main content

sqrust_rules/ambiguous/
order_by_position.rs

1use sqrust_core::{Diagnostic, FileContext, Rule};
2
3use crate::capitalisation::SkipMap;
4
5use super::group_by_position::{
6    match_keyword, scan_positional_list, skip_whitespace, ORDER_BY_STOP_KEYWORDS,
7};
8
9pub struct OrderByPosition;
10
11impl Rule for OrderByPosition {
12    fn name(&self) -> &'static str {
13        "Ambiguous/OrderByPosition"
14    }
15
16    fn check(&self, ctx: &FileContext) -> Vec<Diagnostic> {
17        let source = &ctx.source;
18        let bytes = source.as_bytes();
19        let len = bytes.len();
20        let skip_map = SkipMap::build(source);
21
22        let mut diags = Vec::new();
23        let mut i = 0;
24
25        while i < len {
26            // Skip non-code positions (strings, comments).
27            if !skip_map.is_code(i) {
28                i += 1;
29                continue;
30            }
31
32            // Try to match ORDER at a word boundary.
33            if let Some(after_order) = match_keyword(bytes, &skip_map, i, b"ORDER") {
34                let after_ws = skip_whitespace(bytes, after_order);
35
36                if let Some(after_by) = match_keyword(bytes, &skip_map, after_ws, b"BY") {
37                    scan_positional_list(
38                        bytes,
39                        &skip_map,
40                        source,
41                        after_by,
42                        self.name(),
43                        "Avoid positional ORDER BY references; use column names",
44                        ORDER_BY_STOP_KEYWORDS,
45                        &mut diags,
46                    );
47                    i = after_by;
48                    continue;
49                }
50            }
51
52            i += 1;
53        }
54
55        diags
56    }
57}