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

Is there a way to assign a Jsonata function? #406

Closed
markmelville opened this issue Jan 30, 2020 · 3 comments
Closed

Is there a way to assign a Jsonata function? #406

markmelville opened this issue Jan 30, 2020 · 3 comments
Labels

Comments

@markmelville
Copy link
Contributor

markmelville commented Jan 30, 2020

I want to add several "helper functions" to my jsonata expressions. For example, take this expression evaluated against the Invoice model:

Account.(`Account Name` & ' is ' & [status,'active'][0])

yields: "Firefly is active"

I can write a function with the neat transformation syntax and do this:

(
  $cancel:=| $ | {'status':'cancelled'} |;
  $cancel(Account).(`Account Name` & ' is ' & [status,'active'][0])
)

which yields: "Firefly is cancelled" :(

I am trying to add such extension functions, which are written in Jsonata, using assign. But assign only accepts a literal or a javascript function. I want to do something like this:

let expr = jsonata("$cancel(Account).(`Account Name` & ' is ' & [status,'active'][0])");
let function = jsonata("| $ | {'status':'cancelled'} |");
expr.assign("cancel", function);
expr.evaluate(invoice);

I've tried using a few of the compiled function's internals which I spied. Still no luck.

expr.assign("cancel", function.evaluate);
expr.assign("cancel", function.implementation);
expr.assign("cancel", function.apply);

Is it possible to do? Thanks.

@markmelville
Copy link
Contributor Author

markmelville commented Jan 30, 2020

The alternate approaches I'm exploring are:

  1. just concatenate one big string :
let expression = "$cancel(Account).(`Account Name` & ' is ' & [status,'active'][0])"
let functions = {cancel: "| $ | {'status':'cancelled'} |"};
jsonata("("+Object.entries(functions).map(([k,v])=>`$${k}:=${v}`).join(";")+";"+expression+")");
  1. wrap the invocation of a compiled expression in an arrow function:
let f = "| $ | {'status':'cancelled'} |";
let cancel = jsonata("($f:=" + f + ";$f($))");
expr.assign("cancel",i=>cancel.evaluate(i));

which works, but only for 1-arg functions

@andrew-coleman
Copy link
Member

Going back to your original code, it works if you add .evaluate() to the function you are defining:

let expr = jsonata("$cancel(Account).(`Account Name` & ' is ' & [status,'active'][0])");
let func = jsonata("| $ | {'status':'cancelled'} |").evaluate();
expr.assign("cancel", func);
expr.evaluate(invoice);

@markmelville
Copy link
Contributor Author

Makes sense. The bindings must be JavaScript constructs, and the way to turn a Jsonata function to a Javascript function is not to compile it, but to evaluate it.

Thanks, Andrew!

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

No branches or pull requests

3 participants