-- | This module translates the IR of boolean expressions into TSQL boolean
-- expressions.
--
-- Boolean expressions typically arise from permissions and where-clause
-- filters.
module Hasura.Backends.MSSQL.FromIr.Expression
  ( fromGBoolExp,
  )
where

import Control.Monad.Validate
import Data.HashMap.Strict qualified as HM
import Hasura.Backends.MSSQL.FromIr
  ( Error (UnsupportedOpExpG),
    FromIr,
    NameTemplate (TableTemplate),
    generateAlias,
  )
import Hasura.Backends.MSSQL.FromIr.Constants (existsFieldName, trueExpression)
import Hasura.Backends.MSSQL.Instances.Types ()
import Hasura.Backends.MSSQL.Types.Internal as TSQL
import Hasura.Prelude
import Hasura.RQL.IR qualified as IR
import Hasura.RQL.Types.Column qualified as IR
import Hasura.RQL.Types.Relationships.Local qualified as IR
import Hasura.SQL.Backend

-- | Translate boolean expressions into TSQL 'Expression's.
--
-- The `IR.AnnBoolExpFld` references fields and columns. The entity (e.g. table)
-- that binds these columns is supplied in the `ReaderT EntityAlias`
-- environment, such that the columns can be referred to unambiguously.
fromGBoolExp ::
  IR.GBoolExp 'MSSQL (IR.AnnBoolExpFld 'MSSQL Expression) ->
  ReaderT EntityAlias FromIr Expression
fromGBoolExp :: GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp =
  \case
    IR.BoolAnd [GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)]
expressions ->
      ([Expression] -> Expression)
-> ReaderT EntityAlias FromIr [Expression]
-> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Expression] -> Expression
AndExpression ((GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
 -> ReaderT EntityAlias FromIr Expression)
-> [GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)]
-> ReaderT EntityAlias FromIr [Expression]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp [GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)]
expressions)
    IR.BoolOr [GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)]
expressions ->
      ([Expression] -> Expression)
-> ReaderT EntityAlias FromIr [Expression]
-> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Expression] -> Expression
OrExpression ((GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
 -> ReaderT EntityAlias FromIr Expression)
-> [GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)]
-> ReaderT EntityAlias FromIr [Expression]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp [GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)]
expressions)
    IR.BoolNot GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
expression ->
      (Expression -> Expression)
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Expression -> Expression
NotExpression (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
expression)
    IR.BoolExists GExists 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
gExists ->
      GExists 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGExists GExists 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
gExists
    IR.BoolField AnnBoolExpFld 'MSSQL Expression
expression ->
      AnnBoolExpFld 'MSSQL Expression
-> ReaderT EntityAlias FromIr Expression
fromAnnBoolExpFld AnnBoolExpFld 'MSSQL Expression
expression
  where
    fromGExists :: IR.GExists 'MSSQL (IR.AnnBoolExpFld 'MSSQL Expression) -> ReaderT EntityAlias FromIr Expression
    fromGExists :: GExists 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGExists IR.GExists {TableName 'MSSQL
_geTable :: forall (backend :: BackendType) field.
GExists backend field -> TableName backend
_geTable :: TableName 'MSSQL
_geTable, GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
_geWhere :: forall (backend :: BackendType) field.
GExists backend field -> GBoolExp backend field
_geWhere :: GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
_geWhere} = do
      From
selectFrom <- FromIr From -> ReaderT EntityAlias FromIr From
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TableName -> FromIr From
aliasQualifiedTable TableName 'MSSQL
TableName
_geTable)
      From
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Expression
forall a.
From
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
scopedTo From
selectFrom (ReaderT EntityAlias FromIr Expression
 -> ReaderT EntityAlias FromIr Expression)
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ do
        Expression
whereExpression <- GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
_geWhere
        Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$
          Select -> Expression
ExistsExpression (Select -> Expression) -> Select -> Expression
forall a b. (a -> b) -> a -> b
$
            Select
emptySelect
              { $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Maybe a
Nothing,
                $sel:selectProjections:Select :: [Projection]
selectProjections =
                  [ Aliased Expression -> Projection
ExpressionProjection
                      ( Aliased :: forall a. a -> Text -> Aliased a
Aliased
                          { $sel:aliasedThing:Aliased :: Expression
aliasedThing = Expression
trueExpression,
                            $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
existsFieldName
                          }
                      )
                  ],
                $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
Just From
selectFrom,
                $sel:selectJoins:Select :: [Join]
selectJoins = [Join]
forall a. Monoid a => a
mempty,
                $sel:selectWhere:Select :: Where
selectWhere = [Expression] -> Where
Where [Expression
whereExpression],
                $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
                $sel:selectFor:Select :: For
selectFor = For
NoFor,
                $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
              }

-- | Translate boolean expressions into TSQL 'Expression's.
--
-- The `IR.AnnBoolExpFld` references fields and columns. The entity (e.g. table)
-- that binds these columns is supplied in the `ReaderT EntityAlias`
-- environment, such that the columns can be referred to unambiguously.
fromAnnBoolExpFld ::
  IR.AnnBoolExpFld 'MSSQL Expression ->
  ReaderT EntityAlias FromIr Expression
fromAnnBoolExpFld :: AnnBoolExpFld 'MSSQL Expression
-> ReaderT EntityAlias FromIr Expression
fromAnnBoolExpFld =
  \case
    IR.AVColumn ColumnInfo 'MSSQL
