Commit 247469b3 authored by Jérome Perrin's avatar Jérome Perrin

erp5_sql_browser: Simple tool to run SQL queries in the browser

parent e2f8c897
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_sql_browser</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>import datetime\n
import json\n
from DateTime import DateTime\n
\n
response = container.REQUEST.RESPONSE\n
\n
try:\n
results = context.manage_test(query)\n
data = [ results.names() ]\n
data.extend(results.tuples())\n
except Exception, e:\n
response.setStatus(500)\n
try:\n
response.write(str(e[1]))\n
except Exception, _:\n
response.write(str(e))\n
return\n
\n
# handle non JSON serializable data\n
new_data = [data[0]]\n
for line in data[1:]:\n
new_line = []\n
for v in line:\n
if isinstance(v, DateTime):\n
v = v.ISO()\n
if isinstance(v, datetime.datetime):\n
v = v.isoformat()\n
new_line.append(v)\n
new_data.append(new_line)\n
\n
response.setHeader(\'Content-Type\', \'application/json\')\n
return json.dumps(new_data, indent=2)\n
\n
\n
\n
\n
\n
\n
import datetime\n
import json\n
from DateTime import DateTime\n
\n
response = container.REQUEST.RESPONSE\n
\n
try:\n
results = context.manage_test(query)\n
data = [ results.names() ]\n
data.extend(results.dictionaries())\n
except Exception, e:\n
response.setStatus(500)\n
try:\n
response.write(str(e[1]))\n
except Exception, _:\n
response.write(str(e))\n
return\n
\n
# handle non JSON serializable data\n
new_data = [data[0]]\n
for line in data[1:]:\n
new_line = {}\n
for k, v in line.items():\n
if isinstance(v, DateTime):\n
v = v.ISO()\n
if isinstance(v, datetime.datetime):\n
v = v.isoformat()\n
line[k] = v#new_line.append(v)\n
new_data.append(line)\n
\n
response.setHeader(\'Content-Type\', \'application/json\')\n
return json.dumps(new_data, indent=2)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>query=""</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ZMySQLDAConnection_getQueryResultAsJSON</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from json import dumps\n
table_dict = {}\n
\n
connection = context\n
\n
# make sure connection is open\n
connection()\n
\n
for table in connection.manage_test("SHOW TABLES"):\n
table_dict[table[0]] = []\n
for column in connection.manage_test("SHOW COLUMNS FROM `%s`" % table[0]):\n
table_dict[table[0]].append(column[0])\n
table_dict[table[0]].append("`%s`" % column[0])\n
\n
container.REQUEST.RESPONSE.setHeader(\'content-type\', \'application/json\')\n
return dumps(table_dict)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ZMySQLDAConnection_getSchemaAsJSON</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34503950.54</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>ZMySQLDAConnection_viewQueryBrowser</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
<!DOCTYPE html>\n
<html>\n
<head>\n
<title>SQL Browser</title>\n
\n
<script type="text/javascript" src="jquery/core/jquery-1.9.min.js"></script>\n
<script type="text/javascript" src="jquery/ui/js/jquery-ui.min.js"></script>\n
\n
<!-- "local" handsontable TODO make a bt ? -->\n
<script src="sql_browser/handsontable.full.js"></script>\n
<link rel="stylesheet" media="screen" href="sql_browser/handsontable.full.css">\n
\n
<!-- "local" jquery noty -->\n
<script type="text/javascript" src="sql_browser/jquery.noty.packaged.js"></script>\n
\n
<!-- "local" c3.js (0.4.10) and d3.js (3.5.5) -->\n
<link rel="stylesheet" type="text/css" href="sql_browser/c3.min.css">\n
<script type="text/javascript" src="sql_browser/d3.min.js"></script>\n
<script type="text/javascript" src="sql_browser/c3.min.js"></script>\n
\n
<!-- PivotTable.js libs from erp5_pivot_table -->\n
<link rel="stylesheet" type="text/css" href="pivottable/pivot.css">\n
<script type="text/javascript" src="pivottable/pivot.js"></script>\n
<script type="text/javascript" src="pivottable/gchart_renderers.js"></script>\n
<script type="text/javascript" src="pivottable/c3_renderers.js"></script>\n
\n
\n
<!-- code mirror from erp5_code_mirror bt5 -->\n
<script type="text/javascript" src="codemirror/lib/codemirror.js"></script>\n
<link rel="stylesheet" href="codemirror/lib/codemirror.css">\n
<script type="text/javascript" src="codemirror/mode/sql/sql.js"></script>\n
<script type="text/javascript" src="codemirror/addon/cm_edit/matchbrackets.js"></script>\n
<link rel="stylesheet" href="codemirror/addon/dialog/dialog.css">\n
<script type="text/javascript" src="codemirror/addon/dialog/dialog.js"></script>\n
<script type="text/javascript" src="codemirror/addon/search/searchcursor.js"></script>\n
<script type="text/javascript" src="codemirror/addon/search/search.js"></script>\n
<link rel="stylesheet" href="codemirror/addon/hint/show-hint.css">\n
<script src="codemirror/addon/hint/show-hint.js"></script>\n
<script src="codemirror/addon/hint/anyword-hint.js"></script>\n
<script src="codemirror/addon/hint/sql-hint.js"></script>\n
\n
\n
<style>\n
.CodeMirror {height: 80px;}\n
body {font-family: Verdana;}\n
.c3-line {stroke-width: 3px;}\n
.c3 circle {stroke: white;}\n
.c3 text { font-size: 12px;}\n
.c3 text { font-size: 12px;}\n
.tick line {stroke: white;}\n
</style>\n
</head>\n
\n
<body>\n
<script type="text/javascript">\n
$(function() {\n
var editor,\n
ht = new Handsontable(document.getElementById(\'table_container\'), { data: [[0]], rowHeaders: true, colHeaders: true}),\n
redraw = function(){\n
\n
var derivers = $.pivotUtilities.derivers;\n
var renderers = $.extend($.pivotUtilities.renderers,\n
$.pivotUtilities.c3_renderers);\n
var dateFormat = $.pivotUtilities.derivers.dateFormat;\n
var sortAs = $.pivotUtilities.sortAs;\n
var tpl = $.pivotUtilities.aggregatorTemplates;\n
var sum = $.pivotUtilities.aggregatorTemplates.sum;\n
var numberFormat = $.pivotUtilities.numberFormat;\n
var intFormat = numberFormat({digitsAfterDecimal: 0});\n
var notification = noty({type: "info", text: "Refreshing data", layout: "bottom"});\n
\n
$.getJSON("ZMySQLDAConnection_getQueryResultAsJSON", {query: editor.getValue()}, function(mps) {\n
\n
ht.clear();\n
if (mps.length > 1) {\n
ht.updateSettings({\n
data: mps.slice(1),\n
colHeaders: mps[0]\n
});\n
} else {\n
ht.updateSettings({ data: [[0]], colHeaders: true})\n
}\n
\n
\n
$("#output").pivotUI(mps, {\n
renderers: renderers,\n
\n
hiddenAttributes: [],\n
\n
onRefresh: function(config) {\n
// TODO save properties\n
var config_copy = JSON.parse(JSON.stringify(config));\n
//delete some values which are functions\n
delete config_copy["aggregators"];\n
delete config_copy["renderers"];\n
delete config_copy["derivedAttributes"];\n
//delete some bulky default values\n
delete config_copy["rendererOptions"];\n
delete config_copy["localeStrings"];\n
$("#config_json").text(JSON.stringify(config_copy, undefined, 2));\n
}\n
});\n
notification.close();\n
}\n
).fail(function(jqXHR, textStatus, errorThrown) {\n
notification.close();\n
noty({type: "error", text: jqXHR.responseText, timeout: 5000, layout: "bottom" });\n
});\n
};\n
\n
$(function() {\n
editor = CodeMirror.fromTextArea(document.getElementById("query"), {\n
lineNumbers: true,\n
viewportMargin: Infinity,\n
extraKeys: {"Ctrl-Space": "autocomplete", "Ctrl-Enter": redraw, "Alt-Space": redraw},\n
mode: "text/x-mariadb"\n
});\n
$.getJSON("ZMySQLDAConnection_getSchemaAsJSON").then(\n
function(schema) {\n
CodeMirror.commands.autocomplete = function(cm) {\n
CodeMirror.showHint(cm, CodeMirror.hint.sql, {\n
tables: schema\n
} );\n
}\n
});\n
\n
$(\'button[name="Query"]\').click(redraw);\n
\n
// TODO: save presets in JIO\n
// ( also include pivot table config in preset )\n
$(\'button[name="Save"]\').click(function(){alert("TODO");});\n
\n
$(\'#presets\')\n
.append($(\'<option>\', {\n
value: "select * from message_queue where processing_node = -2",\n
text: \'Select failed message_queue activities\'\n
}))\n
.append($(\'<option>\', {\n
value: "update message_queue set processing_node=-1\\n where processing_node=-2\\ and method_id=\'XXX\'",\n
text: \'Restart message_queue\'\n
})).change(function(){editor.setValue($("#presets").val()); redraw();});\n
\n
redraw();\n
});\n
});\n
</script>\n
\n
Presets: <select id="presets"><option selected="selected" value=""></option></select>\n
<button name="Save">Save Preset</button>\n
<br/>\n
<textarea name="query" id="query"></textarea>\n
<button name="Query">Run Query</button>\n
\n
\n
<div id="table_container" style="margin: 10px; height: 300px; overflow: hidden"></div>\n
<div id="output" style="margin: 10px;"></div>\n
\n
<!-- TODO: debug saved configuration -->\n
<div style="display: none">\n
<pre id="config_json"></pre>\n
</div>\n
\n
</body>\n
\n
</html>\n
]]></string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>6813</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>sql_browser</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34437759.35</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>c3.min.css</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/css</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
]]></string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>1972</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
erp5_jquery
erp5_pivot_table
erp5_code_mirror
\ No newline at end of file
"Quick and dirty" web interface to run queries on a ZMySQLDA Connection.
Control + Enter to run query and Control + Space to complete.
\ No newline at end of file
erp5_sql_browser
\ No newline at end of file
erp5_sql_browser
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment