mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
eval_rule: Evaluate rules directly instead of queries (#186)
closes #185 Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
330a6dff72
commit
3d98c3b12e
@@ -208,6 +208,52 @@ impl Engine {
|
||||
&self.modules
|
||||
}
|
||||
|
||||
/// Evaluate rule(s) at given path.
|
||||
///
|
||||
/// [`eval_rule`] is often faster than [`eval_query`] and should be preferred if
|
||||
/// OPA style [`QueryResults`] are not needed.
|
||||
///
|
||||
/// ```
|
||||
/// # use regorus::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Add policy
|
||||
/// engine.add_policy(
|
||||
/// "policy.rego".to_string(),
|
||||
/// r#"
|
||||
/// package example
|
||||
/// import rego.v1
|
||||
///
|
||||
/// x = [1, 2]
|
||||
///
|
||||
/// y := 5 if input.a > 2
|
||||
/// "#.to_string())?;
|
||||
///
|
||||
/// // Evaluate rule.
|
||||
/// let v = engine.eval_rule("data.example.x".to_string())?;
|
||||
/// assert_eq!(v, Value::from(vec![Value::from(1), Value::from(2)]));
|
||||
///
|
||||
/// // y evaluates to undefined.
|
||||
/// let v = engine.eval_rule("data.example.y".to_string())?;
|
||||
/// assert_eq!(v, Value::Undefined);
|
||||
///
|
||||
/// // Evaluating a non-existent rule is an error.
|
||||
/// let r = engine.eval_rule("data.exaample.x".to_string());
|
||||
/// assert!(r.is_err());
|
||||
///
|
||||
/// // Path must be valid rule paths.
|
||||
/// assert!( engine.eval_rule("data".to_string()).is_err());
|
||||
/// assert!( engine.eval_rule("data.example".to_string()).is_err());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn eval_rule(&mut self, path: String) -> Result<Value> {
|
||||
self.prepare_for_eval(false)?;
|
||||
self.interpreter.clean_internal_evaluation_state();
|
||||
self.interpreter.eval_rule_in_path(path)
|
||||
}
|
||||
|
||||
/// Evaluate a Rego query.
|
||||
///
|
||||
/// ```
|
||||
@@ -419,7 +465,7 @@ impl Engine {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn eval_rule(
|
||||
pub fn eval_rule_in_module(
|
||||
&mut self,
|
||||
module: &Ref<Module>,
|
||||
rule: &Ref<Rule>,
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::{Expression, Extension, Location, QueryResult, QueryResults};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use std::collections::btree_map::Entry as BTreeMapEntry;
|
||||
use std::collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap};
|
||||
use std::collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::ops::Bound::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -75,6 +75,7 @@ pub struct Interpreter {
|
||||
|
||||
gather_prints: bool,
|
||||
prints: Vec<String>,
|
||||
rule_paths: HashSet<String>,
|
||||
}
|
||||
|
||||
impl Default for Interpreter {
|
||||
@@ -195,6 +196,7 @@ impl Interpreter {
|
||||
|
||||
gather_prints: false,
|
||||
prints: Vec::default(),
|
||||
rule_paths: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3426,6 +3428,9 @@ impl Interpreter {
|
||||
let comps: Vec<&str> = comps.iter().map(|s| s.text()).collect();
|
||||
for c in 0..comps.len() {
|
||||
let path = self.current_module_path.clone() + "." + &comps[0..c + 1].join(".");
|
||||
if c + 1 == comps.len() {
|
||||
self.rule_paths.insert(path.clone());
|
||||
}
|
||||
|
||||
match self.rules.entry(path) {
|
||||
Entry::Occupied(o) => {
|
||||
@@ -3450,6 +3455,10 @@ impl Interpreter {
|
||||
let comps: Vec<&str> = comps.iter().map(|s| s.text()).collect();
|
||||
for (idx, c) in (0..comps.len()).enumerate() {
|
||||
let path = self.current_module_path.clone() + "." + &comps[0..c + 1].join(".");
|
||||
if c + 1 == comps.len() {
|
||||
self.rule_paths.insert(path.clone());
|
||||
}
|
||||
|
||||
match self.default_rules.entry(path) {
|
||||
Entry::Occupied(o) => {
|
||||
if idx + 1 == comps.len() {
|
||||
@@ -3707,4 +3716,14 @@ impl Interpreter {
|
||||
pub fn take_prints(&mut self) -> Result<Vec<String>> {
|
||||
Ok(std::mem::take(&mut self.prints))
|
||||
}
|
||||
|
||||
pub fn eval_rule_in_path(&mut self, path: String) -> Result<Value> {
|
||||
if !self.rule_paths.contains(&path) {
|
||||
bail!("not a valid rule path");
|
||||
}
|
||||
self.ensure_rule_evaluated(path.clone())?;
|
||||
let parts: Vec<&str> = path.split('.').collect();
|
||||
|
||||
Ok(Self::get_value_chained(self.data.clone(), &parts[1..]))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user