Is there any way to have a function in PostgreSQL return an arbitrary type?
I am trying to use PLV8 to grab and compare fields from a JSON type in PostgreSQL 9.2.
The following works:
CREATE or replace FUNCTION jn (j json, key any ) RETURNS numeric
LANGUAGE plv8
IMMUTABLE
AS $function$
var ej = JSON.parse(j);
if (typeof ej != 'object') return NULL;
return JSON.stringify(ej[key]);
$function$;
SELECT * FROM things WHERE jn(data,'count') <= '10';
Returning the where the count field is <= 10. BUT, it fails if the field is not numeric. I don't want to create a specific function for every type of data my json might hold, is there a way to have the data type inferred somehow and cast implicitly?
See also How do I query using fields inside the new PostgreSQL JSON datatype?
You seem to be looking for functions with Polymorphic types.
Read the above section on types and the last 2 examples in this section.
Note, that types of the key
parameter and function's output should match. If this is not your case, then you should probably return text
and then cast it to the right type outside the function.
I think this will do the job for you:
CREATE or replace FUNCTION jn (j json, key anyelement ) RETURNS anyelement
LANGUAGE plv8
IMMUTABLE
AS $function$
var ej = JSON.parse(j);
if (typeof ej != 'object') return NULL;
return JSON.stringify(ej[key]);
$function$;
Sorry, I don't have 9.2 server around so I cannot test this.
EDIT:
Things is — before you will be able to perform any casts within the function, it must be created first. At creation time function's input parameters' types and return type is fixed. This means you have only 2 possibilities:
anyelement
type, which will force you to have key
parameter having the same type you want to be returned from the function;text
type and cast results outside the function.As PLV8
doesn't support anyelement
types yet, you can actually create a wrapper function on PL/pgSQL on top of it to do the job for you:
CREATE FUNCTION jn_wrap(jn varchar, key anyelement, OUT ret anyelement)
AS $js_wrap$
BEGIN
EXECUTE 'SELECT CAST(jn($1, $2) AS '||pg_typeof(key)||')'
USING jn, key INTO ret;
RETURN ;
END;
$js_wrap$ LANGUAGE plpgsql;
Though I think it might be quite typical, that key
's type will differ from the desired return type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With