columnInfo [OpExpG 'MSSQL Expression]
opExpGs -> do
      [Expression]
expressions <- (OpExpG 'MSSQL Expression -> ReaderT EntityAlias FromIr Expression)
-> [OpExpG 'MSSQL Expression]
-> ReaderT EntityAlias FromIr [Expression]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (ColumnInfo 'MSSQL
-> OpExpG 'MSSQL Expression
-> ReaderT EntityAlias FromIr Expression
fromOpExpG ColumnInfo 'MSSQL
columnInfo) [OpExpG 'MSSQL Expression]
opExpGs
      Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Expression] -> Expression
AndExpression [Expression]
expressions)
    IR.AVRelationship IR.RelInfo {riMapping :: forall (b :: BackendType).
RelInfo b -> HashMap (Column b) (Column b)
riMapping = HashMap (Column 'MSSQL) (Column 'MSSQL)
mapping, riRTable :: forall (b :: BackendType). RelInfo b -> TableName b
riRTable = TableName 'MSSQL
table} GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp -> do
      From
selectFrom <- FromIr From -> ReaderT EntityAlias FromIr From
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TableName -> FromIr From
aliasQualifiedTable TableName 'MSSQL
TableName
table)
      [Expression]
mappingExpression <- From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
translateMapping From
selectFrom HashMap (Column 'MSSQL) (Column 'MSSQL)
HashMap ColumnName ColumnName
mapping
      Expression
whereExpression <- From
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Expression
forall a.
From
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
scopedTo From
selectFrom (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp)
      Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        ( Select -> Expression
ExistsExpression
            Select
emptySelect
              { $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Maybe a
Nothing,
                $sel:selectProjections:Select :: [Projection]
selectProjections =
                  [ Aliased Expression -> Projection
ExpressionProjection
                      ( Aliased :: forall a. a -> Text -> Aliased a
Aliased
                          { $sel:aliasedThing:Aliased :: Expression
aliasedThing = Expression
trueExpression,
                            $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
existsFieldName
                          }
                      )
                  ],
                $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
Just From
selectFrom,
                $sel:selectJoins:Select :: [Join]
selectJoins = [Join]
forall a. Monoid a => a
mempty,
                $sel:selectWhere:Select :: Where
selectWhere = [Expression] -> Where
Where ([Expression]
mappingExpression [Expression] -> [Expression] -> [Expression]
forall a. Semigroup a => a -> a -> a
<> [Expression
whereExpression]),
                $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
                $sel:selectFor:Select :: For
selectFor = For
NoFor,
                $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
              }
        )
  where
    -- Translate a relationship field mapping into column equality comparisons.
    translateMapping ::
      From ->
      HashMap ColumnName ColumnName ->
      ReaderT EntityAlias FromIr [Expression]
    translateMapping :: From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
translateMapping From
localFrom =
      ((ColumnName, ColumnName) -> ReaderT EntityAlias FromIr Expression)
-> [(ColumnName, ColumnName)]
-> ReaderT EntityAlias FromIr [Expression]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse
        ( \(ColumnName
remoteColumn, ColumnName
localColumn) -> do
            FieldName
localFieldName <- From
-> ReaderT EntityAlias FromIr FieldName
-> ReaderT EntityAlias FromIr FieldName
forall a.
From
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
scopedTo From
localFrom (ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn ColumnName
localColumn)
            FieldName
remoteFieldName <- ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn ColumnName
remoteColumn
            Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure
              ( Op -> Expression -> Expression -> Expression
OpExpression
                  Op
TSQL.EQ'
                  (FieldName -> Expression
ColumnExpression FieldName
localFieldName)
                  (FieldName -> Expression
ColumnExpression FieldName
remoteFieldName)
              )
        )
        ([(ColumnName, ColumnName)]
 -> ReaderT EntityAlias FromIr [Expression])
-> (HashMap ColumnName ColumnName -> [(ColumnName, ColumnName)])
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap ColumnName ColumnName -> [(ColumnName, ColumnName)]
forall k v. HashMap k v -> [(k, v)]
HM.toList

-- | Scope a translation action to the table bound in a FROM clause.
scopedTo :: From -> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
scopedTo :: From
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
scopedTo From
from = (EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const (From -> EntityAlias
fromAlias From
from))

-- | Translate a column reference occurring in a boolean expression into an
-- equivalent 'Expression'.
--
-- Different text types support different operators. Therefore we cast some text
-- types to "varchar(max)", which supports the most operators.
fromColumnInfo :: IR.ColumnInfo 'MSSQL -> ReaderT EntityAlias FromIr Expression
fromColumnInfo :: ColumnInfo 'MSSQL -> ReaderT EntityAlias FromIr Expression
fromColumnInfo IR.ColumnInfo {ciColumn :: forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn = Column 'MSSQL
column, ColumnType 'MSSQL
ciType :: forall (b :: BackendType). ColumnInfo b -> ColumnType b
ciType :: ColumnType 'MSSQL
ciType} = do
  FieldName
fieldName <- ColumnName -> EntityAlias -> FieldName
TSQL.columnNameToFieldName Column 'MSSQL
ColumnName
column (EntityAlias -> FieldName)
-> ReaderT EntityAlias FromIr EntityAlias
-> ReaderT EntityAlias FromIr FieldName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT EntityAlias FromIr EntityAlias
forall r (m :: * -> *). MonadReader r m => m r
ask
  if ColumnType 'MSSQL -> Bool
shouldCastToVarcharMax ColumnType 'MSSQL
ciType
    then Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ScalarType -> DataLength -> Expression
CastExpression (FieldName -> Expression
ColumnExpression FieldName
fieldName) ScalarType
WvarcharType DataLength
DataLengthMax)
    else Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldName -> Expression
ColumnExpression FieldName
fieldName)
  where
    shouldCastToVarcharMax :: IR.ColumnType 'MSSQL -> Bool
    shouldCastToVarcharMax :: ColumnType 'MSSQL -> Bool
shouldCastToVarcharMax ColumnType 'MSSQL
typ =
      ColumnType 'MSSQL
typ ColumnType 'MSSQL -> ColumnType 'MSSQL -> Bool
forall a. Eq a => a -> a -> Bool
== ScalarType 'MSSQL -> ColumnType 'MSSQL
forall (b :: BackendType). ScalarType b -> ColumnType b
IR.ColumnScalar ScalarType 'MSSQL
ScalarType
TextType Bool -> Bool -> Bool
|| ColumnType 'MSSQL
typ ColumnType 'MSSQL -> ColumnType 'MSSQL -> Bool
forall a. Eq a => a -> a -> Bool
== ScalarType 'MSSQL -> ColumnType 'MSSQL
forall (b :: BackendType). ScalarType b -> ColumnType b
IR.ColumnScalar ScalarType 'MSSQL
ScalarType
WtextType

