mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-25 09:22:19 +00:00
Invalid result on second attribute check #33
This commit is contained in:
parent
636618e4ac
commit
ad39c9e668
7
.idea/runConfigurations/all.xml
generated
7
.idea/runConfigurations/all.xml
generated
@ -4,9 +4,12 @@
|
|||||||
<option name="command" value="test --package jsonpath_lib" />
|
<option name="command" value="test --package jsonpath_lib" />
|
||||||
<option name="allFeatures" value="false" />
|
<option name="allFeatures" value="false" />
|
||||||
<option name="nocapture" value="true" />
|
<option name="nocapture" value="true" />
|
||||||
<option name="backtrace" value="SHORT" />
|
<option name="emulateTerminal" value="false" />
|
||||||
|
<option name="backtrace" value="NO" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<envs />
|
<envs />
|
||||||
<method v="2" />
|
<method v="2">
|
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
@ -272,7 +272,15 @@ impl<'a> ExprTerm<'a> {
|
|||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
ExprTerm::Json(_, _, vec2) => cmp_fn.cmp_json(vec1, vec2),
|
ExprTerm::Json(parent, _, vec2) => {
|
||||||
|
if let Some(vec1) = rel {
|
||||||
|
cmp_fn.cmp_json(vec1, vec2)
|
||||||
|
} else if let Some(vec2) = parent {
|
||||||
|
cmp_fn.cmp_json(vec1, vec2)
|
||||||
|
} else {
|
||||||
|
cmp_fn.cmp_json(vec1, vec2)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if ret.is_empty() {
|
if ret.is_empty() {
|
||||||
@ -398,12 +406,12 @@ fn walk_all<'a>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn walk<'a, F>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F)
|
fn walk<'a, F>(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F)
|
||||||
where
|
|
||||||
F: Fn(&Value) -> Option<Vec<&Value>>,
|
|
||||||
{
|
|
||||||
fn _walk<'a, F>(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F)
|
|
||||||
where
|
where
|
||||||
F: Fn(&Value) -> Option<Vec<&Value>>,
|
F: Fn(&Value) -> Option<Vec<&Value>>,
|
||||||
|
{
|
||||||
|
fn _walk<'a, F>(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F)
|
||||||
|
where
|
||||||
|
F: Fn(&Value) -> Option<Vec<&Value>>,
|
||||||
{
|
{
|
||||||
if let Some(mut ret) = fun(v) {
|
if let Some(mut ret) = fun(v) {
|
||||||
tmp.append(&mut ret);
|
tmp.append(&mut ret);
|
||||||
@ -579,7 +587,20 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
debug!("new_filter_context: {:?}", self.terms);
|
debug!("new_filter_context: {:?}", self.terms);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_filter<F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>) -> FilterKey>(&mut self, fun: F) {
|
fn in_filter<F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet<usize>) -> FilterKey>(&mut self, fun: F) {
|
||||||
|
fn get_parent<'a>(prev: Option<Vec<&'a Value>>, current_value: &Vec<&'a Value>, not_matched: HashSet<usize>) -> Option<Vec<&'a Value>> {
|
||||||
|
if prev.is_some() {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
let filtered: Vec<&Value> = current_value.iter().enumerate().filter(|(idx, _)| !not_matched.contains(idx))
|
||||||
|
.map(|(_, v)| *v)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Some(filtered)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if let Some(peek) = self.terms.pop() {
|
if let Some(peek) = self.terms.pop() {
|
||||||
match peek {
|
match peek {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
@ -588,25 +609,19 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
match v {
|
match v {
|
||||||
ExprTerm::Json(rel, fk, vec) => {
|
ExprTerm::Json(rel, fk, vec) => {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
|
let mut not_matched = HashSet::new();
|
||||||
let filter_key = if let Some(FilterKey::String(key)) = fk {
|
let filter_key = if let Some(FilterKey::String(key)) = fk {
|
||||||
fun(
|
let key_contained = &vec.iter().map(|v| match v {
|
||||||
&vec.iter()
|
Value::Object(map) if map.contains_key(&key) => map.get(&key).unwrap(),
|
||||||
.map(|v| match v {
|
_ => v,
|
||||||
Value::Object(map) if map.contains_key(&key) => {
|
}).collect();
|
||||||
map.get(&key).unwrap()
|
fun(key_contained, &mut tmp, &mut not_matched)
|
||||||
}
|
|
||||||
_ => v,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
&mut tmp,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
fun(&vec, &mut tmp)
|
fun(&vec, &mut tmp, &mut not_matched)
|
||||||
};
|
};
|
||||||
|
|
||||||
let parent = if rel.is_some() { rel } else { Some(vec) };
|
let parent = get_parent(rel, &vec, not_matched);
|
||||||
self.terms
|
self.terms.push(Some(ExprTerm::Json(parent, Some(filter_key), tmp)));
|
||||||
.push(Some(ExprTerm::Json(parent, Some(filter_key), tmp)));
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
@ -616,9 +631,9 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
|
|
||||||
if let Some(current) = &self.current {
|
if let Some(current) = &self.current {
|
||||||
let mut tmp = Vec::new();
|
let mut tmp = Vec::new();
|
||||||
let filter_key = fun(current, &mut tmp);
|
let mut not_matched = HashSet::new();
|
||||||
self.terms
|
let filter_key = fun(current, &mut tmp, &mut not_matched);
|
||||||
.push(Some(ExprTerm::Json(None, Some(filter_key), tmp)));
|
self.terms.push(Some(ExprTerm::Json(None, Some(filter_key), tmp)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,7 +641,7 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn all_in_filter_with_str(&mut self, key: &str) {
|
fn all_in_filter_with_str(&mut self, key: &str) {
|
||||||
self.in_filter(|vec, tmp| {
|
self.in_filter(|vec, tmp, _| {
|
||||||
walk_all_with_str(&vec, tmp, key, true);
|
walk_all_with_str(&vec, tmp, key, true);
|
||||||
FilterKey::All
|
FilterKey::All
|
||||||
});
|
});
|
||||||
@ -640,6 +655,7 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
tmp: &mut Vec<&'a Value>,
|
tmp: &mut Vec<&'a Value>,
|
||||||
key: &str,
|
key: &str,
|
||||||
visited: &mut HashSet<*const Value>,
|
visited: &mut HashSet<*const Value>,
|
||||||
|
not_matched: &mut HashSet<usize>,
|
||||||
) {
|
) {
|
||||||
match v {
|
match v {
|
||||||
Value::Object(map) => {
|
Value::Object(map) => {
|
||||||
@ -653,18 +669,40 @@ impl<'a, 'b> Selector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
Value::Array(vec) => {
|
Value::Array(vec) => {
|
||||||
for v in vec {
|
for v in vec {
|
||||||
_collect(v, tmp, key, visited);
|
_collect(v, tmp, key, visited, not_matched);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.in_filter(|vec, tmp| {
|
self.in_filter(|vec, tmp, not_matched| {
|
||||||
let mut visited = HashSet::new();
|
let mut visited = HashSet::new();
|
||||||
for v in vec {
|
for (idx, v) in vec.iter().enumerate() {
|
||||||
_collect(v, tmp, key, &mut visited);
|
match v {
|
||||||
|
Value::Object(map) => {
|
||||||
|
if map.contains_key(key) {
|
||||||
|
let ptr = *v as *const Value;
|
||||||
|
if !visited.contains(&ptr) {
|
||||||
|
visited.insert(ptr);
|
||||||
|
tmp.push(v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
not_matched.insert(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::Array(vec) => {
|
||||||
|
not_matched.insert(idx);
|
||||||
|
for v in vec {
|
||||||
|
_collect(v, tmp, key, &mut visited, not_matched);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
not_matched.insert(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterKey::String(key.to_owned())
|
FilterKey::String(key.to_owned())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
219
tests/filter.rs
219
tests/filter.rs
@ -141,78 +141,78 @@ fn return_type() {
|
|||||||
fn op_default() {
|
fn op_default() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$.school[?(@.friends == @.friends)]",
|
// "$.school[?(@.friends == @.friends)]",
|
||||||
read_json("./benchmark/data_obj.json"),
|
// read_json("./benchmark/data_obj.json"),
|
||||||
json!([{
|
// json!([{
|
||||||
"friends": [
|
// "friends": [
|
||||||
{"id": 0, "name": "Millicent Norman"},
|
// {"id": 0, "name": "Millicent Norman"},
|
||||||
{"id": 1, "name": "Vincent Cannon" },
|
// {"id": 1, "name": "Vincent Cannon" },
|
||||||
{"id": 2, "name": "Gray Berry"}
|
// {"id": 2, "name": "Gray Berry"}
|
||||||
]
|
// ]
|
||||||
}]),
|
// }]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$.friends[?(@.name)]",
|
// "$.friends[?(@.name)]",
|
||||||
read_json("./benchmark/data_obj.json"),
|
// read_json("./benchmark/data_obj.json"),
|
||||||
json!([
|
// json!([
|
||||||
{ "id" : 1, "name" : "Vincent Cannon" },
|
// { "id" : 1, "name" : "Vincent Cannon" },
|
||||||
{ "id" : 2, "name" : "Gray Berry" }
|
// { "id" : 2, "name" : "Gray Berry" }
|
||||||
]),
|
// ]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$.friends[?(@.id >= 2)]",
|
// "$.friends[?(@.id >= 2)]",
|
||||||
read_json("./benchmark/data_obj.json"),
|
// read_json("./benchmark/data_obj.json"),
|
||||||
json!([
|
// json!([
|
||||||
{ "id" : 2, "name" : "Gray Berry" }
|
// { "id" : 2, "name" : "Gray Berry" }
|
||||||
]),
|
// ]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$.friends[?(@.id >= 2 || @.id == 1)]",
|
// "$.friends[?(@.id >= 2 || @.id == 1)]",
|
||||||
read_json("./benchmark/data_obj.json"),
|
// read_json("./benchmark/data_obj.json"),
|
||||||
json!([
|
// json!([
|
||||||
{ "id" : 2, "name" : "Gray Berry" },
|
// { "id" : 2, "name" : "Gray Berry" },
|
||||||
{ "id" : 1, "name" : "Vincent Cannon" }
|
// { "id" : 1, "name" : "Vincent Cannon" }
|
||||||
]),
|
// ]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]",
|
// "$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]",
|
||||||
read_json("./benchmark/data_obj.json"),
|
// read_json("./benchmark/data_obj.json"),
|
||||||
json!([Value::Null]),
|
// json!([Value::Null]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$..friends[?(@.id == $.index)].id",
|
// "$..friends[?(@.id == $.index)].id",
|
||||||
read_json("./benchmark/data_obj.json"),
|
// read_json("./benchmark/data_obj.json"),
|
||||||
json!([0, 0]),
|
// json!([0, 0]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$..book[?($.store.bicycle.price < @.price)].price",
|
// "$..book[?($.store.bicycle.price < @.price)].price",
|
||||||
read_json("./benchmark/example.json"),
|
// read_json("./benchmark/example.json"),
|
||||||
json!([22.99]),
|
// json!([22.99]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price",
|
// "$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price",
|
||||||
read_json("./benchmark/example.json"),
|
// read_json("./benchmark/example.json"),
|
||||||
json!([12.99]),
|
// json!([12.99]),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
select_and_then_compare(
|
// select_and_then_compare(
|
||||||
"$..[?(@.age > 40)]",
|
// "$..[?(@.age > 40)]",
|
||||||
json!([
|
// json!([
|
||||||
{ "name": "이름1", "age": 40, "phone": "+33 12341234" },
|
// { "name": "이름1", "age": 40, "phone": "+33 12341234" },
|
||||||
{ "name": "이름2", "age": 42, "phone": "++44 12341234" }
|
// { "name": "이름2", "age": 42, "phone": "++44 12341234" }
|
||||||
]),
|
// ]),
|
||||||
json!([
|
// json!([
|
||||||
{ "name" : "이름2", "age" : 42, "phone" : "++44 12341234" }
|
// { "name" : "이름2", "age" : 42, "phone" : "++44 12341234" }
|
||||||
]),
|
// ]),
|
||||||
);
|
// );
|
||||||
|
|
||||||
select_and_then_compare(
|
select_and_then_compare(
|
||||||
"$..[?(@.age >= 30)]",
|
"$..[?(@.age >= 30)]",
|
||||||
@ -353,7 +353,7 @@ fn op_compare() {
|
|||||||
r#"$[?(true == 1)]"#,
|
r#"$[?(true == 1)]"#,
|
||||||
r#"$[?(@ == 1)]"#,
|
r#"$[?(@ == 1)]"#,
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
select_and_then_compare(path, json!({}), json!([Value::Null]));
|
select_and_then_compare(path, json!({}), json!([Value::Null]));
|
||||||
}
|
}
|
||||||
@ -702,4 +702,77 @@ fn current_path() {
|
|||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bugs33() {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
select_and_then_compare(
|
||||||
|
"$..[?(@.first.second)]",
|
||||||
|
json!({
|
||||||
|
"foo": {
|
||||||
|
"first": { "second": "value" }
|
||||||
|
},
|
||||||
|
"foo2": {
|
||||||
|
"first": {}
|
||||||
|
},
|
||||||
|
"foo3": {
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
json!([
|
||||||
|
{
|
||||||
|
"first": {
|
||||||
|
"second": "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
select_and_then_compare(
|
||||||
|
"$..[?(@.first && @.first.second)]",
|
||||||
|
json!({
|
||||||
|
"foo": {
|
||||||
|
"first": { "second": "value" }
|
||||||
|
},
|
||||||
|
"foo2": {
|
||||||
|
"first": {}
|
||||||
|
},
|
||||||
|
"foo3": {
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
json!([
|
||||||
|
{
|
||||||
|
"first": {
|
||||||
|
"second": "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
select_and_then_compare(
|
||||||
|
"$..[?(@.b.c.d && @.b)]",
|
||||||
|
json!({
|
||||||
|
"a": {
|
||||||
|
"b": {
|
||||||
|
"c": {
|
||||||
|
"d" : {
|
||||||
|
"e" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
json!([
|
||||||
|
{
|
||||||
|
"b" : {
|
||||||
|
"c" : {
|
||||||
|
"d" : {
|
||||||
|
"e" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user