Tumgik
#but also for giving me access to the datatypes to build the app around
zvaigzdelasas · 1 year
Text
OpenAPI generated type interfaces are literally so sexy
18 notes · View notes
tototavros · 3 years
Text
after significant early frustration w/ postgresql-simple[1], i’ve got everything up and running after putting a few hours into making it easy
unfortunately, it’s not one of those libraries where you give it your schema and it checks at compile time that all your queries are “valid” (postgresq-simple has no knowledge of the schema, you’re responsible for making sure that the type conversions work) but it gets things done 
more than that, it has some decent typeclass machinery for making sure it’s easy for your queries to be well-typed
i use a lot of newtype wrappers around things (so I don’t accidentally compare PostID to UserIDs), and don’t have to write any boilerplate* to make them accessible to the DB so long as I stick only to composites and newtypes of existing DB structures[2], so I don’t even need to destructure those types when passing them in 
i really wish there were some system where I could say “yeah my column is a Unique, I swear, give me only one or error” on the library side, but it’s not that hard to write a makeshift wrapper around that 
it does require that you use either MonadIO or IO everywhere (it only returns results in IO) so unless you build a query wrapper (which, you probably should), your program may look like it’s threatening to launch nuclear missiles, which I consider the main strike against it as an everyday DB lib. 
* Okay, I have to write deriving (Generic, FromRow, ToRow) or something, and need to make sure that I derive the right way (newtype for newtypes, anyclass for data types), and also consider if things are rows or fields, but that’s pretty simple! 
[1]: it’s my preferred sql library for haskell, having tried persistent, esqueleto, and a bit of squeal; have not tried beam or opaleye, 
[2]: I was worried this was going to be an issue, but it works with byteas and jsonbs well, with the presumable haskell level types already having appropriate instances for the sql en-and-de-coding
note: it’s a little frustrating to have to keep peeling and reassembling data types together, but postgresql-simple works much better if you have specific types for it, rather than your program types, I think this is the case for most DBs tho
example (this will probably show up poorly, sorry):
getUserByCreds (Credentials username pwdhash) =  genericGet (Proxy @UserDB) (query, (username, pwdhash))  where query = "SELECT users.id, users.username, users.password_hash FROM users WHERE users.username = ? AND users.password_hash = ?"
Credentials takes in a Username and a PasswordHash, each of which is a newtype wrapper, one taking either String or Text (I forget, and I can just change the haskell implementation without doing a sql migration), the other a Bytestring, but neither of those needs to be unwrapped because of aforementioned typeclass machinery
The bit with the Proxy passes in a completely empty datatype, with a phantom type parameter of UserDB, which instructs the machinery to assemble my results with type UserDB (it could also just return a tuple containing all the components needed to construct a UserDB as well, the underlying haskell types (both UserDB and the tuple) are the “same” for the purposes of the sql type converter) 
genericGet is just a little wrapper I wrote around the query function to match up with my app stack that factors out the Connection param of query into a MonadReader Connection m, which then gets consumed by my utils functions with either basic IO or my app stack
2 notes · View notes