monga 0.0.6 → 0.0.7

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/README.md CHANGED
@@ -143,7 +143,11 @@ puts "We have got #{docs.size} documents in this pretty array"
143
143
  * [ ] check maxBsonSize / validate
144
144
  * [x] cmd
145
145
  * [x] eval
146
- * [ ] aggregation
146
+ * [x] aggregate
147
+ * [x] distinct
148
+ * [x] group
149
+ * [x] mapReduce
150
+ * [x] text
147
151
  * [ ] gridfs?
148
152
 
149
153
  ### Collection
@@ -1,86 +1,191 @@
1
1
  require 'benchmark'
2
- require 'mongo'
3
- require 'moped'
4
- require File.expand_path('../../lib/monga', __FILE__)
5
2
 
6
- include Mongo
3
+ TOTAL_INSERTS = 10000
4
+ TOTAL_READS = 50
7
5
 
8
- Benchmark.bm do |x|
9
- total = 10000
10
- fetch = 50
11
- mongo_collection = MongoClient.new.db("dbTest").collection("testCollection")
12
- monga_collection = Monga::Client.new(type: :block).get_database("dbTest").get_collection("testCollection")
13
- Monga.logger.level = Logger::ERROR
14
- moped_session = Moped::Session.new([ "127.0.0.1:27017" ])
15
- moped_session.use "dbTest"
6
+ chars = ('a'..'z').to_a
7
+ DOCS = [10, 100, 1000, 10000].map do |size|
8
+ doc = {}
9
+ doc[:title] = "Title"
10
+ doc[:body] = size.times.map{ chars.sample }.join
11
+ [size, doc]
12
+ end
16
13
 
17
- document = {}
18
- document[:title] = "Some title"
19
- chars = ('a'..'z').to_a
20
- document[:body] = 100.times.map{ chars.sample } * ""
14
+ # Mongo Ruby Driver
21
15
 
22
- sleep 0.5
16
+ fork do
17
+ require 'mongo'
18
+ include Mongo
23
19
 
24
- GC.start
20
+ Benchmark.bm do |x|
21
+ collection = MongoClient.new.db("dbTest").collection("testCollection")
25
22
 
26
- x.report("Inserting with mongo") do
27
- total.times do |i|
28
- mongo_collection.insert(document.dup)
29
- end
30
- end
23
+ DOCS.each do |size, doc|
24
+ GC.start
25
+ x.report("Mongo: Inserting #{size}b document") do
26
+ TOTAL_INSERTS.times do
27
+ collection.insert(doc.dup)
28
+ end
29
+ end
31
30
 
32
- GC.start
31
+ GC.start
32
+ x.report("Mongo: Reading #{size}b documents") do
33
+ TOTAL_READS.times do
34
+ collection.find.to_a
35
+ end
36
+ end
33
37
 
34
- x.report("Fetching with mongo") do
35
- fetch.times do
36
- mongo_collection.find.to_a
38
+ collection.drop
37
39
  end
38
40
  end
39
- mongo_collection.drop
41
+ end
40
42
 
41
- sleep 0.5
43
+ Process.waitall
44
+ puts "---"*5
42
45
 
43
- GC.start
46
+ # Monga Driver (blocking mode)
44
47
 
45
- x.report("Inserting with monga") do
46
- total.times do |i|
47
- monga_collection.safe_insert(document.dup)
48
- end
49
- end
48
+ fork do
49
+ require File.expand_path('../../lib/monga', __FILE__)
50
+
51
+ Benchmark.bm do |x|
52
+ collection = Monga::Client.new.get_database("dbTest").get_collection("testCollection")
53
+
54
+ DOCS.each do |size, doc|
55
+ GC.start
56
+ x.report("Monga: Inserting #{size}b document") do
57
+ TOTAL_INSERTS.times do
58
+ collection.safe_insert(doc)
59
+ end
60
+ end
50
61
 
51
- GC.start
62
+ GC.start
63
+ x.report("Monga: Reading #{size}b documents") do
64
+ TOTAL_READS.times do
65
+ collection.find.all
66
+ end
67
+ end
52
68
 
53
- x.report("Fetching with monga") do
54
- fetch.times do
55
- monga_collection.find.all
69
+ collection.drop
56
70
  end
57
71
  end
72
+ end
58
73
 
59
- monga_collection.drop
74
+ Process.waitall
75
+ puts "---"*5
60
76
 
61
- sleep 0.5
77
+ # Moped
62
78
 
63
- GC.start
79
+ fork do
80
+ require 'moped'
64
81
 
65
- x.report("Inserting with moped") do
66
- moped_session.with(safe: true) do |safe|
67
- total.times do |i|
68
- safe[:testCollection].insert(document)
82
+ Benchmark.bm do |x|
83
+ session = Moped::Session.new([ "127.0.0.1:27017" ])
84
+ session.use("dbTest")
85
+
86
+ DOCS.each do |size, doc|
87
+ GC.start
88
+ x.report("Moped: Inserting #{size}b document") do
89
+ session.with(safe: true) do |safe|
90
+ TOTAL_INSERTS.times do
91
+ safe[:testCollection].insert(doc)
92
+ end
93
+ end
69
94
  end
