use
MongoDBTest
qw/skip_unless_mongod build_client get_test_db server_version server_type/
;
skip_unless_mongod();
my
$conn
= build_client();
my
$testdb
= get_test_db(
$conn
);
my
$server_version
= server_version(
$conn
);
my
$server_type
= server_type(
$conn
);
my
$coll
=
$testdb
->get_collection(
'test_collection'
);
my
$coll2
=
$testdb
->get_collection(
"cap_collection"
);
my
$create_capped_cmd
= [
create
=>
"cap_collection"
,
capped
=> 1,
size
=> 10000 ];
my
$cursor
;
my
@values
;
{
$coll
->drop;
$coll
->insert_one({
foo
=> 9,
bar
=> 3,
shazbot
=> 1 });
$coll
->insert_one({
foo
=> 2,
bar
=> 5 });
$coll
->insert_one({
foo
=> -3,
bar
=> 4 });
$coll
->insert_one({
foo
=> 4,
bar
=> 9,
shazbot
=> 1 });
}
{
@values
=
$coll
->query({}, {
sort_by
=> {
foo
=> 1 } })->all;
is(
scalar
@values
, 4);
is (
$values
[0]->{foo}, -3);
is (
$values
[1]->{foo}, 2);
is (
$values
[2]->{foo}, 4);
is (
$values
[3]->{foo}, 9);
@values
=
$coll
->query({}, {
sort_by
=> {
bar
=> -1 } })->all;
is(
scalar
@values
, 4);
is(
$values
[0]->{bar}, 9);
is(
$values
[1]->{bar}, 5);
is(
$values
[2]->{bar}, 4);
is(
$values
[3]->{bar}, 3);
}
{
@values
=
$coll
->query({
shazbot
=> 1 }, {
sort_by
=> {
foo
=> -1 } })->all;
is(
scalar
@values
, 2);
is(
$values
[0]->{foo}, 9);
is(
$values
[1]->{foo}, 4);
}
{
@values
=
$coll
->query({}, {
limit
=> 3,
sort_by
=> {
foo
=> 1 } })->all;
is(
scalar
@values
, 3) or diag explain \
@values
;
is (
$values
[0]->{foo}, -3);
is (
$values
[1]->{foo}, 2);
is (
$values
[2]->{foo}, 4);
}
{
my
$c
=
$coll
->query({}, {
limit
=> 3,
sort_by
=> {
foo
=> 1 } });
is(
$c
->result->_limit, 3,
'query limit was propagated'
);
}
{
@values
=
$coll
->query({}, {
limit
=> 3,
skip
=> 1,
sort_by
=> {
foo
=> 1 } })->all;
is(
scalar
@values
, 3);
is (
$values
[0]->{foo}, 2);
is (
$values
[1]->{foo}, 4);
is (
$values
[2]->{foo}, 9);
}
$coll
->drop;
{
is(
$coll
->query->
next
,
undef
,
'test undef'
);
is_deeply([
$coll
->query->all], []);
my
$id1
=
$coll
->insert_one({
x
=> 1})->inserted_id;
my
$id2
=
$coll
->insert_one({
x
=> 5})->inserted_id;
is(
$coll
->count_documents({}), 2);
$cursor
=
$coll
->query;
is(
$cursor
->
next
->{
'x'
}, 1);
is(
$cursor
->
next
->{
'x'
}, 5);
is(
$cursor
->
next
,
undef
);
my
$cursor2
=
$coll
->query({
x
=> 5});
is_deeply([
$cursor2
->all], [{
_id
=>
$id2
,
x
=> 5}]);
is_deeply([
$coll
->query->all], [{
_id
=>
$id1
,
x
=> 1}, {
_id
=>
$id2
,
x
=> 5}]);
}
{
my
$cursor_sort
=
$coll
->query->
sort
({
'x'
=> -1});
is(
$cursor_sort
->has_next, 1);
is(
$cursor_sort
->
next
->{
'x'
}, 5,
'Cursor->sort'
);
is(
$cursor_sort
->
next
->{
'x'
}, 1);
$cursor_sort
=
$coll
->query->
sort
({
'x'
=> 1});
is(
$cursor_sort
->
next
->{
'x'
}, 1);
is(
$cursor_sort
->
next
->{
'x'
}, 5);
my
$hash
= Tie::IxHash->new(
"x"
=> -1);
$cursor_sort
=
$coll
->query->
sort
(
$hash
);
is(
$cursor_sort
->has_next, 1);
is(
$cursor_sort
->
next
->{
'x'
}, 5,
'Tie::IxHash cursor->sort'
);
is(
$cursor_sort
->
next
->{
'x'
}, 1);
}
{
$coll
->insert_one({
x
=> 2});
$coll
->insert_one({
x
=> 3});
$coll
->insert_one({
x
=> 4});
my
$paging
=
$coll
->query->skip(1)->limit(2);
is(
$paging
->has_next, 1,
'check skip/limit'
);
$paging
->
next
;
is(
$paging
->has_next, 1);
$paging
->
next
;
is(
int
$paging
->has_next, 0);
}
{
$coll
=
$testdb
->get_collection(
'test'
);
$coll
->drop;
$coll
->indexes->create_one({
'sn'
=>1});
my
$bulk
=
$coll
->unordered_bulk;
$bulk
->insert_one({
sn
=>
$_
})
for
0 .. 5000;
$bulk
->execute;
$cursor
=
$coll
->query;
my
$count
= 0;
while
(
my
$doc
=
$cursor
->
next
()) {
$count
++;
}
is(5001,
$count
);
my
@all
=
$coll
->find->limit(3999)->all;
is( 0+
@all
, 3999,
"got limited documents"
);
}
{
my
(
$r1
,
$r2
);
ok(
$cursor
->
reset
,
"first reset"
);
ok( (
$r1
=
$cursor
->
next
),
"first doc after first reset"
);
ok(
$cursor
->
reset
,
"second reset"
);
ok( (
$r2
=
$cursor
->
next
),
"first doc after second reset"
);
is(
$r1
->{
'sn'
},
$r2
->{
'sn'
},
'reset'
);
}
{
my
$exp
=
$cursor
->explain;
if
(
$server_version
>= v2.7.3 ) {
is (
$exp
->{executionStats}{nReturned}, 5001,
"count of items"
);
$cursor
->
reset
;
$exp
=
$cursor
->limit(20)->explain;
is (
$exp
->{executionStats}{nReturned}, 20,
"explain with limit"
);
$cursor
->
reset
;
$exp
=
$cursor
->limit(-20)->explain;
is (
$exp
->{executionStats}{nReturned}, 20,
"explain with negative limit"
);
}
else
{
is(
$exp
->{
'n'
}, 5001,
'explain'
);
is(
$exp
->{
'cursor'
},
'BasicCursor'
);
$cursor
->
reset
;
$exp
=
$cursor
->limit(20)->explain;
is(20,
$exp
->{
'n'
},
'explain limit'
);
$cursor
->
reset
;
$exp
=
$cursor
->limit(-20)->explain;
is(20,
$exp
->{
'n'
});
}
}
{
$cursor
->
reset
;
my
$hinted
=
$cursor
->hint({
'x'
=> 1});
is(
$hinted
,
$cursor
,
"hint returns self"
);
$coll
->drop;
$coll
->insert_one({
'num'
=> 1,
'foo'
=> 1});
like( exception {
$coll
->query->hint( {
'num'
=> 1 } )->explain },
qr/MongoDB::(Database)?Error/
,
"check error on hint with explain"
);
}
{
$cursor
=
$coll
->find();
$cursor
=
$cursor
->tailable(1);
is(
$cursor
->_query->options->{cursorType},
'tailable'
,
"set tailable"
);
$cursor
=
$cursor
->tailable(0);
is(
$cursor
->_query->options->{cursorType},
'non_tailable'
,
"clear tailable"
);
$cursor
=
$cursor
->tailable_await(1);
is(
$cursor
->_query->options->{cursorType},
'tailable_await'
,
"set tailable_await"
);
$cursor
=
$cursor
->tailable_await(0);
is(
$cursor
->_query->options->{cursorType},
'non_tailable'
,
"clear tailable_await"
);
$cursor
=
$cursor
->tailable(1);
is(
$cursor
->_query->options->{cursorType},
'tailable'
,
"set tailable"
);
$cursor
=
$cursor
->tailable_await(0);
is(
$cursor
->_query->options->{cursorType},
'non_tailable'
,
"clear tailable_await"
);
$cursor
=
$cursor
->tailable_await(1);
is(
$cursor
->_query->options->{cursorType},
'tailable_await'
,
"set tailable_await"
);
$cursor
=
$cursor
->tailable(0);
is(
$cursor
->_query->options->{cursorType},
'non_tailable'
,
"clear tailable"
);
$coll
->drop;
$coll
->insert_one({
"x"
=> 1});
$cursor
=
$coll
->find()->tailable(0);
my
$doc
=
$cursor
->
next
;
is(
$doc
->{
'x'
}, 1);
$cursor
=
$coll
->find();
$cursor
->immortal(1);
ok(
$cursor
->_query->options->{noCursorTimeout},
"set immortal"
);
$cursor
->immortal(0);
ok(!
$cursor
->_query->options->{noCursorTimeout},
"clear immortal"
);
}
{
$coll
->drop;
$coll
->insert_one({
"x"
=> 1});
$cursor
=
$coll
->find;
my
$doc
=
$cursor
->
next
;
is(
$doc
->{
'x'
}, 1);
my
$exp
=
$cursor
->explain;
$doc
=
$cursor
->
next
;
is(
$doc
,
undef
) or diag explain
$doc
;
}
{
$coll
->drop;
$coll
->insert_one( {
x
=>
$_
} )
for
1 .. 1000;
$cursor
=
$coll
->find;
my
$info
=
$cursor
->info;
is_deeply(
$info
, {
num
=> 0},
"before execution, info only has num field"
);
ok(
$cursor
->has_next,
"cursor executed and has results"
);
$info
=
$cursor
->info;
ok(
$info
->{
'num'
} > 0,
"cursor reports more than zero results"
);
is(
$info
->{
'at'
}, 0,
"cursor still not iterated"
);
is(
$info
->{
'start'
}, 0);
ok(
$info
->{
'cursor_id'
},
"cursor_id non-zero"
);
$cursor
->
next
;
$info
=
$cursor
->info;
is(
$info
->{
'at'
}, 1);
$cursor
->all;
$info
=
$cursor
->info;
is(
$info
->{at}, 1000);
is(
$info
->{num}, 1000,
'cursor_num after ->all'
);
}
{
$coll
->drop;
for
(
my
$i
=0;
$i
< 5;
$i
++) {
$coll
->insert_one({
x
=>
$i
});
}
$cursor
=
$coll
->query({}, {
limit
=> 10,
skip
=> 0,
sort_by
=> {
created
=> 1 }});
is(
$coll
->count_documents({}), 5);
}
subtest
"delayed tailable cursor"
=>
sub
{
$coll2
->drop;
$testdb
->run_command(
$create_capped_cmd
);
$coll2
->insert_one( {
x
=>
$_
} )
for
0 .. 9;
my
$cursor
=
$coll2
->find()->
sort
({
x
=> -1})->limit(1);
my
$last_doc
=
$cursor
->
next
();
$cursor
=
$coll2
->find({
_id
=> {
'$gt'
=>
$last_doc
->{_id}}})->tailable(1);
$cursor
->
next
();
for
(
my
$i
=10;
$i
< 20;
$i
++) {
$coll2
->insert_one({
x
=>
$i
});
}
my
$count
=()=
$cursor
->all;
is(
$count
, 10);
};
subtest
"await data"
=>
sub
{
$coll2
->drop;
$testdb
->run_command(
$create_capped_cmd
);
$coll2
->insert_one( {
x
=>
$_
} )
for
0 .. 9;
my
$cursor
=
$coll2
->find()->
sort
( {
x
=> -1 } )->limit(1);
my
$last_doc
=
$cursor
->
next
();
my
$start
=
time
;
$cursor
=
$coll2
->find( {
_id
=> {
'$gt'
=>
$last_doc
->{_id} } } )->tailable_await(1)
->max_await_time_ms(2000);
$cursor
->
next
();
my
$end
=
time
;
ok(
$end
>=
$start
+ 1,
"cursor blocked to await data"
)
or diag
"START: $start; END: $end"
;
};
done_testing;