-
Notifications
You must be signed in to change notification settings - Fork 218
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
Call user-defined functions #4542
Comments
Can we adjust the example so |
But |
Perhaps |
Ah I see. We could have a Can you confirm what the SQL output would look like? |
I suppose it would look like this: SELECT
*,
get_magic_name(name) AS magic_name
FROM
animals |
OK great. I think this can be handled by an s-string at the moment. If there were substantial demand we could add a What do you think about adding an example to the docs? |
Hi @vanillajonathan , I once answered a question on HackerNews which I think speaks to what you are looking for: https://news.ycombinator.com/item?id=37569946 Unfortunately the JSON DuckDB extension isn't loaded in the playground so the example doesn't produce Query Results but hopefully the SQL produced explains enough: > prqlc compile <<EOF
let get = func path obj -> s"""{obj} -> {path}"""
let getstr = func path obj -> s"""{obj} ->> {path}"""
let extract = func obj path -> s"""json_extract({obj}, {path})"""
from [{data='{"duck": [1, 2, 3]}'}]
select { data | get '$.duck[0]', data | getstr '$.duck[1]', extract data '$.duck[2]' }
EOF
WITH table_0 AS (
SELECT
'{"duck": [1, 2, 3]}' AS data
)
SELECT
data -> '$.duck[0]',
data ->> '$.duck[1]',
json_extract(data, '$.duck[2]')
FROM
table_0
-- Generated by PRQL compiler version:0.9.4 (https://prql-lang.org) I've been meaning to add this to the docs somewhere as I think JSON functionality is something that would speak to a lot of people. Will try and get to it. |
I think this is tricky to use. You cannot just declare an line s-string like: from animals
derive {
magic_name = s"get_magic_name" name
} because you get the error:
So you have to do declare the function with a let get_magic_name = param_name -> s"""get_magic_name({param_name})"""
from animals
derive {
magic_name = name | get_magic_name
} which is a bit cumbersome. It would be nice to not have to do that. Would be easier: from animals
derive {
magic_name = name | udf.get_magic_name
} |
Oh I see. That's an interesting idea. So in that case it would have to infer how many parameters it is being passed and then generate AST node equivalent to the corresponding s-string. Not my area of expertise how feasible that is at the moment but I could see it working in principle. We had a discussion elsewhere about a possible from animals
derive {
magic_name = name | db.fn.get_magic_name
} That should indicate to the compiler that |
Yeah! |
I definitely see the case here. I'm not sure the proposal quite fits — it uses a namespace to indicate a type. TBC, it's not crazy — maybe we store all the UDFs in a namespace. But in this case it works for any string, which isn't quite consistent — it's like a magic namespace where we can add anything — sounds like a type! We could have a function like
...though we would need to implement something to allow passing a tuple of params; this only supports a single param... |
Yeah, a With risk of sounding whiny, PRQL is meant to make our lives easier but I feel that: from animals
derive {
magic_name = name | (udf get_magic_name)
} looks harder to read, write and understand than SQL: SELECT
*,
get_magic_name(name) AS magic_name
FROM
animals |
A couple more thoughts to add to this interesting discussion! The query above can be written fully equivalently as:
which is really close to the original request (just with Also, if PRQL doesn't have awareness of the database schema, then it isn't going to actually know if
which would compile to: SELECT
*,
concat(first_name, ' ', last_name) AS full_name
FROM
animals This would end up being another "escape hatch" to regular SQL, just as S-strings are right now. I'm not sure if I have a preference in any of this. I think my tendency would be to declare all of the UDFs that I care about in a module, which would allow for type checking and make things a bit more explicit - but I'm not sure this is the most user-friendly.
The above snippet works in the playground right now. |
What's up?
I would like to call a user-defined function (UDF) named
get_magic_name
and pass it thename
column as parameter.Error:
Perhaps user-defined functions could be reached from a pseudo namespace called
udf
like:The text was updated successfully, but these errors were encountered: