spiderfw 0.6.21 → 0.6.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/CHANGELOG +33 -0
  2. data/Rakefile +0 -1
  3. data/VERSION +1 -1
  4. data/apps/core/admin/_init.rb +4 -0
  5. data/apps/core/admin/admin.rb +20 -4
  6. data/apps/core/admin/controllers/admin_controller.rb +63 -4
  7. data/apps/core/admin/controllers/app_admin_controller.rb +15 -0
  8. data/apps/core/admin/data/locale/it/LC_MESSAGES/admin.mo +0 -0
  9. data/apps/core/admin/po/admin.pot +33 -0
  10. data/apps/core/admin/po/it/admin.po +34 -0
  11. data/apps/core/admin/public/css/admin.css +13 -0
  12. data/apps/core/admin/public/css/login.css +51 -0
  13. data/apps/core/admin/public/css/sass/admin.css +198 -0
  14. data/apps/core/admin/public/css/sass/bootstrap/bootstrap.css +3107 -0
  15. data/apps/core/admin/public/img/css/header_bg.png +0 -0
  16. data/apps/core/admin/public/img/css/noise.png +0 -0
  17. data/apps/core/admin/public/img/css/side_bg.png +0 -0
  18. data/apps/core/admin/public/img/icons/logout.png +0 -0
  19. data/apps/core/admin/public/img/icons-s845a69dd9f.png +0 -0
  20. data/apps/core/admin/public/js/bootstrap-alerts.js +113 -0
  21. data/apps/core/admin/public/js/bootstrap-buttons.js +62 -0
  22. data/apps/core/admin/public/js/bootstrap-dropdown.js +55 -0
  23. data/apps/core/admin/public/js/bootstrap-modal.js +260 -0
  24. data/apps/core/admin/public/js/bootstrap-popover.js +90 -0
  25. data/apps/core/admin/public/js/bootstrap-scrollspy.js +107 -0
  26. data/apps/core/admin/public/js/bootstrap-tabs.js +80 -0
  27. data/apps/core/admin/public/js/bootstrap-twipsy.js +321 -0
  28. data/apps/core/admin/public/sass/admin.scss +167 -0
  29. data/apps/core/admin/public/sass/bootstrap/bootstrap.scss +29 -0
  30. data/apps/core/admin/public/sass/bootstrap/forms.scss +478 -0
  31. data/apps/core/admin/public/sass/bootstrap/mixins.scss +220 -0
  32. data/apps/core/admin/public/sass/bootstrap/patterns.scss +1062 -0
  33. data/apps/core/admin/public/sass/bootstrap/reset.scss +141 -0
  34. data/apps/core/admin/public/sass/bootstrap/scaffolding.scss +136 -0
  35. data/apps/core/admin/public/sass/bootstrap/tables.scss +224 -0
  36. data/apps/core/admin/public/sass/bootstrap/type.scss +187 -0
  37. data/apps/core/admin/public/sass/bootstrap/variables.scss +60 -0
  38. data/apps/core/admin/public/sass/grid.scss +54 -0
  39. data/apps/core/admin/views/_app_info.shtml +5 -0
  40. data/apps/core/admin/views/admin.layout.shtml +35 -0
  41. data/apps/core/admin/views/index.shtml +1 -1
  42. data/apps/core/admin/views/login.layout.shtml +13 -0
  43. data/apps/core/auth/controllers/mixins/auth_helper.rb +1 -1
  44. data/apps/core/auth/models/super_user.rb +6 -0
  45. data/apps/core/auth/models/user.rb +9 -0
  46. data/apps/core/components/assets.rb +5 -1
  47. data/apps/core/components/data/locale/it/LC_MESSAGES/spider_components.mo +0 -0
  48. data/apps/core/components/po/it/spider_components.po +23 -9
  49. data/apps/core/components/po/spider_components.pot +16 -8
  50. data/apps/core/components/public/css/admin.css +0 -12
  51. data/apps/core/components/public/css/crud.css +16 -19
  52. data/apps/core/components/public/css/table.css +11 -5
  53. data/apps/core/components/public/js/less-1.1.3.min.js +16 -0
  54. data/apps/core/components/public/widgets/table.js +1 -1
  55. data/apps/core/components/widgets/admin/admin.rb +10 -0
  56. data/apps/core/components/widgets/admin/admin.shtml +24 -4
  57. data/apps/core/components/widgets/confirm/confirm.rb +2 -2
  58. data/apps/core/components/widgets/confirm/confirm.shtml +5 -2
  59. data/apps/core/components/widgets/crud/crud.rb +10 -1
  60. data/apps/core/components/widgets/crud/crud.shtml +18 -21
  61. data/apps/core/components/widgets/menu/menu.shtml +1 -2
  62. data/apps/core/components/widgets/switcher/switcher.rb +6 -3
  63. data/apps/core/components/widgets/switcher/templates/default.shtml +3 -1
  64. data/apps/core/components/widgets/table/table.rb +3 -2
  65. data/apps/core/components/widgets/table/table.shtml +44 -25
  66. data/apps/core/forms/data/locale/it/LC_MESSAGES/spider_forms.mo +0 -0
  67. data/apps/core/forms/po/it/spider_forms.po +7 -2
  68. data/apps/core/forms/po/spider_forms.pot +5 -1
  69. data/apps/core/forms/public/css/form.css +3 -3
  70. data/apps/core/forms/public/css/html_area.css +0 -1
  71. data/apps/core/forms/public/date_time.js +4 -3
  72. data/apps/core/forms/public/select.js +5 -4
  73. data/apps/core/forms/tags/element_label.erb +1 -1
  74. data/apps/core/forms/tags/row.erb +1 -1
  75. data/apps/core/forms/widgets/form/form.rb +23 -1
  76. data/apps/core/forms/widgets/form/form.shtml +7 -8
  77. data/apps/core/forms/widgets/inputs/checkbox/checkbox.shtml +3 -3
  78. data/apps/core/forms/widgets/inputs/date_time/date_time.shtml +3 -3
  79. data/apps/core/forms/widgets/inputs/file_input/file_input.rb +4 -2
  80. data/apps/core/forms/widgets/inputs/file_input/file_input.shtml +1 -1
  81. data/apps/core/forms/widgets/inputs/hidden/hidden.shtml +1 -1
  82. data/apps/core/forms/widgets/inputs/html_area/html_area.shtml +2 -2
  83. data/apps/core/forms/widgets/inputs/password/password.shtml +3 -3
  84. data/apps/core/forms/widgets/inputs/search_select/search_select.shtml +2 -2
  85. data/apps/core/forms/widgets/inputs/select/select.shtml +16 -13
  86. data/apps/core/forms/widgets/inputs/text/text.shtml +3 -3
  87. data/apps/core/forms/widgets/inputs/text_area/text_area.shtml +5 -2
  88. data/apps/core/forms/widgets/inputs/time_span/time_span.shtml +3 -3
  89. data/apps/messenger/_init.rb +10 -2
  90. data/apps/messenger/controllers/messenger_admin_controller.rb +53 -0
  91. data/apps/messenger/controllers/messenger_controller.rb +2 -0
  92. data/apps/messenger/controllers/mixins/messenger_helper.rb +2 -2
  93. data/apps/messenger/models/message.rb +1 -1
  94. data/apps/messenger/public/app_icon.png +0 -0
  95. data/apps/messenger/views/admin/_admin.layout.shtml +26 -0
  96. data/apps/messenger/views/admin/index.shtml +13 -0
  97. data/apps/messenger/views/admin/queue.shtml +28 -0
  98. data/apps/messenger/views/index.shtml +3 -3
  99. data/data/locale/it/LC_MESSAGES/spider.mo +0 -0
  100. data/lib/spiderfw/app.rb +10 -1
  101. data/lib/spiderfw/cache/template_cache.rb +21 -22
  102. data/lib/spiderfw/cmd/commands/app.rb +3 -3
  103. data/lib/spiderfw/cmd/commands/setup.rb +1 -1
  104. data/lib/spiderfw/config/options/spider.rb +18 -2
  105. data/lib/spiderfw/controller/controller.rb +9 -3
  106. data/lib/spiderfw/controller/dispatcher.rb +25 -12
  107. data/lib/spiderfw/controller/home_controller.rb +3 -3
  108. data/lib/spiderfw/controller/http_controller.rb +11 -0
  109. data/lib/spiderfw/controller/mixins/static_content.rb +3 -12
  110. data/lib/spiderfw/controller/mixins/visual.rb +21 -20
  111. data/lib/spiderfw/controller/request.rb +1 -3
  112. data/lib/spiderfw/http/adapters/mongrel.rb +1 -1
  113. data/lib/spiderfw/i18n/gettext.rb +14 -0
  114. data/lib/spiderfw/i18n/shtml_parser.rb +2 -2
  115. data/lib/spiderfw/model/base_model.rb +4 -3
  116. data/lib/spiderfw/model/mappers/db_mapper.rb +137 -79
  117. data/lib/spiderfw/model/mappers/mapper.rb +6 -2
  118. data/lib/spiderfw/model/migrations/drop_element.rb +1 -1
  119. data/lib/spiderfw/model/migrations/previous_model.rb +73 -0
  120. data/lib/spiderfw/model/migrations/rename_element.rb +42 -0
  121. data/lib/spiderfw/model/migrations.rb +14 -1
  122. data/lib/spiderfw/model/mixins/tree.rb +65 -19
  123. data/lib/spiderfw/model/model_hash.rb +9 -5
  124. data/lib/spiderfw/model/query.rb +8 -0
  125. data/lib/spiderfw/model/query_funcs.rb +23 -0
  126. data/lib/spiderfw/model/query_set.rb +1 -1
  127. data/lib/spiderfw/model/request.rb +11 -3
  128. data/lib/spiderfw/model/storage/db/adapters/mysql.rb +28 -1
  129. data/lib/spiderfw/model/storage/db/adapters/oracle.rb +10 -10
  130. data/lib/spiderfw/model/storage/db/db_schema.rb +20 -3
  131. data/lib/spiderfw/model/storage/db/db_storage.rb +39 -17
  132. data/lib/spiderfw/setup/app_manager.rb +69 -31
  133. data/lib/spiderfw/setup/setup_task.rb +76 -8
  134. data/lib/spiderfw/spider.rb +21 -1
  135. data/lib/spiderfw/templates/blocks/text.rb +4 -4
  136. data/lib/spiderfw/templates/blocks/text_domain.rb +25 -0
  137. data/lib/spiderfw/templates/blocks/widget.rb +1 -1
  138. data/lib/spiderfw/templates/layout.rb +160 -92
  139. data/lib/spiderfw/templates/resources/less.rb +10 -2
  140. data/lib/spiderfw/templates/resources/sass.rb +66 -9
  141. data/lib/spiderfw/templates/template.rb +35 -10
  142. data/lib/spiderfw/templates/template_blocks.rb +6 -3
  143. data/lib/spiderfw/utils/logger.rb +20 -0
  144. data/lib/spiderfw/utils/memory.rb +7 -3
  145. data/lib/spiderfw/widget/widget.rb +13 -7
  146. data/lib/spiderfw/widget/widget_attributes.rb +2 -2
  147. data/spider.gemspec +1 -0
  148. metadata +68 -11
  149. data/apps/core/admin/views/spider_admin.layout.shtml +0 -23
