insert/insertMany/save: create (if needed) and return '_id' field

This commit is contained in:
Scott R. Parish 2010-03-13 21:44:00 -06:00
parent 3956adab00
commit 56fcb3a90e
2 changed files with 31 additions and 17 deletions

View file

@ -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
View file

@ -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)