-- | Get FieldSource from a TAFExp type table aggregate field
fromColumn :: ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn :: ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn ColumnName
column = ColumnName -> EntityAlias -> FieldName
columnNameToFieldName ColumnName
column (EntityAlias -> FieldName)
-> ReaderT EntityAlias FromIr EntityAlias
-> ReaderT EntityAlias FromIr FieldName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT EntityAlias FromIr EntityAlias
forall r (m :: * -> *). MonadReader r m => m r
ask

-- | Translate a single `IR.OpExpG` operation on a column into an expression.
fromOpExpG :: IR.ColumnInfo 'MSSQL -> IR.OpExpG 'MSSQL Expression -> ReaderT EntityAlias FromIr Expression
fromOpExpG :: ColumnInfo 'MSSQL
-> OpExpG 'MSSQL Expression
-> ReaderT EntityAlias FromIr Expression
fromOpExpG ColumnInfo 'MSSQL
columnInfo OpExpG 'MSSQL Expression
op = do
  Expression
column <- ColumnInfo 'MSSQL -> ReaderT EntityAlias FromIr Expression
fromColumnInfo ColumnInfo 'MSSQL
columnInfo
  case OpExpG 'MSSQL Expression
op of
    OpExpG 'MSSQL Expression
IR.ANISNULL -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Expression -> Expression
TSQL.IsNullExpression Expression
column
    OpExpG 'MSSQL Expression
IR.ANISNOTNULL -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Expression -> Expression
TSQL.IsNotNullExpression Expression
column
    IR.AEQ Bool
False Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Expression -> Expression -> Expression
nullableBoolEquality Expression
column Expression
val
    IR.AEQ Bool
True Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.EQ' Expression
column Expression
val
    IR.ANE Bool
False Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Expression -> Expression -> Expression
nullableBoolInequality Expression
column Expression
val
    IR.ANE Bool
True Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.NEQ' Expression
column Expression
val
    IR.AGT Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.GT Expression
column Expression
val
    IR.ALT Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.LT Expression
column Expression
val
    IR.AGTE Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.GTE Expression
column Expression
val
    IR.ALTE Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.LTE Expression
column Expression
val
    IR.AIN Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.IN Expression
column Expression
val
    IR.ANIN Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.NIN Expression
column Expression
val
    IR.ALIKE Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.LIKE Expression
column Expression
val
    IR.ANLIKE Expression
val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.NLIKE Expression
column Expression
val
    IR.ABackendSpecific BooleanOperators 'MSSQL Expression
o -> case BooleanOperators 'MSSQL Expression
o of
      ASTContains val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ SpatialOp -> Expression -> Expression -> Expression
TSQL.STOpExpression SpatialOp
TSQL.STContains Expression
column Expression
val
      ASTCrosses val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ SpatialOp -> Expression -> Expression -> Expression
TSQL.STOpExpression SpatialOp
TSQL.STCrosses Expression
column Expression
val
      ASTEquals val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ SpatialOp -> Expression -> Expression -> Expression
TSQL.STOpExpression SpatialOp
TSQL.STEquals Expression
column Expression
val
      ASTIntersects val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ SpatialOp -> Expression -> Expression -> Expression
TSQL.STOpExpression SpatialOp
TSQL.STIntersects Expression
column Expression
val
      ASTOverlaps val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ SpatialOp -> Expression -> Expression -> Expression
TSQL.STOpExpression SpatialOp
TSQL.STOverlaps Expression
column Expression
val
      ASTTouches val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ SpatialOp -> Expression -> Expression -> Expression
TSQL.STOpExpression SpatialOp
TSQL.STTouches Expression
column Expression
val
      ASTWithin val -> Expression -> ReaderT EntityAlias FromIr Expression
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ SpatialOp -> Expression -> Expression -> Expression
TSQL.STOpExpression SpatialOp
TSQL.STWithin Expression
column Expression
val
    -- As of March 2021, only geometry/geography casts are supported
    IR.ACast CastExp 'MSSQL Expression
_casts -> NonEmpty Error -> ReaderT EntityAlias FromIr Expression
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (Error -> NonEmpty Error
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OpExpG 'MSSQL Expression -> Error
UnsupportedOpExpG OpExpG 'MSSQL Expression
op)) -- mkCastsExp casts

    -- We do not yet support column names in permissions
    IR.CEQ RootOrCurrentColumn 'MSSQL
