mongo3 0.0.4 → 0.0.5

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.
Files changed (45) hide show
  1. data/HISTORY +6 -1
  2. data/README.rdoc +2 -0
  3. data/Rakefile +0 -1
  4. data/data/populate +4 -4
  5. data/lib/controllers/collections.rb +42 -8
  6. data/lib/controllers/databases.rb +11 -1
  7. data/lib/controllers/explore.rb +49 -12
  8. data/lib/helpers/collection_helper.rb +18 -0
  9. data/lib/helpers/crumb_helper.rb +4 -4
  10. data/lib/helpers/database_helper.rb +17 -0
  11. data/lib/helpers/explore_helper.rb +30 -0
  12. data/lib/helpers/flash_helper.rb +7 -0
  13. data/lib/helpers/main_helper.rb +12 -30
  14. data/lib/helpers/paths_helper.rb +40 -0
  15. data/lib/mongo3.rb +1 -1
  16. data/lib/mongo3/connection.rb +95 -34
  17. data/lib/mongo3/node.rb +43 -28
  18. data/lib/public/images/edit.png +0 -0
  19. data/lib/public/images/selected_bg.png +0 -0
  20. data/lib/public/stylesheets/mongo3.css +87 -76
  21. data/lib/views/collections/_index_form.erb +35 -0
  22. data/lib/views/collections/_index_rows.erb +54 -0
  23. data/lib/views/collections/_indexes.erb +3 -0
  24. data/lib/views/collections/_results.erb +1 -2
  25. data/lib/views/collections/_rows.erb +26 -22
  26. data/lib/views/collections/_search_form.erb +2 -3
  27. data/lib/views/collections/list.erb +18 -6
  28. data/lib/views/collections/update.js.erb +2 -0
  29. data/lib/views/collections/update_indexes.js.erb +3 -0
  30. data/lib/views/databases/_results.erb +30 -26
  31. data/lib/views/databases/list.erb +7 -3
  32. data/lib/views/explore/_node_info.erb +131 -0
  33. data/lib/views/explore/center_js.erb +1 -0
  34. data/lib/views/explore/explore.erb +11 -80
  35. data/lib/views/explore/more_data_js.erb +1 -0
  36. data/lib/views/explore/update.js.erb +5 -0
  37. data/lib/views/explore/update_crumb_js.erb +2 -1
  38. data/lib/views/layout.erb +2 -2
  39. data/lib/views/shared/flash.js.erb +9 -7
  40. data/spec/landscape.yml +3 -0
  41. data/spec/mongo3/connection_spec.rb +146 -0
  42. data/spec/mongo3/node_spec.rb +26 -8
  43. data/spec/spec_helper.rb +4 -1
  44. data/tasks/rdoc.rake +2 -2
  45. metadata +23 -2
data/lib/mongo3.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  module Mongo3
3
3
 
4
4
  # :stopdoc:
5
- VERSION = '0.0.4'
5
+ VERSION = '0.0.5'
6
6
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
7
7
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
8
8
  # :startdoc:
@@ -5,15 +5,62 @@ module Mongo3
5
5
  @config_file = config_file
6
6
  end
7
7
 
8
- def drop_db( path_names )
8
+ # drop a database using context and db name
9
+ def drop_database( path_names, db_name )
9
10
  path_name_tokens = path_names.split( "|" )
10
11
  env = path_name_tokens[1]
12
+ connect_for( env ) do |con|
13
+ con.drop_database( db_name )
14
+ end
15
+ end
16
+
17
+ def drop_db( path_names )
18
+ path_name_tokens = path_names.split( "|" )
19
+ env = path_name_tokens[1]
11
20
  connect_for( env ) do |con|
12
21
  db_name = path_name_tokens.pop
13
22
  con.drop_database( db_name )
14
23
  end
15
24
  end
16
25
 
