groundhog-mysql 0.7.0.1 → 0.8
raw patch · 3 files changed
+135/−124 lines, 3 filesdep +resourcetdep ~groundhogdep ~mysql-simpledep ~transformersPVP ok
version bump matches the API change (PVP)
Dependencies added: resourcet
Dependency ranges changed: groundhog, mysql-simple, transformers
API changes (from Hackage documentation)
- Database.Groundhog.MySQL: connectDatabase :: ConnectInfo -> String
- Database.Groundhog.MySQL: connectHost :: ConnectInfo -> String
- Database.Groundhog.MySQL: connectOptions :: ConnectInfo -> [Option]
- Database.Groundhog.MySQL: connectPassword :: ConnectInfo -> String
- Database.Groundhog.MySQL: connectPath :: ConnectInfo -> FilePath
- Database.Groundhog.MySQL: connectPort :: ConnectInfo -> Word16
- Database.Groundhog.MySQL: connectSSL :: ConnectInfo -> Maybe SSLInfo
- Database.Groundhog.MySQL: connectUser :: ConnectInfo -> String
- Database.Groundhog.MySQL: instance (MonadBaseControl IO m, MonadIO m, MonadLogger m) => PersistBackend (DbPersist MySQL m)
- Database.Groundhog.MySQL: instance (MonadBaseControl IO m, MonadIO m, MonadLogger m) => SchemaAnalyzer (DbPersist MySQL m)
- Database.Groundhog.MySQL: instance ConnectionManager (Pool MySQL) MySQL
- Database.Groundhog.MySQL: instance ConnectionManager MySQL MySQL
- Database.Groundhog.MySQL: instance DbDescriptor MySQL
- Database.Groundhog.MySQL: instance FloatingSqlDb MySQL
- Database.Groundhog.MySQL: instance Param P
- Database.Groundhog.MySQL: instance Savepoint MySQL
- Database.Groundhog.MySQL: instance SingleConnectionManager MySQL MySQL
- Database.Groundhog.MySQL: instance SqlDb MySQL
- Database.Groundhog.MySQL: sslCA :: SSLInfo -> FilePath
- Database.Groundhog.MySQL: sslCAPath :: SSLInfo -> FilePath
- Database.Groundhog.MySQL: sslCert :: SSLInfo -> FilePath
- Database.Groundhog.MySQL: sslCiphers :: SSLInfo -> String
- Database.Groundhog.MySQL: sslKey :: SSLInfo -> FilePath
+ Database.Groundhog.MySQL: [connectDatabase] :: ConnectInfo -> String
+ Database.Groundhog.MySQL: [connectHost] :: ConnectInfo -> String
+ Database.Groundhog.MySQL: [connectOptions] :: ConnectInfo -> [Option]
+ Database.Groundhog.MySQL: [connectPassword] :: ConnectInfo -> String
+ Database.Groundhog.MySQL: [connectPath] :: ConnectInfo -> FilePath
+ Database.Groundhog.MySQL: [connectPort] :: ConnectInfo -> Word16
+ Database.Groundhog.MySQL: [connectSSL] :: ConnectInfo -> Maybe SSLInfo
+ Database.Groundhog.MySQL: [connectUser] :: ConnectInfo -> String
+ Database.Groundhog.MySQL: [sslCAPath] :: SSLInfo -> FilePath
+ Database.Groundhog.MySQL: [sslCA] :: SSLInfo -> FilePath
+ Database.Groundhog.MySQL: [sslCert] :: SSLInfo -> FilePath
+ Database.Groundhog.MySQL: [sslCiphers] :: SSLInfo -> String
+ Database.Groundhog.MySQL: [sslKey] :: SSLInfo -> FilePath
+ Database.Groundhog.MySQL: instance Database.Groundhog.Core.ConnectionManager Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Core.DbDescriptor Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Core.ExtractConnection (Data.Pool.Pool Database.Groundhog.MySQL.MySQL) Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Core.ExtractConnection Database.Groundhog.MySQL.MySQL Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Core.PersistBackendConn Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Core.Savepoint Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Generic.Migration.SchemaAnalyzer Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Generic.Sql.FloatingSqlDb Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.Groundhog.Generic.Sql.SqlDb Database.Groundhog.MySQL.MySQL
+ Database.Groundhog.MySQL: instance Database.MySQL.Simple.Param.Param Database.Groundhog.MySQL.P
- Database.Groundhog.MySQL: runDbConn :: (MonadBaseControl IO m, MonadIO m, ConnectionManager cm conn) => DbPersist conn (NoLoggingT m) a -> cm -> m a
+ Database.Groundhog.MySQL: runDbConn :: (MonadIO m, MonadBaseControl IO m, ConnectionManager conn, ExtractConnection cm conn) => Action conn a -> cm -> m a
Files
- Database/Groundhog/MySQL.hs +126/−120
- changelog +4/−0
- groundhog-mysql.cabal +5/−4
Database/Groundhog/MySQL.hs view
@@ -35,10 +35,11 @@ import Control.Arrow (first, second, (***)) import Control.Monad (liftM, liftM2, (>=>)) import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad.Logger (MonadLogger, logDebugS) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Control (MonadBaseControl) import Control.Monad.Trans.Reader (ask)+import Control.Monad.Trans.State (mapStateT)+import Data.Acquire (mkAcquire) import Data.ByteString.Char8 (ByteString) import Data.Char (toUpper) import Data.Function (on)@@ -67,53 +68,55 @@ log' a = mkExpr $ function "log" [toExpr a] logBase' b x = mkExpr $ function "log" [toExpr b, toExpr x] -instance (MonadBaseControl IO m, MonadIO m, MonadLogger m) => PersistBackend (DbPersist MySQL m) where- type PhantomDb (DbPersist MySQL m) = MySQL- insert v = insert' v- insert_ v = insert_' v- insertBy u v = H.insertBy renderConfig queryRaw' True u v- insertByAll v = H.insertByAll renderConfig queryRaw' True v- replace k v = H.replace renderConfig queryRaw' executeRaw' insertIntoConstructorTable k v- replaceBy k v = H.replaceBy renderConfig executeRaw' k v- select options = H.select renderConfig queryRaw' preColumns noLimit options- selectAll = H.selectAll renderConfig queryRaw'- get k = H.get renderConfig queryRaw' k- getBy k = H.getBy renderConfig queryRaw' k- update upds cond = H.update renderConfig executeRaw' upds cond- delete cond = H.delete renderConfig executeRaw' cond- deleteBy k = H.deleteBy renderConfig executeRaw' k- deleteAll v = H.deleteAll renderConfig executeRaw' v- count cond = H.count renderConfig queryRaw' cond- countAll fakeV = H.countAll renderConfig queryRaw' fakeV- project p options = H.project renderConfig queryRaw' preColumns noLimit p options- migrate fakeV = migrate' fakeV+instance PersistBackendConn MySQL where+ insert v = runDb' $ insert' v+ insert_ v = runDb' $ insert_' v+ insertBy u v = runDb' $ H.insertBy renderConfig queryRaw' True u v+ insertByAll v = runDb' $ H.insertByAll renderConfig queryRaw' True v+ replace k v = runDb' $ H.replace renderConfig queryRaw' executeRaw' insertIntoConstructorTable k v+ replaceBy k v = runDb' $ H.replaceBy renderConfig executeRaw' k v+ select options = runDb' $ H.select renderConfig queryRaw' preColumns noLimit options+ selectStream options = runDb' $ H.selectStream renderConfig queryRaw' preColumns noLimit options+ selectAll = runDb' $ H.selectAll renderConfig queryRaw'+ selectAllStream = runDb' $ H.selectAllStream renderConfig queryRaw'+ get k = runDb' $ H.get renderConfig queryRaw' k+ getBy k = runDb' $ H.getBy renderConfig queryRaw' k+ update upds cond = runDb' $ H.update renderConfig executeRaw' upds cond+ delete cond = runDb' $ H.delete renderConfig executeRaw' cond+ deleteBy k = runDb' $ H.deleteBy renderConfig executeRaw' k+ deleteAll v = runDb' $ H.deleteAll renderConfig executeRaw' v+ count cond = runDb' $ H.count renderConfig queryRaw' cond+ countAll fakeV = runDb' $ H.countAll renderConfig queryRaw' fakeV+ project p options = runDb' $ H.project renderConfig queryRaw' preColumns noLimit p options+ projectStream p options = runDb' $ H.projectStream renderConfig queryRaw' preColumns noLimit p options+ migrate fakeV = mapStateT runDb' $ migrate' fakeV - executeRaw _ query ps = executeRaw' (fromString query) ps- queryRaw _ query ps f = queryRaw' (fromString query) ps f+ executeRaw _ query ps = runDb' $ executeRaw' (fromString query) ps+ queryRaw _ query ps = runDb' $ queryRaw' (fromString query) ps - insertList l = insertList' l- getList k = getList' k+ insertList l = runDb' $ insertList' l+ getList k = runDb' $ getList' k -instance (MonadBaseControl IO m, MonadIO m, MonadLogger m) => SchemaAnalyzer (DbPersist MySQL m) where- schemaExists schema = queryRaw' "SELECT 1 FROM information_schema.schemata WHERE schema_name=?" [toPrimitivePersistValue proxy schema] (fmap isJust)- getCurrentSchema = queryRaw' "SELECT database()" [] (fmap (>>= fst . fromPurePersistValues proxy))- listTables schema = queryRaw' "SELECT table_name FROM information_schema.tables WHERE table_schema=coalesce(?,database())" [toPrimitivePersistValue proxy schema] (mapAllRows $ return . fst . fromPurePersistValues proxy)- listTableTriggers name = queryRaw' "SELECT trigger_name FROM information_schema.triggers WHERE event_object_schema=coalesce(?,database()) AND event_object_table=?" (toPurePersistValues proxy name []) (mapAllRows $ return . fst . fromPurePersistValues proxy)- analyzeTable = analyzeTable'- analyzeTrigger name = do- x <- queryRaw' "SELECT action_statement FROM information_schema.triggers WHERE trigger_schema=coalesce(?,database()) AND trigger_name=?" (toPurePersistValues proxy name []) id+instance SchemaAnalyzer MySQL where+ schemaExists schema = runDb' $ queryRaw' "SELECT 1 FROM information_schema.schemata WHERE schema_name=?" [toPrimitivePersistValue schema] >>= firstRow >>= return . isJust+ getCurrentSchema = runDb' $ queryRaw' "SELECT database()" [] >>= firstRow >>= return . (>>= fst . fromPurePersistValues)+ listTables schema = runDb' $ queryRaw' "SELECT table_name FROM information_schema.tables WHERE table_schema=coalesce(?,database())" [toPrimitivePersistValue schema] >>= mapStream (return . fst . fromPurePersistValues) >>= streamToList+ listTableTriggers name = runDb' $ queryRaw' "SELECT trigger_name FROM information_schema.triggers WHERE event_object_schema=coalesce(?,database()) AND event_object_table=?" (toPurePersistValues name []) >>= mapStream (return . fst . fromPurePersistValues) >>= streamToList+ analyzeTable = runDb' . analyzeTable'+ analyzeTrigger name = runDb' $ do+ x <- queryRaw' "SELECT action_statement FROM information_schema.triggers WHERE trigger_schema=coalesce(?,database()) AND trigger_name=?" (toPurePersistValues name []) >>= firstRow return $ case x of Nothing -> Nothing- Just src -> fst $ fromPurePersistValues proxy src- analyzeFunction name = do- result <- queryRaw' "SELECT param_list, returns, body_utf8 from mysql.proc WHERE db = coalesce(?, database()) AND name = ?" (toPurePersistValues proxy name []) id+ Just src -> fst $ fromPurePersistValues src+ analyzeFunction name = runDb' $ do+ result <- queryRaw' "SELECT param_list, returns, body_utf8 from mysql.proc WHERE db = coalesce(?, database()) AND name = ?" (toPurePersistValues name []) >>= firstRow let read' typ = readSqlType typ typ (Nothing, Nothing, Nothing) return $ case result of Nothing -> Nothing -- TODO: parse param_list Just result' -> Just (Just [DbOther (OtherTypeDef [Left param_list])], if ret == "" then Nothing else Just $ read' ret, src) where- (param_list, ret, src) = fst . fromPurePersistValues proxy $ result'- getMigrationPack = fmap (migrationPack . fromJust) getCurrentSchema+ (param_list, ret, src) = fst . fromPurePersistValues $ result'+ getMigrationPack = liftM (migrationPack . fromJust) getCurrentSchema withMySQLPool :: (MonadBaseControl IO m, MonadIO m) => MySQL.ConnectInfo@@ -142,19 +145,18 @@ liftIO $ MySQL.execute_ c $ "RELEASE SAVEPOINT" <> name' return x -instance ConnectionManager MySQL MySQL where+instance ConnectionManager MySQL where withConn f conn@(MySQL c) = do liftIO $ MySQL.execute_ c "start transaction" x <- onException (f conn) (liftIO $ MySQL.rollback c) liftIO $ MySQL.commit c return x- withConnNoTransaction f conn = f conn -instance ConnectionManager (Pool MySQL) MySQL where- withConn f pconn = withResource pconn (withConn f)- withConnNoTransaction f pconn = withResource pconn (withConnNoTransaction f)+instance ExtractConnection MySQL MySQL where+ extractConn f conn = f conn -instance SingleConnectionManager MySQL MySQL+instance ExtractConnection (Pool MySQL) MySQL where+ extractConn f pconn = withResource pconn f open' :: MySQL.ConnectInfo -> IO MySQL open' ci = do@@ -165,12 +167,12 @@ close' :: MySQL -> IO () close' (MySQL conn) = MySQL.close conn -insert' :: (PersistEntity v, MonadBaseControl IO m, MonadIO m, MonadLogger m) => v -> DbPersist MySQL m (AutoKey v)+insert' :: PersistEntity v => v -> Action MySQL (AutoKey v) insert' v = do -- constructor number and the rest of the field values vals <- toEntityPersistValues' v let e = entityDef proxy v- let constructorNum = fromPrimitivePersistValue proxy (head vals)+ let constructorNum = fromPrimitivePersistValue (head vals) liftM fst $ if isSimple (constructors e) then do@@ -189,12 +191,12 @@ executeRaw' cQuery (vals' []) pureFromPersistValue [rowid] -insert_' :: (PersistEntity v, MonadBaseControl IO m, MonadIO m, MonadLogger m) => v -> DbPersist MySQL m ()+insert_' :: PersistEntity v => v -> Action MySQL () insert_' v = do -- constructor number and the rest of the field values vals <- toEntityPersistValues' v let e = entityDef proxy v- let constructorNum = fromPrimitivePersistValue proxy (head vals)+ let constructorNum = fromPrimitivePersistValue (head vals) if isSimple (constructors e) then do@@ -220,7 +222,7 @@ xs -> "(" <> commasJoin xs <> ") VALUES(" <> placeholders <> ")" RenderS placeholders vals' = commasJoin $ map renderPersistValue vals -insertList' :: forall m a.(MonadBaseControl IO m, MonadIO m, MonadLogger m, PersistField a) => [a] -> DbPersist MySQL m Int64+insertList' :: forall a. PersistField a => [a] -> Action MySQL Int64 insertList' (l :: [a]) = do let mainName = "List" <> delim' <> delim' <> fromString (persistName (undefined :: a)) executeRaw' ("INSERT INTO " <> escapeS mainName <> "()VALUES()") []@@ -228,34 +230,34 @@ let valuesName = mainName <> delim' <> "values" let fields = [("ord", dbType proxy (0 :: Int)), ("value", dbType proxy (undefined :: a))] let query = "INSERT INTO " <> escapeS valuesName <> "(id," <> renderFields escapeS fields <> ")VALUES(?," <> renderFields (const $ fromChar '?') fields <> ")"- let go :: Int -> [a] -> DbPersist MySQL m ()+ let go :: Int -> [a] -> Action MySQL () go n (x:xs) = do x' <- toPersistValues x- executeRaw' query $ (k:) . (toPrimitivePersistValue proxy n:) . x' $ []+ executeRaw' query $ (k:) . (toPrimitivePersistValue n:) . x' $ [] go (n + 1) xs go _ [] = return () go 0 l- return $ fromPrimitivePersistValue proxy k+ return $ fromPrimitivePersistValue k -getList' :: forall m a.(MonadBaseControl IO m, MonadIO m, MonadLogger m, PersistField a) => Int64 -> DbPersist MySQL m [a]+getList' :: forall a . PersistField a => Int64 -> Action MySQL [a] getList' k = do let mainName = "List" <> delim' <> delim' <> fromString (persistName (undefined :: a)) let valuesName = mainName <> delim' <> "values" let value = ("value", dbType proxy (undefined :: a)) let query = "SELECT " <> renderFields escapeS [value] <> " FROM " <> escapeS valuesName <> " WHERE id=? ORDER BY ord"- queryRaw' query [toPrimitivePersistValue proxy k] $ mapAllRows (liftM fst . fromPersistValues)+ queryRaw' query [toPrimitivePersistValue k] >>= mapStream (liftM fst . fromPersistValues) >>= streamToList -getLastInsertId :: (MonadBaseControl IO m, MonadIO m, MonadLogger m) => DbPersist MySQL m PersistValue+getLastInsertId :: Action MySQL PersistValue getLastInsertId = do- x <- queryRaw' "SELECT last_insert_id()" [] id+ x <- queryRaw' "SELECT last_insert_id()" [] >>= firstRow return $ maybe (error "getLastInsertId: Nothing") head x ---------- -executeRaw' :: (MonadIO m, MonadLogger m) => Utf8 -> [PersistValue] -> DbPersist MySQL m ()+executeRaw' :: Utf8 -> [PersistValue] -> Action MySQL () executeRaw' query vals = do- $logDebugS "SQL" $ fromString $ show (fromUtf8 query) ++ " " ++ show vals- MySQL conn <- DbPersist ask+-- $logDebugS "SQL" $ fromString $ show (fromUtf8 query) ++ " " ++ show vals+ MySQL conn <- ask let stmt = getStatement query liftIO $ do _ <- MySQL.execute conn stmt (map P vals)@@ -272,35 +274,36 @@ delim' :: Utf8 delim' = fromChar delim -toEntityPersistValues' :: (MonadBaseControl IO m, MonadIO m, MonadLogger m, PersistEntity v) => v -> DbPersist MySQL m [PersistValue]+toEntityPersistValues' :: PersistEntity v => v -> Action MySQL [PersistValue] toEntityPersistValues' = liftM ($ []) . toEntityPersistValues --- MIGRATION -migrate' :: (PersistEntity v, MonadBaseControl IO m, MonadIO m, MonadLogger m) => v -> Migration (DbPersist MySQL m)+migrate' :: PersistEntity v => v -> Migration (Action MySQL) migrate' v = do migPack <- lift getMigrationPack migrateRecursively (migrateSchema migPack) (migrateEntity migPack) (migrateList migPack) v -migrationPack :: (MonadBaseControl IO m, MonadIO m, MonadLogger m) => String -> GM.MigrationPack (DbPersist MySQL m)-migrationPack currentSchema = GM.MigrationPack- compareTypes- (compareRefs currentSchema)- compareUniqs- compareDefaults- migTriggerOnDelete- migTriggerOnUpdate- GM.defaultMigConstr- escape- "BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY"- mainTableId- defaultPriority- (\uniques refs -> ([], map AddUnique uniques ++ map AddReference refs))- showSqlType- showColumn- (showAlterDb currentSchema)- Restrict- Restrict+migrationPack :: String -> GM.MigrationPack MySQL+migrationPack currentSchema = m where+ m = GM.MigrationPack+ compareTypes+ (compareRefs currentSchema)+ compareUniqs+ compareDefaults+ migTriggerOnDelete+ migTriggerOnUpdate+ (GM.defaultMigConstr m)+ escape+ "BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY"+ mainTableId+ defaultPriority+ (\uniques refs -> ([], map AddUnique uniques ++ map AddReference refs))+ showSqlType+ showColumn+ (showAlterDb currentSchema)+ Restrict+ Restrict showColumn :: Column -> String showColumn (Column n nu t def) = concat@@ -314,7 +317,7 @@ Just s -> " DEFAULT " ++ s ] -migTriggerOnDelete :: (MonadBaseControl IO m, MonadIO m, MonadLogger m) => QualifiedName -> [(String, String)] -> DbPersist MySQL m (Bool, [AlterDB])+migTriggerOnDelete :: QualifiedName -> [(String, String)] -> Action MySQL (Bool, [AlterDB]) migTriggerOnDelete name deletes = do let addTrigger = AddTriggerOnDelete name name (concatMap snd deletes) x <- analyzeTrigger name@@ -330,7 +333,7 @@ -- | Schema name, table name and a list of field names and according delete statements -- assume that this function is called only for ephemeral fields-migTriggerOnUpdate :: (MonadBaseControl IO m, MonadIO m, MonadLogger m) => QualifiedName -> [(String, String)] -> DbPersist MySQL m [(Bool, [AlterDB])]+migTriggerOnUpdate :: QualifiedName -> [(String, String)] -> Action MySQL [(Bool, [AlterDB])] migTriggerOnUpdate tName deletes = do let trigName = second (++ "_ON_UPDATE") tName f (fieldName, del) = "IF NOT (NEW." ++ escape fieldName ++ " <=> OLD." ++ escape fieldName ++ ") THEN " ++ del ++ " END IF;"@@ -347,9 +350,9 @@ -- this can happen when an ephemeral field was added or removed. else [DropTrigger trigName tName, addTrigger]) -analyzeTable' :: (MonadBaseControl IO m, MonadIO m, MonadLogger m) => QualifiedName -> DbPersist MySQL m (Maybe TableInfo)+analyzeTable' :: QualifiedName -> Action MySQL (Maybe TableInfo) analyzeTable' name = do- table <- queryRaw' "SELECT * FROM information_schema.tables WHERE table_schema = coalesce(?, database()) AND table_name = ?" (toPurePersistValues proxy name []) id+ table <- queryRaw' "SELECT * FROM information_schema.tables WHERE table_schema = coalesce(?, database()) AND table_name = ?" (toPurePersistValues name []) >>= firstRow case table of Just _ -> do let colQuery = "SELECT c.column_name, c.is_nullable, c.data_type, c.column_type, c.column_default, c.character_maximum_length, c.numeric_precision, c.numeric_scale, c.extra\@@ -357,11 +360,11 @@ \ WHERE c.table_schema = coalesce(?, database()) AND c.table_name=?\ \ ORDER BY c.ordinal_position" - cols <- queryRaw' colQuery (toPurePersistValues proxy name []) (mapAllRows $ return . first getColumn . fst . fromPurePersistValues proxy)+ cols <- queryRaw' colQuery (toPurePersistValues name []) >>= mapStream (return . first getColumn . fst . fromPurePersistValues) >>= streamToList -- MySQL has no difference between unique keys and indexes let constraintQuery = "SELECT u.constraint_name, u.column_name FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage u USING (constraint_catalog, constraint_schema, constraint_name, table_schema, table_name) WHERE tc.constraint_type=? AND tc.table_schema=coalesce(?,database()) AND u.table_name=? ORDER BY u.constraint_name, u.column_name"- uniqConstraints <- queryRaw' constraintQuery (toPurePersistValues proxy ("UNIQUE" :: String, name) []) (mapAllRows $ return . fst . fromPurePersistValues proxy)- uniqPrimary <- queryRaw' constraintQuery (toPurePersistValues proxy ("PRIMARY KEY" :: String, name) []) (mapAllRows $ return . fst . fromPurePersistValues proxy)+ uniqConstraints <- queryRaw' constraintQuery (toPurePersistValues ("UNIQUE" :: String, name) []) >>= mapStream (return . fst . fromPurePersistValues) >>= streamToList+ uniqPrimary <- queryRaw' constraintQuery (toPurePersistValues ("PRIMARY KEY" :: String, name) []) >>= mapStream (return . fst . fromPurePersistValues) >>= streamToList let mkUniqs typ = map (\us -> UniqueDef (fst $ head us) typ (map (Left . snd) us)) . groupBy ((==) `on` fst) isAutoincremented = case filter (\c -> colName (fst c) `elem` map snd uniqPrimary) cols of [(c, extra)] -> colType c `elem` [DbInt32, DbInt64] && "auto_increment" `isInfixOf` (extra :: String)@@ -375,14 +378,14 @@ getColumn ((column_name, is_nullable, data_type, column_type, d), modifiers) = Column column_name (is_nullable == "YES") t d where t = readSqlType data_type column_type modifiers -analyzeTableReferences :: (MonadBaseControl IO m, MonadIO m, MonadLogger m) => QualifiedName -> DbPersist MySQL m [(Maybe String, Reference)]+analyzeTableReferences :: QualifiedName -> Action MySQL [(Maybe String, Reference)] analyzeTableReferences name = do let query = "SELECT tc.constraint_name, u.referenced_table_schema, u.referenced_table_name, rc.delete_rule, rc.update_rule, u.column_name, u.referenced_column_name FROM information_schema.table_constraints tc\ \ INNER JOIN information_schema.key_column_usage u USING (constraint_catalog, constraint_schema, constraint_name, table_schema, table_name)\ \ INNER JOIN information_schema.referential_constraints rc USING (constraint_catalog, constraint_schema, constraint_name)\ \ WHERE tc.constraint_type='FOREIGN KEY' AND tc.table_schema=coalesce(?, database()) AND tc.table_name=?\ \ ORDER BY tc.constraint_name"- x <- queryRaw' query (toPurePersistValues proxy name []) $ mapAllRows (return . fst . fromPurePersistValues proxy)+ x <- queryRaw' query (toPurePersistValues name []) >>= mapStream (return . fst . fromPurePersistValues) >>= streamToList -- (refName, ((parentTableSchema, parentTable, onDelete, onUpdate), (childColumn, parentColumn))) let mkReference xs = (Just refName, Reference parentTable pairs (mkAction onDelete) (mkAction onUpdate)) where pairs = map (snd . snd) xs@@ -569,41 +572,44 @@ getStatement :: Utf8 -> MySQL.Query getStatement sql = MySQL.Query $ fromUtf8 sql -queryRaw' :: (MonadBaseControl IO m, MonadIO m, MonadLogger m) => Utf8 -> [PersistValue] -> (RowPopper (DbPersist MySQL m) -> DbPersist MySQL m a) -> DbPersist MySQL m a-queryRaw' query vals func = do- $logDebugS "SQL" $ fromString $ show (fromUtf8 query) ++ " " ++ show vals- MySQL conn <- DbPersist ask- liftIO $ MySQL.formatQuery conn (getStatement query) (map P vals) >>= MySQLBase.query conn- result <- liftIO $ MySQLBase.storeResult conn- -- Find out the type of the columns- fields <- liftIO $ MySQLBase.fetchFields result- let getters = [maybe PersistNull (getGetter (MySQLBase.fieldType f) f . Just) | f <- fields]- convert = use getters where- use (g:gs) (col:cols) = v `seq` vs `seq` (v:vs) where- v = g col- vs = use gs cols- use _ _ = []- let go acc = do- row <- MySQLBase.fetchRow result- case row of- [] -> return (acc [])- _ -> let converted = convert row- in converted `seq` go (acc . (converted:))- -- TODO: this variable is ugly. Switching to pipes or conduit might help- rowsVar <- liftIO $ flip finally (MySQLBase.freeResult result) (go id) >>= newIORef- func $ do- rows <- liftIO $ readIORef rowsVar- case rows of- [] -> return Nothing- (x:xs) -> do- liftIO $ writeIORef rowsVar xs- return $ Just x+queryRaw' :: Utf8 -> [PersistValue] -> Action MySQL (RowStream [PersistValue])+queryRaw' query vals = do+-- $logDebugS "SQL" $ fromString $ show (fromUtf8 query) ++ " " ++ show vals+ MySQL conn <- ask+ let open = do+ MySQL.formatQuery conn (getStatement query) (map P vals) >>= MySQLBase.query conn+ result <- MySQLBase.storeResult conn+ -- Find out the type of the columns+ fields <- MySQLBase.fetchFields result+ let getters = [maybe PersistNull (getGetter (MySQLBase.fieldType f) f . Just) | f <- fields]+ convert = use getters where+ use (g:gs) (col:cols) = v `seq` vs `seq` (v:vs) where+ v = g col+ vs = use gs cols+ use _ _ = []+ let go acc = do+ row <- MySQLBase.fetchRow result+ case row of+ [] -> return (acc [])+ _ -> let converted = convert row+ in converted `seq` go (acc . (converted:))+ -- TODO: this variable is ugly. Switching to pipes or conduit might help+ rowsVar <- flip finally (MySQLBase.freeResult result) (go id) >>= newIORef+ return $ do+ rows <- readIORef rowsVar+ case rows of+ [] -> return Nothing+ (x:xs) -> do+ writeIORef rowsVar xs+ return $ Just x+ return $ mkAcquire open (const $ return ()) -- | Avoid orphan instances. newtype P = P PersistValue instance MySQL.Param P where render (P (PersistString t)) = MySQL.render t+ render (P (PersistText t)) = MySQL.render t render (P (PersistByteString bs)) = MySQL.render bs render (P (PersistInt64 i)) = MySQL.render i render (P (PersistDouble d)) = MySQL.render d@@ -651,8 +657,8 @@ -- Null getGetter MySQLBase.Null = \_ _ -> PersistNull -- Controversial conversions-getGetter MySQLBase.Set = convertPV PersistString-getGetter MySQLBase.Enum = convertPV PersistString+getGetter MySQLBase.Set = convertPV PersistText+getGetter MySQLBase.Enum = convertPV PersistText -- Unsupported getGetter other = error $ "MySQL.getGetter: type " ++ show other ++ " not supported."
changelog view
@@ -1,3 +1,7 @@+0.8+* Support for GHC 8+* Bumped MySQL dependencies+ 0.7.0.1 * Support for monad-control 1.0
groundhog-mysql.cabal view
@@ -1,5 +1,5 @@ name: groundhog-mysql-version: 0.7.0.1+version: 0.8 license: BSD3 license-file: LICENSE author: Boris Lykah <lykahb@gmail.com>@@ -16,16 +16,17 @@ library build-depends: base >= 4 && < 5- , mysql-simple >= 0.2.2.3 && < 0.3+ , mysql-simple >= 0.2.2.3 && < 0.5 , mysql >= 0.1.1.3 && < 0.2 , bytestring >= 0.9- , transformers >= 0.2.1 && < 0.5- , groundhog >= 0.7 && < 0.8+ , transformers >= 0.2.1 && < 0.6+ , groundhog >= 0.8 && < 0.9 , monad-control >= 0.3 && < 1.1 , monad-logger >= 0.3 && < 0.4 , containers >= 0.2 , text >= 0.8 , resource-pool >= 0.2.1 , time >= 1.1+ , resourcet >= 1.1.2 exposed-modules: Database.Groundhog.MySQL ghc-options: -Wall -fno-warn-unused-do-bind