groundhog 0.4.2.1 → 0.4.2.2
raw patch · 8 files changed
+131/−46 lines, 8 files
Files
- Database/Groundhog/Core.hs +9/−8
- Database/Groundhog/Generic.hs +3/−3
- Database/Groundhog/Generic/Migration.hs +27/−12
- Database/Groundhog/Generic/PersistBackendHelpers.hs +16/−16
- Database/Groundhog/Generic/Sql.hs +2/−2
- Database/Groundhog/Instances.hs +4/−4
- changelog +66/−0
- groundhog.cabal +4/−1
Database/Groundhog/Core.hs view
@@ -112,7 +112,7 @@ -- | Constructs the value from the list of 'PersistValue' fromEntityPersistValues :: PersistBackend m => [PersistValue] -> m (v, [PersistValue]) -- | Returns constructor number and a list of uniques names and corresponding field values- getUniques :: DbDescriptor db => Proxy db -> v -> (Int, [(String, [PersistValue] -> [PersistValue])])+ getUniques :: DbDescriptor db => proxy db -> v -> (Int, [(String, [PersistValue] -> [PersistValue])]) -- | Is internally used by FieldLike Field instance -- We could avoid this function if class FieldLike allowed FieldLike Fields Data or FieldLike (Fields Data). However that would require additional extensions in user-space code entityFieldChain :: Field v c a -> FieldChain@@ -129,6 +129,7 @@ -- | It allows to store autogenerated keys of one database in another data KeyForBackend db v = (DbDescriptor db, PersistEntity v) => KeyForBackend (AutoKeyType db) +{-# DEPRECATED Proxy "use polymophic proxy or another data constructor like [] instead" #-} data Proxy a data HFalse@@ -256,7 +257,7 @@ -- | Value of this type can be used as a part of a query. For example, it can be RenderS for relational databases, or BSON for MongoDB. type QueryRaw db :: * -> * -- | Name of backend- backendName :: Proxy db -> String+ backendName :: proxy db -> String class (Monad m, DbDescriptor (PhantomDb m)) => PersistBackend m where -- | A token which defines the DB type. For example, different monads working with Sqlite, return may Sqlite type.@@ -365,7 +366,7 @@ -- define the constructor, but the entity has only one. -- For example, in @select $ AutoKeyField ==. k@ the condition would need type annotation with constructor name only if we select a sum type. class PersistEntity v => EntityConstr v c where- entityConstrNum :: Proxy v -> c (a :: * -> *) -> Int+ entityConstrNum :: proxy v -> c (a :: * -> *) -> Int class PurePersistField uKey => IsUniqueKey uKey where -- | Creates value of unique key using the data extracted from the passed value@@ -505,13 +506,13 @@ -- | Represents all datatypes that map into several columns. Getting values for those columns is pure. class PersistField a => PurePersistField a where- toPurePersistValues :: DbDescriptor db => Proxy db -> a -> ([PersistValue] -> [PersistValue])- fromPurePersistValues :: DbDescriptor db => Proxy db -> [PersistValue] -> (a, [PersistValue])+ toPurePersistValues :: DbDescriptor db => proxy db -> a -> ([PersistValue] -> [PersistValue])+ fromPurePersistValues :: DbDescriptor db => proxy db -> [PersistValue] -> (a, [PersistValue]) --- | Datatypes which can be converted directly to 'PersistValue'. The no-value parameter @DbDescriptor db => Proxy db@ allows conversion depend the database details while keeping it pure. A type which has an instance of 'PrimitivePersistField' should be an instance of superclasses 'SinglePersistField' and 'PurePersistField' as well.+-- | Datatypes which can be converted directly to 'PersistValue'. The no-value parameter @DbDescriptor db => proxy db@ allows conversion depend the database details while keeping it pure. A type which has an instance of 'PrimitivePersistField' should be an instance of superclasses 'SinglePersistField' and 'PurePersistField' as well. class PersistField a => PrimitivePersistField a where- toPrimitivePersistValue :: DbDescriptor db => Proxy db -> a -> PersistValue- fromPrimitivePersistValue :: DbDescriptor db => Proxy db -> PersistValue -> a+ toPrimitivePersistValue :: DbDescriptor db => proxy db -> a -> PersistValue+ fromPrimitivePersistValue :: DbDescriptor db => proxy db -> PersistValue -> a delim :: Char delim = '#'
Database/Groundhog/Generic.hs view
@@ -207,10 +207,10 @@ primFromPersistValue (x:xs) = phantomDb >>= \p -> return (fromPrimitivePersistValue p x, xs) primFromPersistValue xs = (\a -> fail (failMessage a xs) >> return (a, xs)) undefined -primToPurePersistValues :: (DbDescriptor db, PrimitivePersistField a) => Proxy db -> a -> ([PersistValue] -> [PersistValue])+primToPurePersistValues :: (DbDescriptor db, PrimitivePersistField a) => proxy db -> a -> ([PersistValue] -> [PersistValue]) primToPurePersistValues p a = (toPrimitivePersistValue p a:) -primFromPurePersistValues :: (DbDescriptor db, PrimitivePersistField a) => Proxy db -> [PersistValue] -> (a, [PersistValue])+primFromPurePersistValues :: (DbDescriptor db, PrimitivePersistField a) => proxy db -> [PersistValue] -> (a, [PersistValue]) primFromPurePersistValues p (x:xs) = (fromPrimitivePersistValue p x, xs) primFromPurePersistValues _ xs = (\a -> error (failMessage a xs) `asTypeOf` (a, xs)) undefined @@ -287,7 +287,7 @@ mapAllRows f pop = go where go = pop >>= maybe (return []) (f >=> \a -> liftM (a:) go) -phantomDb :: PersistBackend m => m (Proxy (PhantomDb m))+phantomDb :: PersistBackend m => m (proxy (PhantomDb m)) phantomDb = return $ error "phantomDb" isSimple :: [ConstructorDef] -> Bool
Database/Groundhog/Generic/Migration.hs view
@@ -12,6 +12,7 @@ , SchemaAnalyzer(..) , mkColumns , migrateRecursively+ , migrateSchema , migrateEntity , migrateList , getAlters@@ -22,10 +23,10 @@ import Database.Groundhog.Core import Database.Groundhog.Generic-import Database.Groundhog.Generic.Sql (tableName)+import Database.Groundhog.Generic.Sql (mainTableName, tableName) import Control.Arrow ((***), (&&&))-import Control.Monad (liftM)+import Control.Monad (liftM, when) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State (StateT (..), gets, modify) import Data.Function (on)@@ -80,6 +81,8 @@ | CreateOrReplaceFunction String -- | Function schema, function name | DropFunction (Maybe String) String+ -- | Schema name, if not exists+ | CreateSchema String Bool deriving Show data UniqueDef' = UniqueDef' {@@ -153,25 +156,35 @@ -- The stateful Map is used to avoid duplicate migrations when an entity type -- occurs several times in a datatype migrateRecursively :: (Monad m, PersistEntity v) => - (EntityDef -> m SingleMigration) -- ^ migrate entity+ (String -> m SingleMigration) -- ^ migrate schema+ -> (EntityDef -> m SingleMigration) -- ^ migrate entity -> (DbType -> m SingleMigration) -- ^ migrate list -> v -- ^ initial entity -> StateT NamedMigrations m ()-migrateRecursively migE migL = go . dbType where- go l@(DbList lName t) = f lName (migL l) (go t)+migrateRecursively migS migE migL = go . dbType where+ go l@(DbList lName t) = f ("list " ++ lName) (migL l) (go t) go (DbEmbedded (EmbeddedDef _ ts) ref) = mapM_ (go . snd) ts >> migRef ref go (DbTypePrimitive _ _ _ ref) = migRef ref- f name mig cont = do- v <- gets (Map.lookup name)- case v of- Nothing -> lift mig >>= modify . Map.insert name >> cont- _ -> return () allSubtypes = map snd . concatMap constrParams . constructors- -- TODO: use schema-qualified name migRef ref = case ref of- Just (Left (e, _), _, _) -> f (entityName e) (migE e) (mapM_ go (allSubtypes e))+ Just (Left (e, _), _, _) -> do+ case entitySchema e of+ Just name -> f ("schema " ++ name) (migS name) (return ())+ Nothing -> return ()+ f ("entity " ++ mainTableName id e) (migE e) (mapM_ go (allSubtypes e)) _ -> return ()+ f name mig cont = do+ v <- gets (Map.lookup name)+ when (v == Nothing) $+ lift mig >>= modify . Map.insert name >> cont +migrateSchema :: (Monad m, SchemaAnalyzer m) => MigrationPack m -> String -> m SingleMigration+migrateSchema MigrationPack{..} schema = do+ x <- schemaExists schema+ return $ if x+ then Right []+ else showAlterDb $ CreateSchema schema False+ migrateEntity :: (Monad m, SchemaAnalyzer m) => MigrationPack m -> EntityDef -> m SingleMigration migrateEntity m@MigrationPack{..} e = do let name = entityName e@@ -358,6 +371,8 @@ _ -> Nothing class Monad m => SchemaAnalyzer m where+ schemaExists :: String -- ^ Schema name+ -> m Bool listTables :: Maybe String -- ^ Schema name -> m [String] listTableTriggers :: Maybe String -- ^ Schema name
Database/Groundhog/Generic/PersistBackendHelpers.hs view
@@ -35,7 +35,7 @@ => RenderConfig -> (forall a . Utf8 -> [PersistValue] -> (RowPopper m -> m a) -> m a) -> Key v BackendSpecific -> m (Maybe v) get RenderConfig{..} queryFunc (k :: Key v BackendSpecific) = do let e = entityDef (undefined :: v)- let proxy = undefined :: Proxy (PhantomDb m)+ let proxy = undefined :: proxy (PhantomDb m) if isSimple (constructors e) then do let constr = head $ constructors e@@ -67,7 +67,7 @@ SelectOptions cond limit offset ords = getSelectOptions options e = entityDef (undefined :: v)- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) orders = renderOrders conf ords (lim, limps) = case (limit, offset) of (Nothing, Nothing) -> ("", [])@@ -80,7 +80,7 @@ whereClause = maybe "" (\c -> " WHERE " <> getQuery c) cond' doSelectQuery = queryFunc query binds $ mapAllRows $ liftM fst . fromEntityPersistValues . (toPrimitivePersistValue proxy cNum:) binds = maybe id getValues cond' $ limps- cNum = entityConstrNum (undefined :: Proxy v) (undefined :: c a)+ cNum = entityConstrNum (undefined :: proxy v) (undefined :: c a) constr = constructors e !! cNum selectAll :: forall m v . (PersistBackend m, PersistEntity v)@@ -97,7 +97,7 @@ let query = "SELECT " <> fields <> " FROM " <> tableName esc e constr queryFunc query [] $ mapAllRows $ mkEntity proxy cNum e = entityDef (undefined :: v)- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) getBy :: forall m v u . (PersistBackend m, PersistEntity v, IsUniqueKey (Key v (Unique u))) => RenderConfig@@ -123,7 +123,7 @@ project conf@RenderConfig{..} queryFunc noLimit p options = doSelectQuery where SelectOptions cond limit offset ords = getSelectOptions options e = entityDef (undefined :: v)- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) orders = renderOrders conf ords (lim, limps) = case (limit, offset) of (Nothing, Nothing) -> ("", [])@@ -137,15 +137,15 @@ whereClause = maybe "" (\c -> " WHERE " <> getQuery c) cond' doSelectQuery = queryFunc query binds $ mapAllRows $ liftM fst . projectionResult p binds = fieldVals . maybe id getValues cond' $ limps- constr = constructors e !! entityConstrNum (undefined :: Proxy v) (undefined :: c a)+ constr = constructors e !! entityConstrNum (undefined :: proxy v) (undefined :: c a) count :: forall m db r v c . (SqlDb db, QueryRaw db ~ Snippet db, db ~ PhantomDb m, r ~ RestrictionHolder v c, PersistBackend m, PersistEntity v, EntityConstr v c) => RenderConfig -> (forall a . Utf8 -> [PersistValue] -> (RowPopper m -> m a) -> m a) -> Cond db r -> m Int count conf@RenderConfig{..} queryFunc cond = do let e = entityDef (undefined :: v)- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) cond' = renderCond conf cond- constr = constructors e !! entityConstrNum (undefined :: Proxy v) (undefined :: c a)+ constr = constructors e !! entityConstrNum (undefined :: proxy v) (undefined :: c a) query = "SELECT COUNT(*) FROM " <> tableName esc e constr <> whereClause where whereClause = maybe "" (\c -> " WHERE " <> getQuery c) cond' x <- queryFunc query (maybe [] (flip getValues []) cond') id@@ -160,7 +160,7 @@ replace RenderConfig{..} queryFunc execFunc insertIntoConstructorTable k v = do vals <- toEntityPersistValues' v let e = entityDef v- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) constructorNum = fromPrimitivePersistValue proxy (head vals) constr = constructors e !! constructorNum k' = toPrimitivePersistValue proxy k@@ -218,7 +218,7 @@ case renderUpdates conf upds of Just upds' -> do let cond' = renderCond conf cond- constr = constructors e !! entityConstrNum (undefined :: Proxy v) (undefined :: c a)+ constr = constructors e !! entityConstrNum (undefined :: proxy v) (undefined :: c a) query = "UPDATE " <> tableName esc e constr <> " SET " <> whereClause where whereClause = maybe (getQuery upds') (\c -> getQuery upds' <> " WHERE " <> getQuery c) cond' execFunc query (getValues upds' <> maybe mempty getValues cond' $ [])@@ -228,7 +228,7 @@ => RenderConfig -> (Utf8 -> [PersistValue] -> m ()) -> Cond db r -> m () delete conf@RenderConfig{..} execFunc cond = execFunc query (maybe [] (($ []) . getValues) cond') where e = entityDef (undefined :: v)- constr = constructors e !! entityConstrNum (undefined :: Proxy v) (undefined :: c a)+ constr = constructors e !! entityConstrNum (undefined :: proxy v) (undefined :: c a) cond' = renderCond conf cond whereClause = maybe "" (\c -> " WHERE " <> getQuery c) cond' query = if isSimple (constructors e)@@ -243,7 +243,7 @@ -> v -> m (Either (AutoKey v) (AutoKey v)) insertByAll RenderConfig{..} queryFunc manyNulls v = do let e = entityDef v- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) (constructorNum, uniques) = getUniques proxy v constr = constructors e !! constructorNum uniqueDefs = constrUniques constr@@ -266,7 +266,7 @@ => RenderConfig -> (Utf8 -> [PersistValue] -> m ()) -> Key v BackendSpecific -> m () deleteBy RenderConfig{..} execFunc k = execFunc query [toPrimitivePersistValue proxy k] where e = entityDef ((undefined :: Key v u -> v) k)- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) constr = head $ constructors e idName = if isSimple (constructors e) then fromJust $ constrId esc constr@@ -285,7 +285,7 @@ => RenderConfig -> (forall a . Utf8 -> [PersistValue] -> (RowPopper m -> m a) -> m a) -> v -> m Int countAll RenderConfig{..} queryFunc (_ :: v) = do let e = entityDef (undefined :: v)- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) query = "SELECT COUNT(*) FROM " <> mainTableName esc e x <- queryFunc query [] id case x of@@ -301,7 +301,7 @@ insertBy conf@RenderConfig{..} queryFunc manyNulls u v = do uniques <- toPersistValues $ (extractUnique v `asTypeOf` ((undefined :: u (UniqueMarker v) -> Key v (Unique u)) u)) let e = entityDef v- proxy = undefined :: Proxy (PhantomDb m)+ proxy = undefined :: proxy (PhantomDb m) uFields = renderChain conf (fieldChain u) [] RenderS cond vals = intercalateS " AND " $ mkUniqueCond uFields uniques -- skip condition if any value is NULL. It allows to insert many values with duplicate unique key@@ -322,7 +322,7 @@ constrId escape = fmap (escape . fromString) . constrAutoKeyName -- | receives constructor number and row of values from the constructor table-mkEntity :: (PersistEntity v, PersistBackend m) => Proxy (PhantomDb m) -> Int -> [PersistValue] -> m (AutoKey v, v)+mkEntity :: (PersistEntity v, PersistBackend m) => proxy (PhantomDb m) -> Int -> [PersistValue] -> m (AutoKey v, v) mkEntity proxy i xs = fromEntityPersistValues (toPrimitivePersistValue proxy i:xs') >>= \(v, _) -> return (k, v) where (k, xs') = fromPurePersistValues proxy xs
Database/Groundhog/Generic/Sql.hs view
@@ -119,7 +119,7 @@ ExprCond a -> case renderCondPriority conf p a of Nothing -> error "renderExprPriority: empty condition" Just x -> x) where- proxy = (undefined :: f db r -> Proxy db) expr+ proxy = (undefined :: f db r -> proxy db) expr ensureOne :: [a] -> (a -> b) -> b ensureOne xs f = case xs of [x] -> f x@@ -132,7 +132,7 @@ ExprPure a -> let vals = toPurePersistValues proxy a [] in map renderPersistValue vals ExprCond a -> maybeToList $ renderCondPriority conf p a) where- proxy = (undefined :: f db r -> Proxy db) expr+ proxy = (undefined :: f db r -> proxy db) expr renderPersistValue :: PersistValue -> RenderS db r renderPersistValue (PersistCustom s as) = RenderS s (as++)
Database/Groundhog/Instances.hs view
@@ -470,10 +470,10 @@ projectionExprs c = ((map ExprField chains)++) where chains = map (\f -> (f, [])) $ constrParams constr e = entityDef ((undefined :: c (ConstructorMarker v) -> v) c)- cNum = entityConstrNum ((undefined :: c (ConstructorMarker v) -> Proxy v) c) c+ cNum = entityConstrNum ((undefined :: c (ConstructorMarker v) -> proxy v) c) c constr = constructors e !! cNum projectionResult c xs = toSinglePersistValue cNum >>= \cNum' -> fromEntityPersistValues (cNum':xs) where- cNum = entityConstrNum ((undefined :: c (ConstructorMarker v) -> Proxy v) c) c+ cNum = entityConstrNum ((undefined :: c (ConstructorMarker v) -> proxy v) c) c instance (PersistEntity v, IsUniqueKey k, k ~ Key v (Unique u), r ~ RestrictionHolder v c) => Projection (u (UniqueMarker v)) db r k where@@ -530,7 +530,7 @@ k = (undefined :: AutoKeyField v c -> AutoKey v) a e = entityDef ((undefined :: AutoKeyField v c -> v) a)- cNum = entityConstrNum ((undefined :: AutoKeyField v c -> Proxy v) a) ((undefined :: AutoKeyField v c -> c (ConstructorMarker v)) a)+ cNum = entityConstrNum ((undefined :: AutoKeyField v c -> proxy v) a) ((undefined :: AutoKeyField v c -> c (ConstructorMarker v)) a) instance (EntityConstr v c, PersistField a) => FieldLike (SubField v c a) db (RestrictionHolder v c) a where fieldChain (SubField a) = a@@ -546,7 +546,7 @@ constr = head $ constructors (entityDef ((undefined :: u (UniqueMarker v) -> v) u)) instance (PersistEntity v, EntityConstr' (IsSumType v) c) => EntityConstr v c where- entityConstrNum v = entityConstrNum' $ (undefined :: Proxy v -> IsSumType v) v+ entityConstrNum v = entityConstrNum' $ (undefined :: proxy v -> IsSumType v) v class EntityConstr' flag c where entityConstrNum' :: flag -> c (a :: * -> *) -> Int instance EntityConstr' HFalse c where
+ changelog view
@@ -0,0 +1,66 @@+0.4.2.2+* Create missing schemas (or databases in MySQL terminology) during migration+* Replace datatype Proxy with type variable++0.4.2+* Cond can be used as expression+* Expressions instances for Fractional, Floating, Integral+* Operator case_++0.4.1+* Added functions replaceBy and deleteAll+* Renamed deleteByKey to deleteBy+* Instances of UTCTime and ZonedTime can read both values with time zone and without it++0.4.0.3+* Added function runDbConnNoTransaction to run a monadic action without creating a transaction around it++0.4.0.2+* Fix for nullable fields in unique constraint++0.4.0.1+* Added migration helper function Database.Groundhog.Generic.getQueries+* Added comparison function Database.Groundhog.Expression.isFieldNothing++0.4.0+* References to tables not mapped by groundhog+* Default column values+* Better type inference for expressions+* Constructor for empty condition CondEmpty+* Logging queries based on monad-logger++0.3.1+* Removed superclass constraints SinglePersistField and PurePersistField for PrimitivePersistField+* Fixed prefixing columns of nested embedded datatypes when not all names are specified++0.3+* Custom compositional functions and operators+* ConnectionManager which helps to extract connections from pools, application state, etc.+* Support for savepoints+* Schema qualified tables+* Added unique constraints of type PRIMARY+* Reference clauses ON DELETE and ON UPDATE.+* Exposed database introspection capabilities with class SchemaAnalyzer++0.2+* Database indexes+* Support DB-specific column types+* Renaming and refactoring++0.1.0.2+* Removed overly restrictive upper bound for bytestring package++0.1.0.1+* Compatibility with GHC 7.6++0.1.0+The library was almost completely overhauled.+* Support for embedded datatypes+* New syntax for select+* Embedded datatypes+* Composite foreign keys and natural keys+* Projections of datatype fields+* Codegeneration modules are moved to groundhog-th package++0.0.1+The first release. It has support for polymorphic datatypes and sum types.
groundhog.cabal view
@@ -1,5 +1,5 @@ name: groundhog-version: 0.4.2.1+version: 0.4.2.2 license: BSD3 license-file: LICENSE author: Boris Lykah <lykahb@gmail.com>@@ -11,6 +11,9 @@ cabal-version: >= 1.6 build-type: Simple homepage: http://github.com/lykahb/groundhog++extra-source-files:+ changelog library build-depends: base >= 4 && < 5