rel8 icon indicating copy to clipboard operation
rel8 copied to clipboard

Functions with named parameters

Open chris-martin opened this issue 3 years ago • 4 comments

I watched Oliver's Zurihac talk this morning and I've already switched a few postgresql-simple queries over to rel8 :smile:

There is one that I don't know how to write well:

select token_id, token_secret
from tc.admin_log_in( p_username := ?,
                      p_password := ? )

I believe I could write this using function (I had not trouble doing this to implement another query that calls crypt), but I would have to specify the arguments positionally, which is the sort of error-prone thing I'm trying to avoid. Is there a recommended way to generate the named argument syntax using :=?

chris-martin avatar Jun 22 '21 08:06 chris-martin

Ah, I didn't even know Postgres had named parameters. I think the bigger issue here though is going to be that tc.admin_log_in seems to itself return a query? I don't think we have a way to support functions that return queries.

shane-circuithub avatar Jun 22 '21 11:06 shane-circuithub

The function returns a composite type, which it looks like rel8 supports? I don't know if there's a difference between that and returning a query, I'm a little fuzzy on the terminology and on PL/pgSQL in general.

create type tc.admin_log_in_result as
    ( code admin_log_in_result_code
    , tc_admin_id integer
    , token_id text
    , token_secret text
    );

create function tc.admin_log_in
    ( p_username text
    , p_password text
    )
    returns tc.admin_log_in_result

as $$declare
...

chris-martin avatar Jun 23 '21 05:06 chris-martin

I guess handling the function's result is covered by issue #71

chris-martin avatar Jun 23 '21 06:06 chris-martin

Interesting, so the function itself doesn't indicate it returns a query, just a composite type, and PostgreSQL must be somehow able to work with that in FROM. You're right that #71 should cover the ability to select from a function, so let's keep that there. For composite types, you can use:

data AdminLogInResult = AdminLogInResult
  { code :: AdminLogInResultCode
  , adminId :: Int64
  , tokenId :: Text
  , tokenSecret :: Text
  }
  deriving (Generic)
  deriving DBType via Composite AdminLogInResult

instance DBComposite AdminLogInResult where
  compositeTypeName = "admin_log_in_result"
  compositeFields = nameHKD @AdminLogInResult "code" "tc_admin_id" "token_id" "token_secret"

This still leaves us with the problem of named parameters though. Maybe we can do this with namedFunction and the named library.

ocharles avatar Jun 23 '21 08:06 ocharles