Class: QBuilder

Inherits:
Gtk::HPaned
  • Object
show all
Includes:
Conf, ManqodCommon
Defined in:
lib/FormHolder/Form/InputHolder/QBuilder.rb

Overview

this file is part of manqod manqod is distributed under the CDDL licence the author of manqod is Dobai-Pataky Balint([email protected])

Constant Summary

Constants included from ManqodCommon

ManqodCommon::CRITICAL, ManqodCommon::DEBUG, ManqodCommon::ERROR, ManqodCommon::INFO, ManqodCommon::NORMAL, ManqodCommon::WARNING

Constants included from Eprint

Eprint::DOMAIN, Eprint::LEVEL

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Conf

#get_conf, #load_conf, #save_conf, #set_conf

Methods included from ManqodCommon

#add_where, #admin, #admin_cache, #admin_qrow, #admin_rows, #backtrace_to_debug, #cache, #changed_ids_of_base, #client, #client_fields, #client_image_of_id, #client_qrow, #client_query, #client_rows, #eeval, #escape_string, #getBinding, #guess_base, #guess_table, #image_of_id, #lzero, #manqod_db, #measure, #myexec, #nick, #nick_id, #number_format, #qrow, #query, #reconnect_manqod_db, #rows, #run_events, #send_message, #sendmail, #set_manqod_db_uri, #set_nick

Methods included from Eprint

#ecode, #edebug, #eerror, #einfo, #enormal, #eprint, #ewarn, #gtk_set_edebug, #set_edebug, #tell_exception

Constructor Details

#initialize(pc) ⇒ QBuilder

Returns a new instance of QBuilder.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 9

def initialize(pc)
@pc=pc
@qobjects=Array.new
super()

whsv=false
begin
  whsv=Gtk::SourceView::BUILD_VERSION
  rescue => err
  einfo("no Gtk::SourceView, falling back")
end

add1(Gtk::VBox.new(false,1).
  pack_start(@info=Gtk::Table.new(2,3),false).
  pack_start(Gtk::ScrolledWindow.new.set_policy(Gtk::PolicyType::AUTOMATIC,Gtk::PolicyType::AUTOMATIC).add_with_viewport(@holder=Gtk::VBox.new(false,0))).
  pack_start(@controls=Gtk::VBox.new,false,true))
add2(@rb=RelationBuilder.new(false))

@info.attach_defaults(Gtk::Label.new("name"),0,1,0,1).attach_defaults(@name=Gtk::Entry.new,1,2,0,1).
  attach_defaults(Gtk::Label.new("base"),0,1,1,2).attach_defaults(Gtk::HBox.new.pack_start(@base=Gtk::ComboBox.new(Gtk::ListStore.new(Integer,String))).pack_end(@goto_button=Gtk::Button.new.set_image(Gtk::Image.new(Gtk::Stock::JUMP_TO,Gtk::IconSize.from_name(get_conf(0,0,"button-size")))),false,false),1,2,1,2).
  attach_defaults(Gtk::Label.new("comment"),0,1,2,3).attach_defaults(@comment=Gtk::Entry.new,1,2,2,3)
update_base_selector
@goto_button.signal_connect('clicked'){|me|
  base_object.center_on_link
}
@base.pack_start(renderer=Gtk::CellRendererText.new,false).add_attribute(renderer,:text,1).signal_connect("changed"){|me|
  save_query
  if bo=base_object
    bo.set_obj_id(me.active_iter[0]) unless me.active_iter.nil?
    else
    bo=QObject.new(self,rb.table_by_id(me.active_iter[0]))
  end
  update(self)
#     base_object.center_on_link
  @rb.set_base_object(bo.link)
  false
}
@name.signal_connect("activate"){|me|save_query;false}
@comment.signal_connect("activate"){|me|save_query;false}

@where=whsv ? Gtk::SourceView.new : Gtk::TextView.new
@group_by=whsv ? Gtk::SourceView.new : Gtk::TextView.new

