module Sqel.Statement where import qualified Hasql.Decoders as Decoders import Hasql.Decoders (Row, noResult) import qualified Hasql.Encoders as Encoders import Hasql.Encoders (Params) import Hasql.Statement (Statement (Statement)) import Lens.Micro ((^.)) import Sqel.Data.Codec (Encoder (Encoder)) import qualified Sqel.Data.PgType as PgTable import Sqel.Data.PgType ( ColumnType (ColumnPrim), PgColumn (PgColumn), PgColumnName (PgColumnName), PgColumns (PgColumns), PgTable (PgTable), ) import Sqel.Data.Projection (Projection) import Sqel.Data.QuerySchema (QuerySchema (QuerySchema)) import Sqel.Data.Selector (Selector (Selector)) import Sqel.Data.Sql (Sql (Sql), sql) import Sqel.Data.SqlFragment ( CommaSep (CommaSep), Delete (Delete), Insert (Insert), Returning (Returning), Update (Update), ) import Sqel.Data.TableSchema (TableSchema (TableSchema)) import Sqel.ResultShape (ResultShape (resultShape)) import qualified Sqel.Sql.Select as Sql import qualified Sqel.Sql.Type as Sql import Sqel.Text.Quote (dquote) statement :: ResultShape d result => Bool -> Sql -> Row d -> Params p -> Statement p result statement :: forall d result p. ResultShape d result => Bool -> Sql -> Row d -> Params p -> Statement p result statement Bool prep (Sql Text s) Row d row Params p params = forall a b. ByteString -> Params a -> Result b -> Bool -> Statement a b Statement (forall a b. ConvertUtf8 a b => a -> b encodeUtf8 Text s) Params p params (forall d r. ResultShape d r => Row d -> Result r resultShape Row d row) Bool prep unprepared :: ∀ result d p . ResultShape d result => Sql -> Row d -> Params p -> Statement p result unprepared :: forall result d p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result unprepared = forall d result p. ResultShape d result => Bool -> Sql -> Row d -> Params p -> Statement p result statement Bool False prepared :: ResultShape d result => Sql -> Row d -> Params p -> Statement p result prepared :: forall d result p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result prepared = forall d result p. ResultShape d result => Bool -> Sql -> Row d -> Params p -> Statement p result statement Bool True plain :: Sql -> Statement () () plain :: Sql -> Statement () () plain Sql s = forall a b. ByteString -> Params a -> Result b -> Bool -> Statement a b Statement (forall a b. ConvertUtf8 a b => a -> b encodeUtf8 Sql s) forall a. Monoid a => a mempty Result () noResult Bool False selectWhere :: ∀ result proj q table . ResultShape proj result => QuerySchema q table -> Projection proj table -> Statement q result selectWhere :: forall result proj q table. ResultShape proj result => QuerySchema q table -> Projection proj table -> Statement q result selectWhere q :: QuerySchema q table q@(QuerySchema [SelectFragment] _ (Encoder Params q qp Params () _)) Projection proj table t = forall d result p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result prepared (forall {k1} {k2} (f :: k1 -> k2 -> *) (proj :: k1) q (table :: k2). ToSql (Select (f proj table)) => QuerySchema q table -> f proj table -> Sql Sql.selectWhereGen QuerySchema q table q Projection proj table t) (Projection proj table t forall s a. s -> Getting a s a -> a ^. forall a. IsLabel "decoder" a => a #decoder) Params q qp delete :: ResultShape a result => QuerySchema q a -> TableSchema a -> Statement q result delete :: forall a result q. ResultShape a result => QuerySchema q a -> TableSchema a -> Statement q result delete (QuerySchema [SelectFragment] query (Encoder Params q qp Params () _)) (TableSchema PgTable a col Row a row Params a _) = forall d result p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result prepared [sql|##{Delete col} ##{query} ##{Returning col}|] Row a row Params q qp insert :: TableSchema a -> Statement a () insert :: forall a. TableSchema a -> Statement a () insert (TableSchema PgTable a col Row a _ Params a params) = forall d result p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result prepared [sql|##{Insert col}|] forall (f :: * -> *). Applicative f => f () unit Params a params uniqueColumn :: PgColumn -> Maybe Selector uniqueColumn :: PgColumn -> Maybe Selector uniqueColumn = \case PgColumn (PgColumnName Text name) (ColumnPrim PgPrimName _ Bool True [Sql] _) -> forall a. a -> Maybe a Just (Sql -> Selector Selector (Text -> Sql Sql (forall a. Exon a => a -> a dquote Text name))) PgColumn _ -> forall a. Maybe a Nothing pattern UniqueName :: Selector -> PgColumn pattern $mUniqueName :: forall {r}. PgColumn -> (Selector -> r) -> ((# #) -> r) -> r UniqueName sel <- (uniqueColumn -> Just sel) conflictFragment :: PgTable a -> Sql conflictFragment :: forall {k} (a :: k). PgTable a -> Sql conflictFragment table :: PgTable a table@PgTable {$sel:columns:PgTable :: forall {k} (a :: k). PgTable a -> PgColumns columns = PgColumns [PgColumn] columns} = Maybe (NonEmpty Sql) -> Sql format Maybe (NonEmpty Sql) uniques where format :: Maybe (NonEmpty Sql) -> Sql format Maybe (NonEmpty Sql) Nothing = Sql "" format (Just NonEmpty Sql cols) = [sql|on conflict (##{CommaSep (toList cols)}) do ##{Update table}|] uniques :: Maybe (NonEmpty Sql) uniques = forall a. [a] -> Maybe (NonEmpty a) nonEmpty [Sql n | UniqueName (Selector Sql n) <- [PgColumn] columns] upsertSql :: PgTable a -> Sql upsertSql :: forall {k} (a :: k). PgTable a -> Sql upsertSql PgTable a tab = [sql|##{Insert tab} #{conflict}|] where conflict :: Sql conflict = forall {k} (a :: k). PgTable a -> Sql conflictFragment PgTable a tab upsert :: TableSchema a -> Statement a () upsert :: forall a. TableSchema a -> Statement a () upsert (TableSchema PgTable a tab Row a _ Params a params) = forall d result p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result prepared (forall {k} (a :: k). PgTable a -> Sql upsertSql PgTable a tab) forall (f :: * -> *). Applicative f => f () unit Params a params dbColumns :: Sql -> Statement Text [(Text, Text, Text, Maybe Text)] dbColumns :: Sql -> Statement Text [(Text, Text, Text, Maybe Text)] dbColumns Sql code = forall d result p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result prepared Sql code Row (Text, Text, Text, Maybe Text) decoder Params Text encoder where decoder :: Row (Text, Text, Text, Maybe Text) decoder = (,,,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Row Text text' forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> Row Text text' forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> Row Text text' forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> forall a. NullableOrNot Value a -> Row a Decoders.column (forall (decoder :: * -> *) a. decoder a -> NullableOrNot decoder (Maybe a) Decoders.nullable Value Text Decoders.text) text' :: Row Text text' = forall a. NullableOrNot Value a -> Row a Decoders.column (forall (decoder :: * -> *) a. decoder a -> NullableOrNot decoder a Decoders.nonNullable Value Text Decoders.text) encoder :: Params Text encoder = forall a. NullableOrNot Value a -> Params a Encoders.param (forall (encoder :: * -> *) a. encoder a -> NullableOrNot encoder a Encoders.nonNullable Value Text Encoders.text) columnsSql :: Sql -> Sql -> Sql -> Sql columnsSql :: Sql -> Sql -> Sql -> Sql columnsSql Sql entity Sql container Sql namePrefix = [sql|select c.#{entity}_name, c.data_type, c.#{namePrefix}udt_name, e.data_type from information_schema.#{entity}s c left join information_schema.element_types e on ((c.#{container}_catalog, c.#{container}_schema, c.#{container}_name, 'TABLE', c.dtd_identifier) = (e.object_catalog, e.object_schema, e.object_name, e.object_type, e.collection_type_identifier)) where c.#{container}_name = $1|] tableColumnsSql :: Sql tableColumnsSql :: Sql tableColumnsSql = Sql -> Sql -> Sql -> Sql columnsSql Sql "column" Sql "table" Sql "" typeColumnsSql :: Sql typeColumnsSql :: Sql typeColumnsSql = Sql -> Sql -> Sql -> Sql columnsSql Sql "attribute" Sql "udt" Sql "attribute_" createTable :: PgTable a -> Statement () () createTable :: forall {k} (a :: k). PgTable a -> Statement () () createTable PgTable a table = forall result d p. ResultShape d result => Sql -> Row d -> Params p -> Statement p result unprepared (forall {k} (a :: k). PgTable a -> Sql Sql.createTable PgTable a table) forall (f :: * -> *). Applicative f => f () unit forall a. Monoid a => a mempty