When I define a sync function that takes 1 or more parameters, it works as you'd expect in a resource of type 'Javascript Query', but fails when trying to use it with a variable parameter in a Transformer resource query when trying to pass a local transformer variable
Example:
I define a sync function that takes a single parameter 'param1', and adds 2 to it.
Calling this sync function works in a Javascript query:
let aNumber = 2;
// This works
let result1 = myFun({param1: 2})
// So does this
let result2 = myFun({param1: aNumber});
// This alternative invocation does not work
// let result3 = {{ myFun({param1: aNumber}) }}
return {result1, result2}
When I try to call it in a transformer, it does not work correctly.
let aNumber = 2;
// A non-variable paramter works. Note that unlike Javascript
// query, it needs to be wrapped with braces.
let result1 = {{ myFun({param1: 2}) }};
// using something from the app scope, like another query, works:
let result2 = {{ myFun({param1: anotherQuery.data.numberField}) }};
// Try to use our transformer-local variable, and it fails:
// 'aNumber not defined'
// let result3 = {{ myFun({param1: aNumber}) }};
// Try the bare version, and it fails with 'myFun not defined'
// let result4 = myFun({param1: 2});
return {result1, result2}
Unfortunately, unlike transformers, javascript queries can't be used as data sources.
When doing complex processing of other queries, it's common to define local variables to the transformer to hold partially processed values, so allowing transformers to pass in local variables, (like JS queries support), would be useful.
...javascript queries can't be used as data sources.
Can you elaborate on this? I use JS Queries as data sources for components like tables regularly. Example:
If you're setting a data source dynamically (by clicking the little "FX" icon in some components), you'll access the data with js_query_name.data instead of the .value of a transformer or variable.
huh, ok, that's useful to know. Maybe i was trying to access the value property.
Thanks for that, that helps.
Still doesn't change the root issue of the inconsistency of where you can pass variables in to sync functions though. IT's especially egragious because it means you can't use a sync function on the data of a query as part of the built in query transformer - as you only have access to the 'data' property there
I find that transformers are a commonly misunderstood part of the Retool experience. At a high level, they are designed to take in data and operate on that data in relative isolation. That's why queries can't be triggered from within a transformer, for example. Given the nature of sync functions, though, it does feel a bit like a design oversight that it's not possible to pass in local data.
Fortunately, as @dguzzo pointed out, you absolutely can use the return values of JS queries as data sources! The one thing to keep in mind is that JS queries don't run automatically and need to be triggered, typically as a success handler attached to the original resource query.
Sync functions in the app editor are a relatively new feature and I know the team is looking for feedback, so I'll pass this on!
UPDATE: We have a fix that will specifically add data to the template string scope within a transformer! It's currently scheduled to go live with version 3.119.
Hey Darren, thanks for the info - I'm guessing you went live with this change, since it broke some uses of sync functions in transformers in our org
It looks like when passing a query data field in to a sync function, it's getting mutated in some cases.
Previously, when passing in an array of objects, you'd get an array in the sync function.
Now, when passing in an array, it gets converted in to an object, where each key is the array index of the array member.
eg, ["a", "b", "c"] is now being converted to {"0":"a", "1": "b", "2":"c"}
Thanks for letting me know! I'll ask the team whether this was intentional or not, as the same pattern does show up elsewhere. For all intents and purposes, the two are synonymous - an array is just an object with keys equal to indices - but I can imagine that it might not be the most intuitive change.
One quick fix that requires minimal modification to your existing code is to explicitly turn the object back into an array using Object.values(variableName).