packages feed

sqel-0.0.1.0: lib/Sqel/Data/PgTypeName.hs

module Sqel.Data.PgTypeName where

import Data.Aeson (FromJSON (parseJSON), ToJSON (toJSON))
import Data.GADT.Show (GShow (gshowsPrec))
import Exon (exon)
import Prettyprinter (Pretty (pretty))

import Sqel.Data.Sel (SelPrefix (DefaultPrefix), TypeName)
import Sqel.Data.Sql (ToSql (toSql), sql, sqlQuote)
import Sqel.Data.SqlFragment (From (From), Into (Into))
import Sqel.SOP.Constraint (symbolText)
import Sqel.Text.DbIdentifier (dbIdentifierT)

type PgTypeName :: Bool -> Type
data PgTypeName table where
  UnsafePgTableName :: Text -> PgTypeName 'True
  UnsafePgCompName :: Text -> PgTypeName 'False

instance GShow PgTypeName where gshowsPrec = showsPrec

type PgTableName =
  PgTypeName 'True

type PgCompName =
  PgTypeName 'False

getPgTypeName :: PgTypeName table -> Text
getPgTypeName = \case
  UnsafePgTableName n -> n
  UnsafePgCompName n -> n

pattern PgTypeName :: Text -> PgTypeName table
pattern PgTypeName name <- (getPgTypeName -> name)
{-# complete PgTypeName #-}

pattern PgTableName :: Text -> PgTypeName table
pattern PgTableName name <- (UnsafePgTableName name)

pattern PgCompName :: Text -> PgTypeName table
pattern PgCompName name <- (UnsafePgCompName name)

{-# complete PgTableName, PgCompName #-}

pattern PgOnlyTableName :: Text -> PgTypeName 'True
pattern PgOnlyTableName name <- (UnsafePgTableName name)

{-# complete PgOnlyTableName #-}

pattern PgOnlyCompName :: Text -> PgTypeName 'False
pattern PgOnlyCompName name <- (UnsafePgCompName name)

{-# complete PgOnlyCompName #-}

instance Eq (PgTypeName table) where
  UnsafePgTableName l == UnsafePgTableName r = l == r
  UnsafePgCompName l == UnsafePgCompName r = l == r

instance Show (PgTypeName table) where
  showsPrec d =
    showParen (d > 10) . \case
      UnsafePgTableName n -> [exon|UnsafePgTableName #{showsPrec 11 n}|]
      UnsafePgCompName n -> [exon|UnsafePgCompName #{showsPrec 11 n}|]

instance Pretty (PgTypeName table) where
  pretty (UnsafePgCompName n) = pretty n
  pretty (UnsafePgTableName n) = pretty n

instance ToSql (PgTypeName table) where
  toSql (PgTypeName n) =
    sqlQuote n

instance ToSql (From PgTableName) where
  toSql (From n) =
    [sql|from ##{n}|]

instance ToSql (Into PgTableName) where
  toSql (Into n) =
    [sql|into ##{n}|]

instance FromJSON PgTableName where
  parseJSON v = UnsafePgTableName <$> parseJSON v

instance FromJSON PgCompName where
  parseJSON v = UnsafePgCompName <$> parseJSON v

instance ToJSON (PgTypeName t) where
  toJSON = toJSON . getPgTypeName

pgTableName ::
  Text ->
  PgTypeName 'True
pgTableName =
  UnsafePgTableName . dbIdentifierT

pgCompName ::
  Text ->
  PgTypeName 'False
pgCompName name =
  UnsafePgCompName (dbIdentifierT name)

instance IsString PgTableName where
  fromString =
    pgTableName . fromString

instance IsString PgCompName where
  fromString =
    pgCompName . fromString

instance Ord (PgTypeName table) where
  compare = comparing getPgTypeName

type MkPgTypeName :: SelPrefix -> Symbol -> Bool -> Symbol -> Constraint
class KnownSymbol tname => MkPgTypeName prefix name table tname | prefix name table -> tname where
  pgTypeName :: PgTypeName table

instance (
    KnownSymbol name
  ) => MkPgTypeName 'DefaultPrefix name 'True name where
    pgTypeName = pgTableName (symbolText @name)

instance (
    TypeName prefix name tname
  ) => MkPgTypeName prefix name 'False tname where
    pgTypeName = pgCompName (symbolText @tname)