Skip to content
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

Fix chain operator to respect array constructor #7

Merged
merged 3 commits into from
Sep 27, 2024

Conversation

netomi
Copy link
Contributor

@netomi netomi commented Sep 16, 2024

This fixes the implementation to be able to force the map function to return an array even if there is a single element.

This seems to be common for all jsonata implementations, that map returns a single element if its result is a singleton list. The commonly shared workaround is to add [] at the end of the function as explained here: jsonata-js/jsonata#462 (comment)

This was not working before, the fix propagates the keep_array setting to the parent AST element in some cases to support that. I am not sure if this is generally correct, it fixes the test cases though that I added to illustrate the problem.

@netomi
Copy link
Contributor Author

netomi commented Sep 16, 2024

FYI: this PR also includes the changes from the other PR as they are a prerequisite for the test cases.

Once the other PR got merged, that changes should not be visible in the diff anmore.

@rayokota
Copy link
Owner

Thanks @netomi , I'll take a look

Copy link
Owner

@rayokota rayokota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @netomi , left some comments

src/jsonata/parser.py Outdated Show resolved Hide resolved
assert expression.evaluate(None) == [1]

def test_singleton_map_with_chain(self):
expression = jsonata.Jsonata("$ ~> $map($square)[]")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I try the following in jsonata.js, it fails. Perhaps this is a bug in jsonata.js as well (unless I'm doing something wrong)? If so, I'll wait until it is fixed there before making the fix here.

            var expr = jsonata("$ ~> $map($square)[]");
            expr.registerFunction("square", function(x) {
                return x * x;
            });
            var result = await expr.evaluate([1]);
            var expected = [1];
            expect(result).to.deep.equal(expected);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, I did not test the behavior of the original jsonata.js implementation. Your observation is correct, that also does not work there and the problem seems to be that the chain operator does not correctly propagate whether any child expression is forced to keep the array.

Will report the problem there with a reference to this ticket. Probably the same fix needs to be applied there.

However I want to express that without this working, the map function is pretty much useless to me in my use-case. The workaround is to always create a lambda function myself to operate on all values of an array, which is a bit of a pain. I dont see any value in a map function that returns different results depending on the input values.

@@ -1180,6 +1180,7 @@ def lambda1(terms):
result.position = expr.position
result.lhs = self.process_ast(expr.lhs)
result.rhs = self.process_ast(expr.rhs)
result.keep_array = result.lhs.keep_array or result.rhs.keep_array
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this is the fix that is needed in jsonata.js? If so, I'll wait until the fix is made there first.

assert expression.evaluate(None) == [1, 4, 9]

def test_singleton_map(self):
expression = jsonata.Jsonata("$map([1], $square)[]")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test seems to pass without any changes

@netomi
Copy link
Contributor Author

netomi commented Sep 23, 2024

Created jsonata-js/jsonata#714

@netomi netomi changed the title Fix: Support keep array for map Fix chain operator to respect array constructor Sep 23, 2024
@netomi
Copy link
Contributor Author

netomi commented Sep 23, 2024

The additional test cases can be removed once the PR to the upstream repo has been accepted and merged as the test cases are added to the test suite there which is already used in this project.

Copy link
Owner

@rayokota rayokota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @netomi , LGTM

@rayokota rayokota merged commit 384ed87 into rayokota:master Sep 27, 2024
12 checks passed
@netomi netomi deleted the support-keep-array-for-map branch September 27, 2024 15:28
@rayokota
Copy link
Owner

@netomi , I've released 0.5.0 with this fix.

@netomi
Copy link
Contributor Author

netomi commented Sep 29, 2024

thanks a lot for your quick action, I am really looking forward to use this library more in my projects.

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.

2 participants