Skip to content

Commit 4b5535f

Browse files
committed
feat: support condition type SemVer, Number, Date
1 parent 70af020 commit 4b5535f

File tree

1 file changed

+119
-46
lines changed

1 file changed

+119
-46
lines changed

src/evalutate.rs

Lines changed: 119 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use crate::user::FPUser;
22
use crate::FPError;
33
use byteorder::{BigEndian, ReadBytesExt};
44
use regex::Regex;
5+
use semver::Version;
56
use serde::{Deserialize, Serialize};
67
use serde_json::Value;
78
use sha1::Digest;
8-
use std::collections::HashMap;
99
use std::string::String;
10+
use std::{collections::HashMap, str::FromStr};
1011
use tracing::{info, warn};
1112

1213
#[derive(Serialize, Deserialize, Debug, PartialEq)]
@@ -286,7 +287,11 @@ impl Rule {
286287
enum ConditionType {
287288
String,
288289
Segment,
289-
Date, // no implement
290+
Date,
291+
Number,
292+
SemVer,
293+
#[serde(other)]
294+
Unknown,
290295
}
291296

292297
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
@@ -301,15 +306,16 @@ struct Condition {
301306
impl Condition {
302307
pub fn meet(&self, user: &FPUser, segment_repo: Option<&HashMap<String, Segment>>) -> bool {
303308
match &self.r#type {
304-
ConditionType::String => self.match_string_condition(user, &self.predicate),
305-
ConditionType::Segment => {
306-
self.match_segment_condition(user, &self.predicate, segment_repo)
307-
}
309+
ConditionType::String => self.match_string(user, &self.predicate),
310+
ConditionType::Segment => self.match_segment(user, &self.predicate, segment_repo),
311+
ConditionType::Number => self.match_ordering::<f64>(user, &self.predicate),
312+
ConditionType::SemVer => self.match_ordering::<Version>(user, &self.predicate),
313+
ConditionType::Date => self.match_timestamp(user, &self.predicate),
308314
_ => false,
309315
}
310316
}
311317

312-
fn match_segment_condition(
318+
fn match_segment(
313319
&self,
314320
user: &FPUser,
315321
predicate: &str,
@@ -325,22 +331,66 @@ impl Condition {
325331
}
326332
}
327333

328-
fn match_string_condition(&self, user: &FPUser, predicate: &str) -> bool {
329-
if let Some(custom_value) = user.get(&self.subject) {
334+
fn match_string(&self, user: &FPUser, predicate: &str) -> bool {
335+
if let Some(c) = user.get(&self.subject) {
336+
return match predicate {
337+
"is one of" => self.do_match::<String>(c, |c, o| c.eq(o)),
338+
"ends with" => self.do_match::<String>(c, |c, o| c.ends_with(o)),
339+
"starts with" => self.do_match::<String>(c, |c, o| c.starts_with(o)),
340+
"contains" => self.do_match::<String>(c, |c, o| c.contains(o)),
341+
"matches regex" => {
342+
self.do_match::<String>(c, |c, o| match Regex::new(o) {
343+
Ok(re) => re.is_match(c),
344+
Err(_) => false, // invalid regex should be checked when load config
345+
})
346+
}
347+
"is not any of" => !self.match_string(user, "is one of"),
348+
"does not end with" => !self.match_string(user, "ends with"),
349+
"does not start with" => !self.match_string(user, "starts with"),
350+
"does not contain" => !self.match_string(user, "contains"),
351+
"does not match regex" => !self.match_string(user, "matches regex"),
352+
_ => {
353+
info!("unknown predicate {}", predicate);
354+
false
355+
}
356+
};
357+
}
358+
info!("user attr missing: {}", self.subject);
359+
false
360+
}
361+
362+
fn match_ordering<T: FromStr + PartialOrd>(&self, user: &FPUser, predicate: &str) -> bool {
363+
if let Some(c) = user.get(&self.subject) {
364+
let c: T = match c.parse() {
365+
Ok(v) => v,
366+
Err(_) => return false,
367+
};
368+
return match predicate {
369+
"=" => self.do_match::<T>(&c, |c, o| c.eq(o)),
370+
"!=" => !self.match_ordering::<T>(user, "="),
371+
">" => self.do_match::<T>(&c, |c, o| c.gt(o)),
372+
">=" => self.do_match::<T>(&c, |c, o| c.ge(o)),
373+
"<" => self.do_match::<T>(&c, |c, o| c.lt(o)),
374+
"<=" => self.do_match::<T>(&c, |c, o| c.le(o)),
375+
_ => {
376+
info!("unknown predicate {}", predicate);
377+
false
378+
}
379+
};
380+
}
381+
info!("user attr missing: {}", self.subject);
382+
false
383+
}
384+
385+
fn match_timestamp(&self, user: &FPUser, predicate: &str) -> bool {
386+
if let Some(c) = user.get(&self.subject) {
387+
let c: u64 = match c.parse() {
388+
Ok(v) => v,
389+
Err(_) => return false,
390+
};
330391
return match predicate {
331-
"is one of" => self.match_objects(|object| custom_value.eq(object)),
332-
"ends with" => self.match_objects(|object| custom_value.ends_with(object)),
333-
"starts with" => self.match_objects(|object| custom_value.starts_with(object)),
334-
"contains" => self.match_objects(|object| custom_value.contains(object)),
335-
"matches regex" => self.match_objects(|object| match Regex::new(object) {
336-
Ok(re) => re.is_match(custom_value),
337-
Err(_) => false, // invalid regex should be checked when load config
338-
}),
339-
"is not any of" => !self.match_string_condition(user, "is one of"),
340-
"does not end with" => !self.match_string_condition(user, "ends with"),
341-
"does not start with" => !self.match_string_condition(user, "starts with"),
342-
"does not contain" => !self.match_string_condition(user, "contains"),
343-
"does not match regex" => !self.match_string_condition(user, "matches regex"),
392+
">=" => self.do_match::<u64>(&c, |c, o| c.ge(o)),
393+
"<" => self.do_match::<u64>(&c, |c, o| c.lt(o)),
344394
_ => {
345395
info!("unknown predicate {}", predicate);
346396
false
@@ -351,8 +401,14 @@ impl Condition {
351401
false
352402
}
353403

354-
fn match_objects(&self, f: impl Fn(&String) -> bool) -> bool {
355-
self.objects.iter().map(f).any(|x| x)
404+
fn do_match<T: FromStr>(&self, t: &T, f: fn(&T, &T) -> bool) -> bool {
405+
self.objects
406+
.iter()
407+
.map(|o| match o.parse::<T>() {
408+
Ok(o) => f(t, &o),
409+
Err(_) => false,
410+
})
411+
.any(|x| x)
356412
}
357413

358414
fn user_in_segments(&self, user: &FPUser, repo: &HashMap<String, Segment>) -> bool {
@@ -674,6 +730,23 @@ mod string_condition_tests {
674730
use std::fs;
675731
use std::path::PathBuf;
676732

733+
#[test]
734+
fn test_unkown_condition() {
735+
let json_str = r#"
736+
{
737+
"type": "new_type",
738+
"subject": "new_subject",
739+
"predicate": ">",
740+
"objects": []
741+
}
742+
"#;
743+
744+
let condition = serde_json::from_str::<Condition>(&json_str);
745+
assert!(condition.is_ok());
746+
let condition = condition.unwrap();
747+
assert_eq!(condition.r#type, ConditionType::Unknown);
748+
}
749+
677750
#[test]
678751
fn test_match_is_one_of() {
679752
let condition = Condition {
@@ -684,7 +757,7 @@ mod string_condition_tests {
684757
};
685758

686759
let user = FPUser::new(String::from("not care")).with("name", "world");
687-
assert!(condition.match_string_condition(&user, &condition.predicate));
760+
assert!(condition.match_string(&user, &condition.predicate));
688761
}
689762

690763
#[test]
@@ -698,7 +771,7 @@ mod string_condition_tests {
698771

699772
let user = FPUser::new(String::from("not care")).with("name", "not_in");
700773

701-
assert!(!condition.match_string_condition(&user, &condition.predicate));
774+
assert!(!condition.match_string(&user, &condition.predicate));
702775
}
703776

704777
#[test]
@@ -712,7 +785,7 @@ mod string_condition_tests {
712785

713786
let user = FPUser::new(String::from("not care"));
714787

715-
assert!(!condition.match_string_condition(&user, &condition.predicate));
788+
assert!(!condition.match_string(&user, &condition.predicate));
716789
}
717790

718791
#[test]
@@ -725,7 +798,7 @@ mod string_condition_tests {
725798
};
726799

727800
let user = FPUser::new(String::from("not care")).with("name", "welcome");
728-
assert!(condition.match_string_condition(&user, &condition.predicate));
801+
assert!(condition.match_string(&user, &condition.predicate));
729802
}
730803

731804
#[test]
@@ -739,7 +812,7 @@ mod string_condition_tests {
739812

740813
let user = FPUser::new(String::from("not care")).with("name", "not_in");
741814

742-
assert!(condition.match_string_condition(&user, &condition.predicate));
815+
assert!(condition.match_string(&user, &condition.predicate));
743816
}
744817

745818
#[test]
@@ -753,7 +826,7 @@ mod string_condition_tests {
753826

754827
let user = FPUser::new(String::from("not care")).with("name", "bob world");
755828

756-
assert!(condition.match_string_condition(&user, &condition.predicate));
829+
assert!(condition.match_string(&user, &condition.predicate));
757830
}
758831

759832
#[test]
@@ -767,7 +840,7 @@ mod string_condition_tests {
767840

768841
let user = FPUser::new(String::from("not care")).with("name", "bob");
769842

770-
assert!(!condition.match_string_condition(&user, &condition.predicate));
843+
assert!(!condition.match_string(&user, &condition.predicate));
771844
}
772845

773846
#[test]
@@ -781,7 +854,7 @@ mod string_condition_tests {
781854

782855
let user = FPUser::new(String::from("not care")).with("name", "bob");
783856

784-
assert!(condition.match_string_condition(&user, &condition.predicate));
857+
assert!(condition.match_string(&user, &condition.predicate));
785858
}
786859

787860
#[test]
@@ -795,7 +868,7 @@ mod string_condition_tests {
795868

796869
let user = FPUser::new(String::from("not care")).with("name", "bob world");
797870

798-
assert!(!condition.match_string_condition(&user, &condition.predicate));
871+
assert!(!condition.match_string(&user, &condition.predicate));
799872
}
800873

801874
#[test]
@@ -809,7 +882,7 @@ mod string_condition_tests {
809882

810883
let user = FPUser::new(String::from("not care")).with("name", "world bob");
811884

812-
assert!(condition.match_string_condition(&user, &condition.predicate));
885+
assert!(condition.match_string(&user, &condition.predicate));
813886
}
814887

815888
#[test]
@@ -823,7 +896,7 @@ mod string_condition_tests {
823896

824897
let user = FPUser::new(String::from("not care")).with("name", "bob");
825898

826-
assert!(!condition.match_string_condition(&user, &condition.predicate));
899+
assert!(!condition.match_string(&user, &condition.predicate));
827900
}
828901

829902
#[test]
@@ -837,7 +910,7 @@ mod string_condition_tests {
837910

838911
let user = FPUser::new(String::from("not care")).with("name", "bob");
839912

840-
assert!(condition.match_string_condition(&user, &condition.predicate));
913+
assert!(condition.match_string(&user, &condition.predicate));
841914
}
842915

843916
#[test]
@@ -851,7 +924,7 @@ mod string_condition_tests {
851924

852925
let user = FPUser::new(String::from("not care")).with("name", "world bob");
853926

854-
assert!(!condition.match_string_condition(&user, &condition.predicate));
927+
assert!(!condition.match_string(&user, &condition.predicate));
855928
}
856929

857930
#[test]
@@ -865,7 +938,7 @@ mod string_condition_tests {
865938

866939
let user = FPUser::new(String::from("not care")).with("name", "alice world bob");
867940

868-
assert!(condition.match_string_condition(&user, &condition.predicate));
941+
assert!(condition.match_string(&user, &condition.predicate));
869942
}
870943

871944
#[test]
@@ -879,7 +952,7 @@ mod string_condition_tests {
879952

880953
let user = FPUser::new(String::from("not care")).with("name", "alice bob");
881954

882-
assert!(!condition.match_string_condition(&user, &condition.predicate));
955+
assert!(!condition.match_string(&user, &condition.predicate));
883956
}
884957

885958
#[test]
@@ -893,7 +966,7 @@ mod string_condition_tests {
893966

894967
let user = FPUser::new(String::from("not care")).with("name", "alice bob");
895968

896-
assert!(condition.match_string_condition(&user, &condition.predicate));
969+
assert!(condition.match_string(&user, &condition.predicate));
897970
}
898971

899972
#[test]
@@ -907,7 +980,7 @@ mod string_condition_tests {
907980

908981
let user = FPUser::new(String::from("not care")).with("name", "alice world bob");
909982

910-
assert!(!condition.match_string_condition(&user, &condition.predicate));
983+
assert!(!condition.match_string(&user, &condition.predicate));
911984
}
912985

913986
#[test]
@@ -921,7 +994,7 @@ mod string_condition_tests {
921994

922995
let user = FPUser::new(String::from("not care")).with("name", "alice world bob");
923996

924-
assert!(condition.match_string_condition(&user, &condition.predicate));
997+
assert!(condition.match_string(&user, &condition.predicate));
925998
}
926999

9271000
#[test]
@@ -935,7 +1008,7 @@ mod string_condition_tests {
9351008

9361009
let user = FPUser::new(String::from("not care")).with("name", "alice orld bob hello3");
9371010

938-
assert!(condition.match_string_condition(&user, &condition.predicate));
1011+
assert!(condition.match_string(&user, &condition.predicate));
9391012
}
9401013

9411014
#[test]
@@ -949,7 +1022,7 @@ mod string_condition_tests {
9491022

9501023
let user = FPUser::new(String::from("not care")).with("name", "alice orld bob hello");
9511024

952-
assert!(!condition.match_string_condition(&user, &condition.predicate));
1025+
assert!(!condition.match_string(&user, &condition.predicate));
9531026
}
9541027

9551028
#[test]
@@ -963,7 +1036,7 @@ mod string_condition_tests {
9631036

9641037
let user = FPUser::new(String::from("not care")).with("name", "alice orld bob hello");
9651038

966-
assert!(condition.match_string_condition(&user, &condition.predicate));
1039+
assert!(condition.match_string(&user, &condition.predicate));
9671040
}
9681041

9691042
#[test]
@@ -977,7 +1050,7 @@ mod string_condition_tests {
9771050

9781051
let user = FPUser::new(String::from("not care")).with("name", "\\\\\\");
9791052

980-
assert!(!condition.match_string_condition(&user, &condition.predicate));
1053+
assert!(!condition.match_string(&user, &condition.predicate));
9811054
}
9821055

9831056
#[test]

0 commit comments

Comments
 (0)