70
- end
71
- end
72
95
 
73
- GC.start
96
+ GC.start
97
+ x.report("Moped: Reading #{size}b documents") do
98
+ TOTAL_READS.times do
99
+ session[:testCollection].find.to_a
100
+ end
101
+ end
74
102
 
75
- x.report("Fetching with moped") do
76
- fetch.times do
77
- moped_session[:testCollection].find.to_a
103
+ session[:testCollection].drop
78
104
  end
79
105
  end
80
-
81
- monga_collection.drop
82
106
  end
83
107
 
108
+ Process.waitall
109
+
110
+ # # require 'moped'
111
+
112
+ # # include Mongo
113
+
114
+ # Benchmark.bm do |x|
115
+ # total = 1000
116
+ # fetch = 50
117
+ # # mongo_collection = MongoClient.new.db("dbTest").collection("testCollection")
118
+ # monga_collection = Monga::Client.new(type: :block).get_database("dbTest").get_collection("testCollection")
119
+ # Monga.logger.level = Logger::ERROR
120
+ # # moped_session = Moped::Session.new([ "127.0.0.1:27017" ])
121
+ # # moped_session.use "dbTest"
122
+
123
+ # document = {}
124
+ # document[:title] = "Some title"
125
+ # document[:body] = 10000.times.map{ chars.sample } * ""
126
+
127
+ # # sleep 0.5
128
+
129
+ # # GC.start
130
+
131
+ # # x.report("Inserting with mongo") do
132
+ # # total.times do |i|
133
+ # # mongo_collection.insert(document.dup)
134
+ # # end
135
+ # # end
136
+
137
+ # # GC.start
138
+
139
+ # # x.report("Fetching with mongo") do
140
+ # # fetch.times do
141
+ # # mongo_collection.find.to_a
142
+ # # end
143
+ # # end
144
+ # # mongo_collection.drop
145
+
146
+ # # sleep 0.5
147
+
148
+ # # GC.start
149
+
150
+ # x.report("Inserting with monga") do
151
+ # total.times do |i|
152
+ # monga_collection.safe_insert(document)
153
+ # end
154
+ # end
155
+
156
+ # GC.start
157
+
158
+ # x.report("Fetching with monga") do
159
+ # fetch.times do
160
+ # monga_collection.find.all
161
+ # end
162
+ # end
163
+
164
+ # monga_collection.drop
165
+
166
+ # # sleep 0.5
167
+
168
+ # # GC.start
169
+
170
+ # # x.report("Inserting with moped") do
171
+ # # moped_session.with(safe: true) do |safe|
172
+ # # total.times do |i|
173
+ # # safe[:testCollection].insert(document)
174
+ # # end
175
+ # # end
176
+ # # end
177
+
178
+ # # GC.start
179
+
180
+ # # x.report("Fetching with moped") do
181
+ # # fetch.times do
182
+ # # moped_session[:testCollection].find.to_a
183
+ # # end
184
+ # # end
185
+
186
+ # # monga_collection.drop
187
+ # end
188
+
84
189
 
85
190
 
86
191
 
@@ -8,7 +8,7 @@ module Monga
8
8
  end
9
9
 
10
10
  # Querying database. It returns cursor.
11
- # Alias to collection#query is colleciotn#find
11
+ # Alias to collection#query is collection#find
12
12
  #
13
13
  # cursor = collection.find(title: "Madonna")
14
14
  # # choose fields to return
@@ -132,6 +132,62 @@ module Monga
132
132
  end
133
133
  end
134
134
 
135
+ def map_reduce(opts, &blk)
136
+ @db.map_reduce(@collection_name, opts) do |err, resp|
137
+ if block_given?
138
+ yield(err, resp)
139
+ else
140
+ raise err if err
141
+ return resp
142
+ end
143
+ end
144
+ end
145
+
146
+ def aggregate(pipeline, &blk)
147
+ @db.aggregate(@collection_name, pipeline) do |err, resp|
148
+ if block_given?
149
+ yield(err, resp)
150
+ else
151
+ raise err if err
152
+ return resp
153
+ end
154
+ end
155
+ end
156
+
157
+ def distinct(opts, &blk)
158
+ @db.distinct(collection_name, opts) do |err, resp|
159
+ if block_given?
160
+ yield(err, resp)
161
+ else
162
+ raise err if err
163
+ return resp
164
+ end
165
+ end
166
+ end
167
+
168
+ def group(opts, &blk)
169
+ @db.group(collection_name, opts) do |err, resp|
170
+ if block_given?
171
+ yield(err, resp)
172
+ else
173
+ raise err if err
174
+ return resp
175
+ end
176
+ end
177
+ end
178
+
179
+ def text(search, opts = {}, &blk)
180
+ opts[:search] = search
181
+ @db.text(collection_name, opts) do |err, resp|
182
+ if block_given?
183
+ yield(err, resp)
184
+ else
185
+ raise err if err
186
+ return resp
187
+ end
188
+ end
189
+ end
190
+
135
191
  # Safe methods
136
192
  [:update, :insert, :delete, :remove, :ensure_index].each do |meth|
137
193
  class_eval <<-EOS
@@ -6,17 +6,6 @@ module Monga
6
6
 