@holder.pack_start(
  Gtk::Frame.new.
    set_label_widget(Gtk::HBox.new(false,10).pack_start(Gtk::Label.new("SELECT")).pack_end(select_button=Gtk::Button.new)).
    set_shadow_type(Gtk::ShadowType::IN).
    add(@select=Gtk::VBox.new),false,true).
  pack_start(Gtk::Frame.new.
    set_label_widget(Gtk::HBox.new(false,10).pack_start(Gtk::Label.new("FROM")).pack_end(from_button=Gtk::Button.new)).
    set_shadow_type(Gtk::ShadowType::IN).
    add(@from=Gtk::VBox.new),false,true).
  pack_start(Gtk::Frame.new("WHERE").set_shadow_type(Gtk::ShadowType::IN).add(@where),false,true).
  pack_start(Gtk::Frame.new("GROUP BY").set_shadow_type(Gtk::ShadowType::IN).add(@group_by),false,true).
  pack_start(Gtk::Label.new,true,true)

@controls.pack_start(Gtk::HBox.new(false).
    pack_start(@autotest=Gtk::ToggleButton.new("auto")).
    pack_start(@test_now=Gtk::Button.new("test")).
    pack_start(@view_sql=Gtk::Button.new("show")).
    pack_start(@explain_sql=Gtk::Button.new("explain")).
    pack_start(@save_as_view=Gtk::Button.new("store")),false,true).
  pack_start(Gtk::ScrolledWindow.new.set_policy(Gtk::PolicyType::AUTOMATIC,Gtk::PolicyType::AUTOMATIC).add_with_viewport(@result=Gtk::Button.new),false)
@where.buffer.set_language(Gtk::SourceLanguageManager.new.get_language("sql")) if whsv
@where.signal_connect("focus-out-event"){|me,ev|
  if @autotest.active?
    save_query
    test_query
  end
  false
}
@group_by.buffer.set_language(Gtk::SourceLanguageManager.new.get_language("sql")) if whsv
@group_by.signal_connect("focus-out-event"){|me,ev|
  if @autotest.active?
    save_query
    test_query
  end
  false
}
@test_now.signal_connect("pressed"){|me|
    save_query
    test_query
}
@view_sql.signal_connect("pressed"){|me|
    save_query
    w=Gtk::Dialog.new(@name.text,parentM.get_ancestor(Gtk::Window),Gtk::Dialog::DESTROY_WITH_PARENT ,[ Gtk::Stock::CLOSE, Gtk::Dialog::RESPONSE_NONE ])
    w.vbox.add(Gtk::ScrolledWindow.new.add(sview=Gtk::SourceView.new.set_editable(false))).set_size_request(800,400)
    sview.buffer.set_text(sql).set_language(Gtk::SourceLanguageManager.new.get_language("sql"))
    sview.set_highlight_current_line(true).
      set_show_line_numbers(true)
    w.show_all
    w.run{|response| w.destroy}
}
@explain_sql.signal_connect("pressed"){|me|
    save_query
    w=Gtk::Dialog.new(@name.text,parentM.get_ancestor(Gtk::Window),Gtk::Dialog::DESTROY_WITH_PARENT ,[ Gtk::Stock::CLOSE, Gtk::Dialog::RESPONSE_NONE ])
    w.vbox.add(Gtk::ScrolledWindow.new.add(eview=Gtk::TreeView.new(emodel=Gtk::ListStore.new(String,String,String,String,String,String,String,String,String)))).set_size_request(1000,400)
    eheader={0=>{:data=>'id',:header=>'Id'},
      1=>{:data=>'select_type',:header=>'Select Type'},
      2=>{:data=>'table',:header=>'Table'},
      3=>{:data=>'type',:header=>'Type'},
      4=>{:data=>'possible_keys',:header=>'Possible Keys'},
      5=>{:data=>'key',:header=>'Key'},
      6=>{:data=>'ref',:header=>'Ref'},
      7=>{:data=>'rows',:header=>'Rows'},
      8=>{:data=>'Extra',:header=>'Extra'}
    }
    eheader.each_pair{|hid,h|
      eview.append_column(Gtk::TreeViewColumn.new(h[:header],Gtk::CellRendererText.new, {:text => hid}))
    }
    begin
    client_rows("explain #{sql}"){|row|
      iter=emodel.append
      eheader.each_pair{|hid,h| iter[hid]=row[h[:data]] }
    }
    rescue
    end
    w.show_all
    w.run{|response| w.destroy}
}
@result.signal_connect("pressed"){|me,ev|
    begin
      w=Gtk::Dialog.new(@name.text,parentM.get_ancestor(Gtk::Window),Gtk::Dialog::DESTROY_WITH_PARENT ,[ Gtk::Stock::CLOSE, Gtk::Dialog::RESPONSE_NONE ])
      res=ManqodDB.instance.manqod_db.client.query(sql)
      htypes=Array.new
      headers=Hash.new
      row=res.fetch_hash(true)
      #build headertypes
      i=0
      row.each_key{|k|
        htypes.push(String)
        headers[i]=k
        i+=1
      }
      model=Gtk::ListStore.new(*htypes)
      sview=Gtk::TreeView.new(model)
      #create and add columns
      headers.sort.each{|k|
        col=Gtk::TreeViewColumn.new(k[1],Gtk::CellRendererText.new, {:text => k[0]}).set_resizable(true).set_sort_column_id(k[0]).set_reorderable(true)
        sview.append_column(col)
      }
      begin
        i=model.append
        row.each{|k,v| i[headers.key(k)]=v}
      end while (row=res.fetch_hash(true))
      sview.set_model(model)
      w.vbox.add(Gtk::ScrolledWindow.new.add(sview).set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC)).set_size_request(600,400)
      w.show_all
      w.run{|response| w.destroy}
    rescue =>err
      warn(err,backtrace_to_debug(err))
    end
}
@save_as_view.signal_connect("pressed"){|me|
  store_query
}


select_button.set_image(Gtk::Image.new(Gtk::Stock::ADD,Gtk::IconSize::MENU)).set_relief(Gtk::ReliefStyle::NONE)
select_button.signal_connect('clicked'){|me|
  QObject.new(self,{"custom"=>"true", "obj_type"=>"f", "field"=>"*"}).store
  update(self)
}

from_button.set_image(Gtk::Image.new(Gtk::Stock::ADD,Gtk::IconSize::MENU)).set_relief(Gtk::ReliefStyle::NONE)
from_button.signal_connect('clicked'){|me|
  QObject.new(self,{"custom"=>"true", "field"=>"left join ", "obj_type"=>"r"})
  update(self)
}
# holder.pack_end(button_holder,false,false,1)
  
#   add(rb_holder)

#   set_query_id(query_id)
@rb.add_observer(self)
signal_connect("destroy"){|me| save_query}
end

Instance Attribute Details

#fromObject (readonly)

Returns the value of attribute from.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def from
  @from
end

#groupbyObject (readonly)

Returns the value of attribute groupby.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def groupby
  @groupby
end

#pcObject (readonly)

Returns the value of attribute pc.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def pc
  @pc
end

#qobjectsObject (readonly)

Returns the value of attribute qobjects.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def qobjects
  @qobjects
end

#query_idObject (readonly)

Returns the value of attribute query_id.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def query_id
  @query_id
end

#rbObject (readonly)

Returns the value of attribute rb.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def rb
  @rb
end

#selectObject (readonly)

Returns the value of attribute select.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def select
  @select
end

#whereObject (readonly)

Returns the value of attribute where.



186
187
188
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 186

def where
  @where
end

Instance Method Details

#baseObject



306
307
308
309
310
311
312
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 306

def base
  if @base.active_iter
    @base.active_iter[0]
    else
    0
  end
end

#base_objectObject



283
284
285
286
287
288
289
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 283

def base_object
  found=nil
  @qobjects.each{|qobject|
    found=qobject if qobject.obj_type == "b"
  }
  found
end

#commentObject



316
317
318
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 316

def comment
  @comment.text
end

#group_by_clauseObject



329
330
331
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 329

def group_by_clause
  @group_by.buffer.text
end

#inspectObject



353
354
355
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 353

def inspect
  "QBuilder"
end

#itemObject



294
295
296
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 294

def item
  pc.item
end

#nameObject



313
314
315
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 313

def name
  @name.text
end

#parentMObject



291
292
293
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 291

def parentM
  pc.parentM
end


319
320
321
322
323
324
325
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 319

def qobject_by_link(link)
  found=nil
  @qobjects.each{|qobject|
    found=qobject if qobject.link == link
  }
  found
end

#save_queryObject



227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 227

def save_query
  if @query_id == 0 or @query_id == -1
    query("insert into `queries` set `base`='#{base}', name='#{name}', comment='#{comment}', `where_clause` = '#{escape_string(where_clause)}', `group_by` = '#{escape_string(group_by_clause)}', `sql`='#{escape_string(sql)}'")
    @query_id=qrow("select id from queries order by id desc limit 1")["id"]
    edebug("new query created: #{name}(#{@query_id})","relation-builder","debug")
    parentM.parentselected=@query_id.to_i
    parentM.runmode="modify"
  else
    query("update `queries` set `base`='#{base}', name='#{name}', comment='#{comment}', `where_clause` = '#{escape_string(where_clause)}', `group_by` = '#{escape_string(group_by_clause)}', `sql`='#{escape_string(sql)}' where id='#{@query_id}'")
    edebug("query updated: #{name}(#{@query_id})","relation-builder","debug")
  end
