Permalink
Browse files

allow to send commands to db and make use of it, minor ui changes

  • Loading branch information...
1 parent 0d8f520 commit 70ed900a4e19481ea6f2c79f4a6870a3a0e4b81c @Fiedzia committed Jun 24, 2010
View
7 TODO.rst
@@ -3,16 +3,15 @@ TODO list (varius bugs, tweaks and ideas)
* Bugs/annoyances
- - Binary and Code data types are not supported by python json_utility
+ - Binary and Code data types are not supported by python json_utility.
(the only way to use them is to traverse json and manually replace Binary/Code objects)
- Regular exression type g flag is ommited by python driver ( because it doesn't exist in python )
- properly discover list of sort candidates from json structure
- introduce some menu interface, currently ordering is now unpredictable and plugins just mess with dom
- document edition:
after editing coloring of odd documents doesn't work, also collapse/expand button ignores them
- allow adding new / removing documents
+ - allow adding new / removing documents
changing _id generates new document. Thats might require help information, some people might be surprised
- - query builder: removing conditions clears first condition
- add no_collection_selected signal
@@ -23,7 +22,7 @@ TODO list (varius bugs, tweaks and ideas)
- consider async solution for server side
(tornado, node.js or erlang are good candidates)
- console with full mongo syntax support, maybe pyv8 could be usefull. Other solution is to popen mongo.
- - how about implementing mongo driver entirely in js on browser side with websockets?
+ - how about implementing mongo driver entirely in js on browser side with websockets? (what about support for binary data in browser?)
- db/collection disk usage charts
- inline editor, double click value to change it, or right click to operate it ( like add to query builder)
- maintain collection of usefull mongodb data dumps for tutorial purpose
View
2 fangofmongo/fom/urls.py
@@ -9,6 +9,8 @@
(r'rest/mongo/(?P<host>.+)/(?P<port>\d+)/databases/$', 'fom.views.list_databases'),
(r'rest/mongo/(?P<host>.+)/(?P<port>\d+)/database/(?P<dbname>.+)/stats/$', 'fom.views.db_stats'),
+ (r'rest/mongo/(?P<host>.+)/(?P<port>\d+)/database/(?P<dbname>.+)/cmd/$', 'fom.views.db_run_command'),
+
(r'rest/mongo/(?P<host>.+)/(?P<port>\d+)/collections/(?P<dbname>.+)/$', 'fom.views.list_collections'),
(r'rest/mongo/(?P<host>.+)/(?P<port>\d+)/collection/(?P<dbname>.+)/(?P<collname>.+)/stats/$', 'fom.views.coll_stats'),
(r'rest/mongo/(?P<host>.+)/(?P<port>\d+)/collection/(?P<dbname>.+)/(?P<collname>.+)/indexes/$', 'fom.views.coll_indexes'),
View
30 fangofmongo/fom/views.py
@@ -230,6 +230,36 @@ def coll_stats(request, host, port, dbname, collname):
resp['Cache-Control'] = 'no-cache'
return resp
+
+
+#@auth_required
+def db_run_command(request, host, port, dbname):
+ """
+ From GET take: login, password : database credentials(optional, currently ignored)
+ cmd:
+ command to perform, in json format
+
+ Excute command again given database.
+ """
+ try:
+ conn = pymongo.Connection(host = host, port = int(port))
+ db = conn[dbname]
+ cmd = json.loads(request.GET['cmd'], object_hook=json_util.object_hook)
+ resp = db.command(cmd)
+ json_response = json.dumps({'data':resp},default=pymongo.json_util.default)
+ except (Exception), e:
+ json_response = json.dumps({'error': repr(e)})
+ import traceback
+ traceback.print_stack()
+ finally:
+ conn.disconnect()
+
+ resp = HttpResponse(json_response, mimetype='application/json')
+ resp['Cache-Control'] = 'no-cache'
+ return resp
+
+
+
#@auth_required
def coll_query(request, host, port, dbname, collname):
"""
View
3 fangofmongo/plugins/mongo_collection.fomxml
@@ -453,6 +453,9 @@ $(window).load( function() {$('#mongo_ui_header_tools_coll_info').fom_plugin_col
<option value='[["_id",-1]]'>_id DESC</option>
</select>
</td>
+ <td>
+ <input type="text" id="mongo_ui_coll_info_data_sort" value=""/>
+ </td>
</tr>
</table>
<table>
View
128 fangofmongo/static/fom/js/fangofmongo_ui.js
@@ -80,19 +80,19 @@ Fom_query_builder = $.extend({}, $.ui.fom_object.prototype,{
$(this.div).append('<table>\
<tr>\
<td>Field</td>\
- <td><button class="fom_query_builder_btn_add">+</button></td>\
+ <td><button class="fom_query_builder_btn_add" title="add condition">+</button></td>\
</tr>\
<tr>\
<td>Condition</td>\
- <td><button class="fom_query_builder_btn_del">-</button></td>\
+ <td><button class="fom_query_builder_btn_del" title="remove condition">-</button></td>\
</tr>\
<tr>\
<td>Value</td>\
<td></td>\
</tr>\
</table>');
} else { //vertical layout
- $(this.div).append('<table><tr><td><button class="fom_query_builder_btn_add">+</button></td><td><button class="fom_query_builder_btn_del">-</button></td></tr></table>');
+ $(this.div).append('<table><tr><td><button class="fom_query_builder_btn_add" title="add condition">+</button></td><td><button class="fom_query_builder_btn_del" title="remove condition">-</button></td></tr></table>');
};
this.table = $(this.div).children()[0];
$(this.table).find('.fom_query_builder_btn_add').click( function() {
@@ -513,13 +513,6 @@ Fom_item_list = $.extend({}, $.ui.fom_object.prototype,{
$('#' + this.options['div_id']).append("\
<div id='" + this.dialog_id + "'>\
<div style='width: 99%; height: 99%; display: table;'>\
- <div style='display: table-row; height: auto;'>\
- <div class='search_toolbox' style=' height: auto; display: table-cell;'>\
- <input type='text' name='" + this.input_id +"' id='" + this.input_id + "'/>\
- <button id='" + this.search_id + "'>Search</button>\
- <button id='" + this.clear_id + "'>Clear</button>\
- </div>\
- </div>\
<div style='display: table-row; height: auto;'>\
<div style=' display: table-cell; height: 99%; '>\
<div class='fom_ui_note'></div>\
@@ -529,6 +522,13 @@ Fom_item_list = $.extend({}, $.ui.fom_object.prototype,{
</div>\
</div>\
<div style='display: table-row; height: auto;'>\
+ <div class='search_toolbox' style=' height: auto; display: table-cell;'>\
+ <input type='text' name='" + this.input_id +"' id='" + this.input_id + "'/>\
+ <button id='" + this.search_id + "'>Search</button>\
+ <button id='" + this.clear_id + "'>Clear</button>\
+ </div>\
+ </div>\
+ <div style='display: table-row; height: auto;'>\
<div class='toolbox' style='height: auto; display: table-cell;'></div>\
</div>\
</div>\
@@ -703,51 +703,75 @@ $.widget("ui.fom_ui_list", Fom_item_list);
class which allows to access mongodb via ajax calls
*/
-Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
+Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
_init: function() {
$('#mongo_ui_header_tools_bus').fom_bus('add_listener', this);
-
+
//this.host = null;
//this.port = null;
//this.collection = null;
//this.database = null; },
- },
+ },
// process server response to exec_cmd
process_response: function(caller_id, data) {
caller_id.process_response(data);
}, // end of process_reponse
-
+
/* //this is intended to be use for console plugin
exec_cmd: function(console_obj, cmd){
var url = '/fangofmongo/rest/mongo/cmd/';
var caller_id = console_obj;
var my_console = this;
$.post(url, {'cmd':'help'}, function(data){ my_console.process_response(caller_id, data); }, "json");
-
+
}, //end of exec_cmd:*/
-
+
+
+ /*
+ * run command against database
+ * params:
+ * command: Object with command to perform
+ */
+ run_command: function(database, command, callback){
+ var url = '/fangofmongo/rest/mongo/' + encodeURIComponent(this.options['host']) + '/' + encodeURIComponent(this.options['port']) + '/';
+ url += 'database/' + encodeURIComponent(database) + '/cmd/'
+ $.getJSON( url,
+ {cmd:JSON.stringify(command)},
+ function(data){
+ if ( 'error' in data ) { alert('error: ' + data['error']); return data; }
+ //alert(JSON.stringify(data));
+ callback(data);
+
+ });
+
+ }, //end of run_command
+
/* Get list of databases from mongo server
params:
search (string, optional): text to search
method (string, optional): search method, either null (text search) or 're' (search will be interpreted as regular expression)
*/
get_db_list: function(search, method){
- var url = '/fangofmongo/rest/mongo/' + encodeURIComponent(this.options['host']) + '/' + encodeURIComponent(this.options['port']) + '/';
- var params = '';
- if (search != '') { params += 'search=' + encodeURIComponent(search); };
- if (method != '') { params += '&method=' + encodeURIComponent(method); };
- if (params != '') { params = '?' + params; };
- //alert('json url: ' + url+'databases/');
- $.getJSON( url + 'databases/' + params,
- function(data, search, method){
-
+ this.run_command('admin', //database
+ {listDatabases : 1}, //command
+ function(data) { // callback
if ( 'error' in data ) { alert('error: ' + data['error']); return; }
- $('#mongo_ui_header_tools_bus').fom_bus('signal', 'database_list_received', this, {'search':search, 'method':method, 'data' : data['data'] } );
+ var db_list = Array();
+ for(obj in data['data']['databases'])
+ {
+ db_list.push(data['data']['databases'][obj]['name']);
+ }
+ db_list.sort();
- });
+ if(search) {
+ db_list = $('#fom_utils').fom_utils('filter_list',db_list, search, method);
+ }
+ $('#mongo_ui_header_tools_bus').fom_bus('signal', 'database_list_received', this, {'search':search, 'method':method, 'data' : db_list } );
+ }
+ );
}, //end of get_db_list:
@@ -758,25 +782,30 @@ Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
method (string, optional): search method, either null (text search) or 're' (search will be interpreted as regular expression)
*/
get_collection_list: function(search, method){
- var url = '/fangofmongo/rest/mongo/' + encodeURIComponent(this.options['host']) + '/' + encodeURIComponent(this.options['port']) + '/';
- var params = '';
- if (search != '') { params += 'search=' + encodeURIComponent(search); };
- if (method != '') { params += '&method=' + encodeURIComponent(method); };
- if (params != '') { params = '?' + params; };
- try{
- $.getJSON( url + 'collections/'+ encodeURIComponent(this.options['database']) +'/' + params,
- function(data,search, method){
- if ( 'error' in data ) { alert('error: ' + data['error']); return; }
- $('#mongo_ui_header_tools_bus').fom_bus('signal', 'collection_list_received', this, {'search':search, 'method':method, 'data' : data['data'] } );
-
+
+ this.get_data(
+ {$where :'this.name.indexOf("' + this.options['database'] + '.") == 0 && this.name.indexOf("$") == -1'},
+ {
+ sort: [['name',1]],
+ callback: function(data){
+ if ( 'error' in data ) { alert('error: ' + data['error']); return; }
+ var coll_list = Array();
+ for(obj in data['data'])
+ coll_list.push(data['data'][obj]['name'].substr(this.options['database'].length+1)); //strip database_name and dot
+ if (search)
+ coll_list = $('#fom_utils').fom_utils('filter_list',coll_list, search, method);
+ $('#mongo_ui_header_tools_bus').fom_bus('signal', 'collection_list_received', this, {'search':search, 'method':method, 'data' : coll_list } );
+ },
+ context: this,
+ database: this.options['database'],
+ collection: 'system.namespaces'
}
- ); //end of $.getJSON
-
- } catch(e) {alert(e);};
+ );
+
}, // end of get_collection_list
-
+
/*
save document
options:
@@ -789,9 +818,9 @@ Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
if (!("document" in options)) {
throw("save_document: Missing document");
}
-
+
try {
-
+
$.ajax({
type: 'POST',
url: url + 'collection/' + encodeURIComponent(this.options['database']) +'/' + encodeURIComponent(this.options['collection']) + '/save_document/',
@@ -863,7 +892,7 @@ Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
options: dictionary with:
limit: number of documents to retrieve
skip: how many documents ommit from results
- sorting: sort order, in mongo format: array of arrays ["fieldname", "ordering"], for example: [["_id",1]]
+ sort: sort order, in mongo format: array of arrays ["fieldname", "ordering"], for example: [["_id",1]]
callback: callback function
context: context object
returns JSON with results
@@ -876,10 +905,13 @@ Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
limit: options['limit'],
skip: options['skip']
};
+ var db = 'database' in options ? options['database'] : this.options['database'];
+ var coll = 'collection' in options ? options['collection'] : this.options['collection'];
+
if (options['sort'])
query_data['sort'] = JSON.stringify(options['sort']);
$.ajax({
- url: url + 'collection/' + this.options['database'] + '/' + this.options['collection'] + '/query/' + params,
+ url: url + 'collection/' + encodeURIComponent(db) + '/' + encodeURIComponent(coll) + '/query/' + params,
dataType: 'json',
data: query_data,
success: options['callback'],
@@ -937,7 +969,7 @@ Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
default: throw ('operation: incorrect params');
}
break;
-
+
default: throw ('operation: incorrect params');
}
$.ajax({
@@ -948,7 +980,7 @@ Fom_mongo_ajax = $.extend({}, $.ui.fom_object.prototype, {
dataType: 'json',
context: ('context' in options) ? options['context'] : null,
error: function(XMLHttpRequest, textStatus, errorThrown) {
- alert('get_data failed status' + textStatus + ' error:' + errorThrown);
+ alert('operation failed status: ' + textStatus + ' error:' + errorThrown);
},
});
},
View
35 fangofmongo/static/fom/js/fangofmongo_utils.js
@@ -112,6 +112,41 @@ $.widget("ui.fom_utils", {
},
/*
+ Filter list
+ params:
+ search
+ text to search
+ method
+ either null or 're'
+ if 're' then search is treated as text containing regular expression
+
+ */
+ filter_list:function(item_list, search, method)
+ {
+ var new_list = Array();
+ if(search) {
+ if (method == 're') {
+ var re = new RegExp(search, "i");
+ for(var i = item_list.length-1; i>=0; i--) {
+ if(r.test(item_list[i])) {
+ new_list.push(item_list[i]);
+ }
+ }
+ } else {
+ for(var i = item_list.length-1; i>=0; i--) {
+ if(item_list[i].toLowerCase().indexOf( search.toLowerCase() ) != -1 ) {
+ new_list.push(item_list[i]);
+ }
+ }
+ }
+ } else
+ return item_list;
+
+ return new_list;
+ },
+
+
+ /*
* add event handlers to dom resulted from call to format_mongo_json_data
* params:
* node: dom node (class: fom_ui_json_data)

0 comments on commit 70ed900

Please sign in to comment.