Parcourir la source

query_builder modified to take care of sub queries

version-14
Brahma K il y a 14 ans
Parent
révision
a016155f19
4 fichiers modifiés avec 94 ajouts et 87 suppressions
  1. +48
    -48
      cgi-bin/webnotes/widgets/query_builder.py
  2. +9
    -9
      cgi-bin/webnotes/widgets/search.py
  3. +35
    -28
      js/webpage/search.js
  4. +2
    -2
      js/wnf.compressed.js

+ 48
- 48
cgi-bin/webnotes/widgets/query_builder.py Voir le fichier

@@ -14,7 +14,7 @@ def get_search_criteria_list(dt):
def load_report_list():
webnotes.response['rep_list'] = get_search_criteria_list(form.getvalue('dt'))

# Get, scrub metadata
# ====================================================================

@@ -37,20 +37,20 @@ def get_parent_dt(dt):

def get_sql_meta(tl):
std_columns = {
'owner':('Owner', '', '', '100'),
'creation':('Created on', 'Date', '', '100'),
'modified':('Last modified on', 'Date', '', '100'),
'owner':('Owner', '', '', '100'),
'creation':('Created on', 'Date', '', '100'),
'modified':('Last modified on', 'Date', '', '100'),
'modified_by':('Modified By', '', '', '100')
}
meta = {}
for dt in tl:
meta[dt] = std_columns.copy()

# for table doctype, the ID is the parent id
pdt = get_parent_dt(dt)
if pdt:
if pdt:
meta[dt]['parent'] = ('ID', 'Link', pdt, '200')

# get the field properties from DocField
@@ -58,10 +58,10 @@ def get_sql_meta(tl):
for r in res:
if r[0]:
meta[dt][r[0]] = (r[1], r[2], r[3], r[4]);
# name
meta[dt]['name'] = ('ID', 'Link', dt, '200')
return meta

# Additional conditions to fulfill match permission rules
@@ -80,12 +80,12 @@ def getmatchcondition(dt, ud, ur):
return ''

return ' OR '.join(cond)
def add_match_conditions(q, tl, ur, ud):
sl = []
for dt in tl:
s = getmatchcondition(dt, ud, ur)
if s:
if s:
sl.append(s)

# insert the conditions
@@ -94,13 +94,13 @@ def add_match_conditions(q, tl, ur, ud):

condition_end = q.find('ORDER BY')!=-1 and 'ORDER BY' or 'LIMIT'
condition_end = q.find('GROUP BY')!=-1 and 'GROUP BY' or condition_end
if q.find('ORDER BY')!=-1 or q.find('LIMIT')!=-1 or q.find('GROUP BY')!=-1: # if query continues beyond conditions
q = q.split(condition_end)
q = q[0] + condition_st + '(' + ' OR '.join(sl) + ') ' + condition_end + q[1]
else:
q = q + condition_st + '(' + ' OR '.join(sl) + ')'
return q