7
7
  attr_reader :type
8
8
 
9
- CONNECTIONS = {
10
- em: Monga::Connections::EMConnection,
11
- sync: Monga::Connections::FiberedConnection,
12
- block: Monga::Connections::KGIOConnection,
13
- }
14
- PROXY_CONNECTIONS = {
15
- em: Monga::Connections::EMProxyConnection,
16
- sync: Monga::Connections::FiberedProxyConnection,
17
- block: Monga::Connections::ProxyConnection,
18
- }
19
-
20
9
  # Simple connection wrapper.
21
10
  # Accpets
22
11
  # * host/port or server
@@ -35,15 +24,36 @@ module Monga
35
24
  end
36
25
  timeout = opts[:timeout]
37
26
 
38
- conn_type = CONNECTIONS[@type]
39
- raise Monga::Exceptions::WrongConnectionType, "Connection type `#{opts[:type]}` is non valid, choose one of: :em, :sync, or :block" unless conn_type
40
- @connection = conn_type.connect(host, port, timeout)
27
+ @connection = case @type
28
+ when :em
29
+ require File.expand_path("../connections/em_connection", __FILE__)
30
+ Monga::Connections::EMConnection.connect(host, port, timeout)
31
+ when :sync
32
+ require File.expand_path("../connections/em_connection", __FILE__)
33
+ require File.expand_path("../connections/fibered_connection", __FILE__)
34
+ Monga::Connections::FiberedConnection.connect(host, port, timeout)
35
+ when :block
36
+ require File.expand_path("../connections/kgio_connection", __FILE__)
37
+ Monga::Connections::KGIOConnection.connect(host, port, timeout)
38
+ else
39
+ raise Monga::Exceptions::WrongConnectionType, "Connection type `#{opts[:type]}` is non valid, choose one of: :em, :sync, or :block" unless conn_type
40
+ end
41
41
  end
42
-
42
+
43
43
  # Returns name of proxy_connection class
44
44
  def self.proxy_connection_class(type, client)
45
- conn_class = PROXY_CONNECTIONS[type]
46
- conn_class.new(client) if conn_class
45
+ case type
46
+ when :em
47
+ require File.expand_path("../connections/em_proxy_connection", __FILE__)
48
+ Monga::Connections::EMProxyConnection.new(client)
49
+ when :sync
50
+ require File.expand_path("../connections/em_proxy_connection", __FILE__)
51
+ require File.expand_path("../connections/fibered_proxy_connection", __FILE__)
52
+ Monga::Connections::FiberedProxyConnection.new(client)
53
+ when :block
54
+ require File.expand_path("../connections/proxy_connection", __FILE__)
55
+ Monga::Connections::ProxyConnection.new(client)
56
+ end
47
57
  end
48
58
  end
49
59
  end
@@ -1,33 +1,54 @@
1
1
  module Monga::Connections
2
2
  class Buffer
3
- # include Enumerable
3
+ include Enumerable
4
+ EMPTY = ""
4
5
 
5
- attr_reader :buffer, :responses
6
+ attr_reader :buffer, :buffer_size
6
7
 
7
8
  def initialize
8
9
  @buffer = ""
9
10
  @position = 0
10
- @docs = []
11
- @responses = []
11
+ @buffer_size = 0
12
+ @response = []
12
13
  end
13
14
 
14
15
  def append(data)
15
16
  @buffer << data
16
- @buffer_size = @buffer.bytesize
17
- parse
18
- @buffer
17
+ @buffer_size += data.bytesize
18
+ end
19
+
20
+ def each
21
+ while doc = parse_buffer
22
+ yield doc
23
+ end
19
24
  end
20
25
 
21
- def parse
22
- begin
23
- more = parse_meta if @position == 0
24
- parse_doc if @position > 0
25
- end while more && @position == 0
26
+ def parse_buffer
27
+ return if @buffer_size == 0
28
+
29
+ if @position == 0
30
+ parse_doc if parse_meta
31
+ else
32
+ parse_doc
33
+ end
34
+
35
+ if @number_returned == 0
36
+ if @buffer_size == @position
37
+ @buffer.clear
38
+ @buffer_size = 0
39
+ else
40
+ @buffer = @buffer[@position, @buffer_size-@position]
41
+ @buffer_size -= @position
42
+ end
43
+ @position = 0
44
+
45
+ @response
46
+ end
26
47
  end
27
48
 
28
49
  def parse_meta
29
50
  return if @buffer_size < 36
30
- @response = []
51
+ @response.clear
31
52
  @response << ::BinUtils.get_int32_le(@buffer, @position)
32
53
  @response << ::BinUtils.get_int32_le(@buffer, @position += 4)
33
54
  @response << ::BinUtils.get_int32_le(@buffer, @position += 4)
@@ -35,43 +56,36 @@ module Monga::Connections
35
56
  @response << ::BinUtils.get_int32_le(@buffer, @position += 4)
36
57
  @response << ::BinUtils.get_int64_le(@buffer, @position += 4)
37
58
  @response << ::BinUtils.get_int32_le(@buffer, @position += 8)
