spiderfw 0.6.21 → 0.6.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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