Skip to content

Commit 53b1ba9

Browse files
authored
Merge pull request #325 from AdExNetwork/issue-296-get-should-work-with-output
AIP#31 Issue #296 Function::Get should work with output
2 parents 6a95b0b + caa73f1 commit 53b1ba9

File tree

3 files changed

+95
-6
lines changed

3 files changed

+95
-6
lines changed

primitives/src/targeting.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use chrono::Utc;
66
use std::collections::HashMap;
77

88
pub use eval::*;
9+
use serde_json::Number;
910

1011
mod eval;
1112

@@ -24,6 +25,7 @@ impl Input {
2425
let spec = &self.global.channel.spec;
2526

2627
match key {
28+
// AdView scope, accessible only on the AdView
2729
"adView.secondsSinceCampaignImpression" => self
2830
.ad_view
2931
.as_ref()
@@ -34,9 +36,22 @@ impl Input {
3436
.as_ref()
3537
.map(|ad_view| Value::Bool(ad_view.has_custom_preferences))
3638
.ok_or(Error::UnknownVariable),
39+
"adView.navigatorLanguage" => self
40+
.ad_view
41+
.as_ref()
42+
.map(|ad_view| Value::String(ad_view.navigator_language.clone()))
43+
.ok_or(Error::UnknownVariable),
44+
// Global scope, accessible everywhere
3745
"adSlotId" => Ok(Value::String(self.global.ad_slot_id.clone())),
3846
"adSlotType" => Ok(Value::String(self.global.ad_slot_type.clone())),
3947
"publisherId" => Ok(Value::String(self.global.publisher_id.to_checksum())),
48+
"country" => self
49+
.global
50+
.country
51+
.clone()
52+
.ok_or(Error::UnknownVariable)
53+
.map(Value::String),
54+
"eventType" => Ok(Value::String(self.global.event_type.clone())),
4055
"secondsSinceEpoch" => Ok(Value::Number(self.global.seconds_since_epoch.into())),
4156
"userAgentOS" => self
4257
.global
@@ -50,7 +65,7 @@ impl Input {
5065
.clone()
5166
.map(Value::String)
5267
.ok_or(Error::UnknownVariable),
53-
68+
// Global scope, accessible everywhere, campaign-dependant
5469
"adUnitId" => {
5570
let ipfs = self
5671
.global
@@ -112,6 +127,7 @@ impl Input {
112127

113128
Ok(Value::BigNum(earned))
114129
}
130+
// adSlot scope, accessible on Supermarket and AdView
115131
"adSlot.categories" => self
116132
.ad_slot
117133
.as_ref()
@@ -213,6 +229,26 @@ pub struct Output {
213229
pub price: HashMap<String, BigNum>,
214230
}
215231

232+
impl Output {
233+
fn try_get(&self, key: &str) -> Result<Value, Error> {
234+
match key {
235+
"show" => Ok(Value::Bool(self.show)),
236+
"boost" => {
237+
let boost = Number::from_f64(self.boost).ok_or(Error::TypeError)?;
238+
Ok(Value::Number(boost))
239+
}
240+
price_key if price_key.starts_with("price.") => {
241+
let price = self
242+
.price
243+
.get(price_key.trim_start_matches("price."))
244+
.ok_or(Error::UnknownVariable)?;
245+
Ok(Value::BigNum(price.clone()))
246+
}
247+
_ => Err(Error::UnknownVariable),
248+
}
249+
}
250+
}
251+
216252
impl From<&Channel> for Output {
217253
fn from(channel: &Channel) -> Self {
218254
let price = match &channel.spec.pricing_bounds {
@@ -325,6 +361,26 @@ mod test {
325361
assert!(input.try_get("adSlot.alexaRank").is_ok());
326362
}
327363

364+
#[test]
365+
fn test_try_get_of_output() {
366+
let output = Output {
367+
show: false,
368+
boost: 5.5,
369+
price: vec![("one".to_string(), 100.into())].into_iter().collect(),
370+
};
371+
372+
assert_eq!(Ok(Value::Bool(false)), output.try_get("show"));
373+
assert_eq!(
374+
Ok(Value::Number(
375+
Number::from_f64(5.5).expect("Should make a number")
376+
)),
377+
output.try_get("boost")
378+
);
379+
assert_eq!(Ok(Value::BigNum(100.into())), output.try_get("price.one"));
380+
assert_eq!(Err(Error::UnknownVariable), output.try_get("price.unknown"));
381+
assert_eq!(Err(Error::UnknownVariable), output.try_get("unknown"));
382+
}
383+
328384
#[test]
329385
fn test_output_from_channel() {
330386
use crate::channel::{Pricing, PricingBounds};

primitives/src/targeting/eval.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,9 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result<Option<Value>
895895
.try_bignum()?;
896896
let deposit_asset = &input.global.channel.deposit_asset;
897897

898-
let divisor = DEPOSIT_ASSETS_MAP.get(deposit_asset).ok_or(Error::TypeError)?;
898+
let divisor = DEPOSIT_ASSETS_MAP
899+
.get(deposit_asset)
900+
.ok_or(Error::TypeError)?;
899901
let amount_in_usd = amount.div(divisor).to_f64().ok_or(Error::TypeError)?;
900902
let amount_as_number = Number::from_f64(amount_in_usd).ok_or(Error::TypeError)?;
901903
Some(Value::Number(amount_as_number))
@@ -944,7 +946,11 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result<Option<Value>
944946

945947
return Ok(None);
946948
}
947-
Function::Get(key) => Some(input.try_get(key)?),
949+
Function::Get(key) => match input.try_get(key) {
950+
Ok(value) => Some(value),
951+
Err(Error::UnknownVariable) => Some(output.try_get(key)?),
952+
Err(e) => return Err(e),
953+
},
948954
Function::Bn(value) => {
949955
let big_num = value.clone().try_bignum()?;
950956

primitives/src/targeting/eval_test.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,28 @@ mod dsl_test {
253253

254254
assert_eq!(Some(&BigNum::from(20)), output.price.get("IMPRESSION"));
255255
}
256+
257+
#[test]
258+
fn test_get_eval() {
259+
let input = get_default_input();
260+
let mut output = Output {
261+
show: true,
262+
boost: 42.0,
263+
price: Default::default(),
264+
};
265+
266+
let input_country = Function::Get("country".to_string())
267+
.eval(&input, &mut output)
268+
.expect("Should get input.global.country");
269+
assert_eq!(Some(Value::String("bg".to_string())), input_country);
270+
271+
let output_boost = Function::Get("boost".to_string())
272+
.eval(&input, &mut output)
273+
.expect("Should get output.boost");
274+
let expected_output_boost = Number::from_f64(42.0).expect("should create Number");
275+
276+
assert_eq!(Some(Value::Number(expected_output_boost)), output_boost);
277+
}
256278
}
257279

258280
mod math_functions {
@@ -1063,9 +1085,12 @@ mod control_flow_and_logic {
10631085
boost: 1.0,
10641086
price: Default::default(),
10651087
};
1066-
Rule::Function(Function::new_only_show_if(Value::Bool(true))).eval(&input, &mut output);
1088+
let result = Function::new_only_show_if(Value::Bool(true)).eval(&input, &mut output);
1089+
assert_eq!(Ok(None), result);
10671090
assert!(output.show);
1068-
Rule::Function(Function::new_only_show_if(Value::Bool(false))).eval(&input, &mut output);
1091+
1092+
let result = Function::new_only_show_if(Value::Bool(false)).eval(&input, &mut output);
1093+
assert_eq!(Ok(None), result);
10691094
assert!(!output.show);
10701095
}
10711096
#[test]
@@ -1317,7 +1342,9 @@ mod string_and_array {
13171342
for (key, value) in &*DEPOSIT_ASSETS_MAP {
13181343
input.global.channel.deposit_asset = key.to_string();
13191344
let amount_crypto = BigNum::from(100).mul(value);
1320-
let amount_usd = Some(Value::Number(Number::from_f64(100.0).expect("should create a float")));
1345+
let amount_usd = Some(Value::Number(
1346+
Number::from_f64(100.0).expect("should create a float"),
1347+
));
13211348
let rule = Rule::Function(Function::new_get_price_in_usd(Rule::Value(Value::BigNum(
13221349
amount_crypto,
13231350
))));

0 commit comments

Comments
 (0)