26
+ def indexes_for( path_names )
27
+ path_name_tokens = path_names.split( "|" )
28
+ env = path_name_tokens[1]
29
+ indexes = {}
30
+ connect_for( env ) do |con|
31
+ cltn_name = path_name_tokens.pop
32
+ db_name = path_name_tokens.pop
33
+ db = con.db( db_name )
34
+ cltn = db[cltn_name]
35
+ indexes = cltn.index_information
36
+ end
37
+ indexes
38
+ end
39
+
40
+ def drop_index( path_names, index )
41
+ path_name_tokens = path_names.split( "|" )
42
+ env = path_name_tokens[1]
43
+ connect_for( env ) do |con|
44
+ cltn_name = path_name_tokens.pop
45
+ db_name = path_name_tokens.pop
46
+ db = con.db( db_name )
47
+ cltn = db[cltn_name]
48
+ cltn.drop_index( index )
49
+ end
50
+ end
51
+
52
+ def create_index( path_names, index, constraints )
53
+ path_name_tokens = path_names.split( "|" )
54
+ env = path_name_tokens[1]
55
+ connect_for( env ) do |con|
56
+ cltn_name = path_name_tokens.pop
57
+ db_name = path_name_tokens.pop
58
+ db = con.db( db_name )
59
+ cltn = db[cltn_name]
60
+ cltn.create_index( index, constraints ? constraints['unique'] == 1 : false )
61
+ end
62
+ end
63
+
17
64
  def drop_cltn( path_names )
18
65
  path_name_tokens = path_names.split( "|" )
19
66
  env = path_name_tokens[1]
@@ -75,7 +122,7 @@ module Mongo3
75
122
  # info[:links][:drop] = "/databases/drop/"
76
123
  info[:size] = to_mb( con.database_info[db_name] )
77
124
  info[:node] = db.nodes
78
- info[:collections] = db.collection_names.size
125
+ info[:collections] = collection_names( db ).size
79
126
  info[:error] = db.error
80
127
  info[:last_status] = db.last_status
81
128
  end
@@ -104,7 +151,7 @@ module Mongo3
104
151
  connect_for( env ) do |con|
105
152
  db_name = path_name_tokens.pop
106
153
  db = con.db( db_name )
107
- cltn = db.collection_names.sort
154
+ cltn = collection_names(db).sort
108
155
 
109
156
  list = WillPaginate::Collection.create( page, per_page, cltn.size ) do |pager|
110
157
  offset = (page-1)*per_page
@@ -131,15 +178,17 @@ module Mongo3
131
178
  cltn_name = path_name_tokens.pop
132
179
  db_name = path_name_tokens.pop
133
180
  db = con.db( db_name )
134
- cltn = db[cltn_name]
181
+ cltn = db[cltn_name]
182
+ count = cltn.find( query_params.first ).count
135
183
 
136
- list = WillPaginate::Collection.create( page, per_page, cltn.count ) do |pager|
184
+ list = WillPaginate::Collection.create( page, per_page, count ) do |pager|
137
185
  offset = (page-1)*per_page
138
- sort = query_params.last.empty? ? [ ['_id', Mongo::DESCENDING] ] : query_params.last
139
- pager.replace( cltn.find( query_params.first,
186
+ sort = query_params.last.empty? ? [ ['_id', Mongo::DESCENDING] ] : query_params.last
187
+ results = cltn.find( query_params.first,
140
188
  :sort => sort,
141
189
  :skip => offset,
142
- :limit => per_page ).to_a)
190
+ :limit => per_page ).to_a
191
+ pager.replace( results )
143
192
  end
144
193
  end
145
194
  list
@@ -177,26 +226,27 @@ module Mongo3
177
226
  config.each_pair do |env, info|
178
227
  node = Node.new( env, env, :dyna => true )
179
228
  root << node
