insert/insertMany/save: create (if needed) and return '_id' field
This commit is contained in:
parent
3956adab00
commit
56fcb3a90e
2 changed files with 31 additions and 17 deletions
|
@ -90,7 +90,8 @@ import System.Random
|
||||||
-- | A list of handles to database connections
|
-- | A list of handles to database connections
|
||||||
data Connection = Connection {
|
data Connection = Connection {
|
||||||
cHandle :: IORef Handle,
|
cHandle :: IORef Handle,
|
||||||
cRand :: IORef [Int]
|
cRand :: IORef [Int],
|
||||||
|
cOidGen :: ObjectIdGen
|
||||||
}
|
}
|
||||||
|
|
||||||
data ConnectOpt
|
data ConnectOpt
|
||||||
|
@ -123,7 +124,8 @@ newConnection servers opts = do
|
||||||
fromIntegral (maxBound :: Int32)) r
|
fromIntegral (maxBound :: Int32)) r
|
||||||
nsRef <- newIORef ns
|
nsRef <- newIORef ns
|
||||||
hRef <- openHandle (head servers) >>= newIORef
|
hRef <- openHandle (head servers) >>= newIORef
|
||||||
let c = Connection hRef nsRef
|
oidGen <- mkObjectIdGen
|
||||||
|
let c = Connection hRef nsRef oidGen
|
||||||
res <- isMaster c
|
res <- isMaster c
|
||||||
if fromBson (fromLookup $ List.lookup (s2L "ismaster") res) == (1::Int) ||
|
if fromBson (fromLookup $ List.lookup (s2L "ismaster") res) == (1::Int) ||
|
||||||
isJust (List.elemIndex SlaveOK opts)
|
isJust (List.elemIndex SlaveOK opts)
|
||||||
|
@ -496,27 +498,41 @@ delete c col sel = do
|
||||||
remove :: Connection -> FullCollection -> Selector -> IO RequestID
|
remove :: Connection -> FullCollection -> Selector -> IO RequestID
|
||||||
remove = delete
|
remove = delete
|
||||||
|
|
||||||
-- | Insert a single document into /FullCollection/.
|
moveOidToFrontOrGen :: Connection -> BsonDoc -> IO BsonDoc
|
||||||
insert :: Connection -> FullCollection -> BsonDoc -> IO RequestID
|
moveOidToFrontOrGen c doc =
|
||||||
|
case List.lookup (s2L "_id") doc of
|
||||||
|
Nothing -> do
|
||||||
|
oid <- genObjectId $ cOidGen c
|
||||||
|
return $ (s2L "_id", oid) : doc
|
||||||
|
Just oid -> do
|
||||||
|
let keyEq = (\(k1, _) (k2, _) -> k1 == k2)
|
||||||
|
delByKey = \k -> List.deleteBy keyEq (k, undefined)
|
||||||
|
return $ (s2L "_id", oid) : delByKey (s2L "_id") doc
|
||||||
|
|
||||||
|
-- | Insert a single document into /FullCollection/ returning the /_id/ field.
|
||||||
|
insert :: Connection -> FullCollection -> BsonDoc -> IO BsonValue
|
||||||
insert c col doc = do
|
insert c col doc = do
|
||||||
|
doc' <- moveOidToFrontOrGen c doc
|
||||||
let body = runPut $ do
|
let body = runPut $ do
|
||||||
putI32 0
|
putI32 0
|
||||||
putCol col
|
putCol col
|
||||||
putBsonDoc doc
|
putBsonDoc doc'
|
||||||
(reqID, msg) <- packMsg c OPInsert body
|
(_reqID, msg) <- packMsg c OPInsert body
|
||||||
cPut c msg
|
cPut c msg
|
||||||
return reqID
|
return $ snd $ head doc'
|
||||||
|
|
||||||
-- | Insert a list of documents into /FullCollection/.
|
-- | Insert a list of documents into /FullCollection/ returing the
|
||||||
insertMany :: Connection -> FullCollection -> [BsonDoc] -> IO RequestID
|
-- /_id/ field for each one in the same order as they were given.
|
||||||
|
insertMany :: Connection -> FullCollection -> [BsonDoc] -> IO [BsonValue]
|
||||||
insertMany c col docs = do
|
insertMany c col docs = do
|
||||||
|
docs' <- mapM (moveOidToFrontOrGen c) docs
|
||||||
let body = runPut $ do
|
let body = runPut $ do
|
||||||
putI32 0
|
putI32 0
|
||||||
putCol col
|
putCol col
|
||||||
forM_ docs putBsonDoc
|
forM_ docs' putBsonDoc
|
||||||
(reqID, msg) <- packMsg c OPInsert body
|
(_, msg) <- packMsg c OPInsert body
|
||||||
cPut c msg
|
cPut c msg
|
||||||
return reqID
|
return $ List.map (snd . head) docs'
|
||||||
|
|
||||||
-- | Open a cursor to find documents. If you need full functionality,
|
-- | Open a cursor to find documents. If you need full functionality,
|
||||||
-- see 'query'
|
-- see 'query'
|
||||||
|
@ -741,11 +757,12 @@ mapReduceWScopes c fc m ms r rs opts =
|
||||||
-- if there is an _id present in the /BsonDoc/ then it already has
|
-- if there is an _id present in the /BsonDoc/ then it already has
|
||||||
-- a place in the DB, so we update it using the _id, otherwise
|
-- a place in the DB, so we update it using the _id, otherwise
|
||||||
-- we insert it
|
-- we insert it
|
||||||
save :: Connection -> FullCollection -> BsonDoc -> IO RequestID
|
save :: Connection -> FullCollection -> BsonDoc -> IO BsonValue
|
||||||
save c fc doc =
|
save c fc doc =
|
||||||
case List.lookup (s2L "_id") doc of
|
case List.lookup (s2L "_id") doc of
|
||||||
Nothing -> insert c fc doc
|
Nothing -> insert c fc doc
|
||||||
Just obj -> update c fc [UFUpsert] (toBsonDoc [("_id", obj)]) doc
|
Just oid -> update c fc [UFUpsert] (toBsonDoc [("_id", oid)]) doc >>
|
||||||
|
return oid
|
||||||
|
|
||||||
-- | Use this in the place of the query portion of a select type query
|
-- | Use this in the place of the query portion of a select type query
|
||||||
-- This uses javascript and a scope supplied by a /BsonDoc/ to evaluate
|
-- This uses javascript and a scope supplied by a /BsonDoc/ to evaluate
|
||||||
|
|
3
TODO
3
TODO
|
@ -1,8 +1,6 @@
|
||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
+ inject _id if not given, return it
|
|
||||||
|
|
||||||
BSON
|
BSON
|
||||||
----
|
----
|
||||||
+ on insert/update: reject keys that start with "$" or "."
|
+ on insert/update: reject keys that start with "$" or "."
|
||||||
|
@ -63,7 +61,6 @@ MongoDB
|
||||||
+ support safe operations
|
+ support safe operations
|
||||||
+ auto-reconnection
|
+ auto-reconnection
|
||||||
+ auto-destoy connection (how?/when?)
|
+ auto-destoy connection (how?/when?)
|
||||||
+ pymongo returns the new ObjectId(s) on insert
|
|
||||||
+ don't read into cursor until needed, but have cursor send getMore before
|
+ don't read into cursor until needed, but have cursor send getMore before
|
||||||
it is actually out of docs (so network is finished by the time we're ready
|
it is actually out of docs (so network is finished by the time we're ready
|
||||||
to consume more)
|
to consume more)
|
||||||
|
|
Loading…
Reference in a new issue