_rhsCol -> NonEmpty Error -> ReaderT EntityAlias FromIr Expression
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (Error -> NonEmpty Error
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OpExpG 'MSSQL Expression -> Error
UnsupportedOpExpG OpExpG 'MSSQL Expression
op)) -- S.BECompare S.SEQ lhs $ mkQCol rhsCol
    IR.CNE RootOrCurrentColumn 'MSSQL
_rhsCol -> NonEmpty Error -> ReaderT EntityAlias FromIr Expression
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (Error -> NonEmpty Error
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OpExpG 'MSSQL Expression -> Error
UnsupportedOpExpG OpExpG 'MSSQL Expression
op)) -- S.BECompare S.SNE lhs $ mkQCol rhsCol
    IR.CGT RootOrCurrentColumn 'MSSQL
_rhsCol -> NonEmpty Error -> ReaderT EntityAlias FromIr Expression
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (Error -> NonEmpty Error
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OpExpG 'MSSQL Expression -> Error
UnsupportedOpExpG OpExpG 'MSSQL Expression
op)) -- S.BECompare S.SGT lhs $ mkQCol rhsCol
    IR.CLT RootOrCurrentColumn 'MSSQL
_rhsCol -> NonEmpty Error -> ReaderT EntityAlias FromIr Expression
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (Error -> NonEmpty Error
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OpExpG 'MSSQL Expression -> Error
UnsupportedOpExpG OpExpG 'MSSQL Expression
op)) -- S.BECompare S.SLT lhs $ mkQCol rhsCol
    IR.CGTE RootOrCurrentColumn 'MSSQL
_rhsCol -> NonEmpty Error -> ReaderT EntityAlias FromIr Expression
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (Error -> NonEmpty Error
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OpExpG 'MSSQL Expression -> Error
UnsupportedOpExpG OpExpG 'MSSQL Expression
op)) -- S.BECompare S.SGTE lhs $ mkQCol rhsCol
    IR.CLTE RootOrCurrentColumn 'MSSQL
_rhsCol -> NonEmpty Error -> ReaderT EntityAlias FromIr Expression
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (Error -> NonEmpty Error
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OpExpG 'MSSQL Expression -> Error
UnsupportedOpExpG OpExpG 'MSSQL Expression
op)) -- S.BECompare S.SLTE lhs $ mkQCol rhsCol

nullableBoolEquality :: Expression -> Expression -> Expression
nullableBoolEquality :: Expression -> Expression -> Expression
nullableBoolEquality Expression
x Expression
y =
  [Expression] -> Expression
OrExpression
    [ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.EQ' Expression
x Expression
y,
      [Expression] -> Expression
AndExpression [Expression -> Expression
IsNullExpression Expression
x, Expression -> Expression
IsNullExpression Expression
y]
    ]

nullableBoolInequality :: Expression -> Expression -> Expression
nullableBoolInequality :: Expression -> Expression -> Expression
nullableBoolInequality Expression
x Expression
y =
  [Expression] -> Expression
OrExpression
    [ Op -> Expression -> Expression -> Expression
OpExpression Op
TSQL.NEQ' Expression
x Expression
y,
      [Expression] -> Expression
AndExpression [Expression -> Expression
IsNotNullExpression Expression
x, Expression -> Expression
IsNullExpression Expression
y]
    ]

aliasQualifiedTable :: TableName -> FromIr From
aliasQualifiedTable :: TableName -> FromIr From
aliasQualifiedTable schemadTableName :: TableName
schemadTableName@(TableName {Text
$sel:tableName:TableName :: TableName -> Text
tableName :: Text
tableName}) = do
  Text
alias <- NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
TableTemplate Text
tableName)
  From -> FromIr From
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    ( Aliased TableName -> From
FromQualifiedTable
        ( Aliased :: forall a. a -> Text -> Aliased a
Aliased
            { $sel:aliasedThing:Aliased :: TableName
aliasedThing = TableName
schemadTableName,
              $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
alias
            }
        )
    )