@@ -0,0 +1,73 @@
1
+ module Spider; module Migrations
2
+
3
+ module PreviousModel
4
+
5
+ def self.included(klass)
6
+ klass.extend(ClassMethods)
7
+ klass.with_mapper do
8
+ def schema_table_name
9
+ if @model.previous_model_of
10
+ model.previous_model_of.mapper.schema.table.name
11
+ else
12
+ super.gsub('previousmodels__', '')
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ def to_new_model
19
+ nm = self.class.previous_model_of
20
+ obj = nm.new
21
+ vals = self.to_hash
22
+ vals.each do |k, v|
23
+ obj.set(k, v) if nm.elements[k]
24
+ end
25
+ obj
26
+ end
27
+
28
+ module ClassMethods
29
+
30
+
31
+ def previous_model_of(model=nil)
32
+ @replacement_model = model if model
33
+ @replacement_model
34
+ end
35
+
36
+
37
+ def class_table_inheritance(params={})
38
+ unless params[:name]
39
+ spm = nil
40
+ mpm = nil
41
+ if @replacement_model
42
+ spm = @replacement_model.parent_module
43
+ else
44
+ spm = self.parent_module.parent_module
45
+ end
46
+ if superclass.respond_to?(:previous_model_of)
47
+ if superclass.previous_model_of
48
+ mpm = superclass.previous_model_of
49
+ else
50
+ mpm = superclass.parent_module.parent_module
51
+ end
52
+ else
53
+ mpm = superclass.parent_module
54
+ end
55
+ integrated_name = (spm == mpm) ? superclass.short_name : superclass.name
56
+ integrated_name = Spider::Inflector.underscore(integrated_name).gsub('/', '_')
57
+ params[:name] = integrated_name
58
+ end
59
+ super(params)
60
+ end
61
+
62
+ def element(name, type, attributes={}, &proc)
63
+ super
64
+ if @elements[name].junction?
65
+ @elements[name].model.send(:include, PreviousModel)
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end; end
@@ -0,0 +1,42 @@
1
+ module Spider; module Migrations
2
+
3
+ class RenameElement < Migration
4
+
5
+ def initialize(model, element, new_element, options={})
6
+ @model = model
7
+ @element = element
8
+ @new_element = new_element
9
+ @options = {}
10
+ end
11
+
12
+ def run
13
+ field = @options[:field_name]
14
+ schema_field = nil
15
+ new_schema_field = nil
16
+ unless field
17
+ schema_field = @model.mapper.schema.field(@element)
18
+ field = schema_field.name if schema_field
19
+ end
20
+ field ||= @model.mapper.storage.column_name(@element)
21
+ new_field = @options[:new_field_name]
22
+ unless new_field
23
+ new_schema_field = @model.mapper.schema.field(@new_element)
24
+ new_field = new_schema_field.name if new_schema_field
25
+ end
26
+ new_field ||= @model.mapper.storage.column_name(@new_element)
27
+ f = new_schema_field || schema_field
28
+ raise "Neither #{@element} nor #{@new_element} were found in schema" unless f
29
+
30
+ desc = @model.mapper.storage.describe_table(@model.mapper.schema.table)
31
+ if desc[:columns][field] && !desc[:columns][new_field]
32
+ @model.mapper.storage.change_field(@model.mapper.schema.table, field, new_field, f.type, f.attributes)
33
+ end
34
+ end
35
+
36
+ def undo
37
+ self.class.new(@model, @new_element, @element).run
38
+ end
39
+
40
+ end
41
+
42
+ end; end
@@ -1,8 +1,10 @@
1
1
  require 'spiderfw/model/migrations/migration'
