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

Change scope constructor from private to protected #221

Closed
fjtirado opened this issue Sep 14, 2022 · 3 comments · Fixed by #378
Closed

Change scope constructor from private to protected #221

fjtirado opened this issue Sep 14, 2022 · 3 comments · Fixed by #378

Comments

@fjtirado
Copy link
Contributor

fjtirado commented Sep 14, 2022

It will be great if scope class can be extended (although the class is not final, the construtor is private)
For example, to dynamically retrieve variable values from an extenal source by overriding getValue method.
AFAIK, the only way to change the behaviour of getValue is by invoking setValue, but there might be cases where your variable source (for example a DB) has a dynamic nature.

@eiiches
Copy link
Owner

eiiches commented Sep 17, 2022

You are right, currently, variable values must be pre-computed and there's no way to do dynamic or lazy evaluation. The closest you can do is to implement a custom function instead of using a variable:

scope.addFunction("foo", 0, new Function() {
    @Override
    public void apply(Scope scope, List<Expression> args, JsonNode in, Path path, PathOutput output, Version version) throws JsonQueryException {
        JsonNode value = ... // obtain the value here
        output.emit(value, null);
    }
});

I'm willing to support dynamic/lazy variables, but rather than allowing subclassing the scope class, I want to add a new setValue overload that takes a ValueSource instance:

interface ValueSource {
    JsonNode getValue();
}

public class Scope {
    public void setValue(String name, JsonNode value) { ... };
    public void setValue(String name, ValueSource valueSource) { ... }; // the new overload
}

// This can be used like this:
// scope.setValue("foo", () -> new TextNode("this value is lazily evaluated"));

What do you think? Does this work for you?

@fjtirado
Copy link
Contributor Author

fjtirado commented Sep 19, 2022

@eiiches Thanks for the response.
Yes, this new setValue method will do the trick.
I use a similar idea to implement a hack some time ago to support some prefixed JQ variables here, but now I have the luxury of waiting for you to add this new functionality ;)
Once you add the new function method, I can replace the FunctionJsonNode hack by just a lambda.

@fjtirado
Copy link
Contributor Author

fjtirado commented Dec 22, 2022

@eiiches Should I open a PR implementing what we discussed? I think the method to be added should be


public interface ValueSource extends Function<String,JsonNode> {
}
  public void setValue(ValueSource valueSource) { ... }; // the new overload

So you can write
scope.setValue( k -> new TextNode(k+" value is lazily evaluated"));

The point is that you do not know if your external source can resolve a particular key at the moment you are configuring the scope

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 a pull request may close this issue.

2 participants