Skip to content

[Feature request] New variables #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

trin4ik
Copy link

@trin4ik trin4ik commented Sep 28, 2023

Hello.
First of all, thank you for this project.
Secondly, this is not PR, but some thoughts on the new look of JsonLogic.

Callable $data

Sometimes we need dynamic data using sql/cache/etc

JWadhams\JsonLogic::apply(
  [
    "in" => [
      "my_tag",
      ["var" => "post_tags"]
    ]
  ],
  function (?string $tags_type = null) {
    switch ($tags_type) {
      ...
      case "post_tags": {
        return DB::query("SELECT ...")->toArray();
      }
      ...
    }
    return null;
  }
);

Static variables/iterations + some sugar

The problem with var logic is recursions like some, reduce, etc. This is due to the fact that we overwrite data, e.g:

...
} elseif ($op === "filter") {
    $scopedData = static::apply($values[0], $data);
    $scopedLogic = $values[1];

    if (!$scopedData || !is_array($scopedData)) {
        return [];
    }

    return array_values(
        array_filter($scopedData, function ($datum) use ($scopedLogic) {
            return static::truthy(static::apply($scopedLogic, $datum)); // <-- Now our data has been overwritten
        })
    );
} elseif ($op === "map") {
...

https://github.com/jwadhams/json-logic-php/blame/e4ea3a46f44d3d34740276f7a21f8f052b029743/src/JWadhams/JsonLogic.php#L263-L267C15

We have lost the original $data, but sometimes we need access to it.
Example. My post has some tags, such as: ["php", "js", "webdev", "docker"], I want to group all cloud posts into a separate category. For searching I want to use logic like:

JsonLogic::apply(
  [
    "some" => [
      ["k8s", "docker", "cloud native"],
      [
        "in": [
          ["var" => ""],
          ["var" => "tags"] // <-- here problem
        ]
      ]
    ]
  ],
  ["tags" => ["php", "js", "webdev", "docker"]
);

Right now we can't access the original $data in recursion.
Here's what I suggest.
Add new logic for the $var keys (like var) and $iteration to look like this:

JsonLogic::apply(
  [
    "some" => [
      ["k8s", "docker", "cloud native"],
      [
        "in": [
          "$iteration",
          ["$var" => "tags"]
        ]
      ]
    ]
  ],
  ["tags" => ["php", "js", "webdev", "docker"]]
);

(in sample i use sugar for "$iteration", it can be used similarly: ["$iteration"], ["$iteration" => null], etc)

Why i think it is best solution:

  1. Full compatibility with current logic, no modification of old rules/logic required
  2. Logical separation between user-variables and iterative-variables

Problem/Todo

  • $iteration only at current level, I think we should make access to upper levels of $iteration.
  • Cache for called $data, n+1 recursion logic problem
  • We need to switch to OOP. Static accessor - I like it, but we need some structure in code

What does the community think about this?

@trin4ik
Copy link
Author

trin4ik commented Sep 29, 2023

Cache for callable

Simple and stupid cache for callable $data.

$cache_key = md5(implode(':', [
    json_encode($logic),
    (new \ReflectionFunction($data))->__toString(),
    $a
]));

if (isset(static::$callable_cache[$cache_key])) {
    return static::$callable_cache[$cache_key];
}

if no change in $logic, $a (params) and function reflection (the most important thing -- a start line of code), then we don't need to call this function again

Callable params

In the current version, we access our $data via var, or its key if it is an object/array. For example: {'var': ['items.0.qty']}. In the case of callable $data, it is much more important to be able to pass multiple parameters than to be able to "reach" the right key. Example:

JWadhams\JsonLogic::apply(
  [
    "in" => [
      "k8s",
      ['$var' => [["tags", 2]]]
    ]
  ],
  function ($type, $post_id) {
    if ($type === 'tags') {
      if ($post_id == 1) return ["php", "js"];
      if ($post_id == 2) return ["docker", "k8s"];
    }
    return [];
  }
)

Important: To maintain backward compatibility with $default, you must pass the first element of the array as an array to get the argument list on the input to the function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant