mongo3 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
+ }