mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-17 20:41:49 +03:00
459a7adbfb
While it looks like a lot of work in FromIr.hs, you can rather review the type changes in `Hasura.Backends.MySQL.Types.Internal` and the changes to FromIr are only to reflect that. Essentially we're simplifying the FromIr code to not think about SQL-based joins: instead, FromIr produces fields necessary for the dataloader Plan/Execute to do their job properly. I've done my best to ensure that all the hunks in the diff in this PR are minimal for slightly easier perusing. I think future PRs will be more intentionally well structured, rather than created retroactively. **Preceding PR:** #2549 **Next PR**: #2367 The tests have been run like this on my machine. I don't know more beyond that. ``` docker run -i -e "PYTEST_ADDOPTS=--color=yes" -e "TERM=xterm-256color" --net=host -v`pwd`:`pwd` -w`pwd`/server/tests-py chrisdone/hasura-pytest:b0f26f615 pytest --hge-urls="http://localhost:8080" --pg-urls="postgres://chinook:chinook@localhost:5432/chinook" --backend mysql -k MySQL ``` PR-URL: https://github.com/hasura/graphql-engine-mono/pull/2608 Co-authored-by: Abby Sassel <3883855+sassela@users.noreply.github.com> GitOrigin-RevId: a6483335c3036963360dde7d7d7eaf10859351cb
68 lines
2.3 KiB
Haskell
68 lines
2.3 KiB
Haskell
-- | Planning MySQL queries and subscriptions.
|
|
module Hasura.Backends.MySQL.Plan
|
|
( planQuery,
|
|
queryToActionForest,
|
|
)
|
|
where
|
|
|
|
import Control.Monad.Validate
|
|
import Data.Aeson qualified as J
|
|
import Data.ByteString.Lazy (toStrict)
|
|
import Data.Text.Extended
|
|
import Data.Tree
|
|
import Hasura.Backends.MySQL.DataLoader.Plan qualified as DataLoader
|
|
import Hasura.Backends.MySQL.FromIr
|
|
import Hasura.Backends.MySQL.Types
|
|
import Hasura.Base.Error
|
|
import Hasura.GraphQL.Parser qualified as GraphQL
|
|
import Hasura.Prelude hiding (first)
|
|
import Hasura.RQL.IR
|
|
import Hasura.RQL.Types.Column qualified as RQL
|
|
import Hasura.SQL.Backend
|
|
import Hasura.Session
|
|
|
|
-- | Plan the query and then produce a forest of actions for the executor.
|
|
queryToActionForest ::
|
|
MonadError QErr m =>
|
|
UserInfo ->
|
|
QueryDB 'MySQL (Const Void) (GraphQL.UnpreparedValue 'MySQL) ->
|
|
m (DataLoader.HeadAndTail, Forest DataLoader.PlannedAction)
|
|
queryToActionForest userInfo qrf = do
|
|
select <- planQuery (_uiSession userInfo) qrf
|
|
let (!headAndTail, !plannedActionsList) =
|
|
DataLoader.runPlan
|
|
(DataLoader.planSelectHeadAndTail Nothing Nothing select)
|
|
!actionsForest = DataLoader.actionsForest id plannedActionsList
|
|
pure (headAndTail, actionsForest)
|
|
|
|
planQuery ::
|
|
MonadError QErr m =>
|
|
SessionVariables ->
|
|
QueryDB 'MySQL (Const Void) (GraphQL.UnpreparedValue 'MySQL) ->
|
|
m Select
|
|
planQuery sessionVariables queryDB = do
|
|
rootField <- traverse (prepareValueQuery sessionVariables) queryDB
|
|
sel <-
|
|
runValidate (runFromIr (fromRootField rootField))
|
|
`onLeft` (throw400 NotSupported . tshow)
|
|
pure $
|
|
sel
|
|
|
|
-- | Prepare a value without any query planning; we just execute the
|
|
-- query with the values embedded.
|
|
prepareValueQuery ::
|
|
MonadError QErr m =>
|
|
SessionVariables ->
|
|
GraphQL.UnpreparedValue 'MySQL ->
|
|
m Expression
|
|
prepareValueQuery sessionVariables =
|
|
\case
|
|
GraphQL.UVLiteral x -> pure x
|
|
GraphQL.UVSession -> pure $ ValueExpression $ BinaryValue $ toStrict $ J.encode sessionVariables
|
|
GraphQL.UVParameter _ RQL.ColumnValue {..} -> pure $ ValueExpression cvValue
|
|
GraphQL.UVSessionVar _typ sessionVariable -> do
|
|
value <-
|
|
getSessionVariableValue sessionVariable sessionVariables
|
|
`onNothing` throw400 NotFound ("missing session variable: " <>> sessionVariable)
|
|
pure $ ValueExpression $ TextValue value
|