180
- if node.name == bm_env
181
- connect_for( env ) do |con|
182
- count = 0
183
- data = { :dyna => true }
184
- con.database_names.each do |db_name|
185
- db = con.db( db_name, :strict => true )
186
- cltns = db.collection_names.size
187
- db_node = Node.new( "#{env}_#{count}", "#{db_name}(#{cltns})", data.clone )
188
- node << db_node
189
- count += 1
190
- if bm_db and db_node.name =~ /^#{bm_db}/
191
- cltn_count = 0
192
- data = { :dyna => false }
193
- db.collection_names.each do |cltn_name|
194
- size = db[cltn_name].count
195
- cltn_node = Node.new( "#{db_name}_#{cltn_count}", "#{cltn_name}(#{size})", data.clone )
196
- db_node << cltn_node
197
- cltn_count += 1
198
- end
199
- end
229
+
230
+ next unless node.name == bm_env
231
+
232
+ connect_for( env ) do |con|
233
+ count = 0
234
+ data = { :dyna => true }
235
+ database_names( con ).each do |db_name|
236
+ db = con.db( db_name, :strict => true )
237
+ cltns = collection_names( db )
238
+ db_node = Node.new( "#{env}_#{count}", "#{db_name}(#{cltns.size})", data.clone )
239
+ node << db_node
240
+ count += 1
241
+ if bm_db and db_node.name =~ /^#{bm_db}/
242
+ cltn_count = 0
243
+ data = { :dyna => false }
244
+ cltns.each do |cltn_name|
245
+ size = db[cltn_name].count
246
+ cltn_node = Node.new( "#{db_name}_#{cltn_count}", "#{cltn_name}(#{size})", data.clone )
247
+ db_node << cltn_node
248
+ cltn_count += 1
249
+ end
200
250
  end
201
251
  end
202
252
  end
@@ -209,13 +259,13 @@ module Mongo3
209
259
  path_name_tokens = path_names.split( "|" )
210
260
  env = path_name_tokens[1]
211
261
 
212
- if db_request?( path_name_tokens )
262
+ if db_request?( path_name_tokens )
213
263
  sub_tree = build_db_tree( parent_id, env )
214
264
  else
215
265
  db_name = path_name_tokens.last
216
266
  sub_tree = build_cltn_tree( parent_id, env, db_name )
217
267
  end
218
- sub_tree.to_adjacencies
268
+ sub_tree
219
269
  end
220
270
 
221
271
  # Connects to host and spews out all available dbs
@@ -230,9 +280,9 @@ module Mongo3
230
280
 
231
281
  count = 0
232
282
  data = { :dyna => true }
233
- con.database_names.each do |db_name|
283
+ database_names( con ).each do |db_name|
234
284
  db = con.db( db_name, :strict => true )
235
- cltns = db.collection_names.size
285
+ cltns = collection_names( db ).size
236
286
  node = Node.new( "#{env}_#{count}", "#{db_name}(#{cltns})", data.clone )
237
287
  sub_root << node
238
288
  count += 1
@@ -254,7 +304,7 @@ module Mongo3
254
304
 
255
305
  count = 0
256
306
  data = { :dyna => false }
257
- db.collection_names.each do |cltn_name|
307
+ collection_names( db ).each do |cltn_name|
258
308
  size = db[cltn_name].count
259
309
  node = Node.new( "#{db_name}_#{count}", "#{cltn_name}(#{size})", data.clone )
260
310
  sub_root << node
@@ -267,12 +317,23 @@ module Mongo3
267
317
  # =========================================================================
268
318
  private
269
319
 
320
+ def collection_names( db )
321
+ excludes = %w[system.indexes]
322
+ db.collection_names - excludes
323
+ end
324
+
325
+ # Filters out system dbs
326
+ def database_names( con )
327
+ excludes = %w[admin local slave]
328
+ con.database_names - excludes
329
+ end
330
+
270
331
  # Connects to mongo given an environment
271
332
  # BOZO !! Auth...
272
333
  def connect_for( env, &block )
273
334
  info = landscape[env]
274
335
  puts ">>> Connecting for #{env} -- #{info['host']}-#{info['port']}"
275
- con = Mongo::Connection.new( info['host'], info['port'] )
336
+ con = Mongo::Connection.new( info['host'], info['port'], { :slave_ok => true } )
276
337
 
277
338
  if info['user'] and info['password']
278
339
  con.db( 'admin' ).authenticate( info['user'], info['password'] )
data/lib/mongo3/node.rb CHANGED
@@ -1,14 +1,15 @@
1
1
  require 'json'
2
+ require 'mongo/util/ordered_hash'
2
3
 
3
4
  module Mongo3
4
5
  class Node
5
6
  attr_accessor :oid, :name, :children, :data, :parent
6
7
 
7
- def initialize( oid, name, data={} )
8
+ def initialize( oid, name, data=nil )
8
9
  @oid = oid
9
10
  @name = name
10
11
  @children = []
11
- @data = data || {}
12
+ @data = data || OrderedHash.new
12
13
  @parent = nil
13
14
  end
14
15
 
@@ -23,14 +24,18 @@ module Mongo3
23
24
  update_paths( new_one )
24
25
  end
25
26
 
26
- def update_paths( node )
27
- node.data[:path_names] = node.path( :name )
28
- node.data[:path_ids] = node.path( :oid )
29
- node.children.each do |child|
30
- child.update_paths( child )
27
+ def find( node_id )
28
+ _find( self, node_id )
29
+ end
30
+
31
+ def _find( node, node_id )
32
+ return node if node.oid == node_id
33
+ unless node.children.empty?
34
+ node.children.each { |c| found = _find( c, node_id ); return found if found }
31
35
  end
32
- end
33
-
36
+ nil
37
+ end
38
+
34
39
  # convert a tree node to a set of adjacencies
35
40
  def to_adjacencies
36
41
  root_level = { :id => self.oid, :name => self.name, :data => self.data, :adjacencies => [] }
@@ -42,27 +47,14 @@ module Mongo3
42
47
  cltn
43
48
  end
44
49
 
45
- def path( accessor=:oid )
46
- path = []
47
- traverse( path, self, accessor )
48
- path.reverse.join( "|" )
49
- end
50
-
51
- def traverse( path, node, accessor )
52
- path << node.send( accessor ).gsub( /\(\d+\)/, "" )
53
- if node.parent
54
- traverse( path, node.parent, accessor )
55
- end
56
- end
57
-
58
50
  # converts to json
59
51
  def to_json(*a)
60
- {
61
- 'id' => oid,
62
- 'name' => self.name,
63
- 'children' => self.children,
64
- 'data' => self.data
65
- }.to_json(*a)
52
+ hash = OrderedHash.new
53
+ hash[:id] = oid
54
+ hash[:name] = self.name
55
+ hash[:children] = self.children
56
+ hash[:data] = self.data
57
+ hash.to_json(*a)
66
58
  end
67
59
 
68
60
  # Debug...
@@ -79,6 +71,29 @@ module Mongo3
79
71
  puts ' '*level + "%-#{20-level}s (%d) [%s] -- %s" % [adj[:id], adj[:adjacencies].size, adj[:name], (adj[:data] ? adj[:data].inspect : 'N/A' )]
80
72
  end
81
73
  end
74
+
75
+ # =========================================================================
76
+ private
77
+
78
+ def update_paths( node )
79
+ node.data[:path_names] = node.send( :path, :name )
80
+ node.data[:path_ids] = node.send( :path, :oid )
81
+ node.children.each do |child|
82
+ child.send( :update_paths, child )
83
+ end
84
+ end
85
+
86
+ def path( accessor=:oid )
87
+ path = []
88
+ traverse( path, self, accessor )
89
+ path.reverse.join( "|" )
90
+ end
82
91
 
92
+ def traverse( path, node, accessor )
93
+ path << node.send( accessor ).to_s.gsub( /\(\d+\)/, "" )
94
+ if node.parent
95
+ traverse( path, node.parent, accessor )
96
+ end
97
+ end
83
98
  end
84
99
  end
Binary file
Binary file
@@ -19,16 +19,24 @@ body {
19
19
  margin: 0;
20
20
  }
21
21
 
22
+ img {
23
+ border: none;
24
+ vertical-align: text-top;
25
+ }
26
+
27
+ /* Flash */
22
28
  div.flash {
23
29
  display: none;
30
+ width: 95%;
24
31
  padding: 10px;
25
- font-size: .8em;
32
+ margin: 20px 0 0px 300px;
33
+ font-size: .5em;
26
34
  color: #fff;
27
35
  border: 1px #92b948 solid;
28
- -moz-border-radius-bottomleft: 0px;
29
- -moz-border-radius-topleft: 20px;
30
- -moz-border-radius-bottomright: 20px;
31
- -moz-border-radius-topright: 0px;
36
+ -moz-border-radius-bottomleft: 20px;
37
+ -moz-border-radius-topleft: 0px;
38
+ -moz-border-radius-bottomright: 0px;
39
+ -moz-border-radius-topright: 20px;
32
40
  }
