ukrbublik / react-awesome-query-builder

User-friendly query builder for React
https://ukrbublik.github.io/react-awesome-query-builder
MIT License
1.96k stars 493 forks source link

JsonLogic array management #270

Open Angelus1383 opened 4 years ago

Angelus1383 commented 4 years ago

This component support JsonLogic as input/output format, but I'm unable to find how manage json array (In particular I don't see how use all/some/none operations). Is this a documentation lack or this part of JsonLogic rules is not supported?

Here an example from JsonLogic docs.

Data

{
    "integers": [1,2,3,4,5]
}

JsonLogic Rule

{
    "some" : [
        {"var" : "integers"}, 
        {">" : [{"var" : ""}, 10]} 
    ]
}

Expected result

false

Operato

ukrbublik commented 4 years ago

You can see example of usage of jsonlogic's all operator with multiselect field type (like Colors in demo). It supports multiselect_equals operator which will produce jsonlogic like

    {
      "all": [
        {
          "var": "multicolor"
        },
        {
          "in": [
            {
              "var": ""
            },
            [
              "yellow",
              "green"
            ]
          ]
        }
      ]
    }

some/none ops are not supported for arrays for now, at least in default config. You can request adding 'em in default config (create issue) or maybe write PR if you can (taking multiselect_equals as example)

ukrbublik commented 4 years ago

JsonLogic is import/expoer format only. If you see a way to use it in rule somehow, please describe how it should look and behavoir. Closing this issue cause lack of description

kryptx commented 3 years ago

You can see example of usage of jsonlogic's all operator with multiselect field type (like Colors in demo). It supports multiselect_equals operator which will produce jsonlogic like

    {
      "all": [
        {
          "var": "multicolor"
        },
        {
          "in": [
            {
              "var": ""
            },
            [
              "yellow",
              "green"
            ]
          ]
        }
      ]
    }

I don't think this is doing what it might appear to be doing. Suppose my document is:

{
  "items": [ "a", "b", "c" ]
}

and I want to write an expression which evaluates to true if items contains all of the values "a" and "b" (I'll call these two values the query), and false if it does not. This component with the multiselect_equals operator will produce:

    {
      "all": [
        {
          "var": "items"
        },
        {
          "in": [
            {
              "var": ""
            },
            [
              "a",
              "b"
            ]
          ]
        }
      ]
    }

which evaluates to true if the query contains all of the values in items. This is the inverse of my requirement; it evaluates to false for my case because the value c is not one of a or b. In my own personal estimation, a query where "items is a subset of [...]" is less useful than "items contains the subset [...]" would be.

Fortunately, some and none do not have this problem, because they are only concerned with whether the intersection of the arrays is of length 0. in other words, some(a, b) is the same as some(b, a) and the same is true for none.

I have had difficulty producing the JsonLogic needed to satisfy my actual requirement for all, but the following would work. The value 2 can be computed from the length of the input argument:

{
  "==": [
    2,
    {
      "reduce": [
        {"var":"items"},
        {"+":[
          {"var":"accumulator"},
          {"if":[{"in":[{"var":"current"}, ["a","b"]]},1,0]}
        ]},
        0
      ]
    }
  ]
}

As an additional wrench, I always save and load the tree as JsonLogic. So in order to implement this as an operator, I would need an equivalent to the jsonLogicImport option that was recently added for funcs, but for operators.

As far as i can tell, my only options are: 1: Fork the library (either submit a PR or publish the fork) 2: Implement superset of as a func instead of using the all operator (the user would then have to pick "equals" and then "function" and then "superset of") -- and I'm not even sure this would work because the func output would be placed { "==":[{"var":"items"}, /* right here */ ]} which I think would force me to produce an exact copy of all items if the match succeeds.

Is there another way to do what I'm trying to do?

ukrbublik commented 3 years ago

So in order to implement this as an operator, I would need an equivalent to the jsonLogicImport option that was recently added for funcs, but for operators.

Yes, seems correct.

1: Fork the library (either submit a PR or publish the fork)

You can try to create PR (always welcomed!) or I can work on this feature when I have free time. Adding new reasonable operators to codebase is a good thing.

kryptx commented 3 years ago

Thanks for validating and reopening. We definitely may submit some contributions, but on this issue for now we've accepted that the user can work around this by entering each of the "all" values individually.