2
+ require 'spiderfw/model/migrations/previous_model'
2
3
  require 'spiderfw/model/migrations/irreversible_migration'
3
4
  require 'spiderfw/model/migrations/replace'
4
5
  require 'spiderfw/model/migrations/drop_element'
5
6
  require 'spiderfw/model/migrations/drop_table'
7
+ require 'spiderfw/model/migrations/rename_element'
6
8
 
7
9
  module Spider
8
10
 
@@ -17,7 +19,18 @@ module Spider
17
19
  end
18
20
 
19
21
  def self.drop_table!(model, options={})
20
- Spider::Migrations::DropTable.new(model, element, options={})
22
+ Spider::Migrations::DropTable.new(model, options={})
23
+ end
24
+
25
+ def self.rename_element(model, element, new_element, options={})
26
+ RenameElement.new(model, element, new_element, options={})
27
+ end
28
+
29
+ def self.previous_model(model, previous=nil)
30
+ model.send(:include, PreviousModel)
31
+ if previous
32
+ model.previous_model_of(previous)
33
+ end
21
34
  end
22
35
 
23
36
 
@@ -21,15 +21,44 @@ module Spider; module Model
21
21
  res = element.model.find(q)
22
22
  return [] unless res
23
23
  right_stack = []
24
+ parents = []
25
+ first = nil
24
26
  res.each do |obj|
25
- if (right_stack.length > 0)
26
- right_stack.pop while (right_stack[right_stack.length-1] && right_stack[right_stack.length-1] < obj.get(right_el))
27
+ first ||= obj
28
+ if right_stack.length > 0
29
+ while right_stack.length > 0 && right_stack.last < obj.get(right_el)
30
+ right_stack.pop
31
+ p, sub = parents.pop
32
+ p.set_loaded_value(element.name, sub)
33
+ parents.last[1] << p if parents.last
34
+ end
27
35
  obj.set(element.attributes[:tree_depth], right_stack.length)
28
36
  end
29
37
  right_stack << obj.get(right_el)
38
+ parents << [obj, QuerySet.static(self.class)]
39
+ end
40
+
41
+ while pair = parents.pop
42
+ p, sub = pair
43
+ p.set_loaded_value(element.name, sub)
44
+ parents.last[1] << p if parents.last
30
45
  end
46
+
31
47
  return res
32
48
  end
49
+
50
+ def before_save
51
+ self.class.elements_array.select{ |el| el.attributes[:association] == :tree }.each do |el|
52
+ if element_modified?(el)
53
+ cnt = 1
54
+ self.get(el).each do |obj|
55
+ obj.set(el.attributes[:tree_position], cnt)
56
+ cnt += 1
57
+ end
58
+ end
59
+ end
60
+ super
61
+ end
33
62
 
34
63
  module ClassMethods
35
64
 
@@ -189,27 +218,30 @@ module Spider; module Model
189
218
 
190
219
  def before_save(obj, mode)
191
220
  @model.elements_array.select{ |el| el.attributes[:association] == :tree }.each do |el|
192
- unless obj.element_modified?(el.attributes[:reverse]) || obj.element_modified?(el.attributes[:tree_position])
221
+ unless mode == :insert || obj.element_modified?(el.attributes[:reverse]) || obj.element_modified?(el.attributes[:tree_position])
193
222
  next
194
223
  end
195
- if mode == :update
196
- tree_remove(el, obj)
197
- end
198
- parent = obj.get(el.attributes[:reverse])
199
- if parent
200
- sub = parent.get(el.name)
201
- if obj.element_modified?(el.attributes[:tree_position]) && sub.length > 0
202
- pos = obj.get(el.attributes[:tree_position])
203
- if pos == 1
204
- tree_insert_node_first(el, obj, parent)
224
+ # already set by parent
225
+ unless obj.element_modified?(el.attributes[:tree_left])
226
+ if mode == :update
227
+ tree_remove(el, obj)
228
+ end
229
+ parent = obj.get(el.attributes[:reverse])
230
+ if parent
231
+ sub = parent.get(el.name)
232
+ if obj.element_modified?(el.attributes[:tree_position]) && sub.length > 0
233
+ pos = obj.get(el.attributes[:tree_position])
234
+ if pos == 1
235
+ tree_insert_node_first(el, obj, parent)
236
+ else
237
+ tree_insert_node_right(el, obj, sub[pos-2])
238
+ end
205
239
  else
206
- tree_insert_node_right(el, obj, sub[pos-2])
240
+ tree_insert_node_under(el, obj, parent)
207
241
  end
208
242
  else
209
- tree_insert_node_under(el, obj, parent)
243
+ tree_insert_node(el, obj)
210
244
  end
211
- else
212
- tree_insert_node(el, obj)
213
245
  end
214
246
  end
215
247
  super
@@ -268,7 +300,7 @@ module Spider; module Model
268
300
  left_el = tree_el.attributes[:tree_left]; right_el = tree_el.attributes[:tree_right]
269
301
  cur = left+1
270
302
  obj.get(tree_el).each do |child|
271
- cur = tree_assign_values(tree_el, child, cur)
303
+ cur = tree_assign_values(tree_el, child, cur) + 1
272
304
  end
273
305
  obj.set(left_el, left)
274
306
  obj.set(right_el, cur)
@@ -292,7 +324,7 @@ module Spider; module Model
292
324
 
293
325
  def tree_insert_node_right(tree_el, obj, sibling)
294
326
  obj.set(tree_el.attributes[:reverse], sibling.get(tree_el.attributes[:reverse]))
295
- tree_insert_node(tree_el, obj, sibling.get(tree_el.attributes[:tree_right]))
327
+ tree_insert_node(tree_el, obj, sibling.get(tree_el.attributes[:tree_right])+1)
296
328
  end
297
329
 
298
330
  def tree_remove(tree_el, obj)
@@ -337,6 +369,20 @@ module Spider; module Model
337
369
  condition = Condition.new.set(left_el, '>', right)
338
370
  bulk_update({:left_el => QueryFuncs::Expression.new(":#{left_el} - 2")}, condition)
339
371
  end
372
+
373
+ # Ensure that in Unit of Work parents are saved before children
374
+ def get_dependencies(task)
375
+ deps = super
376
+ if task.action == :save
377
+ @model.elements_array.select{ |el| el.attributes[:association] == :tree }.each do |el|
378
+ if task.object.element_modified?(el.attributes[:reverse])
379
+ parent = task.object.get(el.attributes[:reverse])
380
+ deps << [task, MapperTask.new(parent, :save)] if parent
381
+ end
382
+ end
383
+ end
384
+ deps
385
+ end
340
386
 
341
387
 
342
388
 
@@ -32,11 +32,15 @@ module Spider; module Model
32
32
  val = n
33
33
  end
34
34
  key = key.name if key.is_a?(Element)
35
- parts = key.to_s.split('.', 2)
36
- return super(key.to_sym, val) unless parts[1]
37
- parts[0] = parts[0].to_sym
38
- self[parts[0]] = get_deep_obj unless self[parts[0]].is_a?(self.class)
39
- self[parts[0]][parts[1]] = val
35
+ if key.is_a?(String)
36
+ parts = key.split('.', 2)
37
+ return super(key.to_sym, val) unless parts[1]
38
+ parts[0] = parts[0].to_sym
39
+ self[parts[0]] = get_deep_obj unless self[parts[0]].is_a?(self.class)
40
+ self[parts[0]][parts[1]] = val
41
+ else
42
+ super(key, val)
43
+ end
40
44
  end
41
45
 
42
46
  def [](key)
@@ -21,6 +21,7 @@ module Spider; module Model
21
21
  attr_reader :request
22
22
  attr_reader :page_rows
23
23
  attr_reader :page
24
+ attr_accessor :group_by_elements
24
25
 
25
26
  # Instantiates a new query, calling Condition#where on the condition.
26
27
  def self.where(*params)
@@ -82,6 +83,12 @@ module Spider; module Model
82
83
  end
83
84
  return self
84
85
  end
86
+
87
+ def group_by(*elements)
88
+ @group_by_elements ||= []
89
+ @group_by_elements += elements
90
+ return self
91
+ end
85
92
 
86
93
  # Adds each element in the given list to the request.
87
94
  def select(*elements)
@@ -160,6 +167,7 @@ module Spider; module Model
160
167
  cl.offset = @offset
161
168
  cl.limit = @limit
162
169
  cl.polymorphs = @polymorphs.clone
170
+ cl.group_by_elements = @group_by_elements.clone if @group_by_elements
163
171
  return cl
164
172
  end
165
173
 
@@ -94,6 +94,29 @@ module Spider; module QueryFuncs
94
94
  "#{self.func_name.to_s.upcase}(#{elements.map{ |el| el.inspect }.join(', ')})"
95
95
  end
96
96
 