38
- @response << (@number_returned = ::BinUtils.get_int32_le(@buffer, @position += 4))
59
+ @number_returned = ::BinUtils.get_int32_le(@buffer, @position += 4)
60
+ @response << @number_returned
61
+ @position += 4
39
62
  @response << []
40
63
 
41
- @position += 4
42
64
  end
43
65
 
44
66
  def parse_doc
45
- while true
46
- break if done
47
- break if @buffer_size < @position + 4
48
- doc_length = ::BinUtils.get_int32_le(@buffer, @position)
49
- break if @buffer_size < @position + doc_length
67
+ @str_io = nil if @number_returned == @response[7]
50
68
 
51
- doc = @buffer[@position, doc_length]
52
- @response[-1] << CBson.deserialize(doc)
53
- @position += doc_length
69
+ current_pos = @position
70
+ while (l = @buffer_size - @position) > 4
71
+ doc_length = ::BinUtils.get_int32_le(@buffer, @position)
72
+ break if l < doc_length
54
73
  @number_returned -= 1
74
+ @position += doc_length
55
75
  end
56
- end
57
76
 
58
- def each
59
- while resp = @responses.shift
60
- yield resp
77
+ if @str_io
78
+ @str_io << @buffer[current_pos..@position]
79
+ else
80
+ @str_io = StringIO.new @buffer[current_pos..@position]
61
81
  end
62
- end
63
82
 
64
- def done
65
- return false if @number_returned > 0
66
- @responses << @response
67
- @response = nil
68
- if @buffer_size == @position
69
- @buffer.clear
70
- else
71
- @buffer = @buffer[@position, @buffer_size-@position]
83
+ if @number_returned == 0
84
+ @str_io.rewind
85
+ @response[7].times do
86
+ @response[-1] << BSON::Document.from_bson(@str_io)
87
+ end
72
88
  end
73
- @buffer_size = @buffer.bytesize
74
- @position = 0
75
89
  end
76
90
  end
77
91
  end
@@ -1,3 +1,5 @@
1
+ require "eventmachine"
2
+
1
3
  module Monga::Connections
2
4
  class EMConnection < EM::Connection
3
5
  include EM::Deferrable
@@ -1,7 +1,10 @@
1
1
  require 'kgio'
2
- require 'io/nonblock' # ha?
2
+
3
+ # Toy blocking connection over TCP
3
4
  module Monga::Connections
4
5
  class KGIOConnection
6
+ TO_RECV = 512
7
+
5
8
  def self.connect(host, port, timeout)
6
9
  new(host, port, timeout)
7
10
  end
@@ -10,6 +13,7 @@ module Monga::Connections
10
13
  @host, @port, @timout = host, port, timeout
11
14
  @connected = true
12
15
  @buffer = Buffer.new
16
+ @tmp = ""
13
17
  end
14
18
 
15
19
  def connected?
@@ -20,10 +24,10 @@ module Monga::Connections
20
24
  def socket
21
25
  @socket ||= begin
22
26
  sock = Kgio::TCPSocket.new(@host, @port)
27
+ # MacOS doesn't support autopush
23
28
  sock.kgio_autopush = true unless RUBY_PLATFORM['darwin']
24
29
  # check connection
25
30
  sock.kgio_write ""
26
- # Macos doesn't support autopush
27
31
  @connected = true
28
32
  sock
29
33
  end
@@ -31,18 +35,19 @@ module Monga::Connections
31
35
  nil
32
36
  end
33
37
 
34
- # Fake answer, as far as we are blocking
38
+ # Fake answer, as far as we are blocking,
39
+ # but we should support API
35
40
  def responses
36
41
  0
37
42
  end
38
43
 
39
44
  def send_command(msg, request_id=nil, &cb)
40
45
  raise Errno::ECONNREFUSED, "Connection Refused" unless socket
41
- socket.kgio_write msg.to_s
46
+ socket.kgio_write msg
42
47
  if cb
43
48
  read_socket
44
49
 
45
- message = @buffer.responses.shift
50
+ message = @buffer.first
46
51
  rid = message[2]
47
52
 
48
53
  fail "Returned Request Id is not equal to sended one (#{rid} != #{request_id}), #{message}" if rid != request_id
@@ -58,19 +63,24 @@ module Monga::Connections
58
63
  end
59
64
 
60
65
  def read_socket
61
- torecv = 512
62
- length = nil
63
- buf = ''.force_encoding('ASCII-8BIT')
64
- tmp = ''
65
- while torecv > 0
66
- resp = socket.kgio_read(torecv, tmp)
67
- raise Errno::ECONNREFUSED.new "Nil was return. Closing connection" unless resp
68
- buf << resp
69
- size = buf.bytesize
70
- length ||= ::BinUtils.get_int32_le(buf) if size > 4
71
- torecv = length - size if length
66
+ while @buffer.buffer_size < 4
67
+ unless socket.kgio_read(TO_RECV, @tmp)
68
+ raise Errno::ECONNREFUSED.new "Nil was return. Closing connection"
69
+ end
70
+
71
+ @buffer.append(@tmp)
72
+
73
+ size = @buffer.buffer_size
74
+ if size >= 4
75
+ length = ::BinUtils.get_int32_le(@buffer.buffer)
76
+
77
+ torecv = length - size
78
+ if torecv > 0
79
+ socket.read(torecv, @tmp)
80
+ @buffer.append(@tmp)
81
+ end
82
+ end
72
83
  end