# execute server-side script from Search Criteria
@@ -111,7 +111,7 @@ def exec_report(code, res, colnames=[], colwidths=[], coltypes=[], coloptions=[]
for c in colnames:
col_idx[c] = i
i+=1
# load globals (api)
from webnotes import *
from webnotes.utils import *
@@ -127,12 +127,12 @@ def exec_report(code, res, colnames=[], colwidths=[], coltypes=[], coloptions=[]
NEWLINE = '\n'

exec str(code)
if out!=None:
res = out

return res, style, header_html, footer_html, page_template
# ====================================================================

def guess_type(m):
@@ -146,7 +146,7 @@ def guess_type(m):
return 'Date'
else:
return 'Data'
def build_description_simple():
colnames, coltypes, coloptions, colwidths = [], [], [], []

@@ -155,7 +155,7 @@ def build_description_simple():
coltypes.append(guess_type[m[0]])
coloptions.append('')
colwidths.append('100')
return colnames, coltypes, coloptions, colwidths

# ====================================================================
@@ -180,27 +180,27 @@ def build_description_standard(meta, tl):

if (not dt) and merged_meta.get(fn):
# no "AS" given, find type from merged description
desc = merged_meta[fn]
colnames.append(desc[0] or fn)
coltypes.append(desc[1] or '')
coloptions.append(desc[2] or '')
colwidths.append(desc[3] or '100')
elif meta.get(dt,{}).has_key(fn):
# type specified for a multi-table join
# usually from Report Builder
desc = meta[dt][fn]
colnames.append(desc[0] or fn)
coltypes.append(desc[1] or '')
coloptions.append(desc[2] or '')
colwidths.append(desc[3] or '100')
else:
# nothing found
# guess
colnames.append(fn)
coltypes.append(guess_type(f[1]))
coloptions.append('')
@@ -214,21 +214,21 @@ def build_description_standard(meta, tl):
def runquery(q='', ret=0, from_export=0):
import webnotes.utils

formatted = cint(form.getvalue('formatted'))
formatted = cint(form.getvalue('formatted'))
# CASE A: Simple Query
# --------------------
if form.getvalue('simple_query') or form.getvalue('is_simple'):
q = form.getvalue('simple_query') or form.getvalue('query')
if not q: q = form.getvalue('simple_query') or form.getvalue('query')
if q.split()[0].lower() != 'select':
raise Exception, 'Query must be a SELECT'
as_dict = cint(form.getvalue('as_dict'))
res = sql(q, as_dict = as_dict, as_list = not as_dict, formatted=formatted)
# build colnames etc from metadata
colnames, coltypes, coloptions, colwidths = [], [], [], []
# CASE B: Standard Query
# -----------------------
else:
@@ -236,17 +236,17 @@ def runquery(q='', ret=0, from_export=0):

tl = get_sql_tables(q)
meta = get_sql_meta(tl)
q = add_match_conditions(q, tl, webnotes.user.roles, webnotes.user.get_defaults())
# replace special variables
q = q.replace('__user', session['user'])
q = q.replace('__today', webnotes.utils.nowdate())
res = sql(q, as_list=1, formatted=formatted)

colnames, coltypes, coloptions, colwidths = build_description_standard(meta, tl)
# run server script
# -----------------
style, header_html, footer_html, page_template = '', '', '', ''
@@ -254,15 +254,15 @@ def runquery(q='', ret=0, from_export=0):
sc_id = form.getvalue('sc_id')
from webnotes.model.code import get_code
sc_details = webnotes.conn.sql("select module, standard, server_script from `tabSearch Criteria` where name=%s", sc_id)[0]
if sc_details[1]!='No':
if sc_details[1]!='No':
code = get_code(sc_details[0], 'Search Criteria', sc_id, 'py')
else:
code = sc_details[2]
if code:
filter_values = form.has_key('filter_values') and eval(form.getvalue('filter_values','')) or {}
res, style, header_html, footer_html, page_template = exec_report(code, res, colnames, colwidths, coltypes, coloptions, filter_values, q, from_export)
out['colnames'] = colnames
out['coltypes'] = coltypes
out['coloptions'] = coloptions
@@ -270,17 +270,17 @@ def runquery(q='', ret=0, from_export=0):
out['header_html'] = header_html
out['footer_html'] = footer_html
out['page_template'] = page_template
if style:
out['style'] = style
# just the data - return
if ret==1:
return res
return res

out['values'] = res

# return num of entries
# return num of entries
qm = form.has_key('query_max') and form.getvalue('query_max') or ''
if qm and qm.strip():
if qm.split()[0].lower() != 'select':
@@ -298,31 +298,31 @@ def runquery_csv():

# run query
res = runquery(from_export = 1)
q = form.getvalue('query')
rep_name = form.getvalue('report_name')
if not form.has_key('simple_query'):

# Report Name
if not rep_name:
rep_name = get_sql_tables(q)[0]
if not rep_name: rep_name = 'DataExport'
# Headings
heads = []
rows = [[rep_name], out['colnames']] + out['values']
from cStringIO import StringIO
import csv
f = StringIO()
writer = csv.writer(f)
for r in rows:
writer.writerow(r)
f.seek(0)
out['result'] = f.read()
out['type'] = 'csv'


+ 9
- 9
cgi-bin/webnotes/widgets/search.py Voir le fichier

@@ -22,16 +22,16 @@ def getsearchfields():
webnotes.response['searchfields'] = [['name', 'ID', 'Data', '']] + res

def make_query(fields, dt, key, txt, start, length):
return """SELECT %(fields)s
FROM `tab%(dt)s`
return """SELECT %(fields)s
FROM `tab%(dt)s`
WHERE `tab%(dt)s`.`%(key)s` LIKE '%(txt)s' AND `tab%(dt)s`.docstatus != 2
ORDER BY `tab%(dt)s`.`%(key)s`
ORDER BY `tab%(dt)s`.`%(key)s`
DESC LIMIT %(start)s, %(len)s """ % {
'fields': fields,
'dt': dt,
'key': key,
'txt': txt + '%',
'start': start,
'start': start,
'len': length
}

@@ -48,7 +48,7 @@ def get_std_fields_list(dt, key):

def build_for_autosuggest(res):
from webnotes.utils import cstr
results = []
for r in res:
info = ''
@@ -56,10 +56,10 @@ def build_for_autosuggest(res):
info = ','.join([cstr(t) for t in r[1:]])
if len(info) > 30:
info = info[:30] + '...'
results.append({'id':r[0], 'value':r[0], 'info':info})
return results
def scrub_custom_query(query, key, txt):
if '%(key)s' in query:
query = query.replace('%(key)s', key)
@@ -74,7 +74,7 @@ def search_link():
txt = webnotes.form.getvalue('txt')
dt = webnotes.form.getvalue('dt')
query = webnotes.form.getvalue('query')
if query:
res = webnotes.conn.sql(scrub_custom_query(query, 'name', txt))
else:
@@ -97,5 +97,5 @@ def search_widget():
query = scrub_custom_query(user_query, key, txt)
else:
query = make_query(', '.join(get_std_fields_list(dt, key)), dt, key, txt, webnotes.form.getvalue('start') or 0, webnotes.form.getvalue('page_len') or 50)
webnotes.widgets.query_builder.runquery(query)

+ 35
- 28
js/webpage/search.js Voir le fichier

@@ -21,8 +21,8 @@ function makeselector() {
['Button', 'Search'],
['HTML', 'Help'],
['HTML', 'Result']
]);
]);
// search with
var inp = d.widgets['Beginning With'];
var field_sel = d.widgets['Search By'];
@@ -39,7 +39,7 @@ function makeselector() {
}
d.style = 'Link';
d.set_query_description()
if(!d.sel_type)d.sel_type = 'Value';
d.set_title('Select a "'+ d.sel_type +'" for field "'+label+'"');
}
@@ -47,18 +47,18 @@ function makeselector() {
if(d.style!='Search') {
d.rows['Result'].innerHTML ='';
d.values_len = 0;
}
}
d.style = 'Search';
if(d.input) { d.input = null; sel_type = null; }
d.sel_type = get_label_doctype(dt);
d.set_title('Quick Search for ' + dt);
}
inp.onkeydown = function(e) {
inp.onkeydown = function(e) {
if(isIE)var kc = window.event.keyCode;
else var kc = e.keyCode;

if(kc==13) if(!btn.disabled)btn.onclick();
if(kc==13) if(!btn.disabled)btn.onclick();
}

d.set_query_description = function() {
@@ -68,18 +68,18 @@ function makeselector() {
d.rows['Help'].innerHTML =''
}
}
d.onshow = function() {
d.onshow = function() {
if(d.set_doctype!=d.sel_type) {
d.rows['Result'].innerHTML ='';
d.values_len = 0;
}
inp.value = '';
inp.value = '';
if(d.input && d.input.txt.value) {
inp.value = d.input.txt.value;
}
try{inp.focus();} catch(e){}
if(d.input) d.input.set_get_query();

// temp function to strip labels from search fields
@@ -88,10 +88,10 @@ function makeselector() {
for(var i=0; i<lf.length; i++) l.push(lf[i][1]);
return l;
}
// set fields
$ds(d.rows['Search By']);
if(search_fields[d.sel_type]) {
empty_select(field_sel);
add_sel_options(field_sel, get_sf_list(d.sel_type), 'ID');
@@ -121,8 +121,11 @@ function makeselector() {
this.set_working();
d.set_doctype = d.sel_type;
var q = '';
args = {};

if(d.input && d.input.get_query) {
var doc = {};
args.is_simple = 1;
if(cur_frm) doc = locals[cur_frm.doctype][cur_frm.docname];
var q = d.input.get_query(doc, d.input.doctype, d.input.docname);
if(!q) { return ''; }
@@ -131,21 +134,25 @@ function makeselector() {
// for field type, return field name
var get_sf_fieldname = function(v) {
var lf = search_fields[d.sel_type];
// still loading options
if(!lf)
return 'name'
for(var i=0; i<lf.length; i++) if(lf[i][1]==v) return lf[i][0];
}

$c('webnotes.widgets.search.search_widget',
args = {
'txt':strip(inp.value)
,'doctype':d.sel_type
,'query':q
,'searchfield':get_sf_fieldname(sel_val(field_sel))
},
}

// build args
$.extend(args, {
'txt':strip(inp.value)
,'doctype':d.sel_type
,'query':q
,'searchfield':get_sf_fieldname(sel_val(field_sel))
});

// run the query
$c('webnotes.widgets.search.search_widget',
args,
function(r, rtxt) {
btn.done_working();
if(r.coltypes)r.coltypes[0]='Link'; // first column must always be selectable even if it is not a link
@@ -153,7 +160,7 @@ function makeselector() {
d.set_result(r);
}, function() { btn.done_working(); });
}
d.set_result = function(r) {
d.rows['Result'].innerHTML = '';
var c = $a(d.rows['Result'],'div','comment',{paddingBottom:'4px',marginBottom:'4px',borderBottom:'1px solid #CCC', marginLeft:'4px'});
@@ -178,8 +185,8 @@ function makeselector() {
for(var j=1; j<r.values[i].length; j++) cl.push(r.values[i][j]);
var c = $a(div,'div','comment',{marginTop:'2px'}); c.innerHTML = cl.join(', ');
}
}
selector = d;
selector = d;
}

+ 2
- 2
js/wnf.compressed.js Voir le fichier

@@ -1030,11 +1030,11 @@ $ds(d.rows['Search By']);if(search_fields[d.sel_type]){empty_select(field_sel);a
d.onhide=function(){if(page_body.wntoolbar)
page_body.wntoolbar.search_sel.disabled=0;if(d.input&&d.input.txt)
d.input.txt.onchange()}
btn.onclick=function(){if(this.disabled)return;this.set_working();d.set_doctype=d.sel_type;var q='';if(d.input&&d.input.get_query){var doc={};if(cur_frm)doc=locals[cur_frm.doctype][cur_frm.docname];var q=d.input.get_query(doc,d.input.doctype,d.input.docname);if(!q){return'';}}
btn.onclick=function(){if(this.disabled)return;this.set_working();d.set_doctype=d.sel_type;var q='';args={};if(d.input&&d.input.get_query){var doc={};args.is_simple=1;if(cur_frm)doc=locals[cur_frm.doctype][cur_frm.docname];var q=d.input.get_query(doc,d.input.doctype,d.input.docname);if(!q){return'';}}
var get_sf_fieldname=function(v){var lf=search_fields[d.sel_type];if(!lf)
return'name'
for(var i=0;i<lf.length;i++)if(lf[i][1]==v)return lf[i][0];}
$c('webnotes.widgets.search.search_widget',args={'txt':strip(inp.value),'doctype':d.sel_type,'query':q,'searchfield':get_sf_fieldname(sel_val(field_sel))},function(r,rtxt){btn.done_working();if(r.coltypes)r.coltypes[0]='Link';d.values_len=r.values.length;d.set_result(r);},function(){btn.done_working();});}
$.extend(args,{'txt':strip(inp.value),'doctype':d.sel_type,'query':q,'searchfield':get_sf_fieldname(sel_val(field_sel))});$c('webnotes.widgets.search.search_widget',args,function(r,rtxt){btn.done_working();if(r.coltypes)r.coltypes[0]='Link';d.values_len=r.values.length;d.set_result(r);},function(){btn.done_working();});}
d.set_result=function(r){d.rows['Result'].innerHTML='';var c=$a(d.rows['Result'],'div','comment',{paddingBottom:'4px',marginBottom:'4px',borderBottom:'1px solid #CCC',marginLeft:'4px'});if(r.values.length==50)
c.innerHTML='Showing max 50 results. Use filters to narrow down your search';else
c.innerHTML='Showing '+r.values.length+' resuts.';var w=$a(d.rows['Result'],'div','',{height:'240px',overflow:'auto',margin:'4px'});for(var i=0;i<r.values.length;i++){var div=$a(w,'div','',{marginBottom:'4px',paddingBottom:'4px',borderBottom:'1px dashed #CCC'});var l=$a($a(div,'div'),'span','link_type');l.innerHTML=r.values[i][0];l.link_name=r.values[i][0];l.dt=r.coloptions[0];if(d.input)


Chargement…
Annuler
Enregistrer