nikita-volkov / hasql

The fastest PostgreSQL libpq-based driver for Haskell
http://hackage.haskell.org/package/hasql
MIT License
519 stars 55 forks source link

Provide a generic encoding escape hatch #149

Closed robx closed 2 years ago

robx commented 2 years ago

As an alternative to #146, this provides a way for users to provide arbitrary custom value encoders, via

-- Generic binary encoder, given OIDs and an encoding function.
value :: Show a => LibPQ.Oid -> LibPQ.Oid -> (a -> Binary.Encoding) -> Value a
value oid arrayOid encode = ...

Concretely, this addresses the desire within PostgREST to encode JSON directly from a lazy bytestring. The use would be to replace

SQL.encoderAndParam (HE.nullable HE.jsonBytes) (LBS.toStrict <$> body)

with

let jsonBytesLazy = HE.Value (LibPQ.Oid 114) (LibPQ.Oid 199) Binary.bytea_lazy in
  SQL.encoderAndParam (HE.nullable (HE.value jsonBytesLazy) body

to avoid a copy.

Supposing the general approach seems acceptable, some things I'm unsure about:

robx commented 2 years ago

@nikita-volkov any thoughts on this one?

Alternatives might be

nikita-volkov commented 2 years ago

Ooops. Sorry for dragging on this. I'll get back to you in the coming days

nikita-volkov commented 2 years ago

Please check out the commit above. It adds lazy variations of json functions. If all is fine, I'll make a release.

robx commented 2 years ago

Please check out the commit above. It adds lazy variations of json functions. If all is fine, I'll make a release.

It looks perfect!

(I'm in the process of updating the corresponding PostgREST PR with the required dependency updates to verify this in CI, but it should be good to go.)

nikita-volkov commented 2 years ago

Cool. Released as 1.6.1

robx commented 2 years ago

It seems the build is broken:

library/Hasql/Private/Encoders.hs:236:17: error:
    • Couldn't match type ‘LazyByteString.ByteString’
                     with ‘ByteString’
      NB: ‘ByteString’ is defined in ‘Data.ByteString.Internal’
          ‘LazyByteString.ByteString’
            is defined in ‘Data.ByteString.Lazy.Internal’
      Expected type: Value ByteString
        Actual type: Value LazyByteString.ByteString
    • In the expression:
        Value (Value.unsafePTIWithShow PTI.json (const A.json_bytes_lazy))
      In an equation for ‘jsonLazyBytes’:
          jsonLazyBytes
            = Value
                (Value.unsafePTIWithShow PTI.json (const A.json_bytes_lazy))
    |
236 | jsonLazyBytes = Value (Value.unsafePTIWithShow PTI.json (const A.json_bytes_lazy))
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

(see https://github.com/PostgREST/postgrest/runs/8247544920?check_suite_focus=true)

nikita-volkov commented 2 years ago

Oops. Forgot to check the build :) Fixed in 1.6.1.1