73
- @buffer.append(buf)
74
84
  end
75
85
 
76
86
  def primary?
@@ -83,7 +93,7 @@ module Monga::Connections
83
93
  request_id = req.request_id
84
94
  socket.kgio_write command
85
95
  read_socket
86
- message = @buffer.responses.shift
96
+ message = @buffer.first
87
97
  @primary = message.last.first["ismaster"]
88
98
  yield @primary ? :primary : :secondary
89
99
  rescue => e
@@ -146,12 +146,79 @@ module Monga
146
146
  run_cmd(cmd, blk)
147
147
  end
148
148
 
149
- def map_reduce
150
-
149
+ # Run mapReduce command.
150
+ # Available options:
151
+ #
152
+ # * map - A JavaScript function that associates or “maps” a value with a key and emits the key and value pair.
153
+ # * reduce - A JavaScript function that “reduces” to a single object all the values associated with a particular key.
154
+ # * out - Specifies the location of the result of the map-reduce operation.
155
+ # * query - Specifies the selection criteria.
156
+ # * sort - Sorts the input documents.
157
+ # * limit - Specifies a maximum number of documents to return from the collection
158
+ # * finalize
159
+ # * scope
160
+ # * jsMode
161
+ # * verbose
162
+ #
163
+ # Inline response returned by default.
164
+ #
165
+ def map_reduce(collection_name, opts, &blk)
166
+ cmd = {}
167
+ cmd[:mapReduce] = collection_name
168
+ cmd.merge! opts
169
+ cmd[:out] ||= { inline: 1 }
170
+ run_cmd(cmd, blk)
151
171
  end
152
172
 
153
- def aggregate
154
-
173
+ # Run aggregate command.
174
+ #
175
+ def aggregate(collection_name, pipeline, &blk)
176
+ cmd = {}
177
+ cmd[:aggregate] = collection_name
178
+ cmd[:pipeline] = pipeline
179
+ run_cmd(cmd, blk)
180
+ end
181
+
182
+ # Run distinct command.
183
+ # You should pass collection_name and key.
184
+ # Query option is optional.
185
+ #
186
+ def distinct(collection_name, opts, &blk)
187
+ cmd = {}
188
+ cmd[:distinct] = collection_name
189
+ cmd.merge! opts
190
+ run_cmd(cmd, blk)
191
+ end
192
+
193
+ # Run group command.
194
+ # Available options are:
195
+ # key – Specifies one or more document fields to group
196
+ # $reduce – Specifies an aggregation function that operates on the documents during the grouping operation
197
+ # initial – Initializes the aggregation result document
198
+ # $keyf – Specifies a function that creates a “key object” for use as the grouping key
199
+ # cond – Specifies the selection criteria to determine which documents in the collection to process
200
+ # finalize – Specifies a function that runs each item in the result
201
+ #
202
+ def group(collection_name, opts, &blk)
203
+ cmd = {}
204
+ cmd[:group] = opts
205
+ cmd[:group][:ns] ||= collection_name
206
+ run_cmd(cmd, blk)
207
+ end
208
+
209
+ # Run text command.
210
+ # Available options are:
211
+ # search (string) – A string of terms that MongoDB parses and uses to query the text index
212
+ # filter (document) – A query document to further limit the results of the query using another database field
213
+ # project (document) – Allows you to limit the fields returned by the query to only those specified.
214
+ # limit (number) – Specify the maximum number of documents to include in the response
215
+ # language (string) – Specify the language that determines for the search the list of stop words and the rules for the stemmer and tokenizer
216
+ #
217
+ def text(collection_name, opts, &blk)
218
+ cmd = {}
219
+ cmd[:text] = collection_name
220
+ cmd.merge! opts
221
+ run_cmd(cmd, blk)
155
222
  end
156
223
 
157
224
  # Just helper to show all list of collections
@@ -13,7 +13,7 @@ module Monga::Protocol
13
13
  msg = ::BinUtils.append_int32_le!(nil, 0)
14
14
  msg << full_name << Monga::NULL_BYTE
15
15
  ::BinUtils.append_int32_le!(msg, flags)
16
- msg << BSON::BSON_C.serialize(query).to_s
16
+ msg << query.to_bson
17
17
  msg
18
18
  end
19
19
  end
@@ -15,10 +15,11 @@ module Monga::Protocol
15
15
  case documents
16
16
  when Array
17
17
  documents.each do |doc|
18
- msg << BSON::BSON_C.serialize(doc).to_s
18
+ msg << doc.to_bson
19
19
  end
20
20
  when Hash
21
- msg << BSON::BSON_C.serialize(documents).to_s
21
+ # msg << BSON::BSON_C.serialize(documents).to_s
22
+ msg << documents.to_bson
22
23
  end
23
24
  msg
24
25
  end
@@ -26,8 +26,8 @@ module Monga::Protocol
26
26
  msg = ::BinUtils.append_int32_le!(nil, flags)
27
27
  msg << full_name << Monga::NULL_BYTE
28
28
  ::BinUtils.append_int32_le!(msg, skip, limit)