end

#set_query_id(query_id) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 260

def set_query_id(query_id)
  @qobjects.each{|key,qobject| qobject.destroy}
  @qobjects.clear
  @query_id=query_id
  if @query_id and row=qrow("select * from queries where id='#{@query_id}'")
    @name.set_text(row["name"])
    @comment.set_text(row["comment"])
    @where.buffer.set_text(row["where_clause"])
    @group_by.buffer.set_text(row["group_by"])
    found=nil
    rows("select * from qobjects where query_id='#{query_id}' order by id"){|qo|
      #@qobjects[qo["obj_id"]]=
      QObject.new(self,qo)
#       @holder.pack_start_defaults(@qobjects[qo["obj_id"]])
    }
    @base.model.each{|model,path,iter| if iter[0] == row["base"].to_i then found=iter;break;end}
    if found
      @base.set_active_iter(found)
    end
  end
  @qobjects.each{|qobject| qobject.update}
end

#sqlObject



332
333
334
335
336
337
338
339
340
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 332

def sql
  s="select "
  @select.each{|so| s="#{s}\n#{so.text}"}
  s="#{s}\nfrom "
  @from.each{|so| s="#{s}\n#{so.text}"}
  s="#{s}\nwhere #{where_clause}" unless where_clause.length == 0
  s="#{s}\ngroup by #{group_by_clause}" unless group_by_clause.length == 0
  s
end

#store_queryObject



248
249
250
251
252
253
254
255
256
257
258
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 248

def store_query
  save_query
  vsql="create or replace view #{@name.text} as #{sql}"
  begin
    res=ManqodDB.instance.manqod_db.client.query(vsql)
    ret="stored"
  rescue =>err
    ret="#{err}"
  end
  @result.set_label(ret)
end

#test_queryObject



239
240
241
242
243
244
245
246
247
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 239

def test_query
  begin
    res=ManqodDB.instance.manqod_db.client.query(sql)
    ret="fields: #{res.num_fields}\nrows: #{res.num_rows}"
  rescue =>err
    ret="#{err}"
  end
  @result.set_label(ret)
end

#textObject



298
299
300
301
302
303
304
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 298

def text
  if @query_id
    "#{@query_id}"
  else
    ""
  end
end

#to_sObject



357
358
359
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 357

def to_s
  inspect
end

#update(new_value = , notifier = nil) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 188

def update(new_value=item['default'],notifier=nil)
=begin
first argument:
  - new_value - for FormItem compatibility
  - notifier - we are RelationBuilder's observer
second argument
  subnotifier - if notification comes from RelationBuilder, this will be
    RField Button - pressed, so we create or remove qobject for it
    RTable - added or removed
=end

  case new_value.class.name
    when "String"
      item['default']=new_value
      run_events(item['id'],'form_item-BeforeUpdate')
      @rb.update(self)
      set_query_id(item['default'].to_i)
      run_events(item['id'],'form_item-AfterUpdate')
    when "RelationBuilder"
      if notifier.class.name == "RTable" || notifier.nil? #if nil then removed table
        #update base combo
        update_base_selector
      else
        qobject=qobject_by_link(notifier)
        if notifier.active?
          QObject.new(self,notifier) unless qobject
        else
          qobject.delete if qobject
        end
      end
    when "QBuilder"
      #we update ourself
    else
      ewarn("notifier: #{new_value.class.name}","relation-builder")
  end
  @qobjects.each{|qobject| qobject.update}
  test_query if @autotest.active?
  show_all
end

#update_base_selectorObject



342
343
344
345
346
347
348
349
350
351
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 342

def update_base_selector
  exval=@base.active_iter[0].to_i unless @base.active_iter.nil?
  @base.model.clear
  rows("select id,name from tables order by name"){|row|
    iter=@base.model.append
    iter[0]=row["id"].to_i
    iter[1]=row["name"]
    @base.set_active_iter(iter) if iter[0].to_i == exval
  }
end

#where_clauseObject



326
327
328
# File 'lib/FormHolder/Form/InputHolder/QBuilder.rb', line 326

def where_clause
  @where.buffer.text
end