monga 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/README.md +59 -3
- data/lib/monga/client.rb +51 -6
- data/lib/monga/clients/master_slave_client.rb +0 -5
- data/lib/monga/clients/replica_set_client.rb +32 -71
- data/lib/monga/clients/single_instance_client.rb +53 -0
- data/lib/monga/collection.rb +102 -41
- data/lib/monga/connection.rb +38 -13
- data/lib/monga/connection_pool.rb +6 -17
- data/lib/monga/connections/buffer.rb +33 -0
- data/lib/monga/connections/em_connection.rb +25 -56
- data/lib/monga/connections/em_proxy_connection.rb +80 -0
- data/lib/monga/connections/fibered_connection.rb +26 -0
- data/lib/monga/connections/fibered_proxy_connection.rb +23 -0
- data/lib/monga/connections/proxy_connection.rb +4 -0
- data/lib/monga/connections/tcp_connection.rb +57 -0
- data/lib/monga/cursor.rb +197 -95
- data/lib/monga/database.rb +175 -60
- data/lib/monga/{requests → protocol}/delete.rb +1 -2
- data/lib/monga/{requests → protocol}/get_more.rb +1 -1
- data/lib/monga/{requests → protocol}/insert.rb +1 -2
- data/lib/monga/{requests → protocol}/kill_cursors.rb +1 -1
- data/lib/monga/{requests → protocol}/query.rb +3 -3
- data/lib/monga/{requests → protocol}/update.rb +1 -1
- data/lib/monga/request.rb +27 -23
- data/lib/monga/utils/constants.rb +5 -0
- data/lib/monga/utils/exceptions.rb +11 -0
- data/lib/monga.rb +19 -11
- data/monga.gemspec +2 -2
- data/spec/helpers/mongodb.rb +115 -38
- data/spec/monga/block/collection_spec.rb +172 -0
- data/spec/monga/block/cursor_spec.rb +160 -0
- data/spec/monga/block/database_spec.rb +80 -0
- data/spec/monga/block/single_instance_client_spec.rb +31 -0
- data/spec/monga/em/collection_spec.rb +308 -0
- data/spec/monga/em/cursor_spec.rb +256 -0
- data/spec/monga/em/database_spec.rb +140 -0
- data/spec/monga/em/replica_set_client_spec.rb +86 -0
- data/spec/monga/em/single_instance_client_spec.rb +28 -0
- data/spec/monga/sync/collection_spec.rb +247 -0
- data/spec/monga/sync/cursor_spec.rb +211 -0
- data/spec/monga/sync/database_spec.rb +110 -0
- data/spec/monga/sync/replica_set_client_spec.rb +54 -0
- data/spec/monga/sync/single_instance_client_spec.rb +25 -0
- data/spec/spec_helper.rb +2 -20
- metadata +50 -38
- data/lib/monga/clients/client.rb +0 -24
- data/lib/monga/connections/primary.rb +0 -46
- data/lib/monga/connections/secondary.rb +0 -13
- data/lib/monga/exceptions.rb +0 -9
- data/lib/monga/miner.rb +0 -72
- data/lib/monga/response.rb +0 -11
- data/spec/helpers/truncate.rb +0 -15
- data/spec/monga/collection_spec.rb +0 -448
- data/spec/monga/connection_pool_spec.rb +0 -50
- data/spec/monga/connection_spec.rb +0 -64
- data/spec/monga/cursor_spec.rb +0 -186
- data/spec/monga/database_spec.rb +0 -67
- data/spec/monga/replica_set_client_spec.rb +0 -46
- data/spec/monga/requests/delete_spec.rb +0 -0
- data/spec/monga/requests/insert_spec.rb +0 -0
- data/spec/monga/requests/query_spec.rb +0 -28
data/lib/monga/request.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Monga
|
2
2
|
class Request
|
3
|
-
attr_reader :request_id
|
3
|
+
attr_reader :request_id, :connection
|
4
4
|
|
5
5
|
OP_CODES = {
|
6
6
|
reply: 1,
|
@@ -14,12 +14,13 @@ module Monga
|
|
14
14
|
kill_cursors: 2007,
|
15
15
|
}
|
16
16
|
|
17
|
-
def initialize(
|
18
|
-
@
|
17
|
+
def initialize(connection, db_name, collection_name, options = {})
|
18
|
+
@connection = connection
|
19
|
+
@db_name = db_name
|
19
20
|
@collection_name = collection_name
|
20
21
|
@options = options
|
22
|
+
|
21
23
|
@request_id = self.class.request_id
|
22
|
-
@connection = @db.client.aquire_connection
|
23
24
|
end
|
24
25
|
|
25
26
|
def command
|
@@ -37,23 +38,25 @@ module Monga
|
|
37
38
|
|
38
39
|
# Fire and Forget
|
39
40
|
def perform
|
40
|
-
@connection.send_command(command)
|
41
|
-
|
41
|
+
@connection.send_command(command, @request_id)
|
42
|
+
self
|
42
43
|
end
|
43
44
|
|
44
45
|
# Fire and wait
|
45
46
|
def callback_perform
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
@connection.send_command(command, @request_id) do |data|
|
48
|
+
err, resp = parse_response(data)
|
49
|
+
if block_given?
|
50
|
+
yield(err, resp)
|
51
|
+
else
|
52
|
+
err ? raise(err) : resp
|
50
53
|
end
|
51
54
|
end
|
52
55
|
end
|
53
56
|
|
54
57
|
def parse_response(data)
|
55
58
|
if Exception === data
|
56
|
-
data
|
59
|
+
[data, nil]
|
57
60
|
else
|
58
61
|
flags = data[4]
|
59
62
|
number = data[7]
|
@@ -66,7 +69,7 @@ module Monga
|
|
66
69
|
elsif docs.first && (docs.first["err"] || docs.first["errmsg"])
|
67
70
|
Monga::Exceptions::QueryFailure.new(docs.first)
|
68
71
|
else
|
69
|
-
data
|
72
|
+
[nil, data]
|
70
73
|
end
|
71
74
|
end
|
72
75
|
end
|
@@ -90,7 +93,7 @@ module Monga
|
|
90
93
|
end
|
91
94
|
|
92
95
|
def full_name
|
93
|
-
[@
|
96
|
+
[@db_name, @collection_name] * "."
|
94
97
|
end
|
95
98
|
|
96
99
|
def op_code
|
@@ -98,13 +101,14 @@ module Monga
|
|
98
101
|
end
|
99
102
|
|
100
103
|
def command_length
|
101
|
-
HEADER_SIZE + body.size
|
104
|
+
Monga::HEADER_SIZE + body.size
|
102
105
|
end
|
103
106
|
|
104
107
|
def self.request_id
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
+
@@request_id ||= 0
|
109
|
+
@@request_id += 1
|
110
|
+
@@request_id >= 2**32 ? @@request_id = 1 : @@request_id
|
111
|
+
@@request_id
|
108
112
|
end
|
109
113
|
|
110
114
|
def self.op_name(op = nil)
|
@@ -114,9 +118,9 @@ module Monga
|
|
114
118
|
end
|
115
119
|
|
116
120
|
|
117
|
-
require File.expand_path("../
|
118
|
-
require File.expand_path("../
|
119
|
-
require File.expand_path("../
|
120
|
-
require File.expand_path("../
|
121
|
-
require File.expand_path("../
|
122
|
-
require File.expand_path("../
|
121
|
+
require File.expand_path("../protocol/query", __FILE__)
|
122
|
+
require File.expand_path("../protocol/insert", __FILE__)
|
123
|
+
require File.expand_path("../protocol/delete", __FILE__)
|
124
|
+
require File.expand_path("../protocol/update", __FILE__)
|
125
|
+
require File.expand_path("../protocol/get_more", __FILE__)
|
126
|
+
require File.expand_path("../protocol/kill_cursors", __FILE__)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Monga::Exceptions
|
2
|
+
class InvalidClientOption < StandardError; end
|
3
|
+
class UndefinedSocketType < StandardError; end
|
4
|
+
class WrongConnectionType < StandardError; end
|
5
|
+
class Disconnected < StandardError; end
|
6
|
+
class CouldNotConnect < StandardError; end
|
7
|
+
class CouldNotReconnect < StandardError; end
|
8
|
+
class QueryFailure < StandardError; end
|
9
|
+
class CursorNotFound < StandardError; end
|
10
|
+
class ClosedCursor < StandardError; end
|
11
|
+
end
|
data/lib/monga.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
|
-
require "
|
1
|
+
require "em-synchrony"
|
2
2
|
require "bson"
|
3
3
|
require "logger"
|
4
|
+
require "forwardable"
|
4
5
|
|
5
6
|
module Monga
|
6
|
-
DEFAULT_HOST = "127.0.0.1"
|
7
|
-
DEFAULT_PORT = 27017
|
8
|
-
HEADER_SIZE = 16
|
9
|
-
|
10
7
|
extend self
|
11
8
|
|
12
9
|
def logger
|
@@ -18,13 +15,24 @@ module Monga
|
|
18
15
|
end
|
19
16
|
end
|
20
17
|
|
18
|
+
# It is strange, but cursor should be required befor fibered_connection
|
19
|
+
require File.expand_path("../monga/cursor", __FILE__)
|
20
|
+
|
21
|
+
require File.expand_path("../monga/clients/single_instance_client", __FILE__)
|
22
|
+
require File.expand_path("../monga/clients/replica_set_client", __FILE__)
|
23
|
+
require File.expand_path("../monga/connections/em_connection", __FILE__)
|
24
|
+
require File.expand_path("../monga/connections/fibered_connection", __FILE__)
|
25
|
+
require File.expand_path("../monga/connections/tcp_connection", __FILE__)
|
26
|
+
require File.expand_path("../monga/connections/em_proxy_connection", __FILE__)
|
27
|
+
require File.expand_path("../monga/connections/fibered_proxy_connection", __FILE__)
|
28
|
+
require File.expand_path("../monga/connections/proxy_connection", __FILE__)
|
29
|
+
require File.expand_path("../monga/connections/buffer", __FILE__)
|
30
|
+
|
31
|
+
require File.expand_path("../monga/client", __FILE__)
|
21
32
|
require File.expand_path("../monga/connection", __FILE__)
|
22
33
|
require File.expand_path("../monga/connection_pool", __FILE__)
|
23
|
-
require File.expand_path("../monga/client", __FILE__)
|
24
34
|
require File.expand_path("../monga/database", __FILE__)
|
25
35
|
require File.expand_path("../monga/collection", __FILE__)
|
26
|
-
require File.expand_path("../monga/
|
27
|
-
require File.expand_path("../monga/
|
28
|
-
require File.expand_path("../monga/
|
29
|
-
require File.expand_path("../monga/response", __FILE__)
|
30
|
-
require File.expand_path("../monga/request", __FILE__)
|
36
|
+
require File.expand_path("../monga/request", __FILE__)
|
37
|
+
require File.expand_path("../monga/utils/exceptions", __FILE__)
|
38
|
+
require File.expand_path("../monga/utils/constants", __FILE__)
|
data/monga.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "monga"
|
7
|
-
spec.version = "0.0.
|
7
|
+
spec.version = "0.0.3"
|
8
8
|
spec.authors = ["Petr Yanovich"]
|
9
9
|
spec.email = ["fl00r@yandex.ru"]
|
10
10
|
spec.description = %q{MongoDB Ruby Evented Driver on EventMachine}
|
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_development_dependency "bundler", "~> 1.3"
|
21
21
|
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "em-synchrony"
|
22
23
|
|
23
|
-
spec.add_dependency "eventmachine"
|
24
24
|
spec.add_dependency "bson"
|
25
25
|
spec.add_dependency "bson_ext"
|
26
26
|
end
|
data/spec/helpers/mongodb.rb
CHANGED
@@ -1,59 +1,136 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
@
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
module Fake
|
2
|
+
|
3
|
+
# Fake Response.
|
4
|
+
# It could be `ok`, or `primary?` reply.
|
5
|
+
class Response
|
6
|
+
def initialize(data, primary)
|
7
|
+
@data = data
|
8
|
+
@primary = primary
|
9
|
+
end
|
10
|
+
|
11
|
+
def ok(doc = nil)
|
12
|
+
document = doc || { ok: 1.0 }
|
13
|
+
[flags, cursor_id, starting_from, number_returned].pack("LQLL")
|
14
|
+
b = BSON::ByteBuffer.new
|
15
|
+
b.put_int(flags)
|
16
|
+
b.put_long(cursor_id)
|
17
|
+
b.put_int(starting_from)
|
18
|
+
b.put_int(number_returned)
|
19
|
+
b.append!(BSON::BSON_C.serialize(document).to_s)
|
20
|
+
|
21
|
+
header(b) + b.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def primary?
|
25
|
+
doc = { ismaster: @primary }
|
26
|
+
ok(doc)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def header(body)
|
32
|
+
length = 16 + body.to_s.bytesize
|
33
|
+
request_id = 0
|
34
|
+
op_code = 0
|
35
|
+
|
36
|
+
h = BSON::ByteBuffer.new
|
37
|
+
h.put_int(length)
|
38
|
+
h.put_int(request_id)
|
39
|
+
h.put_int(response_to)
|
40
|
+
h.put_int(op_code)
|
41
|
+
h.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def response_to
|
45
|
+
@data.unpack("LLLL")[1]
|
15
46
|
end
|
16
47
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
48
|
+
def flags; 0; end
|
49
|
+
def cursor_id; 0; end
|
50
|
+
def starting_from; 0; end
|
51
|
+
def number_returned; 1; end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Fake MongoDB server.
|
55
|
+
# Replies with `ok` message for all 2004 op queries instead `isMaster`.
|
56
|
+
# For other ops it sends no answer.
|
57
|
+
class Node < EM::Connection
|
58
|
+
def initialize(si)
|
59
|
+
@si = si
|
60
|
+
@si.server = self
|
22
61
|
end
|
23
62
|
|
24
|
-
def
|
25
|
-
|
63
|
+
def primary
|
64
|
+
@si.rs.primary == @si if @si.rs
|
65
|
+
end
|
66
|
+
|
67
|
+
def receive_data(data)
|
68
|
+
begin
|
69
|
+
length, req_id, resp_to, op_code = data.unpack("LLLL")
|
70
|
+
piece = data.slice!(0, length)
|
71
|
+
if op_code == 2004
|
72
|
+
if piece["isMaster"]
|
73
|
+
send_data Fake::Response.new(piece, primary).primary?
|
74
|
+
else
|
75
|
+
send_data Fake::Response.new(piece, primary).ok
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end while data != ""
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Single instance binded on one port.
|
83
|
+
# Could be stopped or started.
|
84
|
+
class SingleInstance
|
85
|
+
attr_reader :rs
|
86
|
+
attr_accessor :server
|
87
|
+
|
88
|
+
def initialize(port, rs=nil)
|
89
|
+
@rs = rs
|
90
|
+
@port = port
|
26
91
|
end
|
27
92
|
|
28
93
|
def start
|
29
|
-
|
30
|
-
@
|
31
|
-
sleep(1)
|
94
|
+
@connected = true
|
95
|
+
@sign = EM.start_server '127.0.0.1', @port, Fake::Node, self
|
32
96
|
end
|
33
97
|
|
34
98
|
def stop
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
99
|
+
@server.close_connection
|
100
|
+
EM.stop_server @sign
|
101
|
+
@connected = false
|
102
|
+
end
|
103
|
+
|
104
|
+
def connected?
|
105
|
+
@connected
|
39
106
|
end
|
40
107
|
end
|
41
108
|
|
109
|
+
# Fake Replica set with a number of Single Instances.
|
110
|
+
# You could stop/start primary/secondary.
|
42
111
|
class ReplicaSet
|
43
|
-
def initialize(ports
|
44
|
-
|
45
|
-
|
46
|
-
@instances = {}
|
47
|
-
ports.each.with_index do |prt, i|
|
48
|
-
dbpath = opts[:dbpath] + "-#{i}"
|
49
|
-
o = opts.merge({ port: prt[:port], dbpath: dbpath })
|
50
|
-
@instances[prt[:port]] = Instance.new(o)
|
112
|
+
def initialize(ports)
|
113
|
+
@instances = ports.map do |port|
|
114
|
+
SingleInstance.new(port, self)
|
51
115
|
end
|
52
116
|
end
|
53
117
|
|
118
|
+
def start_all
|
119
|
+
@instances.each(&:start)
|
120
|
+
end
|
121
|
+
|
122
|
+
def vote
|
123
|
+
@primary = @instances.select{|inst| inst.connected? }.sample
|
124
|
+
end
|
125
|
+
|
54
126
|
def primary
|
55
|
-
|
56
|
-
|
127
|
+
@primary ||= begin
|
128
|
+
@instances.select{|inst| inst.connected? }.sample
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def secondaries
|
133
|
+
@instances - [@primary]
|
57
134
|
end
|
58
135
|
end
|
59
136
|
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monga::Collection do
|
4
|
+
before do
|
5
|
+
@client = Monga::Client.new(type: :block, pool_size: 10)
|
6
|
+
@db = @client["dbTest"]
|
7
|
+
@collection = @db["testCollection"]
|
8
|
+
@collection.safe_remove
|
9
|
+
docs = []
|
10
|
+
10.times do |i|
|
11
|
+
docs << { artist: "Madonna", title: "Track #{i+1}" }
|
12
|
+
docs << { artist: "Radiohead", title: "Track #{i+1}" }
|
13
|
+
end
|
14
|
+
@collection.safe_insert(docs)
|
15
|
+
end
|
16
|
+
|
17
|
+
# QUERY
|
18
|
+
|
19
|
+
describe "query" do
|
20
|
+
it "should fetch all documents" do
|
21
|
+
docs = @collection.find.all
|
22
|
+
docs.size.must_equal 20
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should fetch all docs with skip and limit" do
|
26
|
+
docs = @collection.find.skip(10).limit(4).all
|
27
|
+
docs.size.must_equal 4
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should fetch first" do
|
31
|
+
doc = @collection.first
|
32
|
+
doc.keys.must_equal ["_id", "artist", "title"]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# INSERT
|
37
|
+
|
38
|
+
describe "insert" do
|
39
|
+
before do
|
40
|
+
@collection.safe_ensure_index({ "personal_id" => 1 }, { unique: true, sparse: true })
|
41
|
+
end
|
42
|
+
|
43
|
+
after do
|
44
|
+
@collection.drop_index( personal_id: 1 )
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should insert single doc" do
|
48
|
+
doc = { name: "Peter", age: 18 }
|
49
|
+
@collection.safe_insert(doc)
|
50
|
+
resp = @collection.find(name: "Peter").all
|
51
|
+
resp.size.must_equal 1
|
52
|
+
resp.first["age"].must_equal 18
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should insert batch of docs" do
|
56
|
+
docs = [{ name: "Peter", age: 18 }, {name: "Jhon", age: 18}]
|
57
|
+
@collection.safe_insert(docs)
|
58
|
+
resp = @collection.find(age: 18).all
|
59
|
+
resp.size.must_equal 2
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should fail on uniq index" do
|
63
|
+
docs = [{ name: "Peter", age: 18, personal_id: 20 }, {name: "Jhon", age: 18, personal_id: 20}, {name: "Rebeca", age: 21, personal_id: 5}]
|
64
|
+
proc{ @collection.safe_insert(docs) }.must_raise Monga::Exceptions::QueryFailure
|
65
|
+
@collection.count.must_equal 21
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should continue_on_error" do
|
69
|
+
docs = [{ name: "Peter", age: 18, personal_id: 20 }, {name: "Jhon", age: 18, personal_id: 20}, {name: "Rebeca", age: 21, personal_id: 5}]
|
70
|
+
proc{ @collection.safe_insert(docs, continue_on_error: true) }.must_raise Monga::Exceptions::QueryFailure
|
71
|
+
@collection.count.must_equal 22
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# UPDATE
|
76
|
+
|
77
|
+
describe "update" do
|
78
|
+
it "should make simple update (first matching)" do
|
79
|
+
@collection.safe_update({ artist: "Madonna" }, { "$set" => { country: "USA" } })
|
80
|
+
@collection.count( query: { artist: "Madonna", country: "USA" }).must_equal 1
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should create non existing item (upsert)" do
|
84
|
+
@collection.safe_update({ artist: "Bjork" }, { "$set" => { country: "Iceland" } }, { upsert: true })
|
85
|
+
@collection.count(query: { artist: "Bjork" }).must_equal 1
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should update all matching data (multi_update)" do
|
89
|
+
@collection.safe_update({ artist: "Madonna" }, { "$set" => { country: "USA" } }, {multi_update: true})
|
90
|
+
docs = @collection.find(artist: "Madonna").all
|
91
|
+
docs.each{ |d| d["country"].must_equal "USA" }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# REMOVE
|
96
|
+
|
97
|
+
describe "remove" do
|
98
|
+
it "should delete all matching docs" do
|
99
|
+
@collection.safe_delete(artist: "Madonna")
|
100
|
+
@collection.count(query: { artist: "Madonna" }).must_equal 0
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should delete first matching doc (single_remove)" do
|
104
|
+
@collection.safe_delete({ artist: "Madonna" }, single_remove: true)
|
105
|
+
@collection.count(query: { artist: "Madonna" }).must_equal 9
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# COUNT
|
110
|
+
|
111
|
+
describe "count" do
|
112
|
+
it "should count all docs" do
|
113
|
+
@collection.count.must_equal 20
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should count all docs with query" do
|
117
|
+
@collection.count(query: { artist: "Madonna" }).must_equal 10
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should count all docs with limit" do
|
121
|
+
@collection.count(query: { artist: "Madonna" }, limit: 5).must_equal 5
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should count all docs with limit and skip" do
|
125
|
+
@collection.count(query: { artist: "Madonna" }, limit: 5, skip: 6).must_equal 4
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# ENSURE/DROP INDEX
|
130
|
+
|
131
|
+
describe "ensure_index" do
|
132
|
+
before do
|
133
|
+
@collection.drop_indexes
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should create index" do
|
137
|
+
@collection.safe_ensure_index(title: 1)
|
138
|
+
docs = @collection.get_indexes
|
139
|
+
docs.any?{ |doc| doc["key"] == {"title" => 1}}.must_equal true
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should create sparse index" do
|
143
|
+
@collection.safe_ensure_index({ title: 1 }, sparse: true)
|
144
|
+
docs = @collection.get_indexes
|
145
|
+
docs.any?{ |doc| doc["key"] == {"title" => 1} && doc["sparse"] == true }.must_equal true
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should create unique index" do
|
149
|
+
@collection.safe_ensure_index({ some_field: 1 }, unique: true, sparse: true)
|
150
|
+
docs = @collection.get_indexes
|
151
|
+
docs.any?{ |doc| doc["key"] == {"some_field" => 1} && doc["unique"] == true }.must_equal true
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should drop single index" do
|
155
|
+
@collection.safe_ensure_index(title: 1)
|
156
|
+
docs = @collection.get_indexes
|
157
|
+
docs.any?{ |doc| doc["key"] == {"title" => 1}}.must_equal true
|
158
|
+
@collection.drop_index(title: 1)
|
159
|
+
docs = @collection.get_indexes
|
160
|
+
docs.any?{ |doc| doc["key"] == {"title" => 1}}.must_equal false
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should drop all indexes (except primary on _id)" do
|
164
|
+
@collection.safe_ensure_index(title: 1)
|
165
|
+
docs = @collection.get_indexes
|
166
|
+
docs.any?{ |doc| doc["key"] == {"title" => 1}}.must_equal true
|
167
|
+
@collection.drop_indexes
|
168
|
+
docs = @collection.get_indexes
|
169
|
+
docs.select{ |d| d["ns"] == "dbTest.testCollection" }.size.must_equal 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|