29
- msg << BSON::BSON_C.serialize(query).to_s
30
- msg << BSON::BSON_C.serialize(selector).to_s if selector.any?
29
+ msg << query.to_bson
30
+ msg << selector.to_bson if selector.any?
31
31
  msg
32
32
  end
33
33
  end
@@ -15,8 +15,8 @@ module Monga::Protocol
15
15
  msg = ::BinUtils.append_int32_le!(nil, 0)
16
16
  msg << full_name << Monga::NULL_BYTE
17
17
  ::BinUtils.append_int32_le!(msg, flags)
18
- msg << BSON::BSON_C.serialize(query).to_s
19
- msg << BSON::BSON_C.serialize(update).to_s
18
+ msg << query.to_bson
19
+ msg << update.to_bson
20
20
  msg
21
21
  end
22
22
  end
data/lib/monga.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "em-synchrony"
1
+ gem "bson", "2.0.0.beta"
2
2
  require "bson"
3
3
  require "bin_utils"
4
4
  require "logger"
@@ -21,13 +21,6 @@ require File.expand_path("../monga/cursor", __FILE__)
21
21
 
22
22
  require File.expand_path("../monga/clients/single_instance_client", __FILE__)
23
23
  require File.expand_path("../monga/clients/replica_set_client", __FILE__)
24
- require File.expand_path("../monga/connections/em_connection", __FILE__)
25
- require File.expand_path("../monga/connections/fibered_connection", __FILE__)
26
- require File.expand_path("../monga/connections/tcp_connection", __FILE__)
27
- require File.expand_path("../monga/connections/kgio_connection", __FILE__)
28
- require File.expand_path("../monga/connections/em_proxy_connection", __FILE__)
29
- require File.expand_path("../monga/connections/fibered_proxy_connection", __FILE__)
30
- require File.expand_path("../monga/connections/proxy_connection", __FILE__)
31
24
  require File.expand_path("../monga/connections/buffer", __FILE__)
32
25
 
33
26
  require File.expand_path("../monga/client", __FILE__)
data/monga.gemspec CHANGED
@@ -4,11 +4,11 @@ $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.6"
7
+ spec.version = "0.0.7"
8
8
  spec.authors = ["Petr Yanovich"]
9
9
  spec.email = ["fl00r@yandex.ru"]
10
- spec.description = %q{MongoDB Ruby Evented Driver on EventMachine}
11
- spec.summary = %q{MongoDB Ruby Evented Driver on EventMachine}
10
+ spec.description = %q{Yet another MongoDB Ruby Client}
11
+ spec.summary = %q{Yet another MongoDB Ruby Client}
12
12
  spec.homepage = ""
13
13
  spec.license = "MIT"
14
14
 
@@ -22,7 +22,8 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "kgio"
23
23
  spec.add_development_dependency "em-synchrony"
24
24
 
25
- spec.add_dependency "bson"
26
- spec.add_dependency "bson_ext"
25
+ spec.add_dependency "bson", ["~> 2.0.0.beta"]
26
+ # spec.add_dependency "bson"
27
+ # spec.add_dependency "bson_ext"
27
28
  spec.add_dependency "bin_utils"
28
29
  end
@@ -1,5 +1,6 @@
1
- module Fake
1
+ require 'eventmachine'
2
2
 
3
+ module Fake
3
4
  # Fake Response.
4
5
  # It could be `ok`, or `primary?` reply.
5
6
  class Response
@@ -11,12 +12,10 @@ module Fake
11
12
  def ok(doc = nil)
12
13
  document = doc || { ok: 1.0 }
13
14
  [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)
15
+ b = ::BinUtils.append_int32_le!(nil, flags)
16
+ ::BinUtils.append_int64_le!(b, cursor_id)
17
+ ::BinUtils.append_int32_le!(b, starting_from, number_returned)
18
+ b << document.to_bson
20
19
 
21
20
  header(b) + b.to_s
22
21
  end
@@ -33,12 +32,7 @@ module Fake
33
32
  request_id = 0
34
33
  op_code = 0
35
34
 
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
35
+ h = ::BinUtils.append_int32_le!(nil, flags, request_id, response_to, op_code)
42
36
  end
43
37
 
44
38
  def response_to
@@ -169,4 +169,48 @@ describe Monga::Collection do
169
169
  docs.select{ |d| d["ns"] == "dbTest.testCollection" }.size.must_equal 1
170
170
  end
171
171
  end
