Skip to content
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

Upgrade 0.5.1.0 → 0.9.1.3: Query (Statement) with generic parameter (formerly using ToParam) #353

Open
gasi opened this issue Mar 7, 2024 · 9 comments
Labels

Comments

@gasi
Copy link
Contributor

gasi commented Mar 7, 2024

Hi Eitan,

I’m currently doing a big migration from Squeal 0.5.1.0 → 0.9.1.3 and I love it overall, especially how EncodeParams + DecodeRows gets rid of so much boilerplate.

Problem

I was able to figure out 95% of the work, but I get stuck on turning this query that used to take an arbitrary (generic?) parameter (using ToParam), that can convert to a PostgreSQL type, to a Statement with EncodeParams + DecodeRow. I had to revert and hard-code it to PGtext + Text which broke some of my queries that need PGtimestampz + UTCTime:

Statement: selectContentBy

image

Usage: getBy

image

I tried the following without luck:

selectContentBy ::
  (ToParam Schemas pgty hsty, SOP.Generic hsty) =>
  ( TableExpression 'Ungrouped '[] '[] Schemas '[pgty] from ->
    TableExpression 'Ungrouped '[] '[] Schemas '[pgty] from
  ) ->
  Statement Schemas hsty Content
selectContentBy clauses = Query encode decode sql
  where
    encode :: EncodeParams Schemas pgty hsty
    encode = aParam
    decode = decodeContentWithImage
    sql = -- ...

as I get this error ❌:

zoomhub/src/ZoomHub/Storage/PostgreSQL/Internal.hs:180:33: error: [GHC-18872]
    • Couldn't match kind ‘NullType’ with ‘*’
      When matching types
        pgty0 :: [*]
        '[pgty] :: [NullType]
      Expected: EncodeParams
                  '["public"
                    ::: [ZoomHub.Storage.PostgreSQL.Schema.Schema0.ConfigTable0,
                         ZoomHub.Storage.PostgreSQL.Schema.Schema3.ContentTable3,
                         ZoomHub.Storage.PostgreSQL.Schema.Schema0.ImageTable0,
                         ZoomHub.Storage.PostgreSQL.Schema.Schema0.FlickrTable0]]
                  '[pgty]
                  hsty
        Actual: EncodeParams Schemas pgty0 hsty
    • In the first argument of ‘Query’, namely ‘encode’
      In the expression: Query encode decode sql
      In an equation for ‘selectContentBy’:
          selectContentBy clauses
            = Query encode decode sql
            where
                encode :: EncodeParams Schemas pgty hsty
                encode = aParam
                decode = decodeContentWithImage
                sql = -- ...

I was thinking it might be something obvious you could spot right away. If not, I’m happy to go back and do the work to create a minimally reproducing example.

I appreciate your help 😄

@gasi gasi changed the title Squeal upgrade from 0.5.1.0 → 0.9.1.3 Squeal upgrade from 0.5.1.0 → 0.9.1.3: Query (Statement) with generic parameter (formerly using ToParam) Mar 7, 2024
@gasi gasi changed the title Squeal upgrade from 0.5.1.0 → 0.9.1.3: Query (Statement) with generic parameter (formerly using ToParam) Upgrade from 0.5.1.0 → 0.9.1.3: Query (Statement) with generic parameter (formerly using ToParam) Mar 7, 2024
@gasi gasi changed the title Upgrade from 0.5.1.0 → 0.9.1.3: Query (Statement) with generic parameter (formerly using ToParam) Upgrade 0.5.1.0 → 0.9.1.3: Query (Statement) with generic parameter (formerly using ToParam) Mar 7, 2024
@echatav
Copy link
Contributor

echatav commented Mar 9, 2024

Hmmm. Looks like GHC is inferring the kind of pgty0 too monomorphically, too soon. Can you try turning on PolyKinds? See if that helps. That's what the error poetry tells me:

    • Couldn't match kind ‘NullType’ with ‘*’
      When matching types
        pgty0 :: [*]
        '[pgty] :: [NullType]

@echatav
Copy link
Contributor

echatav commented Mar 9, 2024

Or perhaps there is a mistake in the type annotation of your encode term.

-    encode :: EncodeParams Schemas pgty hsty
+    encode :: EncodeParams Schemas '[pgty] hsty

Turning on ScopedTypeVariables should let GHC identify this pgty with the one in the type annotation of selectContentBy.

@echatav
Copy link
Contributor

echatav commented Mar 9, 2024