97
+ def as(name)
98
+ SelectFunction.new(self, name)
99
+ end
100
+
101
+ end
102
+
103
+ class SelectFunction
104
+ attr_reader :function, :as
105
+
106
+
107
+ def initialize(function, as)
108
+ @function = function
109
+ @as = as
110
+ end
111
+
112
+ def inspect
113
+ "#{@function.inspect} AS #{@as}"
114
+ end
115
+
116
+ def method_missing(method, *args)
117
+ @function.send(method, *args)
118
+ end
119
+
97
120
  end
98
121
 
99
122
  class ZeroArityFunction < Function
@@ -281,7 +281,7 @@ module Spider; module Model
281
281
 
282
282
  # Total number of objects that would be returned had the Query no limit.
283
283
  def total_rows
284
- return @total_rows ? @total_rows : @model.mapper.count(@query.condition)
284
+ return @total_rows ? @total_rows : (@total_rows = @model.mapper.count(@query.condition))
285
285
  end
286
286
 
287
287
  # Current number of objects fetched.
@@ -24,15 +24,23 @@ module Spider; module Model
24
24
  @polymorphs = {}
25
25
  @expandable = true
26
26
  end
27
+
28
+ def self.strict(val=nil, params={})
29
+ r = self.new(val, params)
30
+ r.expandable = false
31
+ r
32
+ end
27
33
 
28
34
  # TODO: fix/remove?
29
35
  def request(element) # :nodoc:
30
- if (element.is_a?(Element))
36
+ if element.is_a?(Element)
31
37
  self[element.name.to_s] = true
32
- else
33
- element.to_s.split(',').each do |el|
38
+ elsif element.is_a?(String)
39
+ element.split(',').each do |el|
34
40
  self[el.strip] = true
35
41
  end
42
+ else
43
+ self[element] = true
36
44
  end
37
45
  end
38
46
 
@@ -290,8 +290,19 @@ module Spider; module Model; module Storage; module Db
290
290
  sql += "#{sql_keys(query)} FROM #{tables_sql} "
291
291
  bind_vars += tables_values
292
292
  where, vals = sql_condition(query)
293
- bind_vars += vals
293
+
294
+ bind_vars += vals if vals
294
295
  sql += "WHERE #{where} " if where && !where.empty?
296
+ having, having_vals = sql_condition(query, true)
297
+ unless having.blank? && query[:group_by].blank?
298
+ group_fields = query[:group_by] || (
299
+ query[:keys].select{ |k| !k.is_a?(FieldExpression)
300
+ } + collect_having_fields(query[:condition])).flatten.uniq
301
+ group_keys = sql_keys(group_fields)
302
+ sql += "GROUP BY #{group_keys} "
303
+ sql += "HAVING #{having} " unless having.blank?
304
+ bind_vars += having_vals if having_vals
305
+ end
295
306
  order = sql_order(query)
296
307
  sql += "ORDER BY #{order} " if order && !order.empty?
297
308
  limit = sql_limit(query)
@@ -304,12 +315,28 @@ module Spider; module Model; module Storage; module Db
304
315
  sql += " AUTO_INCREMENT" if attributes[:autoincrement]
305
316
  return sql
306
317
  end
318
+
319
+ def sql_add_field(table_name, name, type, attributes)
320
+ sqls = super
321
+ sqls[0] += ", ADD PRIMARY KEY(#{name})" if attributes[:primary_key]
322
+ sqls
323
+ end
324
+
325
+ def sql_alter_field(table_name, name, type, attributes)
326
+ sqls = super
327
+ sqls[0] += ", ADD PRIMARY KEY(#{name})" if attributes[:primary_key]
328
+ sqls
329
+ end
307
330
 
308
331
  def sql_create_table(create)
309
332
  sqls = super
310
333
  sqls[0] += " ENGINE=#{@configuration['default_engine']}" if @configuration['default_engine']
311
334
  sqls
312
335
  end
336
+
337
+ def sql_create_primary_key(table_name, fields)
338
+ nil # done in add field or alter field
339
+ end
313
340
 
314
341
  def function(func)
315
342
  return super unless func.func_name == :concat
@@ -118,24 +118,24 @@ module Spider; module Model; module Storage; module Db
118
118
  query[:order] << [query[:keys][0], 'desc'] if query[:order].length < 1