33
41
  div.flash_error {
34
42
  color: #f00;
@@ -45,10 +53,6 @@ div.flash_info {
45
53
  overflow: none;
46
54
  }
47
55
 
48
- span#log {
49
- color: #ff9d2a;
50
- }
51
-
52
56
  div#logo {
53
57
  float: left;
54
58
  width: 45%;
@@ -117,28 +121,6 @@ p.title span{
117
121
  /* ---------------------------------------------------------------------------- */
118
122
  /* Common */
119
123
 
120
- div.item {
121
- border-top: 1px #1c1c1c solid;
122
- padding: 10px 0px 0px 0px;
123
- height: 100px;
124
- clear: both;
125
- width: 100%;
126
- }
127
-
128
- div.item .tag {
129
- float:left;
130
- }
131
-
132
- div.item .lock {
133
- float: right;
134
- width: 5%;
135
- color: #434343;
136
- }
137
-
138
- div.selected {
139
- background: transparent url(/images/li_select.png) repeat-x;
140
- cursor: pointer;
141
- }
142
124
  ul.host_info {
143
125
  font-size: 0.5em;
144
126
  color: #c1c1c1;
@@ -146,7 +128,7 @@ ul.host_info {
146
128
  }
147
129
  span {
148
130
  color: #c1c1c1;
149
- font-size: 0.5em;
131
+ font-size: 1.0em;
150
132
  }
151
133
  p.heading {
152
134
  width: 80%;
@@ -168,11 +150,6 @@ div#details {
168
150
  font-size: 0.5em;
169
151
  color: #fff;
170
152
  background: #1c1c1c;
171
- border: 1px #92b948 solid;
172
- -moz-border-radius-bottomleft: 7px;
173
- -moz-border-radius-topleft: 7px;
174
- -moz-border-radius-bottomright: 7px;
175
- -moz-border-radius-topright: 7px;
176
153
  }
177
154
 
178
155
  .overlay {
@@ -183,10 +160,6 @@ div#details {
183
160
  color: #fff;
184
161
  width: 650px;
185
162
  min-height: 400px;
186
- -moz-border-radius-bottomleft: 7px;
187
- -moz-border-radius-topleft: 7px;
188
- -moz-border-radius-bottomright: 7px;
189
- -moz-border-radius-topright: 7px;
190
163
  -moz-box-shadow: 0 0 90px 5px #000;
191
164
  -webkit-box-shadow: 0 0 90px #000;
192
165
  }
@@ -206,50 +179,55 @@ div#details {
206
179
  div.scrollable {
207
180
  position: relative;
208
181
  overflow: hidden;
209
- height: 440px;
182
+ height: 445px;
183
+ width: 255px;
210
184
  }
211
-
212
- div.scrollable div.items {
213
- width:800px;
214
- position:absolute;
215
- height:20000em;
185
+ div.scrollable div.items {
186
+ width: 255px;
187
+ position: absolute;
188
+ height: 20000em;
216
189
  }
217
190
 
218
191
  #actions {
219
- width:800px;
220
- margin:30px 0 10px 0;
192
+ font-size: 0.5em;
193
+ width: 255px;
194
+ height: 15px;
195
+ margin: 7px 0 1px 0;
221
196
  }
222
-
223
197
  #actions a {
224
198
  font-size: 0.6em;
225
199
  text-decoration: none;
226
200
  cursor: pointer;
227
201
  color: #c1c1c1;
228
202
  }
229
-
230
203
  #actions a:hover {
231
204
  text-decoration: underline;
232
205
  color: #92b948;
233
206
  }
234
-
235
207
  .disabled {
236
208
  visibility:hidden;
237
209
  }
238
-
239
210
  .nextPage {
240
211
  float:right;
241
212
  }
242
213
 
214
+ /* Commons */
215
+ div.borders {
216
+ -moz-border-radius-bottomleft: 7px;
217
+ -moz-border-radius-topleft: 7px;
218
+ -moz-border-radius-bottomright: 7px;
219
+ -moz-border-radius-topright: 7px;
220
+ -webkit-border-top-left-radius: 7px;
221
+ -webkit-border-top-right-radius: 7px;
222
+ -webkit-border-bottom-right-radius: 7px;
223
+ -webkit-border-bottom-left-radius: 7px;
224
+ border: 1px #92b948 solid;
225
+ }
243
226
 