172
+
173
+ # MAP/REDUCE
174
+
175
+ describe "map_reduce" do
176
+ before do
177
+ @collection.safe_remove
178
+ 5.times do |i|
179
+ @collection.safe_insert(title: "The Book", count: i)
180
+ end
181
+ end
182
+
183
+ it "should run map reduce" do
184
+ map_func = "function() {
185
+ emit(this.title, this.count);
186
+ };"
187
+ red_func = "function(docTitle, docCount) {
188
+ return Array.sum(docCount);
189
+ };"
190
+ @collection.map_reduce(map: map_func, reduce: red_func, out: {inline: 1} )["results"].first["value"].must_equal 10.0
191
+ end
192
+ end
193
+
194
+ # AGGREGATE, GROUP, DISTINCT
195
+
196
+ describe "aggregate, group, distinct" do
197
+
198
+ end
199
+
200
+ # TEXT SEARCH
201
+
202
+ # Travis.ci doesn't support text search in mongodb
203
+ # describe "text search" do
204
+ # before do
205
+ # @collection.safe_ensure_index(author: "text")
206
+ # @collection.safe_insert(author: "Lady Gaga", track: "No. 1")
207
+ # @collection.safe_insert(author: "Lady Gaga", track: "No. 2")
208
+ # @collection.safe_insert(author: "Madonna", track: "No. 1")
209
+ # end
210
+
211
+ # it "should find some tracks" do
212
+ # @collection.text("Lady")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1", "No. 2"]
213
+ # @collection.text("Madonna")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1"]
214
+ # end
215
+ # end
172
216
  end
@@ -305,4 +305,74 @@ describe Monga::Collection do
305
305
  end
306
306
  end
307
307
  end
308
+
309
+ # MAP/REDUCE
310
+
311
+ describe "map_reduce" do
312
+ before do
313
+ EM.run do
314
+ @collection.safe_remove do
315
+ docs = []
316
+ 5.times do |i|
317
+ docs << { title: "The Book", count: i }
318
+ end
319
+ @collection.safe_insert(docs) do
320
+ EM.stop
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ it "should run map reduce" do
327
+ EM.run do
328
+ map_func = "function() {
329
+ emit(this.title, this.count);
330
+ };"
331
+ red_func = "function(docTitle, docCount) {
332
+ return Array.sum(docCount);
333
+ };"
334
+ @collection.map_reduce(map: map_func, reduce: red_func, out: {inline: 1} ) do |err, res|
335
+ res["results"].first["value"].must_equal 10.0
336
+ EM.stop
337
+ end
338
+ end
339
+ end
340
+ end
341
+
342
+ # AGGREGATE, GROUP, DISTINCT
343
+
344
+ describe "aggregate, group, distinct" do
345
+
346
+ end
347
+
348
+ # TEXT SEARCH
349
+
350
+ # Travis.ci doesn't support text search in mongodb
351
+ # describe "text search" do
352
+ # before do
353
+ # EM.run do
354
+ # @collection.safe_ensure_index(author: "text") do
355
+ # @collection.safe_insert([
356
+ # { author: "Lady Gaga", track: "No. 1" },
357
+ # { author: "Lady Gaga", track: "No. 2" },
358
+ # { author: "Madonna", track: "No. 1" }
359
+ # ]) do
360
+ # EM.stop
361
+ # end
362
+ # end
363
+ # end
364
+ # end
365
+
366
+ # it "should find some tracks" do
367
+ # EM.run do
368
+ # @collection.text("Lady") do |err, res|
369
+ # res["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1", "No. 2"]
370
+ # @collection.text("Madonna") do |err, res|
371
+ # res["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1"]
372
+ # EM.stop
373
+ # end
374
+ # end
375
+ # end
376
+ # end
377
+ # end
308
378
  end
@@ -244,4 +244,60 @@ describe Monga::Collection do
244
244
  end
245
245
  end
246
246
  end
247
+
248
+ # MAP/REDUCE
249
+
250
+ describe "map_reduce" do
251
+ before do
252
+ EM.synchrony do
253
+ @collection.safe_remove
254
+ 5.times do |i|
255
+ @collection.safe_insert(title: "The Book", count: i)
256
+ end
257
+ EM.stop
258
+ end
259
+ end
260
+
261
+ it "should run map reduce" do
262
+ EM.synchrony do
263
+ map_func = "function() {
264
+ emit(this.title, this.count);
265
+ };"
266
+ red_func = "function(docTitle, docCount) {
267
+ return Array.sum(docCount);
268
+ };"
269
+ @collection.map_reduce(map: map_func, reduce: red_func, out: {inline: 1} )["results"].first["value"].must_equal 10.0
270
+ EM.stop
271
+ end
272
+ end
273
+ end
274
+
275
+ # AGGREGATE, GROUP, DISTINCT
276
+
277
+ describe "aggregate, group, distinct" do
278
+
279
+ end
280
+
281
+ # TEXT SEARCH
282
+
283
+ # Travis.ci doesn't support text search in mongodb
284
+ # describe "text search" do
285
+ # before do
286
+ # EM.synchrony do
287
+ # @collection.safe_ensure_index(author: "text")
288
+ # @collection.safe_insert(author: "Lady Gaga", track: "No. 1")
289
+ # @collection.safe_insert(author: "Lady Gaga", track: "No. 2")
290
+ # @collection.safe_insert(author: "Madonna", track: "No. 1")
291
+ # EM.stop
292
+ # end
293
+ # end
294
+
295
+ # it "should find some tracks" do
296
+ # EM.synchrony do
297
+ # @collection.text("Lady")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1", "No. 2"]
298
+ # @collection.text("Madonna")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1"]
299
+ # EM.stop
300
+ # end
301
+ # end
302
+ # end
247
303
  end
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,8 @@ require LIB_PATH
4
4
  require 'minitest/spec'
5
5
  require 'minitest/autorun'
6
6
  require 'minitest/reporters'