119
119
  query[:order].each do |o|
120
120
  field, direction = o
121
- # i = query[:keys].index(field)
122
- # unless i
123
- # query[:keys].push(field)
124
- # i = query[:keys].length < 1
125
- # end
126
- transformed = "O#{replace_cnt += 1}"
127
- query[:order_replacements][field.to_s] = transformed
121
+
128
122
  if field.is_a?(Spider::Model::Storage::Db::Field) && !query[:tables].include?(field.table)
129
123
  query[:order_on_different_table] = true
130
124
  end
131
125
  if field.is_a?(FieldFunction)
132
126
  query[:order_on_different_table] = true if field.joins.length > 0
133
127
  end
134
- if (field.is_a?(Spider::Model::Storage::Db::Field) && field.type == 'CLOB')
128
+ if field.is_a?(Spider::Model::Storage::Db::Field) && field.type == 'CLOB'
135
129
  field = "CAST(#{field} as varchar2(100))"
136
130
  end
131
+ field_expr = field.is_a?(FieldExpression) ? field.expression : field.to_s
137
132
 
138
- query[:keys] << Db::FieldExpression.new(field.table, transformed, field.type, :expression => "#{field}")
133
+ unless query[:keys].include?(field) || field.is_a?(FieldExpression)
134
+ transformed = "O#{replace_cnt += 1}"
135
+ query[:order_replacements][field.to_s] = transformed
136
+
137
+ query[:keys] << Db::FieldExpression.new(field.table, transformed, field.type, :expression => field_expr)
138
+ end
139
139
  end
140
140
  end
141
141
  keys = sql_keys(query)
@@ -145,7 +145,7 @@ module Spider; module Model; module Storage; module Db
145
145
  bind_vars += tables_values
146
146
 
147
147
  where, vals = sql_condition(query)
148
- bind_vars += vals
148
+ bind_vars += vals if vals
149
149
  sql += "WHERE #{where} " if where && !where.empty?
150
150
 
151
151
  having, having_vals = sql_condition(query, true)
@@ -110,9 +110,14 @@ module Spider; module Model; module Storage; module Db
110
110
  if field.is_a?(Hash)
111
111
  field[:attributes] ||= {}
112
112
  field[:attributes][:expression] ||= field[:expression]
113
- if field[:attributes][:expression]
113
+ field[:attributes][:fixed] ||= field[:fixed]
114
+ if field[:attributes][:expression] || field[:attributes][:fixed]
114
115
  field[:name] = "#{@table}_#{element_name}_#{element_key}".upcase
115
- field = FieldExpression.new(@table, field[:name], field[:type], field[:attributes] || {})
116
+ if field[:attributes][:fixed]
117
+ field = FixedExpression.new(@table, field[:name], field[:type], field[:attributes][:fixed], field[:attributes])
118
+ else
119
+ field = FieldExpression.new(@table, field[:name], field[:type], field[:attributes] || {})
120
+ end
116
121
  else
117
122
  field = Field.new(@table, field[:name], field[:type], field[:attributes] || {})
118
123
  end
@@ -280,9 +285,17 @@ module Spider; module Model; module Storage; module Db
280
285
  end
281
286
 
282
287
  end
288
+
289
+ class FixedExpression < FieldExpression
290
+ def initialize(table, name, type, fixed_value, attributes={})
291
+ attributes[:expression] = fixed_value
292
+ super(table, name, type, attributes)
293
+ end
294
+ end
283
295
 
284
296
  class FieldFunction
285
297
  attr_reader :expression, :table, :joins
298
+ attr_accessor :as
286
299
  def initialize(expression, table, joins)
287
300
  @expression = expression
288
301
  @table = table
@@ -298,7 +311,11 @@ module Spider; module Model; module Storage; module Db
298
311
  end
299
312
 
300
313
  def to_s
301
- @expression
314
+ if @as
315
+ "#{@expression} AS #{@as}"
316
+ else
317
+ @expression
318
+ end
302
319
  end
303
320
  end
304
321