244
227
  /* Explorer css */
245
228
  div#landscape {
246
229
  width: 615px;
247
230
  height: 550px;
248
- -moz-border-radius-bottomleft: 7px;
249
- -moz-border-radius-topleft: 7px;
250
- -moz-border-radius-bottomright: 7px;
251
- -moz-border-radius-topright: 7px;
252
- border: 1px #92b948 solid;
253
231
  float: left;
254
232
  }
255
233
 
@@ -258,11 +236,6 @@ div#right {
258
236
  padding: 10px;
259
237
  width: 254px;
260
238
  height: 530px;
261
- -moz-border-radius-bottomleft: 7px;
262
- -moz-border-radius-topleft: 7px;
263
- -moz-border-radius-bottomright: 7px;
264
- -moz-border-radius-topright: 7px;
265
- border: 1px #92b948 solid;
266
239
  }
267
240
 
268
241
 
@@ -333,13 +306,16 @@ fieldset.check {
333
306
  width: 20%;
334
307
  }
335
308
 
309
+ p.ctx {
310
+ font-size: 0.7em;
311
+ text-align: right;
312
+ }
313
+ p.ctx span {
314
+ color: #92b948;
315
+ }
316
+
336
317
  div.table {
337
- padding: 10px;
338
- -moz-border-radius-bottomleft: 7px;
339
- -moz-border-radius-topleft: 7px;
340
- -moz-border-radius-bottomright: 7px;
341
- -moz-border-radius-topright: 7px;
342
- border: 1px #92b948 solid;
318
+ /* padding: 10px;*/
343
319
  }
344
320
 
345
321
  table.cltn {
@@ -371,18 +347,37 @@ div.cltn div#links {
371
347
  text-align: center;
372
348
  }
373
349
 
350
+ /* Indexes... */
351
+ div#indexes {
352
+ margin: 10px 0px;
353
+ }
354
+ fieldset.sep {
355
+ margin-top: 10px;
356
+ padding: 0 0 0 20px;
357
+ border-top: 1px #434343 solid;
358
+ }
359
+ fieldset.sep legend {
360
+ color: #fff;
361
+ padding: 0 5px;
362
+ font-size: 1.2em;
363
+ }
364
+ img.del_index {
365
+ display:none;
366
+ }
367
+
374
368
  input.search {
375
- background: #fff url(/images/search.png) no-repeat 2px 6px;
376
- width: 80%;
369
+ background: transparent url(/images/search.png) no-repeat 2px 6px;
370
+ width: 96%;
377
371
  border: 2px #434343 solid;
378
- -moz-border-radius-bottomleft: 5px;
379
- -moz-border-radius-bottomright: 5px;
380
- -moz-border-radius-topleft: 5px;
381
- -moz-border-radius-topright: 5px;
372
+ -moz-border-radius-bottomleft: 0px;
373
+ -moz-border-radius-bottomright: 10px;
374
+ -moz-border-radius-topleft: 10px;
375
+ -moz-border-radius-topright: 0px;
382
376
  height: 25px;
383
377
  font-size: 1.2em;
384
- color: #434343;
378
+ color: #92b948;
385
379
  padding: 5px 0px 0px 20px;
380
+ margin: 5px 5px;
386
381
  }
387
382
 
388
383
  button {
@@ -451,6 +446,7 @@ img.wait {
451
446
  }
452
447
 
453
448
  .modal {
449
+ font-size: 0.6em;
454
450
  background-color: #212021;
455
451
  display: none;
456
452
  width: 350px;
@@ -463,3 +459,18 @@ img.wait {
463
459
  -moz-box-shadow: 0 0 20px #92b948;
464
460
  -webkit-box-shadow: 0 0 20px #92b948;
465
461
  }
462
+
463
+ /* Node details */
464
+ div#wrap {
465
+ font-size: 0.7em;
466
+ }
467
+
468
+ /* Node info */
469
+ span#log {
470
+ color: #92b948;
471
+ font-size: 0.5em;
472
+ }
473
+
474
+ div#info {
475
+ min-height: 520px;
476
+ }