Skip to content

Commit ce9912f

Browse files
codingkarthikhasura-bot
authored andcommitted
server: run_sql to not drop the SQL triggers created by the graphql-engine
PR-URL: hasura/graphql-engine-mono#4397 GitOrigin-RevId: dcd43fc31f64af8c6c9c92c66d46a593d5b12fbd
1 parent 8a03aba commit ce9912f

6 files changed

Lines changed: 409 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Bug fixes and improvements
66

7+
- server: don't drop the SQL triggers defined by the graphql-engine when DDL changes are made using the `run_sql` API
78
- server: fixed a bug where timestamp values sent to postgres would erroneously trim leading zeroes (#8096)
89
- server: fix bug when event triggers where defined on tables that contained non lower-case alphabet characters
910
- server: avoid encoding 'varchar' values to UTF8 in MSSQL backends

server/graphql-engine.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,7 @@ test-suite tests-hspec
10181018
, http-client-tls
10191019
, http-conduit
10201020
, http-types
1021+
, HUnit
10211022
, insert-ordered-containers
10221023
, jose
10231024
, kan-extensions
@@ -1081,6 +1082,7 @@ test-suite tests-hspec
10811082
Harness.Http
10821083
Harness.RemoteServer
10831084
Harness.TestEnvironment
1085+
Harness.Webhook
10841086
Harness.Yaml
10851087

10861088
-- Harness.Backend
@@ -1106,6 +1108,7 @@ test-suite tests-hspec
11061108
Test.ColumnPresetsSpec
11071109
Test.CustomFieldNamesSpec
11081110
Test.DirectivesSpec
1111+
Test.EventTriggersRunSQLSpec
11091112
Test.HelloWorldSpec
11101113
Test.InsertCheckPermissionSpec
11111114
Test.InsertEnumColumnSpec

server/src-lib/Hasura/Backends/Postgres/DDL/RunSQL.hs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,8 @@ withMetadataCheck ::
229229
withMetadataCheck source cascade txAccess runSQLQuery = do
230230
SourceInfo _ tableCache functionCache sourceConfig _ _ <- askSourceInfo @('Postgres pgKind) source
231231

232-
let dropTriggersAndRunSQL = do
233-
-- We need to drop existing event triggers so that no interference is caused to the sql query execution
234-
dropExistingEventTriggers tableCache
235-
runSQLQuery
236-
237232
-- Run SQL query and metadata checker in a transaction
238-
(queryResult, metadataUpdater) <- runTxWithMetadataCheck source sourceConfig txAccess tableCache functionCache cascade dropTriggersAndRunSQL
233+
(queryResult, metadataUpdater) <- runTxWithMetadataCheck source sourceConfig txAccess tableCache functionCache cascade runSQLQuery
239234

240235
-- Build schema cache with updated metadata
241236
withNewInconsistentObjsCheck $
@@ -248,12 +243,6 @@ withMetadataCheck source cascade txAccess runSQLQuery = do
248243

249244
pure queryResult
250245
where
251-
dropExistingEventTriggers :: TableCache ('Postgres pgKind) -> Q.TxET QErr m ()
252-
dropExistingEventTriggers tableCache =
253-
forM_ (M.elems tableCache) $ \tableInfo -> do
254-
let eventTriggers = _tiEventTriggerInfoMap tableInfo
255-
forM_ (M.keys eventTriggers) (liftTx . dropTriggerQ)
256-
257246
recreateEventTriggers :: PGSourceConfig -> SchemaCache -> m ()
258247
recreateEventTriggers sourceConfig schemaCache = do
259248
let tables = fromMaybe mempty $ unsafeTableCache @('Postgres pgKind) source $ scSources schemaCache

server/tests-hspec/Harness/Http.hs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
-- | Helper functions for HTTP requests.
22
module Harness.Http
33
( get_,
4+
post,
45
postValue,
56
postValueWithStatus,
67
healthCheck,
@@ -36,15 +37,19 @@ get_ url = do
3637
postValue :: HasCallStack => String -> Http.RequestHeaders -> Value -> IO Value
3738
postValue = postValueWithStatus 200
3839

39-
-- | Post the JSON to the given URL and expected HTTP response code.
40-
-- Produces a very descriptive exception or failure.
41-
postValueWithStatus :: HasCallStack => Int -> String -> Http.RequestHeaders -> Value -> IO Value
42-
postValueWithStatus statusCode url headers value = do
40+
post :: String -> Http.RequestHeaders -> Value -> IO (Http.Response L8.ByteString)
41+
post url headers value = do
4342
let request =
4443
Http.setRequestHeaders headers $
4544
Http.setRequestMethod Http.methodPost $
4645
Http.setRequestBodyJSON value (fromString url)
47-
response <- Http.httpLbs request
46+
Http.httpLbs request
47+
48+
-- | Post the JSON to the given URL and expected HTTP response code.
49+
-- Produces a very descriptive exception or failure.
50+
postValueWithStatus :: HasCallStack => Int -> String -> Http.RequestHeaders -> Value -> IO Value
51+
postValueWithStatus statusCode url headers value = do
52+
response <- post url headers value
4853
let requestBodyString = L8.unpack $ encode value
4954
responseBodyString = L8.unpack $ Http.getResponseBody response
5055
responseStatusCode = Http.getResponseStatusCode response
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
-- | Functions to setup and run a dedicated webhook server
2+
module Harness.Webhook
3+
( run,
4+
EventsQueue (..),
5+
)
6+
where
7+
8+
import Control.Concurrent (forkIO)
9+
import Control.Concurrent.Chan qualified as Chan
10+
import Control.Exception.Safe (bracket)
11+
import Control.Monad.IO.Class (liftIO)
12+
import Data.Aeson qualified as Aeson
13+
import Data.Parser.JSONPath (parseJSONPath)
14+
import Harness.Http qualified as Http
15+
import Harness.TestEnvironment (Server (..), serverUrl)
16+
import Hasura.Base.Error (iResultToMaybe)
17+
import Hasura.Prelude (fromMaybe)
18+
import Hasura.Server.Utils (executeJSONPath)
19+
import Network.Socket qualified as Socket
20+
import Network.Wai.Extended qualified as Wai
21+
import Network.Wai.Handler.Warp qualified as Warp
22+
import Web.Spock.Core qualified as Spock
23+
import Prelude
24+
25+
newtype EventsQueue = EventsQueue (Chan.Chan Aeson.Value)
26+
27+
-- | This function starts a new thread with a minimal server on the
28+
-- first available port. It returns the corresponding 'Server'.
29+
--
30+
-- This new server serves the following routes:
31+
-- - GET on @/@, which returns a simple 200 OK;
32+
-- - POST on @/echo@, which extracts the event data from the body
33+
-- of the request and inserts it into the `EventsQueue`.
34+
--
35+
-- This function performs a health check, using a GET on /, to ensure that the
36+
-- server was started correctly, and will throw an exception if the health check
37+
-- fails. This function does NOT attempt to kill the thread in such a case,
38+
-- which might result in a leak if the thread is still running but the server
39+
-- fails its health check.
40+
run :: IO (Server, EventsQueue)
41+
run = do
42+
let urlPrefix = "http://127.0.0.1"
43+
port <- bracket (Warp.openFreePort) (Socket.close . snd) (pure . fst)
44+
eventsQueueChan <- Chan.newChan
45+
let eventsQueue = EventsQueue eventsQueueChan
46+
threadId <- forkIO $
47+
Spock.runSpockNoBanner port $
48+
Spock.spockT id $ do
49+
Spock.get "/" $
50+
Spock.json $ Aeson.String "OK"
51+
Spock.post "/echo" $ do
52+
req <- Spock.request
53+
body <- liftIO $ Wai.strictRequestBody req
54+
let jsonBody = Aeson.decode body
55+
let eventDataPayload =
56+
-- Only extract the data payload from the request body
57+
let mkJSONPathE = either error id . parseJSONPath
58+
eventJSONPath = mkJSONPathE "$.event.data"
59+
in iResultToMaybe =<< executeJSONPath eventJSONPath <$> jsonBody
60+
liftIO $
61+
Chan.writeChan eventsQueueChan $
62+
fromMaybe (error "error in parsing the event data from the body") eventDataPayload
63+
Spock.setHeader "Content-Type" "application/json; charset=utf-8"
64+
Spock.json $ Aeson.object ["success" Aeson..= True]
65+
let server = Server {port = fromIntegral port, urlPrefix, threadId}
66+
Http.healthCheck $ serverUrl server
67+
pure (server, eventsQueue)

0 commit comments

Comments
 (0)