Skip to content

function to apply #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Database/MongoDB/Query.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module Database.MongoDB.Query (
Projector, Limit, Order, BatchSize,
explain, find, findOne, fetch, count, distinct,
-- *** Cursor
Cursor, nextBatch, next, nextN, rest, closeCursor, isCursorClosed,
Cursor, nextBatch, next, nextN, rest, iterateCursor, closeCursor, isCursorClosed,
-- ** Group
Group(..), GroupKey(..), group,
-- ** MapReduce
Expand Down Expand Up @@ -565,6 +565,11 @@ nextN :: (MonadIO m, MonadBaseControl IO m, Functor m) => Int -> Cursor -> Actio
-- ^ Return next N documents or less if end is reached
nextN n c = catMaybes <$> replicateM n (next c)

iterateCursor :: (MonadIO m, MonadBaseControl IO m, Functor m) => (Document -> a -> Action m a) -> a -> Cursor -> Action m a
-- ^ iteratively runs an action while consuming documents
iterateCursor f st0 c = next c >>= maybe (closeCursor c >> return st0) go
where go doc = f doc st0 >>= (\st1 -> iterateCursor f st1 c)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a potential stack overflow to me, st1 should be strict. Also, this solution seems to have non-deterministic behaviour, inherent to lazy IO. For instance, what if for some reason the consumer didn't read until the end, when will the cursor be closed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Use 'next' to iterate or 'rest' to get all results. A cursor is closed when it is explicitly closed, all results have been read from it, garbage collected, or not used for over 10 minutes". It is already possible to shoot yourself in the foot with current API with "next". But using "next" by hand is a pain in the neck when processing a large stream of docs. That's why I think the API should provide a smart function like this one. My attempt may be broken but I'm willing to improve on it :). Making st1 strict is definitely a good idea because one may expect "imperative" style from this function. I'll look at gracefully handling errors happening in the Action.


rest :: (MonadIO m, MonadBaseControl IO m, Functor m) => Cursor -> Action m [Document]
-- ^ Return remaining documents in query result
rest c = loop (next c)
Expand Down