module Hasql.Generate.Class
    ( HasDelete (..)
    , HasEnum (..)
    , HasInsert (..)
    , HasPrimaryKey (..)
    , HasSelect (..)
    , HasUpdate (..)
    , HasView (..)
    ) where

----------------------------------------------------------------------------------------------------

import           Data.Maybe    ( Maybe )
import           Data.Text     ( Text )

import qualified Hasql.Session

----------------------------------------------------------------------------------------------------

{-  Typeclass providing utility functions for PostgreSQL enum types generated
    by @fromType@.

    * @allValues@ — all constructors in declaration order (matching PostgreSQL
      sort order).
    * @toText@ — convert a constructor to its PostgreSQL label as 'Text'.
    * @fromText@ — parse a PostgreSQL label back to a constructor, returning
      'Nothing' on unrecognised input.
-}
class HasEnum a where
  allValues :: [a]
  toText :: a -> Text
  fromText :: Text -> Maybe a

----------------------------------------------------------------------------------------------------

{-  Typeclass for tables with a primary key that support SELECT-by-PK queries.
    The associated type @SelectKey@ is the PK type (single value or tuple for
    composite keys). Returns @Nothing@ when the key is not found.

    @selectMany@ takes a list of keys and returns all matching rows. Unmatched
    keys are silently omitted. An empty input list returns an empty result.
-}
class HasSelect a where
  type SelectKey a
  select :: SelectKey a -> Hasql.Session.Session (Maybe a)
  selectMany :: [SelectKey a] -> Hasql.Session.Session [a]

{-  Typeclass for tables that support INSERT with RETURNING. All tables get an
    instance; the insert returns the full record (including any server-generated
    columns like serial PKs).

    @insertMany@ inserts multiple rows in a single round-trip using @unnest@-based
    array parameters and returns all inserted rows via @RETURNING@.
-}
class HasInsert a where
  insert :: a -> Hasql.Session.Session a
  insertMany :: [a] -> Hasql.Session.Session [a]

{-  Typeclass for tables with a primary key that support UPDATE-by-PK with
    RETURNING. Returns @Nothing@ if the PK was not found.

    @updateMany@ updates multiple rows in a single round-trip using an @unnest@
    subquery join. Returns only the rows that were actually updated; unmatched
    PKs are silently omitted.
-}
class HasUpdate a where
  update :: a -> Hasql.Session.Session (Maybe a)
  updateMany :: [a] -> Hasql.Session.Session [a]

{-  Typeclass for tables with a primary key that support DELETE-by-PK.
    The associated type @DeleteKey@ is the PK type.

    @deleteMany@ deletes multiple rows in a single round-trip. Unmatched
    keys are silently ignored.
-}
class HasDelete a where
  type DeleteKey a
  delete :: DeleteKey a -> Hasql.Session.Session ()
  deleteMany :: [DeleteKey a] -> Hasql.Session.Session ()

-- | Typeclass for views — read-only relations with no primary key.
class HasView a where
  selectView :: Hasql.Session.Session [a]

{-  Typeclass for tables with a primary key, providing generic PK operations.
    Generated for all tables with PKs regardless of 'newtypePrimaryKeys'.

    @PkOf@ is the PK type (newtype wrapper when enabled, raw type otherwise).
    @RawPkOf@ is always the unwrapped PK type (e.g. @UUID@ or @(UUID, Int32)@).
-}
class HasPrimaryKey a where
  type PkOf a
  type RawPkOf a
  toPk :: a -> PkOf a
  wrapPk :: RawPkOf a -> PkOf a
  unwrapPk :: PkOf a -> RawPkOf a
  rawPk :: a -> RawPkOf a