Skip to content

Commit a7b43b1

Browse files
authored
agent: use strict tables (#1686)
* agent: use strict tables * migrate existing tables to strict * test: verify that all tables are strict * fix column types for device_token and ntf_mode * fix encodings and column types for ntf_sub_action and ntf_sub_smp_action * update schema * remove debug.trace * log
1 parent d6df769 commit a7b43b1

File tree

17 files changed

+269
-123
lines changed

17 files changed

+269
-123
lines changed

simplexmq.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ library
167167
Simplex.Messaging.Agent.Store.Postgres.Migrations.M20250702_conn_invitations_remove_cascade_delete
168168
Simplex.Messaging.Agent.Store.Postgres.Migrations.M20251009_queue_to_subscribe
169169
Simplex.Messaging.Agent.Store.Postgres.Migrations.M20251010_client_notices
170+
Simplex.Messaging.Agent.Store.Postgres.Migrations.M20251230_strict_tables
170171
else
171172
exposed-modules:
172173
Simplex.Messaging.Agent.Store.SQLite
@@ -216,6 +217,7 @@ library
216217
Simplex.Messaging.Agent.Store.SQLite.Migrations.M20250702_conn_invitations_remove_cascade_delete
217218
Simplex.Messaging.Agent.Store.SQLite.Migrations.M20251009_queue_to_subscribe
218219
Simplex.Messaging.Agent.Store.SQLite.Migrations.M20251010_client_notices
220+
Simplex.Messaging.Agent.Store.SQLite.Migrations.M20251230_strict_tables
219221
Simplex.Messaging.Agent.Store.SQLite.Util
220222
if flag(client_postgres) || flag(server_postgres)
221223
exposed-modules:

src/Simplex/Messaging/Agent/Client.hs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ import Simplex.Messaging.Agent.Stats
240240
import Simplex.Messaging.Agent.Store
241241
import Simplex.Messaging.Agent.Store.AgentStore (getClientNotices, updateClientNotices)
242242
import Simplex.Messaging.Agent.Store.Common (DBStore, withTransaction)
243+
import Simplex.Messaging.Agent.Store.DB (SQLError)
243244
import qualified Simplex.Messaging.Agent.Store.DB as DB
244245
import Simplex.Messaging.Agent.Store.Entity
245246
import Simplex.Messaging.Agent.TSessionSubs (TSessionSubs)
@@ -2124,7 +2125,9 @@ withWork_ c doWork getWork action =
21242125
| otherwise -> notifyErr INTERNAL e
21252126
where
21262127
noWork = liftIO $ noWorkToDo doWork
2127-
notifyErr err e = atomically $ writeTBQueue (subQ c) ("", "", AEvt SAEConn $ ERR $ err $ show e)
2128+
notifyErr err e = do
2129+
logError $ "withWork_ error: " <> tshow e
2130+
atomically $ writeTBQueue (subQ c) ("", "", AEvt SAEConn $ ERR $ err $ show e)
21282131

21292132
withWorkItems :: (AnyStoreError e', MonadIO m) => AgentClient -> TMVar () -> ExceptT e m (Either e' [Either e' a]) -> (NonEmpty a -> ExceptT e m ()) -> ExceptT e m ()
21302133
withWorkItems c doWork getWork action = do
@@ -2145,7 +2148,9 @@ withWorkItems c doWork getWork action = do
21452148
| otherwise -> notifyErr INTERNAL e
21462149
where
21472150
noWork = liftIO $ noWorkToDo doWork
2148-
notifyErr err e = atomically $ writeTBQueue (subQ c) ("", "", AEvt SAEConn $ ERR $ err $ show e)
2151+
notifyErr err e = do
2152+
logError $ "withWorkItems error: " <> tshow e
2153+
atomically $ writeTBQueue (subQ c) ("", "", AEvt SAEConn $ ERR $ err $ show e)
21492154

21502155
noWorkToDo :: TMVar () -> IO ()
21512156
noWorkToDo = void . atomically . tryTakeTMVar
@@ -2243,24 +2248,19 @@ withStore :: AgentClient -> (DB.Connection -> IO (Either StoreError a)) -> AM a
22432248
withStore c action = do
22442249
st <- asks store
22452250
withExceptT storeError . ExceptT . liftIO . agentOperationBracket c AODatabase (\_ -> pure ()) $
2246-
withTransaction st action `E.catches` handleDBErrors
2251+
withTransaction st action `E.catch` handleDBErrors
22472252
where
2253+
handleDBErrors :: E.SomeException -> IO (Either StoreError a)
2254+
handleDBErrors e = pure $ Left $ case E.fromException e of
2255+
Just (e' :: SQLError) ->
22482256
#if defined(dbPostgres)
2249-
-- TODO [postgres] postgres specific error handling
2250-
handleDBErrors :: [E.Handler IO (Either StoreError a)]
2251-
handleDBErrors =
2252-
[ E.Handler $ \(E.SomeException e) -> pure . Left $ SEInternal $ bshow e
2253-
]
2257+
SEInternal $ bshow e'
22542258
#else
2255-
handleDBErrors :: [E.Handler IO (Either StoreError a)]
2256-
handleDBErrors =
2257-
[ E.Handler $ \(e :: SQL.SQLError) ->
2258-
let se = SQL.sqlError e
2259-
busy = se == SQL.ErrorBusy || se == SQL.ErrorLocked
2260-
in pure . Left . (if busy then SEDatabaseBusy else SEInternal) $ bshow se,
2261-
E.Handler $ \(E.SomeException e) -> pure . Left $ SEInternal $ bshow e
2262-
]
2259+
let se = SQL.sqlError e'
2260+
busy = se == SQL.ErrorBusy || se == SQL.ErrorLocked
2261+
in (if busy then SEDatabaseBusy else SEInternal) $ bshow e'
22632262
#endif
2263+
Nothing -> SEInternal $ bshow e
22642264

22652265
unsafeWithStore :: AgentClient -> (DB.Connection -> IO a) -> AM' a
22662266
unsafeWithStore c action = do

src/Simplex/Messaging/Agent/NtfSubSupervisor.hs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import qualified Data.List.NonEmpty as L
3636
import qualified Data.Map.Strict as M
3737
import Data.Maybe (catMaybes)
3838
import qualified Data.Set as S
39+
import qualified Data.Text as T
3940
import Data.Time (UTCTime, addUTCTime, getCurrentTime)
4041
import Data.Time.Clock (diffUTCTime)
4142
import Simplex.Messaging.Agent.Client
@@ -46,13 +47,13 @@ import Simplex.Messaging.Agent.Stats
4647
import Simplex.Messaging.Agent.Store
4748
import Simplex.Messaging.Agent.Store.AgentStore
4849
import qualified Simplex.Messaging.Agent.Store.DB as DB
49-
import Simplex.Messaging.Client (NetworkRequestMode (..))
50+
import Simplex.Messaging.Client (NetworkRequestMode (..), nonBlockingWriteTBQueue)
5051
import qualified Simplex.Messaging.Crypto as C
5152
import Simplex.Messaging.Notifications.Protocol
5253
import Simplex.Messaging.Notifications.Types
5354
import Simplex.Messaging.Protocol (NtfServer, sameSrvAddr)
5455
import qualified Simplex.Messaging.Protocol as SMP
55-
import Simplex.Messaging.Util (catchAllErrors, diffToMicroseconds, threadDelay', tryAllErrors, tshow, whenM)
56+
import Simplex.Messaging.Util (catchAllErrors, catchAllErrors', diffToMicroseconds, threadDelay', tryAllErrors, tshow, whenM)
5657
import System.Random (randomR)
5758
import UnliftIO
5859
import UnliftIO.Concurrent (forkIO)
@@ -66,19 +67,15 @@ runNtfSupervisor c = do
6667
Right _ -> pure ()
6768
forever $ do
6869
cmd <- atomically . readTBQueue $ ntfSubQ ns
69-
handleErr . agentOperationBracket c AONtfNetwork waitUntilActive $
70-
runExceptT (processNtfCmd c cmd) >>= \case
71-
Left e -> notifyErr e
72-
Right _ -> return ()
70+
handleErr $ agentOperationBracket c AONtfNetwork waitUntilActive $
71+
processNtfCmd c cmd `catchAllErrors'` notifyErr
7372
where
7473
startTknDelete :: AM ()
7574
startTknDelete = do
7675
pendingDelServers <- withStore' c getPendingDelTknServers
7776
lift . forM_ pendingDelServers $ getNtfTknDelWorker True c
7877
handleErr :: AM' () -> AM' ()
79-
handleErr = E.handle $ \(e :: E.SomeException) -> do
80-
logError $ "runNtfSupervisor error " <> tshow e
81-
notifyErr e
78+
handleErr = E.handle $ \(e :: E.SomeException) -> notifyErr e
8279
notifyErr e = notifyInternalError' c $ "runNtfSupervisor error " <> show e
8380

8481
partitionErrs :: (a -> ConnId) -> [a] -> [Either AgentErrorType b] -> ([(ConnId, AgentErrorType)], [b])
@@ -505,16 +502,18 @@ workerInternalError c connId internalErrStr = do
505502

506503
-- TODO change error
507504
notifyInternalError :: MonadIO m => AgentClient -> ConnId -> String -> m ()
508-
notifyInternalError AgentClient {subQ} connId internalErrStr = atomically $ writeTBQueue subQ ("", connId, AEvt SAEConn $ ERR $ INTERNAL internalErrStr)
509-
{-# INLINE notifyInternalError #-}
505+
notifyInternalError AgentClient {subQ} connId internalErrStr = do
506+
logError $ T.pack internalErrStr
507+
liftIO $ nonBlockingWriteTBQueue subQ ("", connId, AEvt SAEConn $ ERR $ INTERNAL internalErrStr)
510508

511509
notifyInternalError' :: MonadIO m => AgentClient -> String -> m ()
512-
notifyInternalError' AgentClient {subQ} internalErrStr = atomically $ writeTBQueue subQ ("", "", AEvt SAEConn $ ERR $ INTERNAL internalErrStr)
510+
notifyInternalError' c = notifyInternalError c ""
513511
{-# INLINE notifyInternalError' #-}
514512

515513
notifyErrs :: MonadIO m => AgentClient -> [(ConnId, AgentErrorType)] -> m ()
516-
notifyErrs c = mapM_ (notifySub c . ERRS) . L.nonEmpty
517-
{-# INLINE notifyErrs #-}
514+
notifyErrs c errs_ = forM_ (L.nonEmpty errs_) $ \errs -> do
515+
logError $ "notifyErrs: " <> tshow errs
516+
notifySub c $ ERRS errs
518517

519518
getNtfToken :: AM' (Maybe NtfToken)
520519
getNtfToken = do

src/Simplex/Messaging/Agent/Protocol.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,9 +698,9 @@ instance ToJSON NotificationsMode where
698698
instance FromJSON NotificationsMode where
699699
parseJSON = strParseJSON "NotificationsMode"
700700

701-
instance ToField NotificationsMode where toField = toField . strEncode
701+
instance ToField NotificationsMode where toField = toField . decodeLatin1 . strEncode
702702

703-
instance FromField NotificationsMode where fromField = blobFieldDecoder $ parseAll strP
703+
instance FromField NotificationsMode where fromField = fromTextField_ $ eitherToMaybe . strDecode . encodeUtf8
704704

705705
data NotificationInfo = NotificationInfo
706706
{ ntfConnId :: ConnId,

src/Simplex/Messaging/Agent/Store.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
module Simplex.Messaging.Agent.Store where
1818

19-
import Control.Exception (Exception)
19+
import Control.Exception (Exception (..))
2020
import qualified Data.Attoparsec.ByteString.Char8 as A
2121
import Data.ByteString.Char8 (ByteString)
2222
import Data.Int (Int64)
@@ -31,6 +31,7 @@ import Simplex.Messaging.Agent.Protocol
3131
import Simplex.Messaging.Agent.RetryInterval (RI2State)
3232
import Simplex.Messaging.Agent.Store.Entity
3333
import Simplex.Messaging.Agent.Store.Common
34+
import Simplex.Messaging.Agent.Store.DB (SQLError)
3435
import Simplex.Messaging.Agent.Store.Interface (createDBStore)
3536
import Simplex.Messaging.Agent.Store.Migrations.App (appMigrations)
3637
import Simplex.Messaging.Agent.Store.Shared (MigrationConfig (..), MigrationError (..))
@@ -752,7 +753,9 @@ data StoreError
752753
deriving (Eq, Show, Exception)
753754

754755
instance AnyError StoreError where
755-
fromSomeException = SEInternal . bshow
756+
fromSomeException e = SEInternal $ case fromException e of
757+
Just (e' :: SQLError) -> bshow e'
758+
Nothing -> bshow e
756759

757760
class (Show e, AnyError e) => AnyStoreError e where
758761
isWorkItemError :: e -> Bool

src/Simplex/Messaging/Agent/Store/AgentStore.hs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ import Simplex.Messaging.Agent.Stats
285285
import Simplex.Messaging.Agent.Store
286286
import Simplex.Messaging.Agent.Store.Common
287287
import qualified Simplex.Messaging.Agent.Store.DB as DB
288-
import Simplex.Messaging.Agent.Store.DB (Binary (..), BoolInt (..), FromField (..), ToField (..), blobFieldDecoder, fromTextField_)
288+
import Simplex.Messaging.Agent.Store.DB (Binary (..), BoolInt (..), FromField (..), ToField (..), SQLError, blobFieldDecoder, fromTextField_)
289289
import Simplex.Messaging.Agent.Store.Entity
290290
import Simplex.Messaging.Client (SMPTransportSession)
291291
import qualified Simplex.Messaging.Crypto as C
@@ -308,25 +308,24 @@ import qualified UnliftIO.Exception as E
308308
import UnliftIO.STM
309309
#if defined(dbPostgres)
310310
import Data.List (sortOn)
311-
import Database.PostgreSQL.Simple (In (..), Only (..), Query, SqlError, (:.) (..))
311+
import Database.PostgreSQL.Simple (In (..), Only (..), Query, (:.) (..))
312312
import Database.PostgreSQL.Simple.Errors (constraintViolation)
313313
import Database.PostgreSQL.Simple.SqlQQ (sql)
314314
#else
315-
import Database.SQLite.Simple (FromRow (..), Only (..), Query (..), SQLError, ToRow (..), field, (:.) (..))
315+
import Database.SQLite.Simple (FromRow (..), Only (..), Query (..), ToRow (..), field, (:.) (..))
316316
import qualified Database.SQLite.Simple as SQL
317317
import Database.SQLite.Simple.QQ (sql)
318318
#endif
319319

320320
checkConstraint :: StoreError -> IO (Either StoreError a) -> IO (Either StoreError a)
321321
checkConstraint err action = action `E.catch` (pure . Left . handleSQLError err)
322322

323+
handleSQLError :: StoreError -> SQLError -> StoreError
323324
#if defined(dbPostgres)
324-
handleSQLError :: StoreError -> SqlError -> StoreError
325325
handleSQLError err e = case constraintViolation e of
326326
Just _ -> err
327327
Nothing -> SEInternal $ bshow e
328328
#else
329-
handleSQLError :: StoreError -> SQLError -> StoreError
330329
handleSQLError err e
331330
| SQL.sqlError e == SQL.ErrorConstraint = err
332331
| otherwise = SEInternal $ bshow e
@@ -1428,7 +1427,7 @@ createNtfToken db NtfToken {deviceToken = DeviceToken provider token, ntfServer
14281427
INSERT INTO ntf_tokens
14291428
(provider, device_token, ntf_host, ntf_port, tkn_id, tkn_pub_key, tkn_priv_key, tkn_pub_dh_key, tkn_priv_dh_key, tkn_dh_secret, tkn_status, tkn_action, ntf_mode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
14301429
|]
1431-
((provider, token, host, port, ntfTokenId, ntfPubKey, ntfPrivKey, ntfDhPubKey, ntfDhPrivKey, ntfDhSecret) :. (ntfTknStatus, ntfTknAction, ntfMode))
1430+
((provider, Binary token, host, port, ntfTokenId, ntfPubKey, ntfPrivKey, ntfDhPubKey, ntfDhPrivKey, ntfDhSecret) :. (ntfTknStatus, ntfTknAction, ntfMode))
14321431

14331432
getSavedNtfToken :: DB.Connection -> IO (Maybe NtfToken)
14341433
getSavedNtfToken db = do
@@ -1443,7 +1442,7 @@ getSavedNtfToken db = do
14431442
JOIN ntf_servers s USING (ntf_host, ntf_port)
14441443
|]
14451444
where
1446-
ntfToken ((host, port, keyHash) :. (provider, dt, ntfTokenId, ntfPubKey, ntfPrivKey, ntfDhPubKey, ntfDhPrivKey, ntfDhSecret) :. (ntfTknStatus, ntfTknAction, ntfMode_)) =
1445+
ntfToken ((host, port, keyHash) :. (provider, Binary dt, ntfTokenId, ntfPubKey, ntfPrivKey, ntfDhPubKey, ntfDhPrivKey, ntfDhSecret) :. (ntfTknStatus, ntfTknAction, ntfMode_)) =
14471446
let ntfServer = NtfServer host port keyHash
14481447
ntfDhKeys = (ntfDhPubKey, ntfDhPrivKey)
14491448
ntfMode = fromMaybe NMPeriodic ntfMode_
@@ -1459,7 +1458,7 @@ updateNtfTokenRegistration db NtfToken {deviceToken = DeviceToken provider token
14591458
SET tkn_id = ?, tkn_dh_secret = ?, tkn_status = ?, tkn_action = ?, updated_at = ?
14601459
WHERE provider = ? AND device_token = ? AND ntf_host = ? AND ntf_port = ?
14611460
|]
1462-
(tknId, ntfDhSecret, NTRegistered, Nothing :: Maybe NtfTknAction, updatedAt, provider, token, host, port)
1461+
(tknId, ntfDhSecret, NTRegistered, Nothing :: Maybe NtfTknAction, updatedAt, provider, Binary token, host, port)
14631462

14641463
updateDeviceToken :: DB.Connection -> NtfToken -> DeviceToken -> IO ()
14651464
updateDeviceToken db NtfToken {deviceToken = DeviceToken provider token, ntfServer = ProtocolServer {host, port}} (DeviceToken toProvider toToken) = do
@@ -1471,7 +1470,7 @@ updateDeviceToken db NtfToken {deviceToken = DeviceToken provider token, ntfServ
14711470
SET provider = ?, device_token = ?, tkn_status = ?, tkn_action = ?, updated_at = ?
14721471
WHERE provider = ? AND device_token = ? AND ntf_host = ? AND ntf_port = ?
14731472
|]
1474-
(toProvider, toToken, NTRegistered, Nothing :: Maybe NtfTknAction, updatedAt, provider, token, host, port)
1473+
(toProvider, Binary toToken, NTRegistered, Nothing :: Maybe NtfTknAction, updatedAt, provider, Binary token, host, port)
14751474

14761475
updateNtfMode :: DB.Connection -> NtfToken -> NotificationsMode -> IO ()
14771476
updateNtfMode db NtfToken {deviceToken = DeviceToken provider token, ntfServer = ProtocolServer {host, port}} ntfMode = do
@@ -1483,7 +1482,7 @@ updateNtfMode db NtfToken {deviceToken = DeviceToken provider token, ntfServer =
14831482
SET ntf_mode = ?, updated_at = ?
14841483
WHERE provider = ? AND device_token = ? AND ntf_host = ? AND ntf_port = ?
14851484
|]
1486-
(ntfMode, updatedAt, provider, token, host, port)
1485+
(ntfMode, updatedAt, provider, Binary token, host, port)
14871486

14881487
updateNtfToken :: DB.Connection -> NtfToken -> NtfTknStatus -> Maybe NtfTknAction -> IO ()
14891488
updateNtfToken db NtfToken {deviceToken = DeviceToken provider token, ntfServer = ProtocolServer {host, port}} tknStatus tknAction = do
@@ -1495,7 +1494,7 @@ updateNtfToken db NtfToken {deviceToken = DeviceToken provider token, ntfServer
14951494
SET tkn_status = ?, tkn_action = ?, updated_at = ?
14961495
WHERE provider = ? AND device_token = ? AND ntf_host = ? AND ntf_port = ?
14971496
|]
1498-
(tknStatus, tknAction, updatedAt, provider, token, host, port)
1497+
(tknStatus, tknAction, updatedAt, provider, Binary token, host, port)
14991498

15001499
removeNtfToken :: DB.Connection -> NtfToken -> IO ()
15011500
removeNtfToken db NtfToken {deviceToken = DeviceToken provider token, ntfServer = ProtocolServer {host, port}} =
@@ -1505,7 +1504,7 @@ removeNtfToken db NtfToken {deviceToken = DeviceToken provider token, ntfServer
15051504
DELETE FROM ntf_tokens
15061505
WHERE provider = ? AND device_token = ? AND ntf_host = ? AND ntf_port = ?
15071506
|]
1508-
(provider, token, host, port)
1507+
(provider, Binary token, host, port)
15091508

15101509
addNtfTokenToDelete :: DB.Connection -> NtfServer -> C.APrivateAuthKey -> NtfTokenId -> IO ()
15111510
addNtfTokenToDelete db ProtocolServer {host, port, keyHash} ntfPrivKey tknId =
@@ -1819,7 +1818,7 @@ getActiveNtfToken db =
18191818
|]
18201819
(Only NTActive)
18211820
where
1822-
ntfToken ((host, port, keyHash) :. (provider, dt, ntfTokenId, ntfPubKey, ntfPrivKey, ntfDhPubKey, ntfDhPrivKey, ntfDhSecret) :. (ntfTknStatus, ntfTknAction, ntfMode_)) =
1821+
ntfToken ((host, port, keyHash) :. (provider, Binary dt, ntfTokenId, ntfPubKey, ntfPrivKey, ntfDhPubKey, ntfDhPrivKey, ntfDhSecret) :. (ntfTknStatus, ntfTknAction, ntfMode_)) =
18231822
let ntfServer = NtfServer host port keyHash
18241823
ntfDhKeys = (ntfDhPubKey, ntfDhPrivKey)
18251824
ntfMode = fromMaybe NMPeriodic ntfMode_

src/Simplex/Messaging/Agent/Store/Postgres/DB.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Simplex.Messaging.Agent.Store.Postgres.DB
66
PSQL.Connection,
77
FromField (..),
88
ToField (..),
9+
SQLError,
910
PSQL.connect,
1011
PSQL.close,
1112
execute,
@@ -33,6 +34,8 @@ import Database.PostgreSQL.Simple.TypeInfo.Static (textOid, varcharOid)
3334

3435
newtype BoolInt = BI {unBI :: Bool}
3536

37+
type SQLError = PSQL.SqlError
38+
3639
instance FromField BoolInt where
3740
fromField field dat = BI . (/= (0 :: Int)) <$> fromField field dat
3841
{-# INLINE fromField #-}

src/Simplex/Messaging/Agent/Store/Postgres/Migrations/App.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Simplex.Messaging.Agent.Store.Postgres.Migrations.M20250322_short_links
1010
import Simplex.Messaging.Agent.Store.Postgres.Migrations.M20250702_conn_invitations_remove_cascade_delete
1111
import Simplex.Messaging.Agent.Store.Postgres.Migrations.M20251009_queue_to_subscribe
1212
import Simplex.Messaging.Agent.Store.Postgres.Migrations.M20251010_client_notices
13+
import Simplex.Messaging.Agent.Store.Postgres.Migrations.M20251230_strict_tables
1314
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
1415

1516
schemaMigrations :: [(String, Text, Maybe Text)]
@@ -19,7 +20,8 @@ schemaMigrations =
1920
("20250322_short_links", m20250322_short_links, Just down_m20250322_short_links),
2021
("20250702_conn_invitations_remove_cascade_delete", m20250702_conn_invitations_remove_cascade_delete, Just down_m20250702_conn_invitations_remove_cascade_delete),
2122
("20251009_queue_to_subscribe", m20251009_queue_to_subscribe, Just down_m20251009_queue_to_subscribe),
22-
("20251010_client_notices", m20251010_client_notices, Just down_m20251010_client_notices)
23+
("20251010_client_notices", m20251010_client_notices, Just down_m20251010_client_notices),
24+
("20251230_strict_tables", m20251230_strict_tables, Just down_m20251230_strict_tables)
2325
]
2426

2527
-- | The list of migrations in ascending order by date

0 commit comments

Comments
 (0)