@@ -125,8 +125,6 @@ pub fn missing(data: &Value, args: &Vec<&Value>) -> Result<Value, Error> {
125
125
126
126
adjusted_args. into_iter ( ) . fold ( Ok ( ( ) ) , |had_error, arg| {
127
127
had_error?;
128
- // let _parsed_arg = Parsed::from_value(arg)?;
129
- // let evaluated = _parsed_arg.evaluate(data)?;
130
128
let key: KeyType = ( * arg) . try_into ( ) ?;
131
129
match key {
132
130
KeyType :: Null => Ok ( ( ) ) ,
@@ -142,6 +140,75 @@ pub fn missing(data: &Value, args: &Vec<&Value>) -> Result<Value, Error> {
142
140
Ok ( Value :: Array ( missing_keys) )
143
141
}
144
142
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
+
145
212
fn get_key ( data : & Value , key : KeyType ) -> Option < Value > {
146
213
match key {
147
214
// If the key is null, we return the data, always, even if there
0 commit comments