It might typecheck if you just removed the type signature for encode entirely and let GHC infer it.

@gasi
Copy link
Contributor Author

gasi commented Mar 12, 2024

@echatav Thank you so much for taking the time to look into this. I tried your suggestions, but unfortunately, I wasn’t able to resolve the error.

To make it easier for you and potentially contribute to Squeal with an example of a parametrized query, I created this draft PR with an extension of the existing Example.hs with a parametrized query: #354

Does this help you repro and potentially resolve the issue?

Thanks 🙇‍♂️


My dream is that one day a GitHub search for EncodeParams, DecodeRow, consRow, appendRows, etc. will show lots of examples of Squeal in action helping others enjoy this wonderful library. Hopefully figuring out the upgrade in zoomhub/zoomhub#235 will be a first such example ✨

@gasi
Copy link
Contributor Author

gasi commented Mar 12, 2024

P.S. I let GPT-4 loose on this, but Squeal type errors are too powerful for our AI overlords 😜

@echatav
Copy link
Contributor

echatav commented Mar 13, 2024

I've kind of been stuck working on Squeal because every time I try I run into GHC/Postgres installation location problems.

squeal-postgresql          > build (lib + exe)
squeal-postgresql          > Preprocessing library for squeal-postgresql-0.9.1.3..
squeal-postgresql          > Building library for squeal-postgresql-0.9.1.3..
squeal-postgresql          > ld: warning: -single_module is obsolete
squeal-postgresql          > ld: warning: search path '/opt/homebrew/opt/libpq/lib' not found
squeal-postgresql          > ld: library 'pq' not found
squeal-postgresql          > clang: error: linker command failed with exit code 1 (use -v to see invocation)
squeal-postgresql          > `gcc' failed in phase `Linker'. (Exit code: 1)

Googling hasn't helped me. I hate computers. If you help me figure out how I can get GHC to find LibPQ then I can help with Squeal again.

@gasi
Copy link
Contributor Author

gasi commented Mar 13, 2024

@echatav Re: libpq. Ouch, I’m sorry! Are you on macOS / Apple Silicon? I had similar issues and it took me a while to resolve. In fact, that’s what that whole stack LTS upgrade is about (I got a new MacBook laptop last year.) If you want, I’d be happy to hop on a Zoom call with you and try and help out. Shoot me an email to [email protected] if you are interested 😄

Re: generic SELECT. I partially figured it out!

  1. First, it was through discovering ~ for type equality in your docs (but I had to enable AllowAmbiguousTypes 😢): 3a1851b
  2. Then I found out I can drop pgty and infer it from hsty: 168813c
  3. Bonus: Added encoding/decoding custom type to example (however, I haven’t looked into how to make it type-safe yet): 21057aa

I actually was able to get it working first in my own code (without even needing AllowAmbiguousTypes 🤷‍♂️):
zoomhub/zoomhub@c297109#diff-d0b2f0351a2e5459c9b6306ed066f9e76873900c6bfc62fbc24dc5c2cad2f036R219-R232

I’m generally pretty happy about it except for this long from type signature and the need for OidOfNull Schemas. I originally had from inferred using _ + PartialTypeSignatures, but that started causing problems. Suggestions on how to improve it are welcome: zoomhub/zoomhub@c297109#diff-d0b2f0351a2e5459c9b6306ed066f9e76873900c6bfc62fbc24dc5c2cad2f036R182-R217

@echatav
Copy link
Contributor

echatav commented Mar 14, 2024

@gasi Nice job! Yes, I'm on a macbook. I'll send you an email. I've been wanting to get back to Squeal a bit.

@echatav
Copy link
Contributor

echatav commented Mar 14, 2024

Re: type safety. I guess you mean for OrganizationType on the Haskell side having a corresponding Postgres type so the type column isn't stringly-typed. For that you can use Postgres enum types. Squeal even has special support for creating Postgres enums from a Haskell type like so:

>>> :{
data Schwarma = Beef | Lamb | Chicken
  deriving stock GHC.Generic
  deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
  deriving (IsPG, FromPG) via Enumerated Schwarma
:}
>>> :{
let
  createSchwarma :: Definition (Public '[]) '["public" ::: '["schwarma" ::: 'Typedef (PG Schwarma)]]
  createSchwarma = createTypeEnumFrom @Schwarma #schwarma
in
  printSQL createSchwarma
:}
CREATE TYPE "schwarma" AS ENUM ('Beef', 'Lamb', 'Chicken');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants