diff --git a/postgrest.cabal b/postgrest.cabal index 749cf7963..1663009dd 100644 --- a/postgrest.cabal +++ b/postgrest.cabal @@ -62,9 +62,11 @@ library PostgREST.RangeQuery PostgREST.Request.ApiRequest PostgREST.Request.DbRequestBuilder + PostgREST.Request.MutateQuery PostgREST.Request.Preferences - PostgREST.Request.Types PostgREST.Request.QueryParams + PostgREST.Request.ReadQuery + PostgREST.Request.Types PostgREST.Version PostgREST.Workers other-modules: Paths_postgrest diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index a3f79e905..afd97fdf5 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -82,7 +82,7 @@ import PostgREST.Request.Preferences (PreferCount (..), PreferRepresentation (..), toAppliedHeader) import PostgREST.Request.QueryParams (QueryParams (..)) -import PostgREST.Request.Types (ReadRequest, fstFieldNames) +import PostgREST.Request.ReadQuery (ReadRequest, fstFieldNames) import PostgREST.Version (prettyVersion) import PostgREST.Workers (connectionWorker, listener) diff --git a/src/PostgREST/Query/QueryBuilder.hs b/src/PostgREST/Query/QueryBuilder.hs index 0c794cf71..a114892c8 100644 --- a/src/PostgREST/Query/QueryBuilder.hs +++ b/src/PostgREST/Query/QueryBuilder.hs @@ -28,7 +28,9 @@ import PostgREST.DbStructure.Relationship (Cardinality (..), import PostgREST.Request.Preferences (PreferResolution (..)) import PostgREST.Query.SqlFragment -import PostgREST.RangeQuery (allRange) +import PostgREST.RangeQuery (allRange) +import PostgREST.Request.MutateQuery +import PostgREST.Request.ReadQuery import PostgREST.Request.Types import Protolude diff --git a/src/PostgREST/Query/SqlFragment.hs b/src/PostgREST/Query/SqlFragment.hs index 2ca2e0b99..bff595d90 100644 --- a/src/PostgREST/Query/SqlFragment.hs +++ b/src/PostgREST/Query/SqlFragment.hs @@ -50,6 +50,7 @@ import PostgREST.DbStructure.Identifiers (FieldName, QualifiedIdentifier (..)) import PostgREST.RangeQuery (NonnegRange, allRange, rangeLimit, rangeOffset) +import PostgREST.Request.ReadQuery (SelectItem) import PostgREST.Request.Types (Alias, Field, Filter (..), FtsOperator (..), JoinCondition (..), @@ -61,7 +62,7 @@ import PostgREST.Request.Types (Alias, Field, Filter (..), Operation (..), OrderDirection (..), OrderNulls (..), - OrderTerm (..), SelectItem, + OrderTerm (..), SimpleOperator (..), TrileanVal (..)) diff --git a/src/PostgREST/Request/DbRequestBuilder.hs b/src/PostgREST/Request/DbRequestBuilder.hs index 2ac728c8d..9e9c663f1 100644 --- a/src/PostgREST/Request/DbRequestBuilder.hs +++ b/src/PostgREST/Request/DbRequestBuilder.hs @@ -48,7 +48,9 @@ import PostgREST.Request.ApiRequest (Action (..), Mutation (..), Payload (..)) +import PostgREST.Request.MutateQuery import PostgREST.Request.Preferences +import PostgREST.Request.ReadQuery as ReadQuery import PostgREST.Request.Types import qualified PostgREST.Request.QueryParams as QueryParams @@ -263,7 +265,7 @@ addFilters ApiRequest{..} rReq = addFilterToNode :: (EmbedPath, Filter) -> Either ApiRequestError ReadRequest -> Either ApiRequestError ReadRequest addFilterToNode = - updateNode (\flt (Node (q@Select {where_=lf}, i) f) -> Node (q{where_=addFilterToLogicForest flt lf}::ReadQuery, i) f) + updateNode (\flt (Node (q@Select {where_=lf}, i) f) -> Node (q{ReadQuery.where_=addFilterToLogicForest flt lf}, i) f) addOrders :: ApiRequest -> ReadRequest -> Either ApiRequestError ReadRequest addOrders ApiRequest{..} rReq = @@ -295,7 +297,7 @@ addLogicTrees ApiRequest{..} rReq = QueryParams.QueryParams{..} = iQueryParams addLogicTreeToNode :: (EmbedPath, LogicTree) -> Either ApiRequestError ReadRequest -> Either ApiRequestError ReadRequest - addLogicTreeToNode = updateNode (\t (Node (q@Select{where_=lf},i) f) -> Node (q{where_=t:lf}::ReadQuery, i) f) + addLogicTreeToNode = updateNode (\t (Node (q@Select{where_=lf},i) f) -> Node (q{ReadQuery.where_=t:lf}, i) f) -- Find a Node of the Tree and apply a function to it updateNode :: (a -> ReadRequest -> ReadRequest) -> (EmbedPath, a) -> Either ApiRequestError ReadRequest -> Either ApiRequestError ReadRequest diff --git a/src/PostgREST/Request/MutateQuery.hs b/src/PostgREST/Request/MutateQuery.hs new file mode 100644 index 000000000..cf0e62638 --- /dev/null +++ b/src/PostgREST/Request/MutateQuery.hs @@ -0,0 +1,45 @@ +module PostgREST.Request.MutateQuery + ( MutateQuery(..) + , MutateRequest + ) +where + +import qualified Data.ByteString.Lazy as LBS +import qualified Data.Set as S + +import PostgREST.DbStructure.Identifiers (FieldName, + QualifiedIdentifier) +import PostgREST.RangeQuery (NonnegRange) +import PostgREST.Request.Preferences (PreferResolution) +import PostgREST.Request.Types (LogicTree, OrderTerm) + +import Protolude + +type MutateRequest = MutateQuery + +data MutateQuery + = Insert + { in_ :: QualifiedIdentifier + , insCols :: S.Set FieldName + , insBody :: Maybe LBS.ByteString + , onConflict :: Maybe (PreferResolution, [FieldName]) + , where_ :: [LogicTree] + , returning :: [FieldName] + } + | Update + { in_ :: QualifiedIdentifier + , updCols :: S.Set FieldName + , updBody :: Maybe LBS.ByteString + , where_ :: [LogicTree] + , pkFilters :: [FieldName] + , mutRange :: NonnegRange + , mutOrder :: [OrderTerm] + , returning :: [FieldName] + } + | Delete + { in_ :: QualifiedIdentifier + , where_ :: [LogicTree] + , mutRange :: NonnegRange + , mutOrder :: [OrderTerm] + , returning :: [FieldName] + } diff --git a/src/PostgREST/Request/QueryParams.hs b/src/PostgREST/Request/QueryParams.hs index d7cb2ed17..f985b398a 100644 --- a/src/PostgREST/Request/QueryParams.hs +++ b/src/PostgREST/Request/QueryParams.hs @@ -44,16 +44,18 @@ import PostgREST.RangeQuery (NonnegRange, allRange, rangeGeq, rangeLimit, rangeOffset, restrictRange) -import PostgREST.Request.Types (EmbedParam (..), EmbedPath, Field, - Filter (..), FtsOperator (..), - JoinType (..), JsonOperand (..), - JsonOperation (..), JsonPath, ListVal, - LogicOperator (..), LogicTree (..), - OpExpr (..), Operation (..), - OrderDirection (..), OrderNulls (..), - OrderTerm (..), QPError (..), - SelectItem, SimpleOperator (..), - SingleVal, TrileanVal (..)) +import PostgREST.Request.ReadQuery (SelectItem) +import PostgREST.Request.Types (EmbedParam (..), EmbedPath, Field, + Filter (..), FtsOperator (..), + JoinType (..), JsonOperand (..), + JsonOperation (..), JsonPath, + ListVal, LogicOperator (..), + LogicTree (..), OpExpr (..), + Operation (..), + OrderDirection (..), + OrderNulls (..), OrderTerm (..), + QPError (..), SimpleOperator (..), + SingleVal, TrileanVal (..)) import Protolude hiding (try) diff --git a/src/PostgREST/Request/ReadQuery.hs b/src/PostgREST/Request/ReadQuery.hs new file mode 100644 index 000000000..8cdf3d4c3 --- /dev/null +++ b/src/PostgREST/Request/ReadQuery.hs @@ -0,0 +1,48 @@ +module PostgREST.Request.ReadQuery + ( ReadNode + , ReadQuery(..) + , ReadRequest + , SelectItem + , fstFieldNames + ) where + +import Data.Tree (Tree (..)) + +import PostgREST.DbStructure.Identifiers (FieldName, + QualifiedIdentifier) +import PostgREST.DbStructure.Relationship (Relationship) +import PostgREST.RangeQuery (NonnegRange) +import PostgREST.Request.Types (Alias, Cast, Depth, Field, + Hint, JoinCondition, + JoinType, LogicTree, + NodeName, OrderTerm) + + +import Protolude + +type ReadRequest = Tree ReadNode + +type ReadNode = + (ReadQuery, (NodeName, Maybe Relationship, Maybe Alias, Maybe Hint, Maybe JoinType, Depth)) + +-- | The select value in `/tbl?select=alias:field::cast` +type SelectItem = (Field, Maybe Cast, Maybe Alias, Maybe Hint, Maybe JoinType) + +data ReadQuery = Select + { select :: [SelectItem] + , from :: QualifiedIdentifier + -- ^ A table alias is used in case of self joins + , fromAlias :: Maybe Alias + -- ^ Only used for Many to Many joins. Parent and Child joins use explicit joins. + , implicitJoins :: [QualifiedIdentifier] + , where_ :: [LogicTree] + , joinConditions :: [JoinCondition] + , order :: [OrderTerm] + , range_ :: NonnegRange + } + deriving (Eq) + +-- First level FieldNames(e.g get a,b from /table?select=a,b,other(c,d)) +fstFieldNames :: ReadRequest -> [FieldName] +fstFieldNames (Node (sel, _) _) = + fst . (\(f, _, _, _, _) -> f) <$> select sel diff --git a/src/PostgREST/Request/Types.hs b/src/PostgREST/Request/Types.hs index 315e9aeaa..16c076982 100644 --- a/src/PostgREST/Request/Types.hs +++ b/src/PostgREST/Request/Types.hs @@ -1,6 +1,7 @@ {-# LANGUAGE DuplicateRecordFields #-} module PostgREST.Request.Types ( Alias + , Cast , Depth , EmbedParam(..) , ApiRequestError(..) @@ -19,8 +20,6 @@ module PostgREST.Request.Types , ListVal , LogicOperator(..) , LogicTree(..) - , MutateQuery(..) - , MutateRequest , NodeName , OpExpr(..) , Operation (..) @@ -28,21 +27,13 @@ module PostgREST.Request.Types , OrderNulls(..) , OrderTerm(..) , QPError(..) - , ReadNode - , ReadQuery(..) - , ReadRequest - , SelectItem , SingleVal , TrileanVal(..) - , fstFieldNames , SimpleOperator(..) , FtsOperator(..) ) where import qualified Data.ByteString.Lazy as LBS -import qualified Data.Set as S - -import Data.Tree (Tree (..)) import PostgREST.ContentType (ContentType (..)) import PostgREST.DbStructure.Identifiers (FieldName, @@ -50,8 +41,6 @@ import PostgREST.DbStructure.Identifiers (FieldName, import PostgREST.DbStructure.Proc (ProcDescription (..), ProcParam (..)) import PostgREST.DbStructure.Relationship (Relationship) -import PostgREST.RangeQuery (NonnegRange) -import PostgREST.Request.Preferences (PreferResolution) import Protolude @@ -76,30 +65,11 @@ data ApiRequestError data QPError = QPError Text Text -type ReadRequest = Tree ReadNode -type MutateRequest = MutateQuery type CallRequest = CallQuery -type ReadNode = - (ReadQuery, (NodeName, Maybe Relationship, Maybe Alias, Maybe Hint, Maybe JoinType, Depth)) - type NodeName = Text type Depth = Integer -data ReadQuery = Select - { select :: [SelectItem] - , from :: QualifiedIdentifier - -- ^ A table alias is used in case of self joins - , fromAlias :: Maybe Alias - -- ^ Only used for Many to Many joins. Parent and Child joins use explicit joins. - , implicitJoins :: [QualifiedIdentifier] - , where_ :: [LogicTree] - , joinConditions :: [JoinCondition] - , order :: [OrderTerm] - , range_ :: NonnegRange - } - deriving (Eq) - data JoinCondition = JoinCondition (QualifiedIdentifier, FieldName) @@ -123,33 +93,6 @@ data OrderNulls | OrderNullsLast deriving (Eq) -data MutateQuery - = Insert - { in_ :: QualifiedIdentifier - , insCols :: S.Set FieldName - , insBody :: Maybe LBS.ByteString - , onConflict :: Maybe (PreferResolution, [FieldName]) - , where_ :: [LogicTree] - , returning :: [FieldName] - } - | Update - { in_ :: QualifiedIdentifier - , updCols :: S.Set FieldName - , updBody :: Maybe LBS.ByteString - , where_ :: [LogicTree] - , pkFilters :: [FieldName] - , mutRange :: NonnegRange - , mutOrder :: [OrderTerm] - , returning :: [FieldName] - } - | Delete - { in_ :: QualifiedIdentifier - , where_ :: [LogicTree] - , mutRange :: NonnegRange - , mutOrder :: [OrderTerm] - , returning :: [FieldName] - } - data CallQuery = FunctionCall { funCQi :: QualifiedIdentifier , funCParams :: CallParams @@ -163,9 +106,6 @@ data CallParams = KeyParams [ProcParam] -- ^ Call with key params: func(a := val1, b:= val2) | OnePosParam ProcParam -- ^ Call with positional params(only one supported): func(val) --- | The select value in `/tbl?select=alias:field::cast` -type SelectItem = (Field, Maybe Cast, Maybe Alias, Maybe Hint, Maybe JoinType) - type Field = (FieldName, JsonPath) type Cast = Text type Alias = Text @@ -205,12 +145,6 @@ data JsonOperand | JIdx { jVal :: Text } deriving (Eq) --- First level FieldNames(e.g get a,b from /table?select=a,b,other(c,d)) -fstFieldNames :: ReadRequest -> [FieldName] -fstFieldNames (Node (sel, _) _) = - fst . (\(f, _, _, _, _) -> f) <$> select sel - - -- | Boolean logic expression tree e.g. "and(name.eq.N,or(id.eq.1,id.eq.2))" is: -- -- And