{-# LANGUAGE DataKinds #-}

module Database.Esqueleto.Postgis.Spatial
  ( st_contains
  , st_intersects
  , st_within
  , st_touches
  , st_crosses
  , st_disjoint
  , st_equals
  , st_covers
  , st_coveredby
  , st_overlaps
  , st_containsproperly
  , st_3dintersects
  , st_relate
  , st_orderingequals
  , st_dfullywithin
  , st_pointinsidecircle
  ) where

import Database.Esqueleto.Postgis.Geometry (Postgis, SpatialType(..))
import Database.Esqueleto.Experimental (SqlExpr, Value)
import Database.Esqueleto.Internal.Internal (unsafeSqlFunction)
import Data.Text (Text)

-- | Returns TRUE if geometry A contains geometry B.
--   https://postgis.net/docs/ST_Contains.html
st_contains ::
  -- | geom a
  SqlExpr (Value (Postgis 'Geometry a)) ->
  -- | geom b
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_contains :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_contains SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_CONTAINS" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns true if two geometries intersect.
--   Geometries intersect if they have any point in common.
--   https://postgis.net/docs/ST_Intersects.html
st_intersects ::
  SqlExpr (Value (Postgis spatialType a)) -> -- ^ geomA or geogA
  SqlExpr (Value (Postgis spatialType a)) -> -- ^ geomB or geogB
  SqlExpr (Value Bool)
st_intersects :: forall (spatialType :: SpatialType) a.
SqlExpr (Value (Postgis spatialType a))
-> SqlExpr (Value (Postgis spatialType a)) -> SqlExpr (Value Bool)
st_intersects SqlExpr (Value (Postgis spatialType a))
a SqlExpr (Value (Postgis spatialType a))
b = Builder
-> (SqlExpr (Value (Postgis spatialType a)),
    SqlExpr (Value (Postgis spatialType a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Intersects" (SqlExpr (Value (Postgis spatialType a))
a, SqlExpr (Value (Postgis spatialType a))
b)

-- | Returns TRUE if geometry A is within geometry B.
--   Tests if every point of A lies inside (interior or boundary of) B.
--   The inverse of 'st_contains': @st_within a b == st_contains b a@.
--   https://postgis.net/docs/ST_Within.html
st_within ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_within :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_within SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Within" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if geometry A touches geometry B.
--   They have at least one boundary point in common, but no interior points.
--   https://postgis.net/docs/ST_Touches.html
st_touches ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_touches :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_touches SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Touches" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if geometry A crosses geometry B.
--   They have some but not all interior points in common.
--   https://postgis.net/docs/ST_Crosses.html
st_crosses ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_crosses :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_crosses SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Crosses" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if geometry A is disjoint from geometry B.
--   They do not share any space together, the inverse of 'st_intersects'.
--   https://postgis.net/docs/ST_Disjoint.html
st_disjoint ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_disjoint :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_disjoint SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Disjoint" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if geometry A is spatially equal to geometry B.
--   The geometries represent the same region of space regardless of vertex order.
--   https://postgis.net/docs/ST_Equals.html
st_equals ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_equals :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_equals SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Equals" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if geometry/geography A covers geometry/geography B.
--   No point in B is outside A. Similar to 'st_contains' but does not distinguish boundary and interior.
--   https://postgis.net/docs/ST_Covers.html
st_covers ::
  SqlExpr (Value (Postgis spatialType a)) ->
  SqlExpr (Value (Postgis spatialType a)) ->
  SqlExpr (Value Bool)
st_covers :: forall (spatialType :: SpatialType) a.
SqlExpr (Value (Postgis spatialType a))
-> SqlExpr (Value (Postgis spatialType a)) -> SqlExpr (Value Bool)
st_covers SqlExpr (Value (Postgis spatialType a))
a SqlExpr (Value (Postgis spatialType a))
b = Builder
-> (SqlExpr (Value (Postgis spatialType a)),
    SqlExpr (Value (Postgis spatialType a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Covers" (SqlExpr (Value (Postgis spatialType a))
a, SqlExpr (Value (Postgis spatialType a))
b)

-- | Returns TRUE if geometry/geography A is covered by geometry/geography B.
--   No point in A is outside B. The inverse of 'st_covers'.
--   https://postgis.net/docs/ST_CoveredBy.html
st_coveredby ::
  SqlExpr (Value (Postgis spatialType a)) ->
  SqlExpr (Value (Postgis spatialType a)) ->
  SqlExpr (Value Bool)
st_coveredby :: forall (spatialType :: SpatialType) a.
SqlExpr (Value (Postgis spatialType a))
-> SqlExpr (Value (Postgis spatialType a)) -> SqlExpr (Value Bool)
st_coveredby SqlExpr (Value (Postgis spatialType a))
a SqlExpr (Value (Postgis spatialType a))
b = Builder
-> (SqlExpr (Value (Postgis spatialType a)),
    SqlExpr (Value (Postgis spatialType a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_CoveredBy" (SqlExpr (Value (Postgis spatialType a))
a, SqlExpr (Value (Postgis spatialType a))
b)

-- | Returns TRUE if geometry A overlaps geometry B.
--   They share some space but neither contains the other entirely.
--   https://postgis.net/docs/ST_Overlaps.html
st_overlaps ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_overlaps :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_overlaps SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Overlaps" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if geometry A contains geometry B properly.
--   B must lie entirely inside the interior of A (not touching the boundary).
--   https://postgis.net/docs/ST_ContainsProperly.html
st_containsproperly ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_containsproperly :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_containsproperly SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_ContainsProperly" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if two 3D geometries intersect.
--   https://postgis.net/docs/ST_3DIntersects.html
st_3dintersects ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_3dintersects :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_3dintersects SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_3DIntersects" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns the DE-9IM intersection matrix string for two geometries.
--   https://postgis.net/docs/ST_Relate.html
st_relate ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Text)
st_relate :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Text)
st_relate SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Text)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_Relate" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if two geometries are point-by-point equal in the same order.
--   https://postgis.net/docs/ST_OrderingEquals.html
st_orderingequals ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Bool)
st_orderingequals :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a)) -> SqlExpr (Value Bool)
st_orderingequals SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_OrderingEquals" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b)

-- | Returns TRUE if all of the geometries are within the specified distance of one another.
--   https://postgis.net/docs/ST_DFullyWithin.html
st_dfullywithin ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Double) ->
  SqlExpr (Value Bool)
st_dfullywithin :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value Double)
-> SqlExpr (Value Bool)
st_dfullywithin SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value (Postgis 'Geometry a))
b SqlExpr (Value Double)
d = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)),
    SqlExpr (Value (Postgis 'Geometry a)), SqlExpr (Value Double))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_DFullyWithin" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value (Postgis 'Geometry a))
b, SqlExpr (Value Double)
d)

-- | Returns TRUE if the point geometry is inside the circle defined by center_x, center_y and radius.
--   https://postgis.net/docs/ST_PointInsideCircle.html
st_pointinsidecircle ::
  SqlExpr (Value (Postgis 'Geometry a)) ->
  SqlExpr (Value Double) -> -- ^ center_x
  SqlExpr (Value Double) -> -- ^ center_y
  SqlExpr (Value Double) -> -- ^ radius
  SqlExpr (Value Bool)
st_pointinsidecircle :: forall a.
SqlExpr (Value (Postgis 'Geometry a))
-> SqlExpr (Value Double)
-> SqlExpr (Value Double)
-> SqlExpr (Value Double)
-> SqlExpr (Value Bool)
st_pointinsidecircle SqlExpr (Value (Postgis 'Geometry a))
a SqlExpr (Value Double)
cx SqlExpr (Value Double)
cy SqlExpr (Value Double)
r = Builder
-> (SqlExpr (Value (Postgis 'Geometry a)), SqlExpr (Value Double),
    SqlExpr (Value Double), SqlExpr (Value Double))
-> SqlExpr (Value Bool)
forall a b.
UnsafeSqlFunctionArgument a =>
Builder -> a -> SqlExpr (Value b)
unsafeSqlFunction Builder
"ST_PointInsideCircle" (SqlExpr (Value (Postgis 'Geometry a))
a, SqlExpr (Value Double)
cx, SqlExpr (Value Double)
cy, SqlExpr (Value Double)
r)