Skip to content

Commit a4396c7

Browse files
authored
REF: convert missing_some from parser to operator (#3)
* CHORE: remove dead code * REF: convert missing_some from parser to operator As with the other data operators, significantly simplify by converting to an operator now that we've got the `DataOperator` abstractions. Remove the entire `data.rs` module. * DOC: clairify docstring * CHORE: put everything in the wasm tests behind a feature gate * CHORE: remove commented code * CHORE: enable all features in vscode settigs
1 parent 5b32f5c commit a4396c7

File tree

8 files changed

+108
-284
lines changed

8 files changed

+108
-284
lines changed

.vscode/settings.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"editor.formatOnSave": true
2+
"editor.formatOnSave": true,
3+
"rust-analyzer.cargo.allFeatures": true,
34
}

src/data.rs

-270
This file was deleted.

src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use serde_json;
22
use serde_json::Value;
33

4-
mod data;
54
mod error;
65
// TODO consider whether this should be public; move doctests if so
76
pub mod js_op;

src/op/data.rs

+69-2
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ pub fn missing(data: &Value, args: &Vec<&Value>) -> Result<Value, Error> {
125125

126126
adjusted_args.into_iter().fold(Ok(()), |had_error, arg| {
127127
had_error?;
128-
// let _parsed_arg = Parsed::from_value(arg)?;
129-
// let evaluated = _parsed_arg.evaluate(data)?;
130128
let key: KeyType = (*arg).try_into()?;
131129
match key {
132130
KeyType::Null => Ok(()),
@@ -142,6 +140,75 @@ pub fn missing(data: &Value, args: &Vec<&Value>) -> Result<Value, Error> {
142140
Ok(Value::Array(missing_keys))
143141
}
144142

143+
/// Check whether a minimum threshold of keys are present in the data
144+
///
145+
/// Note that I think this function is confusingly named. `contains_at_least`
146+
/// might be better, or something like that. Regardless, it checks to see how
147+
/// many of the specified keys are present in the data. If there are equal
148+
/// to or more than the threshold value _present_ in the data, an empty
149+
/// array is returned. Otherwise, an array containing all missing keys
150+
/// is returned.
151+
pub fn missing_some(data: &Value, args: &Vec<&Value>) -> Result<Value, Error> {
152+
let (threshold_arg, keys_arg) = (args[0], args[1]);
153+
154+
let threshold = match threshold_arg {
155+
Value::Number(n) => n.as_u64(),
156+
_ => None,
157+
}
158+
.ok_or(Error::InvalidArgument {
159+
value: threshold_arg.clone(),
160+
operation: "missing_some".into(),
161+
reason: "missing_some threshold must be a valid, positive integer".into(),
162+
})?;
163+
164+
let keys = match keys_arg {
165+
Value::Array(keys) => Ok(keys),
166+
_ => Err(Error::InvalidArgument {
167+
value: keys_arg.clone(),
168+
operation: "missig_some".into(),
169+
reason: "missing_some keys must be an array".into(),
170+
}),
171+
}?;
172+
173+
let mut missing_keys: Vec<Value> = Vec::new();
174+
let present_count = keys.into_iter().fold(Ok(0 as u64), |last, key| {
175+
// Don't bother evaluating once we've met the threshold.
176+
let prev_present_count = last?;
177+
if prev_present_count >= threshold {
178+
return Ok(prev_present_count);
179+
};
180+
181+
let parsed_key: KeyType = key.try_into()?;
182+
let current_present_count = match parsed_key {
183+
// In the reference implementation, I believe null actually is
184+
// buggy. Since usually, getting "null" as a var against the
185+
// data returns the whole data, "null" in a `missing_some`
186+
// list of keys _automatically_ counts as a present key, regardless
187+
// of what keys are in the data. This behavior is neither in the
188+
// specification nor the tests, so I'm going to SKIP null keys,
189+
// since they aren't valid Object or Array keys in JSON.
190+
KeyType::Null => prev_present_count,
191+
_ => {
192+
if get_key(data, parsed_key).is_none() && !missing_keys.contains(key) {
193+
missing_keys.push((*key).clone());
194+
prev_present_count
195+
} else {
196+
prev_present_count + 1
197+
}
198+
}
199+
};
200+
Ok(current_present_count)
201+
})?;
202+
203+
let met_threshold = present_count >= threshold;
204+
205+
if met_threshold {
206+
Ok(Value::Array(vec![]))
207+
} else {
208+
Ok(Value::Array(missing_keys))
209+
}
210+
}
211+
145212
fn get_key(data: &Value, key: KeyType) -> Option<Value> {
146213
match key {
147214
// If the key is null, we return the data, always, even if there

src/op/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ pub const DATA_OPERATOR_MAP: phf::Map<&'static str, DataOperator> = phf_map! {
166166
operator: data::missing,
167167
num_params: NumParams::Any,
168168
},
169+
"missing_some" => DataOperator {
170+
symbol: "missing_some",
171+
operator: data::missing_some,
172+
num_params: NumParams::Exactly(2),
173+
},
169174
};
170175

171176
pub const LAZY_OPERATOR_MAP: phf::Map<&'static str, LazyOperator> = phf_map! {

0 commit comments

Comments
 (0)