{-# LANGUAGE Arrows #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Dispatch over backends.
--
-- = Creating and consuming 'AnyBackend'
--
-- Creating a new value of type 'AnyBackend' is done via 'mkAnyBackend'.
--
-- Consuming a value of type 'AnyBackend' is done via either 'runAnyBackend' or
-- any of the dispatch functions ('dispatchAnyBackend', 'dispatchAnyBackend'',
-- 'dispatchAnyBackend''').
--
-- For implementation details, or when trying to understand this module, start
-- from 'AnyBackend'.
--
-- = Backend Architecture
--
-- Our multiple backend architecture uses type classes and associated types
-- in order to share code, such as parsing graphql queries, building
-- schemas and metadata, while still accounting for the differences between
-- backends.
--
-- Each backend implements the @Backend@ type class from "Hasura.RQL.Types.Backend"
-- as well as instances for other classes such as @BackendSchema@ from
-- "Hasura.GraphQL.Schema.Backend", and define the associated types and
-- functions, such as @ScalarType@ and @parseScalarValue@, which fit the backend.
--
-- Whenever one of these associated types (@ScalarType@, @Column@, etc.) are
-- used, we need to either push the 'BackendType' to our caller (and making our
-- type @BackendType -> Type@), or use 'AnyBackend' (and allow our type to be
-- 'Type'). This is particularly useful when we need to store a container of
-- any backend.
--
-- In order to actually program abstractly using type classes, we need the
-- type class instances to be available for us to use. This module is a trick
-- to enumerate all supported backends and their respective instances to convince
-- GHC that they can be used.
--
-- = Example usage
--
-- As an example of using this module, consider wanting to write a function
-- that calculates metrics for each source. For example, we want to count
-- the number of tables each source has.
--
-- The @SchemaCache@ (defined in "Hasura.RQL.Types.SchemaCache") holds a hash map
-- from each source to their information.
-- The source information is parameterized by the 'BackendType' and is hidden
-- using an existential type inside 'AnyBackend'. It essentially looks like this:
--
-- > data SourceInfo b = ...
-- >
-- > type SourceCache = HashMap SourceName (AnyBackend SourceInfo)
--
-- Our metrics calculation function cares which backend it receives, but only
-- for its type class instances so it can call the relevant functions:
--
-- > telemetryForSource :: forall (b :: BackendType). SourceInfo b -> TelemetryPayload
--
-- In order to apply this function to all backends and return the telemetry payload for each,
-- we need to map over the hash map and dispatch the function over the relevant backend.
-- we can do this with 'runBackend':
--
-- > telemetries =
-- >   map
-- >     (`runBackend` telemetryForSource)
-- >     (scSources schemaCache)
--
-- If we want to be able to extract some information about the backend type
-- inside @telemetryForSource@, we can do this using 'backendTag':
--
-- > let telemetryForSource :: forall (b :: BackendType). HasTag b => SourceInfo b -> TelemetryPayload
-- >     telemetryForSource =
-- >       let dbKind = reify (backendTag @b)
--
-- Note that we needed to add the 'HasTag' constraint, which now means we can't use 'runBackend'
-- because our function has the wrong type (it has an extra constraint).
-- Instead, we can use 'dispatchAnyBackend' which allows us to have one constraint:
--
-- > telemetries =
-- >   fmap
-- >     (\sourceinfo -> (Any.dispatchAnyBackend @HasTag) sourceinfo telemetryForSource)
-- >     (scSources schemaCache)
--
-- Note that we had to add the constraint name as a type application, and we had
-- to explicitly add a lambda instead of using 'flip'.
module Hasura.SQL.AnyBackend
  ( AnyBackend,
    SatisfiesForAllBackends,
    liftTag,
    mkAnyBackend,
    mapBackend,
    traverseBackend,
    dispatchAnyBackend,
    dispatchAnyBackend',
    dispatchAnyBackend'',
    dispatchAnyBackendArrow,
    dispatchAnyBackendWithTwoConstraints,
    unpackAnyBackend,
    composeAnyBackend,
    runBackend,
    parseAnyBackendFromJSON,
    debugAnyBackendToJSON,
    backendSourceKindFromText,
    parseBackendSourceKindFromJSON,
  )
where

import Control.Applicative
import Control.Arrow.Extended (ArrowChoice)
import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Kind (Constraint, Type)
import Data.Text.NonEmpty (mkNonEmptyText)
import Hasura.Backends.DataConnector.Adapter.Types (DataConnectorName (..))
import Hasura.Incremental (Cacheable)
import Hasura.Prelude
import Hasura.SQL.Backend
import Hasura.SQL.Tag

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

-- * Types and constraints

-- | Allows storing types of kind @BackendType -> Type@ heterogenously.
--
-- Adding a new constructor to 'BackendType' will automatically create a new
-- constructor here.
--
-- Given some type defined as @data T (b :: BackendType) = ...@, we can define
-- @AnyBackend T@ without mentioning any 'BackendType'.
--
-- This is useful for having generic containers of potentially different types
-- of T. For instance, @SourceCache@ is defined as a
-- @HashMap SourceName (AnyBackend SourceInfo)@.
data AnyBackend (i :: BackendType -> Type)
  = PostgresVanillaValue (i ('Postgres 'Vanilla))
  | PostgresCitusValue (i ('Postgres 'Citus))
  | PostgresCockroachValue (i ('Postgres 'Cockroach))
  | MSSQLValue (i 'MSSQL)
  | BigQueryValue (i 'BigQuery)
  | MySQLValue (i 'MySQL)
  | DataConnectorValue (i 'DataConnector)
  deriving ((forall x. AnyBackend i -> Rep (AnyBackend i) x)
-> (forall x. Rep (AnyBackend i) x -> AnyBackend i)
-> Generic (AnyBackend i)
forall x. Rep (AnyBackend i) x -> AnyBackend i
forall x. AnyBackend i -> Rep (AnyBackend i) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (i :: BackendType -> *) x.
Rep (AnyBackend i) x -> AnyBackend i
forall (i :: BackendType -> *) x.
AnyBackend i -> Rep (AnyBackend i) x
$cto :: forall (i :: BackendType -> *) x.
Rep (AnyBackend i) x -> AnyBackend i
$cfrom :: forall (i :: BackendType -> *) x.
AnyBackend i -> Rep (AnyBackend i) x
Generic)

-- | Generates a constraint for all backends.
type AllBackendsSatisfy (c :: BackendType -> Constraint) =
  ( c ('Postgres 'Vanilla),
    c ('Postgres 'Citus),
    c ('Postgres 'Cockroach),
    c 'MSSQL,
    c 'BigQuery,
    c 'MySQL,
    c 'DataConnector
  )

-- | Generates a constraint for a generic type over all backends.
type SatisfiesForAllBackends
  (i :: BackendType -> Type)
  (c :: Type -> Constraint) =
  ( c (i ('Postgres 'Vanilla)),
    c (i ('Postgres 'Citus)),
    c (i ('Postgres 'Cockroach)),
    c (i 'MSSQL),
    c (i 'BigQuery),
    c (i 'MySQL),
    c (i 'DataConnector)
  )

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

-- * Functions on AnyBackend

-- | How to obtain a tag from a runtime value.
liftTag :: BackendType -> AnyBackend BackendTag
liftTag :: BackendType -> AnyBackend BackendTag
liftTag (Postgres PostgresKind
Vanilla) = BackendTag ('Postgres 'Vanilla) -> AnyBackend BackendTag
forall (i :: BackendType -> *).
i ('Postgres 'Vanilla) -> AnyBackend i
PostgresVanillaValue BackendTag ('Postgres 'Vanilla)
PostgresVanillaTag
liftTag (Postgres PostgresKind
Citus) = BackendTag ('Postgres 'Citus) -> AnyBackend BackendTag
forall (i :: BackendType -> *).
i ('Postgres 'Citus) -> AnyBackend i
PostgresCitusValue BackendTag ('Postgres 'Citus)
PostgresCitusTag
liftTag (Postgres PostgresKind
Cockroach) = BackendTag ('Postgres 'Cockroach) -> AnyBackend BackendTag
forall (i :: BackendType -> *).
i ('Postgres 'Cockroach) -> AnyBackend i
PostgresCockroachValue BackendTag ('Postgres 'Cockroach)
PostgresCockroachTag
liftTag BackendType
MSSQL = BackendTag 'MSSQL -> AnyBackend BackendTag
forall (i :: BackendType -> *). i 'MSSQL -> AnyBackend i
MSSQLValue BackendTag 'MSSQL
MSSQLTag
liftTag BackendType
BigQuery = BackendTag 'BigQuery -> AnyBackend BackendTag
forall (i :: BackendType -> *). i 'BigQuery -> AnyBackend i
BigQueryValue BackendTag 'BigQuery
BigQueryTag
liftTag BackendType
MySQL = BackendTag 'MySQL -> AnyBackend BackendTag
forall (i :: BackendType -> *). i 'MySQL -> AnyBackend i
MySQLValue BackendTag 'MySQL
MySQLTag
liftTag BackendType
DataConnector = BackendTag 'DataConnector -> AnyBackend BackendTag
forall (i :: BackendType -> *). i 'DataConnector -> AnyBackend i
DataConnectorValue BackendTag 'DataConnector
DataConnectorTag

-- | Transforms an @AnyBackend i@ into an @AnyBackend j@.
mapBackend ::
  forall
    (i :: BackendType -> Type)
    (j :: BackendType -> Type).
  AnyBackend i ->
  (forall b. i b -> j b) ->
  AnyBackend j
mapBackend :: AnyBackend i
-> (forall (b :: BackendType). i b -> j b) -> AnyBackend j
mapBackend AnyBackend i
e forall (b :: BackendType). i b -> j b
f = case AnyBackend i
e of
  PostgresVanillaValue i ('Postgres 'Vanilla)
x -> j ('Postgres 'Vanilla) -> AnyBackend j
forall (i :: BackendType -> *).
i ('Postgres 'Vanilla) -> AnyBackend i
PostgresVanillaValue (i ('Postgres 'Vanilla) -> j ('Postgres 'Vanilla)
forall (b :: BackendType). i b -> j b
f i ('Postgres 'Vanilla)
x)
  PostgresCitusValue i ('Postgres 'Citus)
x -> j ('Postgres 'Citus) -> AnyBackend j
forall (i :: BackendType -> *).
i ('Postgres 'Citus) -> AnyBackend i
PostgresCitusValue (i ('Postgres 'Citus) -> j ('Postgres 'Citus)
forall (b :: BackendType). i b -> j b
f i ('Postgres 'Citus)
x)
  PostgresCockroachValue i ('Postgres 'Cockroach)
x -> j ('Postgres 'Cockroach) -> AnyBackend j
forall (i :: BackendType -> *).
i ('Postgres 'Cockroach) -> AnyBackend i
PostgresCockroachValue (i ('Postgres 'Cockroach) -> j ('Postgres 'Cockroach)
forall (b :: BackendType). i b -> j b
f i ('Postgres 'Cockroach)
x)
  MSSQLValue i 'MSSQL
x -> j 'MSSQL -> AnyBackend j
forall (i :: BackendType -> *). i 'MSSQL -> AnyBackend i
MSSQLValue (i 'MSSQL -> j 'MSSQL
forall (b :: BackendType). i b -> j b
f i 'MSSQL
x)
  BigQueryValue i 'BigQuery
x -> j 'BigQuery -> AnyBackend j
forall (i :: BackendType -> *). i 'BigQuery -> AnyBackend i
BigQueryValue (i 'BigQuery -> j 'BigQuery
forall (b :: BackendType). i b -> j b
f i 'BigQuery
x)
  MySQLValue i 'MySQL
x -> j 'MySQL -> AnyBackend j
forall (i :: BackendType -> *). i 'MySQL -> AnyBackend i
MySQLValue (i 'MySQL -> j 'MySQL
forall (b :: BackendType). i b -> j b
f i 'MySQL
x)
  DataConnectorValue i 'DataConnector
x -> j 'DataConnector -> AnyBackend j
forall (i :: BackendType -> *). i 'DataConnector -> AnyBackend i
DataConnectorValue (i 'DataConnector -> j 'DataConnector
forall (b :: BackendType). i b -> j b
f i 'DataConnector
x)

-- | Traverse an @AnyBackend i@ into an @f (AnyBackend j)@.
traverseBackend ::
  forall
    (c :: BackendType -> Constraint)
    (i :: BackendType -> Type)
    (j :: BackendType -> Type)
    f.
  (AllBackendsSatisfy c, Functor f) =>
  AnyBackend i ->
  (forall b. c b => i b -> f (j b)) ->
  f (AnyBackend j)
traverseBackend :: AnyBackend i
-> (forall (b :: BackendType). c b => i b -> f (j b))
-> f (AnyBackend j)
traverseBackend AnyBackend i
e forall (b :: BackendType). c b => i b -> f (j b)
f = case AnyBackend i
e of
  PostgresVanillaValue i ('Postgres 'Vanilla)
x -> j ('Postgres 'Vanilla) -> AnyBackend j
forall (i :: BackendType -> *).
i ('Postgres 'Vanilla) -> AnyBackend i
PostgresVanillaValue (j ('Postgres 'Vanilla) -> AnyBackend j)
-> f (j ('Postgres 'Vanilla)) -> f (AnyBackend j)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> i ('Postgres 'Vanilla) -> f (j ('Postgres 'Vanilla))
forall (b :: BackendType). c b => i b -> f (j b)
f i ('Postgres 'Vanilla)
x
  PostgresCitusValue i ('Postgres 'Citus)
x -> j ('Postgres 'Citus) -> AnyBackend j
forall (i :: BackendType -> *).
i ('Postgres 'Citus) -> AnyBackend i
PostgresCitusValue (j ('Postgres 'Citus) -> AnyBackend j)
-> f (j ('Postgres 'Citus)) -> f (AnyBackend j)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> i ('Postgres 'Citus) -> f (j ('Postgres 'Citus))
forall (b :: BackendType). c b => i b -> f (j b)
f i ('Postgres 'Citus)
x
  PostgresCockroachValue i ('Postgres 'Cockroach)
x -> j ('Postgres 'Cockroach) -> AnyBackend j
forall (i :: BackendType -> *).
i ('Postgres 'Cockroach) -> AnyBackend i
PostgresCockroachValue (j ('Postgres 'Cockroach) -> AnyBackend j)
-> f (j ('Postgres 'Cockroach)) -> f (AnyBackend j)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> i ('Postgres 'Cockroach) -> f (j ('Postgres 'Cockroach))
forall (b :: BackendType). c b => i b -> f (j b)
f i ('Postgres 'Cockroach)
x
  MSSQLValue i 'MSSQL
x -> j 'MSSQL -> AnyBackend j
forall (i :: BackendType -> *). i 'MSSQL -> AnyBackend i
MSSQLValue (j 'MSSQL -> AnyBackend j) -> f (j 'MSSQL) -> f (AnyBackend j)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> i 'MSSQL -> f (j 'MSSQL)
forall (b :: BackendType). c b => i b -> f (j b)
f i 'MSSQL
x
  BigQueryValue i 'BigQuery
x -> j 'BigQuery -> AnyBackend j
forall (i :: BackendType -> *). i 'BigQuery -> AnyBackend i
BigQueryValue (j 'BigQuery -> AnyBackend j)
-> f (j 'BigQuery) -> f (AnyBackend j)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> i 'BigQuery -> f (j 'BigQuery)
forall (b :: BackendType). c b => i b -> f (j b)
f i 'BigQuery
x
  MySQLValue i 'MySQL
x -> j 'MySQL -> AnyBackend j
forall (i :: BackendType -> *). i 'MySQL -> AnyBackend i
MySQLValue (j 'MySQL -> AnyBackend j) -> f (j 'MySQL) -> f (AnyBackend j)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> i 'MySQL -> f (j 'MySQL)
forall (b :: BackendType). c b => i b -> f (j b)
f i 'MySQL
x
  DataConnectorValue i 'DataConnector
x -> j 'DataConnector -> AnyBackend j
forall (i :: BackendType -> *). i 'DataConnector -> AnyBackend i
DataConnectorValue (j 'DataConnector -> AnyBackend j)
-> f (j 'DataConnector) -> f (AnyBackend j)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> i 'DataConnector -> f (j 'DataConnector)
forall (b :: BackendType). c b => i b -> f (j b)
f i 'DataConnector
x

-- | Creates a new @AnyBackend i@ for a given backend @b@ by wrapping the given @i b@.
mkAnyBackend ::
  forall
    (b :: BackendType)
    (i :: BackendType -> Type).
  HasTag b =>
  i b ->
  AnyBackend i
mkAnyBackend :: i b -> AnyBackend i
mkAnyBackend i b
x = case HasTag b => BackendTag b
forall (b :: BackendType). HasTag b => BackendTag b
backendTag @b of
  BackendTag b
PostgresVanillaTag -> i ('Postgres 'Vanilla) -> AnyBackend i
forall (i :: BackendType -> *).
i ('Postgres 'Vanilla) -> AnyBackend i
PostgresVanillaValue i b
i ('Postgres 'Vanilla)
x
  BackendTag b
PostgresCitusTag -> i ('Postgres 'Citus) -> AnyBackend i
forall (i :: BackendType -> *).
i ('Postgres 'Citus) -> AnyBackend i
PostgresCitusValue i b
i ('Postgres 'Citus)
x
  BackendTag b
PostgresCockroachTag -> i ('Postgres 'Cockroach) -> AnyBackend i
forall (i :: BackendType -> *).
i ('Postgres 'Cockroach) -> AnyBackend i
PostgresCockroachValue i b
i ('Postgres 'Cockroach)
x
  BackendTag b
MSSQLTag -> i 'MSSQL -> AnyBackend i
forall (i :: BackendType -> *). i 'MSSQL -> AnyBackend i
MSSQLValue i b
i 'MSSQL
x
  BackendTag b
BigQueryTag -> i 'BigQuery -> AnyBackend i
forall (i :: BackendType -> *). i 'BigQuery -> AnyBackend i
BigQueryValue i b
i 'BigQuery
x
  BackendTag b
MySQLTag -> i 'MySQL -> AnyBackend i
forall (i :: BackendType -> *). i 'MySQL -> AnyBackend i
MySQLValue i b
i 'MySQL
x
  BackendTag b
DataConnectorTag -> i 'DataConnector -> AnyBackend i
forall (i :: BackendType -> *). i 'DataConnector -> AnyBackend i
DataConnectorValue i b
i 'DataConnector
x

-- | Dispatch a function to the value inside the @AnyBackend@, that does not
-- require bringing into scope a new class constraint.
runBackend ::
  forall
    (i :: BackendType -> Type)
    (r :: Type).
  AnyBackend i ->
  (forall (b :: BackendType). i b -> r) ->
  r
runBackend :: AnyBackend i -> (forall (b :: BackendType). i b -> r) -> r
runBackend AnyBackend i
b forall (b :: BackendType). i b -> r
f = case AnyBackend i
b of
  PostgresVanillaValue i ('Postgres 'Vanilla)
x -> i ('Postgres 'Vanilla) -> r
forall (b :: BackendType). i b -> r
f i ('Postgres 'Vanilla)
x
  PostgresCitusValue i ('Postgres 'Citus)
x -> i ('Postgres 'Citus) -> r
forall (b :: BackendType). i b -> r
f i ('Postgres 'Citus)
x
  PostgresCockroachValue i ('Postgres 'Cockroach)
x -> i ('Postgres 'Cockroach) -> r
forall (b :: BackendType). i b -> r
f i ('Postgres 'Cockroach)
x
  MSSQLValue i 'MSSQL
x -> i 'MSSQL -> r
forall (b :: BackendType). i b -> r
f i 'MSSQL
x
  BigQueryValue i 'BigQuery
x -> i 'BigQuery -> r
forall (b :: BackendType). i b -> r
f i 'BigQuery
x
  MySQLValue i 'MySQL
x -> i 'MySQL -> r
forall (b :: BackendType). i b -> r
f i 'MySQL
x
  DataConnectorValue i 'DataConnector
x -> i 'DataConnector -> r
forall (b :: BackendType). i b -> r
f i 'DataConnector
x

-- | Dispatch an existential using an universally quantified function while
-- also resolving a different constraint.
-- Use this to dispatch Backend* instances.
-- This is essentially a wrapper around @runAnyBackend f . repackAnyBackend \@c@.
dispatchAnyBackend ::
  forall
    (c :: BackendType -> Constraint)
    (i :: BackendType -> Type)
    (r :: Type).
  AllBackendsSatisfy c =>
  AnyBackend i ->
  (forall (b :: BackendType). c b => i b -> r) ->
  r
dispatchAnyBackend :: AnyBackend i -> (forall (b :: BackendType). c b => i b -> r) -> r
dispatchAnyBackend AnyBackend i
e forall (b :: BackendType). c b => i b -> r
f = case AnyBackend i
e of
  PostgresVanillaValue i ('Postgres 'Vanilla)
x -> i ('Postgres 'Vanilla) -> r
forall (b :: BackendType). c b => i b -> r
f i ('Postgres 'Vanilla)
x
  PostgresCitusValue i ('Postgres 'Citus)
x -> i ('Postgres 'Citus) -> r
forall (b :: BackendType). c b => i b -> r
f i ('Postgres 'Citus)
x
  PostgresCockroachValue i ('Postgres 'Cockroach)
x -> i ('Postgres 'Cockroach) -> r
forall (b :: BackendType). c b => i b -> r
f i ('Postgres 'Cockroach)
x
  MSSQLValue i 'MSSQL
x -> i 'MSSQL -> r
forall (b :: BackendType). c b => i b -> r
f i 'MSSQL
x
  BigQueryValue i 'BigQuery
x -> i 'BigQuery -> r
forall (b :: BackendType). c b => i b -> r
f i 'BigQuery
x
  MySQLValue i 'MySQL
x -> i 'MySQL -> r
forall (b :: BackendType). c b => i b -> r
f i 'MySQL
x
  DataConnectorValue i 'DataConnector
x -> i 'DataConnector -> r
forall (b :: BackendType). c b => i b -> r
f i 'DataConnector
x

dispatchAnyBackendWithTwoConstraints ::
  forall
    (c1 :: BackendType -> Constraint)
    (c2 :: BackendType -> Constraint)
    (i :: BackendType -> Type)
    (r :: Type).
  AllBackendsSatisfy c1 =>
  AllBackendsSatisfy c2 =>
  AnyBackend i ->
  (forall (b :: BackendType). c1 b => c2 b => i b -> r) ->
  r
dispatchAnyBackendWithTwoConstraints :: AnyBackend i
-> (forall (b :: BackendType). (c1 b, c2 b) => i b -> r) -> r
dispatchAnyBackendWithTwoConstraints AnyBackend i
e forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f = case AnyBackend i
e of
  PostgresVanillaValue i ('Postgres 'Vanilla)
x -> i ('Postgres 'Vanilla) -> r
forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f i ('Postgres 'Vanilla)
x
  PostgresCitusValue i ('Postgres 'Citus)
x -> i ('Postgres 'Citus) -> r
forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f i ('Postgres 'Citus)
x
  PostgresCockroachValue i ('Postgres 'Cockroach)
x -> i ('Postgres 'Cockroach) -> r
forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f i ('Postgres 'Cockroach)
x
  MSSQLValue i 'MSSQL
x -> i 'MSSQL -> r
forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f i 'MSSQL
x
  BigQueryValue i 'BigQuery
x -> i 'BigQuery -> r
forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f i 'BigQuery
x
  MySQLValue i 'MySQL
x -> i 'MySQL -> r
forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f i 'MySQL
x
  DataConnectorValue i 'DataConnector
x -> i 'DataConnector -> r
forall (b :: BackendType). (c1 b, c2 b) => i b -> r
f i 'DataConnector
x

-- | Unlike 'dispatchAnyBackend', the expected constraint has a different kind.
-- Use for classes like 'Show', 'ToJSON', etc.
dispatchAnyBackend' ::
  forall
    (c :: Type -> Constraint)
    (i :: BackendType -> Type)
    (r :: Type).
  i `SatisfiesForAllBackends` c =>
  AnyBackend i ->
  (forall (b :: BackendType). c (i b) => i b -> r) ->
  r
dispatchAnyBackend' :: AnyBackend i
-> (forall (b :: BackendType). c (i b) => i b -> r) -> r
dispatchAnyBackend' AnyBackend i
e forall (b :: BackendType). c (i b) => i b -> r
f = case AnyBackend i
e of
  PostgresVanillaValue i ('Postgres 'Vanilla)
x -> i ('Postgres 'Vanilla) -> r
forall (b :: BackendType). c (i b) => i b -> r
f i ('Postgres 'Vanilla)
x
  PostgresCitusValue i ('Postgres 'Citus)
x -> i ('Postgres 'Citus) -> r
forall (b :: BackendType). c (i b) => i b -> r
f i ('Postgres 'Citus)
x
  PostgresCockroachValue i ('Postgres 'Cockroach)
x -> i ('Postgres 'Cockroach) -> r
forall (b :: BackendType). c (i b) => i b -> r
f i ('Postgres 'Cockroach)
x
  MSSQLValue i 'MSSQL
x -> i 'MSSQL -> r
forall (b :: BackendType). c (i b) => i b -> r
f i 'MSSQL
x
  BigQueryValue i 'BigQuery
x -> i 'BigQuery -> r
forall (b :: BackendType). c (i b) => i b -> r
f i 'BigQuery
x
  MySQLValue i 'MySQL
x -> i 'MySQL -> r
forall (b :: BackendType). c (i b) => i b -> r
f i 'MySQL
x
  DataConnectorValue i 'DataConnector
x -> i 'DataConnector -> r
forall (b :: BackendType). c (i b) => i b -> r
f i 'DataConnector
x

-- | This allows you to apply a constraint to the Backend instances (c2)
-- as well as a constraint on the higher-kinded @i b@ type (c1)
dispatchAnyBackend'' ::
  forall
    (c1 :: Type -> Constraint)
    (c2 :: BackendType -> Constraint)
    (i :: BackendType -> Type)
    (r :: Type).
  i `SatisfiesForAllBackends` c1 =>
  AllBackendsSatisfy c2 =>
  AnyBackend i ->
  (forall (b :: BackendType). c2 b => c1 (i b) => i b -> r) ->
  r
dispatchAnyBackend'' :: AnyBackend i
-> (forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r) -> r
dispatchAnyBackend'' AnyBackend i
e forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f = case AnyBackend i
e of
  PostgresVanillaValue i ('Postgres 'Vanilla)
x -> i ('Postgres 'Vanilla) -> r
forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f i ('Postgres 'Vanilla)
x
  PostgresCitusValue i ('Postgres 'Citus)
x -> i ('Postgres 'Citus) -> r
forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f i ('Postgres 'Citus)
x
  PostgresCockroachValue i ('Postgres 'Cockroach)
x -> i ('Postgres 'Cockroach) -> r
forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f i ('Postgres 'Cockroach)
x
  MSSQLValue i 'MSSQL
x -> i 'MSSQL -> r
forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f i 'MSSQL
x
  BigQueryValue i 'BigQuery
x -> i 'BigQuery -> r
forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f i 'BigQuery
x
  MySQLValue i 'MySQL
x -> i 'MySQL -> r
forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f i 'MySQL
x
  DataConnectorValue i 'DataConnector
x -> i 'DataConnector -> r
forall (b :: BackendType). (c2 b, c1 (i b)) => i b -> r
f i 'DataConnector
x

-- | Sometimes we need to run operations on two backends of the same type.
-- If the backends don't contain the same type, the given @r@ value is returned.
-- Otherwise, the function is called with the two wrapped values.
composeAnyBackend ::
  forall
    (c :: BackendType -> Constraint)
    (i :: BackendType -> Type)
    (r :: Type).
  AllBackendsSatisfy c =>
  (forall (b :: BackendType). c b => i b -> i b -> r) ->
  AnyBackend i ->
  AnyBackend i ->
  r ->
  r
composeAnyBackend :: (forall (b :: BackendType). c b => i b -> i b -> r)
-> AnyBackend i -> AnyBackend i -> r -> r
composeAnyBackend forall (b :: BackendType). c b => i b -> i b -> r
f AnyBackend i
e1 AnyBackend i
e2 r
owise = case (AnyBackend i
e1, AnyBackend i
e2) of
  (PostgresVanillaValue i ('Postgres 'Vanilla)
x, PostgresVanillaValue i ('Postgres 'Vanilla)
y) -> i ('Postgres 'Vanilla) -> i ('Postgres 'Vanilla) -> r
forall (b :: BackendType). c b => i b -> i b -> r
f i ('Postgres 'Vanilla)
x i ('Postgres 'Vanilla)
y
  (PostgresCitusValue i ('Postgres 'Citus)
x, PostgresCitusValue i ('Postgres 'Citus)
y) -> i ('Postgres 'Citus) -> i ('Postgres 'Citus) -> r
forall (b :: BackendType). c b => i b -> i b -> r
f i ('Postgres 'Citus)
x i ('Postgres 'Citus)
y
  (PostgresCockroachValue i ('Postgres 'Cockroach)
x, PostgresCockroachValue i ('Postgres 'Cockroach)
y) -> i ('Postgres 'Cockroach) -> i ('Postgres 'Cockroach) -> r
forall (b :: BackendType). c b => i b -> i b -> r
f i ('Postgres 'Cockroach)
x i ('Postgres 'Cockroach)
y
  (MSSQLValue i 'MSSQL
x, MSSQLValue i 'MSSQL
y) -> i 'MSSQL -> i 'MSSQL -> r
forall (b :: BackendType). c b => i b -> i b -> r
f i 'MSSQL
x i 'MSSQL
y
  (BigQueryValue i 'BigQuery
x, BigQueryValue i 'BigQuery
y) -> i 'BigQuery -> i 'BigQuery -> r
forall (b :: BackendType). c b => i b -> i b -> r
f i 'BigQuery
x i 'BigQuery
y
  (MySQLValue i 'MySQL
x, MySQLValue i 'MySQL
y) -> i 'MySQL -> i 'MySQL -> r
forall (b :: BackendType). c b => i b -> i b -> r
f i 'MySQL
x i 'MySQL
y
  (DataConnectorValue i 'DataConnector
x, DataConnectorValue i 'DataConnector
y) -> i 'DataConnector -> i 'DataConnector -> r
forall (b :: BackendType). c b => i b -> i b -> r
f i 'DataConnector
x i 'DataConnector
y
  (AnyBackend i
value1, AnyBackend i
value2) ->
    if AnyBackend i
-> (forall (b :: BackendType). i b -> Const () b)
-> AnyBackend (Const ())
forall (i :: BackendType -> *) (j :: BackendType -> *).
AnyBackend i
-> (forall (b :: BackendType). i b -> j b) -> AnyBackend j
mapBackend AnyBackend i
value1 (() -> Const () b
forall k a (b :: k). a -> Const a b
Const (() -> Const () b) -> (i b -> ()) -> i b -> Const () b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. () -> i b -> ()
forall a b. a -> b -> a
const ()) AnyBackend (Const ()) -> AnyBackend (Const ()) -> Bool
forall a. Eq a => a -> a -> Bool
== AnyBackend i
-> (forall (b :: BackendType). i b -> Const () b)
-> AnyBackend (Const ())
forall (i :: BackendType -> *) (j :: BackendType -> *).
AnyBackend i
-> (forall (b :: BackendType). i b -> j b) -> AnyBackend j
mapBackend AnyBackend i
value2 (() -> Const () b
forall k a (b :: k). a -> Const a b
Const (() -> Const () b) -> (i b -> ()) -> i b -> Const () b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. () -> i b -> ()
forall a b. a -> b -> a
const ())
      then [Char] -> r
forall a. HasCallStack => [Char] -> a
error [Char]
"Programming error: missing case in composeAnyBackend"
      else r
owise

-- | Try to unpack the type of an existential.
-- Returns @Just x@ upon a succesful match, @Nothing@ otherwise.
unpackAnyBackend ::
  forall
    (b :: BackendType)
    (i :: BackendType -> Type).
  HasTag b =>
  AnyBackend i ->
  Maybe (i b)
unpackAnyBackend :: AnyBackend i -> Maybe (i b)
unpackAnyBackend AnyBackend i
exists = case (HasTag b => BackendTag b
forall (b :: BackendType). HasTag b => BackendTag b
backendTag @b, AnyBackend i
exists) of
  (BackendTag b
PostgresVanillaTag, PostgresVanillaValue i ('Postgres 'Vanilla)
x) -> i ('Postgres 'Vanilla) -> Maybe (i ('Postgres 'Vanilla))
forall a. a -> Maybe a
Just i ('Postgres 'Vanilla)
x
  (BackendTag b
PostgresCitusTag, PostgresCitusValue i ('Postgres 'Citus)
x) -> i ('Postgres 'Citus) -> Maybe (i ('Postgres 'Citus))
forall a. a -> Maybe a
Just i ('Postgres 'Citus)
x
  (BackendTag b
PostgresCockroachTag, PostgresCockroachValue i ('Postgres 'Cockroach)
x) -> i ('Postgres 'Cockroach) -> Maybe (i ('Postgres 'Cockroach))
forall a. a -> Maybe a
Just i ('Postgres 'Cockroach)
x
  (BackendTag b
MSSQLTag, MSSQLValue i 'MSSQL
x) -> i 'MSSQL -> Maybe (i 'MSSQL)
forall a. a -> Maybe a
Just i 'MSSQL
x
  (BackendTag b
BigQueryTag, BigQueryValue i 'BigQuery
x) -> i 'BigQuery -> Maybe (i 'BigQuery)
forall a. a -> Maybe a
Just i 'BigQuery
x
  (BackendTag b
MySQLTag, MySQLValue i 'MySQL
x) -> i 'MySQL -> Maybe (i 'MySQL)
forall a. a -> Maybe a
Just i 'MySQL
x
  (BackendTag b
DataConnectorTag, DataConnectorValue i 'DataConnector
x) -> i 'DataConnector -> Maybe (i 'DataConnector)
forall a. a -> Maybe a
Just i 'DataConnector
x
  (BackendTag b
tag, AnyBackend i
value) ->
    if AnyBackend BackendTag
-> (forall (b :: BackendType). BackendTag b -> Const () b)
-> AnyBackend (Const ())
forall (i :: BackendType -> *) (j :: BackendType -> *).
AnyBackend i
-> (forall (b :: BackendType). i b -> j b) -> AnyBackend j
mapBackend (BackendTag b -> AnyBackend BackendTag
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
mkAnyBackend BackendTag b
tag) (() -> Const () b
forall k a (b :: k). a -> Const a b
Const (() -> Const () b)
-> (BackendTag b -> ()) -> BackendTag b -> Const () b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. () -> BackendTag b -> ()
forall a b. a -> b -> a
const ()) AnyBackend (Const ()) -> AnyBackend (Const ()) -> Bool
forall a. Eq a => a -> a -> Bool
== AnyBackend i
-> (forall (b :: BackendType). i b -> Const () b)
-> AnyBackend (Const ())
forall (i :: BackendType -> *) (j :: BackendType -> *).
AnyBackend i
-> (forall (b :: BackendType). i b -> j b) -> AnyBackend j
mapBackend AnyBackend i
value (() -> Const () b
forall k a (b :: k). a -> Const a b
Const (() -> Const () b) -> (i b -> ()) -> i b -> Const () b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. () -> i b -> ()
forall a b. a -> b -> a
const ())
      then [Char] -> Maybe (i b)
forall a. HasCallStack => [Char] -> a
error [Char]
"Programming error: missing case in unpackAnyBackend"
      else Maybe (i b)
forall a. Maybe a
Nothing

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

-- * Special case for arrows

-- | Dispatch variant for use with arrow syntax.
--
-- NOTE: The below function accepts two constraints, if the arrow
-- you want to dispatch only has one constraint then repeat the constraint twice.
-- For example:
--
-- > AB.dispatchAnyBackendArrow @BackendMetadata @BackendMetadata (proc (sourceMetadata, invalidationKeys)
dispatchAnyBackendArrow ::
  forall
    (c1 :: BackendType -> Constraint)
    (c2 :: BackendType -> Constraint)
    (i :: BackendType -> Type)
    (r :: Type)
    (arr :: Type -> Type -> Type)
    x.
  (ArrowChoice arr, AllBackendsSatisfy c1, AllBackendsSatisfy c2) =>
  (forall b. c1 b => c2 b => arr (i b, x) r) ->
  arr (AnyBackend i, x) r
dispatchAnyBackendArrow :: (forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r)
-> arr (AnyBackend i, x) r
dispatchAnyBackendArrow forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow = proc (AnyBackend i
ab, x
x) -> do
  case AnyBackend i
ab of
    PostgresVanillaValue i ('Postgres 'Vanilla)
val ->
      (c1 ('Postgres 'Vanilla), c2 ('Postgres 'Vanilla)) =>
arr (i ('Postgres 'Vanilla), x) r
forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow @('Postgres 'Vanilla) -< (i ('Postgres 'Vanilla)
val, x
x)
    PostgresCitusValue i ('Postgres 'Citus)
val ->
      (c1 ('Postgres 'Citus), c2 ('Postgres 'Citus)) =>
arr (i ('Postgres 'Citus), x) r
forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow @('Postgres 'Citus) -< (i ('Postgres 'Citus)
val, x
x)
    PostgresCockroachValue i ('Postgres 'Cockroach)
val ->
      (c1 ('Postgres 'Cockroach), c2 ('Postgres 'Cockroach)) =>
arr (i ('Postgres 'Cockroach), x) r
forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow @('Postgres 'Cockroach) -< (i ('Postgres 'Cockroach)
val, x
x)
    MSSQLValue i 'MSSQL
val ->
      (c1 'MSSQL, c2 'MSSQL) => arr (i 'MSSQL, x) r
forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow @'MSSQL -< (i 'MSSQL
val, x
x)
    BigQueryValue i 'BigQuery
val ->
      (c1 'BigQuery, c2 'BigQuery) => arr (i 'BigQuery, x) r
forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow @'BigQuery -< (i 'BigQuery
val, x
x)
    MySQLValue i 'MySQL
val ->
      (c1 'MySQL, c2 'MySQL) => arr (i 'MySQL, x) r
forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow @'MySQL -< (i 'MySQL
val, x
x)
    DataConnectorValue i 'DataConnector
val ->
      (c1 'DataConnector, c2 'DataConnector) =>
arr (i 'DataConnector, x) r
forall (b :: BackendType). (c1 b, c2 b) => arr (i b, x) r
arrow @'DataConnector -< (i 'DataConnector
val, x
x)

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

-- * JSON functions

-- | Attempts to parse an 'AnyBackend' from a JSON value, using the provided
-- backend information.
parseAnyBackendFromJSON ::
  i `SatisfiesForAllBackends` FromJSON =>
  BackendType ->
  Value ->
  Parser (AnyBackend i)
parseAnyBackendFromJSON :: BackendType -> Value -> Parser (AnyBackend i)
parseAnyBackendFromJSON BackendType
backendKind Value
value = case BackendType
backendKind of
  Postgres PostgresKind
Vanilla -> i ('Postgres 'Vanilla) -> AnyBackend i
forall (i :: BackendType -> *).
i ('Postgres 'Vanilla) -> AnyBackend i
PostgresVanillaValue (i ('Postgres 'Vanilla) -> AnyBackend i)
-> Parser (i ('Postgres 'Vanilla)) -> Parser (AnyBackend i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (i ('Postgres 'Vanilla))
forall a. FromJSON a => Value -> Parser a
parseJSON Value
value
  Postgres PostgresKind
Citus -> i ('Postgres 'Citus) -> AnyBackend i
forall (i :: BackendType -> *).
i ('Postgres 'Citus) -> AnyBackend i
PostgresCitusValue (i ('Postgres 'Citus) -> AnyBackend i)
-> Parser (i ('Postgres 'Citus)) -> Parser (AnyBackend i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (i ('Postgres 'Citus))
forall a. FromJSON a => Value -> Parser a
parseJSON Value
value
  Postgres PostgresKind
Cockroach -> i ('Postgres 'Cockroach) -> AnyBackend i
forall (i :: BackendType -> *).
i ('Postgres 'Cockroach) -> AnyBackend i
PostgresCockroachValue (i ('Postgres 'Cockroach) -> AnyBackend i)
-> Parser (i ('Postgres 'Cockroach)) -> Parser (AnyBackend i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (i ('Postgres 'Cockroach))
forall a. FromJSON a => Value -> Parser a
parseJSON Value
value
  BackendType
MSSQL -> i 'MSSQL -> AnyBackend i
forall (i :: BackendType -> *). i 'MSSQL -> AnyBackend i
MSSQLValue (i 'MSSQL -> AnyBackend i)
-> Parser (i 'MSSQL) -> Parser (AnyBackend i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (i 'MSSQL)
forall a. FromJSON a => Value -> Parser a
parseJSON Value
value
  BackendType
BigQuery -> i 'BigQuery -> AnyBackend i
forall (i :: BackendType -> *). i 'BigQuery -> AnyBackend i
BigQueryValue (i 'BigQuery -> AnyBackend i)
-> Parser (i 'BigQuery) -> Parser (AnyBackend i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (i 'BigQuery)
forall a. FromJSON a => Value -> Parser a
parseJSON Value
value
  BackendType
MySQL -> i 'MySQL -> AnyBackend i
forall (i :: BackendType -> *). i 'MySQL -> AnyBackend i
MySQLValue (i 'MySQL -> AnyBackend i)
-> Parser (i 'MySQL) -> Parser (AnyBackend i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (i 'MySQL)
forall a. FromJSON a => Value -> Parser a
parseJSON Value
value
  BackendType
DataConnector -> i 'DataConnector -> AnyBackend i
forall (i :: BackendType -> *). i 'DataConnector -> AnyBackend i
DataConnectorValue (i 'DataConnector -> AnyBackend i)
-> Parser (i 'DataConnector) -> Parser (AnyBackend i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (i 'DataConnector)
forall a. FromJSON a => Value -> Parser a
parseJSON Value
value

-- | Outputs a debug JSON value from an 'AnyBackend'. This function must only be
-- used for debug purposes, as it has no way of inserting the backend kind in
-- the output, since there's no guarantee that the output will be an object.
debugAnyBackendToJSON ::
  i `SatisfiesForAllBackends` ToJSON =>
  AnyBackend i ->
  Value
debugAnyBackendToJSON :: AnyBackend i -> Value
debugAnyBackendToJSON AnyBackend i
e = AnyBackend i
-> (forall (b :: BackendType). ToJSON (i b) => i b -> Value)
-> Value
forall (c :: * -> Constraint) (i :: BackendType -> *) r.
SatisfiesForAllBackends i c =>
AnyBackend i
-> (forall (b :: BackendType). c (i b) => i b -> r) -> r
dispatchAnyBackend' @ToJSON AnyBackend i
e forall a. ToJSON a => a -> Value
forall (b :: BackendType). ToJSON (i b) => i b -> Value
toJSON

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

-- * Instances for 'AnyBackend'

deriving instance i `SatisfiesForAllBackends` Show => Show (AnyBackend i)

deriving instance i `SatisfiesForAllBackends` Eq => Eq (AnyBackend i)

instance i `SatisfiesForAllBackends` Hashable => Hashable (AnyBackend i)

instance i `SatisfiesForAllBackends` Cacheable => Cacheable (AnyBackend i)

backendSourceKindFromText :: Text -> Maybe (AnyBackend BackendSourceKind)
backendSourceKindFromText :: Text -> Maybe (AnyBackend BackendSourceKind)
backendSourceKindFromText Text
text =
  BackendSourceKind ('Postgres 'Vanilla)
-> AnyBackend BackendSourceKind
forall (i :: BackendType -> *).
i ('Postgres 'Vanilla) -> AnyBackend i
PostgresVanillaValue (BackendSourceKind ('Postgres 'Vanilla)
 -> AnyBackend BackendSourceKind)
-> Maybe (BackendSourceKind ('Postgres 'Vanilla))
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BackendSourceKind ('Postgres 'Vanilla)
-> Maybe (BackendSourceKind ('Postgres 'Vanilla))
forall (b :: BackendType).
BackendSourceKind b -> Maybe (BackendSourceKind b)
staticKindFromText BackendSourceKind ('Postgres 'Vanilla)
PostgresVanillaKind
    Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind ('Postgres 'Citus)
-> AnyBackend BackendSourceKind
forall (i :: BackendType -> *).
i ('Postgres 'Citus) -> AnyBackend i
PostgresCitusValue (BackendSourceKind ('Postgres 'Citus)
 -> AnyBackend BackendSourceKind)
-> Maybe (BackendSourceKind ('Postgres 'Citus))
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BackendSourceKind ('Postgres 'Citus)
-> Maybe (BackendSourceKind ('Postgres 'Citus))
forall (b :: BackendType).
BackendSourceKind b -> Maybe (BackendSourceKind b)
staticKindFromText BackendSourceKind ('Postgres 'Citus)
PostgresCitusKind
    Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind ('Postgres 'Cockroach)
-> AnyBackend BackendSourceKind
forall (i :: BackendType -> *).
i ('Postgres 'Cockroach) -> AnyBackend i
PostgresCockroachValue (BackendSourceKind ('Postgres 'Cockroach)
 -> AnyBackend BackendSourceKind)
-> Maybe (BackendSourceKind ('Postgres 'Cockroach))
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BackendSourceKind ('Postgres 'Cockroach)
-> Maybe (BackendSourceKind ('Postgres 'Cockroach))
forall (b :: BackendType).
BackendSourceKind b -> Maybe (BackendSourceKind b)
staticKindFromText BackendSourceKind ('Postgres 'Cockroach)
PostgresCockroachKind
    Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'MSSQL -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'MSSQL -> AnyBackend i
MSSQLValue (BackendSourceKind 'MSSQL -> AnyBackend BackendSourceKind)
-> Maybe (BackendSourceKind 'MSSQL)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BackendSourceKind 'MSSQL -> Maybe (BackendSourceKind 'MSSQL)
forall (b :: BackendType).
BackendSourceKind b -> Maybe (BackendSourceKind b)
staticKindFromText BackendSourceKind 'MSSQL
MSSQLKind
    Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'BigQuery -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'BigQuery -> AnyBackend i
BigQueryValue (BackendSourceKind 'BigQuery -> AnyBackend BackendSourceKind)
-> Maybe (BackendSourceKind 'BigQuery)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BackendSourceKind 'BigQuery -> Maybe (BackendSourceKind 'BigQuery)
forall (b :: BackendType).
BackendSourceKind b -> Maybe (BackendSourceKind b)
staticKindFromText BackendSourceKind 'BigQuery
BigQueryKind
    Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'MySQL -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'MySQL -> AnyBackend i
MySQLValue (BackendSourceKind 'MySQL -> AnyBackend BackendSourceKind)
-> Maybe (BackendSourceKind 'MySQL)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BackendSourceKind 'MySQL -> Maybe (BackendSourceKind 'MySQL)
forall (b :: BackendType).
BackendSourceKind b -> Maybe (BackendSourceKind b)
staticKindFromText BackendSourceKind 'MySQL
MySQLKind
    -- IMPORTANT: This must be the last thing here, since it will accept (almost) any string
    Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
-> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'DataConnector -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'DataConnector -> AnyBackend i
DataConnectorValue (BackendSourceKind 'DataConnector -> AnyBackend BackendSourceKind)
-> (NonEmptyText -> BackendSourceKind 'DataConnector)
-> NonEmptyText
-> AnyBackend BackendSourceKind
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DataConnectorName -> BackendSourceKind 'DataConnector
DataConnectorKind (DataConnectorName -> BackendSourceKind 'DataConnector)
-> (NonEmptyText -> DataConnectorName)
-> NonEmptyText
-> BackendSourceKind 'DataConnector
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmptyText -> DataConnectorName
DataConnectorName (NonEmptyText -> AnyBackend BackendSourceKind)
-> Maybe NonEmptyText -> Maybe (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Maybe NonEmptyText
mkNonEmptyText Text
text
  where
    staticKindFromText :: BackendSourceKind b -> Maybe (BackendSourceKind b)
    staticKindFromText :: BackendSourceKind b -> Maybe (BackendSourceKind b)
staticKindFromText BackendSourceKind b
kind =
      if Text
text Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` BackendType -> [Text]
backendTextNames (BackendSourceKind b -> BackendType
forall (b :: BackendType). BackendSourceKind b -> BackendType
backendTypeFromBackendSourceKind BackendSourceKind b
kind)
        then BackendSourceKind b -> Maybe (BackendSourceKind b)
forall a. a -> Maybe a
Just BackendSourceKind b
kind
        else Maybe (BackendSourceKind b)
forall a. Maybe a
Nothing

parseBackendSourceKindFromJSON :: Value -> Parser (AnyBackend BackendSourceKind)
parseBackendSourceKindFromJSON :: Value -> Parser (AnyBackend BackendSourceKind)
parseBackendSourceKindFromJSON Value
value =
  BackendSourceKind ('Postgres 'Vanilla)
-> AnyBackend BackendSourceKind
forall (i :: BackendType -> *).
i ('Postgres 'Vanilla) -> AnyBackend i
PostgresVanillaValue (BackendSourceKind ('Postgres 'Vanilla)
 -> AnyBackend BackendSourceKind)
-> Parser (BackendSourceKind ('Postgres 'Vanilla))
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (BackendSourceKind ('Postgres 'Vanilla))
forall a. FromJSON a => Value -> Parser a
parseJSON @(BackendSourceKind ('Postgres 'Vanilla)) Value
value
    Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind ('Postgres 'Citus)
-> AnyBackend BackendSourceKind
forall (i :: BackendType -> *).
i ('Postgres 'Citus) -> AnyBackend i
PostgresCitusValue (BackendSourceKind ('Postgres 'Citus)
 -> AnyBackend BackendSourceKind)
-> Parser (BackendSourceKind ('Postgres 'Citus))
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (BackendSourceKind ('Postgres 'Citus))
forall a. FromJSON a => Value -> Parser a
parseJSON @(BackendSourceKind ('Postgres 'Citus)) Value
value
    Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind ('Postgres 'Cockroach)
-> AnyBackend BackendSourceKind
forall (i :: BackendType -> *).
i ('Postgres 'Cockroach) -> AnyBackend i
PostgresCockroachValue (BackendSourceKind ('Postgres 'Cockroach)
 -> AnyBackend BackendSourceKind)
-> Parser (BackendSourceKind ('Postgres 'Cockroach))
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (BackendSourceKind ('Postgres 'Cockroach))
forall a. FromJSON a => Value -> Parser a
parseJSON @(BackendSourceKind ('Postgres 'Cockroach)) Value
value
    Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'MSSQL -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'MSSQL -> AnyBackend i
MSSQLValue (BackendSourceKind 'MSSQL -> AnyBackend BackendSourceKind)
-> Parser (BackendSourceKind 'MSSQL)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (BackendSourceKind 'MSSQL)
forall a. FromJSON a => Value -> Parser a
parseJSON @(BackendSourceKind ('MSSQL)) Value
value
    Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'BigQuery -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'BigQuery -> AnyBackend i
BigQueryValue (BackendSourceKind 'BigQuery -> AnyBackend BackendSourceKind)
-> Parser (BackendSourceKind 'BigQuery)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (BackendSourceKind 'BigQuery)
forall a. FromJSON a => Value -> Parser a
parseJSON @(BackendSourceKind ('BigQuery)) Value
value
    Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'MySQL -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'MySQL -> AnyBackend i
MySQLValue (BackendSourceKind 'MySQL -> AnyBackend BackendSourceKind)
-> Parser (BackendSourceKind 'MySQL)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (BackendSourceKind 'MySQL)
forall a. FromJSON a => Value -> Parser a
parseJSON @(BackendSourceKind ('MySQL)) Value
value
    -- IMPORTANT: This must the last thing here, since it will accept (almost) any string
    Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BackendSourceKind 'DataConnector -> AnyBackend BackendSourceKind
forall (i :: BackendType -> *). i 'DataConnector -> AnyBackend i
DataConnectorValue (BackendSourceKind 'DataConnector -> AnyBackend BackendSourceKind)
-> Parser (BackendSourceKind 'DataConnector)
-> Parser (AnyBackend BackendSourceKind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser (BackendSourceKind 'DataConnector)
forall a. FromJSON a => Value -> Parser a
parseJSON @(BackendSourceKind ('DataConnector)) Value
value