7
+ require 'em-synchrony'
8
+
7
9
  MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new
8
10
 
9
11
  Monga.logger.level = Logger::ERROR
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monga
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-29 00:00:00.000000000 Z
12
+ date: 2013-05-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  requirement: !ruby/object:Gem::Requirement
@@ -78,35 +78,19 @@ dependencies:
78
78
  - !ruby/object:Gem::Dependency
79
79
  requirement: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - ! '>='
81
+ - - ~>
82
82
  - !ruby/object:Gem::Version
83
- version: '0'
83
+ version: 2.0.0.beta
84
84
  none: false
85
85
  type: :runtime
86
86
  version_requirements: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - ! '>='
88
+ - - ~>
89
89
  - !ruby/object:Gem::Version
90
- version: '0'
90
+ version: 2.0.0.beta
91
91
  none: false
92
92
  prerelease: false
93
93
  name: bson
94
- - !ruby/object:Gem::Dependency
95
- requirement: !ruby/object:Gem::Requirement
96
- requirements:
97
- - - ! '>='
98
- - !ruby/object:Gem::Version
99
- version: '0'
100
- none: false
101
- type: :runtime
102
- version_requirements: !ruby/object:Gem::Requirement
103
- requirements:
104
- - - ! '>='
105
- - !ruby/object:Gem::Version
106
- version: '0'
107
- none: false
108
- prerelease: false
109
- name: bson_ext
110
94
  - !ruby/object:Gem::Dependency
111
95
  requirement: !ruby/object:Gem::Requirement
112
96
  requirements:
@@ -123,7 +107,7 @@ dependencies:
123
107
  none: false
124
108
  prerelease: false
125
109
  name: bin_utils
126
- description: MongoDB Ruby Evented Driver on EventMachine
110
+ description: Yet another MongoDB Ruby Client
127
111
  email:
128
112
  - fl00r@yandex.ru
129
113
  executables: []
@@ -153,7 +137,6 @@ files:
153
137
  - lib/monga/connections/fibered_proxy_connection.rb
154
138
  - lib/monga/connections/kgio_connection.rb
155
139
  - lib/monga/connections/proxy_connection.rb
156
- - lib/monga/connections/tcp_connection.rb
157
140
  - lib/monga/cursor.rb
158
141
  - lib/monga/database.rb
159
142
  - lib/monga/protocol/delete.rb
@@ -194,7 +177,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
194
177
  requirements:
195
178
  - - ! '>='
196
179
  - !ruby/object:Gem::Version
197
- hash: -3962526029351115610
180
+ hash: -862637376897312253
198
181
  version: '0'
199
182
  segments:
200
183
  - 0
@@ -203,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
186
  requirements:
204
187
  - - ! '>='
205
188
  - !ruby/object:Gem::Version
206
- hash: -3962526029351115610
189
+ hash: -862637376897312253
207
190
  version: '0'
208
191
  segments:
209
192
  - 0
@@ -213,7 +196,7 @@ rubyforge_project:
213
196
  rubygems_version: 1.8.25
214
197
  signing_key:
215
198
  specification_version: 3
216
- summary: MongoDB Ruby Evented Driver on EventMachine
199
+ summary: Yet another MongoDB Ruby Client
217
200
  test_files:
218
201
  - spec/helpers/mongodb.rb
219
202
  - spec/monga/block/collection_spec.rb
@@ -1,59 +0,0 @@
1
- require 'socket'
2
-
3
- # Currently blocking mode is very poor.
4
- # It is working as is.
5
- # Going to support reconnecting and timouts later.
6
- # Use it for tests and prototyping. Not the best choice for production.
7
-
8
- module Monga::Connections
9
- class TCPConnection
10
- def self.connect(host, port, timeout)
11
- new(host, port, timeout)
12
- end
13
-
14
- def initialize(host, port, timeout)
15
- @host, @port, @timout = host, port, timeout
16
- @connected = true
17
- @buffer = Buffer.new
18
- end
19
-
20
- def connected?
21
- @connected
22
- end
23
-
24
- def socket
25
- @socket ||= begin
26
- TCPSocket.new(@host, @port)
27
- end
28
- end
29
-
30
- # Fake answer, as far as we are blocking
31
- def responses
32
- 0
33
- end
34
-
35
- def send_command(msg, request_id=nil, &cb)
36
- socket.send msg.to_s, 0
37
- if cb
38
- length = socket.read(4)
39
- raise Errno::ECONNREFUSED, "Socket returns nothing like it would be closed." unless length
40
- @buffer.append(length)
41
- l = length.unpack("L").first
42
- rest = socket.read(l-4)
43
- @buffer.append(rest)
44
- @buffer.each do |message|
45
- rid = message[2]
46
- fail "Returned Request Id is not equal to sended one" if rid != request_id
47
- cb.call(message)
48
- end
49
- end
50
- rescue Errno::ECONNREFUSED, Errno::EPIPE => e
51
- @connected = false
52
- @socket = nil
53
- if cb
54
- err = Monga::Exceptions::Disconnected.new("Disconnected from #{@host}:#{@port}, #{e.message}")
55
- cb.call(err)
56
- end
57
- end
58
- end
59
- end