`CREATE RLS POLICY ON FOR USING ( ) [RESTRICTIVE] [TENANT ] [ON DENY ...]` Extracts all token-level fields. Predicate compilation (AST parse, auth-ref validation, ScanFilter serialization) is left to the handler in `nodedb` which has access to the required security types.
(upper: &str, parts: &[&str], _trimmed: &str)
| 46 | /// auth-ref validation, ScanFilter serialization) is left to the |
| 47 | /// handler in `nodedb` which has access to the required security types. |
| 48 | fn parse_create_rls_policy(upper: &str, parts: &[&str], _trimmed: &str) -> NodedbStatement { |
| 49 | // parts: CREATE RLS POLICY <name> ON <collection> FOR <type> USING (<pred>) ... |
| 50 | // Indices (0-based): 0 1 2 3 4 5 6 7 8 9+ |
| 51 | |
| 52 | let name = parts.get(3).unwrap_or(&"").to_lowercase(); |
| 53 | let collection = parts |
| 54 | .iter() |
| 55 | .position(|p| p.to_uppercase() == "ON") |
| 56 | .and_then(|i| parts.get(i + 1)) |
| 57 | .map(|s| s.to_lowercase()) |
| 58 | .unwrap_or_default(); |
| 59 | |
| 60 | // FOR keyword → next token is the policy type. |
| 61 | let policy_type = parts |
| 62 | .iter() |
| 63 | .position(|p| p.to_uppercase() == "FOR") |
| 64 | .and_then(|i| parts.get(i + 1)) |
| 65 | .map(|s| s.to_uppercase()) |
| 66 | .unwrap_or_else(|| "ALL".to_string()); |
| 67 | |
| 68 | // USING keyword → everything up to the next keyword (RESTRICTIVE/TENANT/ON) |
| 69 | // is the predicate (including its outer parentheses which we strip). |
| 70 | let predicate_raw = |
| 71 | if let Some(using_idx) = parts.iter().position(|p| p.to_uppercase() == "USING") { |
| 72 | let end = parts[using_idx + 1..] |
| 73 | .iter() |
| 74 | .position(|p| { |
| 75 | let u = p.to_uppercase(); |
| 76 | u == "RESTRICTIVE" || u == "TENANT" || u == "ON" |
| 77 | }) |
| 78 | .map(|i| using_idx + 1 + i) |
| 79 | .unwrap_or(parts.len()); |
| 80 | strip_outer_parens(&parts[using_idx + 1..end].join(" ")) |
| 81 | } else { |
| 82 | // Fall back: look in the upper string between USING( and ) for simple cases. |
| 83 | extract_using_from_upper(upper) |
| 84 | }; |
| 85 | |
| 86 | let is_restrictive = upper.contains("RESTRICTIVE"); |
| 87 | |
| 88 | // ON DENY <...> — everything after "ON DENY" up to RESTRICTIVE/TENANT/end. |
| 89 | let on_deny_raw = { |
| 90 | // Find "ON" followed by "DENY" in parts (not the "ON <collection>" earlier). |
| 91 | let deny_pos = parts |
| 92 | .windows(2) |
| 93 | .position(|w| w[0].to_uppercase() == "ON" && w[1].to_uppercase() == "DENY"); |
| 94 | deny_pos.map(|pos| { |
| 95 | // Collect tokens after DENY until RESTRICTIVE or TENANT. |
| 96 | parts[pos + 2..] |
| 97 | .iter() |
| 98 | .take_while(|p| { |
| 99 | let u = p.to_uppercase(); |
| 100 | u != "RESTRICTIVE" && u != "TENANT" |
| 101 | }) |
| 102 | .copied() |
| 103 | .collect::<Vec<_>>() |
| 104 | .join(" ") |
| 105 | }) |
no test coverage detected