spiderfw 0.5.7 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/Rakefile +17 -6
  2. data/apps/cas_server/controllers/mixins/cas_login_mixin.rb +18 -5
  3. data/apps/cas_server/lib/cas.rb +1 -1
  4. data/apps/cms/models/content.rb +16 -0
  5. data/apps/cms/models/news_item.rb +7 -0
  6. data/apps/cms/models/translation.rb +14 -0
  7. data/apps/cms/views/admin/admin.shtml +16 -0
  8. data/apps/cms/views/admin/content.shtml +4 -0
  9. data/apps/core/acl/_init.rb +10 -0
  10. data/apps/core/acl/controllers/acl_controller.rb +14 -0
  11. data/apps/core/acl/models/permission.rb +11 -0
  12. data/apps/core/acl/views/acl.layout.shtml +8 -0
  13. data/apps/core/acl/views/index.shtml +3 -0
  14. data/apps/core/auth/controllers/mixins/auth_helper.rb +3 -3
  15. data/apps/core/auth/lib/authenticable.rb +4 -0
  16. data/apps/core/auth/models/super_user.rb +1 -0
  17. data/apps/core/auth/po/it/spider_auth.po +18 -10
  18. data/apps/core/auth/po/spider_auth.pot +13 -1
  19. data/apps/core/components/_init.rb +2 -1
  20. data/apps/core/components/po/it/spider_components.po +3 -3
  21. data/apps/core/components/po/spider_components.pot +3 -3
  22. data/apps/core/components/public/css/month_calendar.css +24 -0
  23. data/apps/core/components/public/js/jquery/jquery-1.4.2-min.js +154 -0
  24. data/apps/core/components/public/js/jquery/jquery-1.4.2.js +6240 -0
  25. data/apps/core/components/public/js/jquery/plugins/jquery.form.js +1 -1
  26. data/apps/core/components/public/js/spider.js +26 -20
  27. data/apps/core/components/widgets/admin/admin.rb +1 -1
  28. data/apps/core/components/widgets/crud/crud.rb +1 -1
  29. data/apps/core/components/widgets/list/list.rb +2 -2
  30. data/apps/core/components/widgets/month_calendar/month_calendar.rb +67 -0
  31. data/apps/core/components/widgets/month_calendar/month_calendar.shtml +21 -0
  32. data/apps/core/components/widgets/table/table.rb +4 -2
  33. data/apps/core/components/widgets/table/table.shtml +37 -31
  34. data/apps/core/forms/_init.rb +2 -1
  35. data/apps/core/forms/po/it/spider_forms.po +14 -2
  36. data/apps/core/forms/po/spider_forms.pot +13 -1
  37. data/apps/core/forms/public/css/file_input.css +15 -0
  38. data/apps/core/forms/public/{form.css → css/form.css} +8 -0
  39. data/apps/core/forms/public/file_input.js +37 -0
  40. data/apps/core/forms/tags/element_label.erb +4 -1
  41. data/apps/core/forms/tags/element_row.erb +7 -2
  42. data/apps/core/forms/tags/row.erb +10 -1
  43. data/apps/core/forms/widgets/form/form.rb +43 -10
  44. data/apps/core/forms/widgets/form/form.shtml +12 -5
  45. data/apps/core/forms/widgets/inputs/date_time/date_time.shtml +1 -0
  46. data/apps/core/forms/widgets/inputs/file_input/file_input.rb +43 -0
  47. data/apps/core/forms/widgets/inputs/file_input/file_input.shtml +12 -0
  48. data/apps/core/forms/widgets/inputs/input/input.rb +23 -1
  49. data/apps/core/forms/widgets/inputs/password/password.rb +1 -0
  50. data/apps/core/forms/widgets/inputs/text/text.shtml +1 -1
  51. data/apps/core/forms/widgets/inputs/text_area/text_area.shtml +2 -2
  52. data/apps/git_model_versioning/models/mixins/git_versioned.rb +91 -0
  53. data/apps/hippo/models/mixins/hippo_struct.rb +42 -26
  54. data/apps/master/controllers/git.rb +32 -0
  55. data/apps/messenger/_init.rb +1 -1
  56. data/apps/messenger/config/options.rb +2 -0
  57. data/apps/messenger/config/worker/queue.rb +3 -0
  58. data/apps/messenger/controllers/mixins/{messenger_controller_mixin.rb → messenger_helper.rb} +8 -6
  59. data/apps/messenger/messenger.rb +10 -3
  60. data/apps/messenger/models/message.rb +2 -2
  61. data/apps/messenger/po/it/spider_messenger.po +1 -1
  62. data/apps/messenger/po/spider_messenger.pot +1 -1
  63. data/apps/saml/_init.rb +13 -0
  64. data/apps/saml/controllers/saml2idp.rb +18 -0
  65. data/apps/saml/lib/bindings/http_redirect_binding.rb +14 -0
  66. data/apps/saml/lib/messages/authn_request.rb +52 -0
  67. data/apps/saml/lib/saml.rb +10 -0
  68. data/apps/soap/controllers/soap_controller.rb +12 -2
  69. data/apps/soap/lib/soap.rb +16 -1
  70. data/apps/soap/soap.gemspec +10 -0
  71. data/apps/webdav/lib/locking.rb +2 -2
  72. data/apps/worker/_init.rb +2 -0
  73. data/apps/worker/config/options.rb +1 -0
  74. data/apps/worker/worker.rb +17 -4
  75. data/blueprints/app/__APP__.appspec +4 -0
  76. data/blueprints/app/_init.rb +5 -8
  77. data/blueprints/app/controllers/__APP___controller.rb +2 -1
  78. data/blueprints/app/views/__APP__.layout.shtml +4 -1
  79. data/blueprints/install/config/config.yml +2 -4
  80. data/blueprints/model.rb +15 -0
  81. data/data/locale/it/LC_MESSAGES/spider.mo +0 -0
  82. data/data/locale/it/LC_MESSAGES/spider_auth.mo +0 -0
  83. data/data/locale/it/LC_MESSAGES/spider_components.mo +0 -0
  84. data/data/locale/it/LC_MESSAGES/spider_forms.mo +0 -0
  85. data/data/locale/it/LC_MESSAGES/spider_messenger.mo +0 -0
  86. data/lib/spiderfw/app.rb +93 -31
  87. data/lib/spiderfw/autoload.rb +1 -0
  88. data/lib/spiderfw/cmd/cmd.rb +8 -1
  89. data/lib/spiderfw/cmd/commands/config.rb +54 -0
  90. data/lib/spiderfw/config/configuration.rb +30 -0
  91. data/lib/spiderfw/config/options/spider.rb +18 -6
  92. data/lib/spiderfw/controller/controller.rb +12 -11
  93. data/lib/spiderfw/controller/dispatcher.rb +5 -4
  94. data/lib/spiderfw/controller/http_controller.rb +16 -2
  95. data/lib/spiderfw/controller/mixins/http_mixin.rb +3 -2
  96. data/lib/spiderfw/controller/mixins/static_content.rb +8 -2
  97. data/lib/spiderfw/controller/mixins/visual.rb +72 -52
  98. data/lib/spiderfw/controller/request.rb +7 -3
  99. data/lib/spiderfw/controller/scene.rb +6 -0
  100. data/lib/spiderfw/controller/session.rb +12 -8
  101. data/lib/spiderfw/env.rb +1 -1
  102. data/lib/spiderfw/http/adapters/mongrel.rb +1 -1
  103. data/lib/spiderfw/http/http.rb +48 -19
  104. data/lib/spiderfw/i18n/cldr.rb +53 -3
  105. data/lib/spiderfw/i18n/i18n.rb +52 -2
  106. data/lib/spiderfw/i18n/provider.rb +24 -0
  107. data/lib/spiderfw/i18n/rails.rb +24 -0
  108. data/lib/spiderfw/model/active_record.rb +3 -3
  109. data/lib/spiderfw/model/base_model.rb +45 -14
  110. data/lib/spiderfw/model/condition.rb +11 -2
  111. data/lib/spiderfw/model/data_type.rb +15 -7
  112. data/lib/spiderfw/model/datatypes/decimal.rb +15 -3
  113. data/lib/spiderfw/model/datatypes/file_path.rb +50 -0
  114. data/lib/spiderfw/model/datatypes/serialized_object.rb +0 -4
  115. data/lib/spiderfw/model/datatypes/uuid.rb +3 -3
  116. data/lib/spiderfw/model/datatypes.rb +1 -0
  117. data/lib/spiderfw/model/extended_models/managed.rb +11 -2
  118. data/lib/spiderfw/model/mappers/db_mapper.rb +116 -52
  119. data/lib/spiderfw/model/mappers/mapper.rb +36 -14
  120. data/lib/spiderfw/model/mixins/state_machine.rb +45 -9
  121. data/lib/spiderfw/model/mixins/versioned.rb +1 -1
  122. data/lib/spiderfw/model/model.rb +2 -1
  123. data/lib/spiderfw/model/query_set.rb +21 -3
  124. data/lib/spiderfw/model/request.rb +7 -0
  125. data/lib/spiderfw/model/storage/db/adapters/mssql.rb +2 -1
  126. data/lib/spiderfw/model/storage/db/adapters/mysql.rb +4 -1
  127. data/lib/spiderfw/model/storage/db/adapters/oci8.rb +35 -18
  128. data/lib/spiderfw/model/storage/db/adapters/sqlite.rb +68 -34
  129. data/lib/spiderfw/model/storage/db/connectors/odbc.rb +1 -1
  130. data/lib/spiderfw/model/storage/db/db_schema.rb +33 -4
  131. data/lib/spiderfw/model/storage/db/db_storage.rb +27 -8
  132. data/lib/spiderfw/requires.rb +2 -0
  133. data/lib/spiderfw/tag/tag.rb +1 -1
  134. data/lib/spiderfw/templates/blocks/attr_if.rb +7 -1
  135. data/lib/spiderfw/templates/blocks/each.rb +8 -3
  136. data/lib/spiderfw/templates/blocks/html.rb +12 -22
  137. data/lib/spiderfw/templates/blocks/render.rb +3 -3
  138. data/lib/spiderfw/templates/blocks/run.rb +47 -11
  139. data/lib/spiderfw/templates/blocks/tag_if.rb +2 -2
  140. data/lib/spiderfw/templates/blocks/text.rb +2 -1
  141. data/lib/spiderfw/templates/blocks/widget.rb +5 -3
  142. data/lib/spiderfw/templates/blocks/yield.rb +1 -1
  143. data/lib/spiderfw/templates/template.rb +27 -24
  144. data/lib/spiderfw/templates/template_blocks.rb +37 -14
  145. data/lib/spiderfw/utils/monkey/exception.rb +1 -1
  146. data/lib/spiderfw/utils/monkey/nil_class.rb +7 -0
  147. data/lib/spiderfw/utils/monkey/numeric.rb +15 -0
  148. data/lib/spiderfw/version.rb +1 -1
  149. data/lib/spiderfw/widget/widget.rb +36 -33
  150. data/lib/spiderfw/widget/widget_attributes.rb +1 -1
  151. data/lib/spiderfw.rb +18 -5
  152. data/spider.gemspec +5 -5
  153. metadata +44 -18
  154. data/apps/core/components/public/js/jquery/plugins/jtree/jquery.jtree.1.0.js +0 -187
  155. data/apps/core/components/public/js/jquery/plugins/jtree/jquery.jtree.1.0.min.js +0 -1
  156. data/apps/core/components/public/js/jquery/plugins/jtree/jquery.jtree.spider.1.0.js +0 -193
  157. data/apps/core/forms/widgets/inputs/subform/subform.rb +0 -10
  158. data/apps/core/forms/widgets/inputs/subform/subform.shtml +0 -5
  159. data/apps/messenger/config/worker.rb +0 -3
  160. data/lib/spiderfw/controller/app_controller.rb +0 -14
  161. data/lib/spiderfw/utils/test_case.rb +0 -24
@@ -4,20 +4,22 @@ module Spider; module Model
4
4
 
5
5
  def self.included(model)
6
6
  model.extend(ClassMethods)
7
+ model.mapper_include(MapperMethods)
7
8
  end
8
9
 
9
10
  module ClassMethods
11
+ attr_reader :state_events
10
12
 
11
13
  class StateEvent
14
+ attr_reader :transitions
12
15
 
13
16
  def initialize
14
17
  @transitions = []
15
18
  @action = nil
16
19
  end
17
20
 
18
- def transitions(params=nil)
21
+ def transition(params=nil)
19
22
  @transitions << params if params
20
- @transitions
21
23
  end
22
24
 
23
25
  def action(&proc)
@@ -25,6 +27,10 @@ module Spider; module Model
25
27
  @action
26
28
  end
27
29
 
30
+ def run(obj, old_state, new_state)
31
+ @action.call(obj, old_state, new_state)
32
+ end
33
+
28
34
  end
29
35
 
30
36
  def element_association?(name, ass)
@@ -37,45 +43,75 @@ module Spider; module Model
37
43
 
38
44
  def state(name, type, attributes={}, &proc)
39
45
  attributes[:association] = :state
46
+ raise "States must be models with one primary key" unless type.is_a?(Hash) || !type.is_a?(Spider::Model::BaseModel) || type.primary_keys.length == 1
40
47
  element(name, type, attributes, &proc)
41
48
  end
42
49
 
43
- def state_event(name)
50
+ def state_event(element_name)
44
51
  ev = StateEvent.new
45
52
  yield ev
46
- @state_events ||= []
47
- @state_events << ev
53
+ @state_events ||= {}
54
+ @state_events[element_name] ||= []
55
+ @state_events[element_name] << ev
48
56
  end
49
57
 
50
58
 
51
59
  end
52
60
 
61
+ def _pending_state_events
62
+ @_pending_state_events ||= []
63
+ end
64
+
53
65
  module MapperMethods
54
66
 
55
67
  def before_save(obj, mode)
56
68
  obj.model.elements_array.select{ |el| el.association == :state }.each do |el|
57
- if (obj.model.state_events[el.name] && obj.modified?(el))
69
+ if (obj.model.state_events[el.name] && obj.element_modified?(el))
58
70
  old = obj.get_new
59
71
  old_state = old.get(el.name)
60
72
  new_state = obj.get(el.name)
73
+ old_state = old_state.primary_keys.first if old_state && el.model?
74
+ new_state = new_state.primary_keys.first if new_state && el.model?
61
75
  obj.model.state_events[el.name].each do |event|
62
76
  call_ev = false
63
77
  event.transitions.each do |tr|
64
- if (!tr[:from] || tr[:from] == old_state) && (!tr[:to] || tr[:to] == new_state)
78
+ from_ok = false
79
+ to_ok = false
80
+ if tr[:from]
81
+ tr[:from] = [tr[:from]] unless tr[:from].is_a?(Array)
82
+ from_ok = true if tr[:from].include?(old_state)
83
+ else
84
+ from_ok = true
85
+ end
86
+ if tr[:to]
87
+ tr[:to] = [tr[:to]] unless tr[:to].is_a?(Array)
88
+ to_ok = true if tr[:to].include?(new_state)
89
+ else
90
+ to_ok = true
91
+ end
92
+ if from_ok && to_ok
65
93
  call_ev = true
66
94
  break
67
95
  end
68
96
  end
69
97
  if (call_ev)
70
- event.run(obj)
98
+ obj._pending_state_events << [event, old_state, new_state]
71
99
  end
72
100
  end
73
101
  end
74
102
  end
103
+ super
104
+ end
105
+
106
+ def after_save(obj, mode)
107
+ super
108
+ obj._pending_state_events.each do |event, old_state, new_state|
109
+ event.run(obj.get_new, old_state, new_state)
110
+ end
75
111
  end
76
112
 
77
113
  end
78
114
 
79
115
  end
80
116
 
81
- end; end
117
+ end; end
@@ -63,7 +63,7 @@ module Spider; module Model
63
63
  junction.versioning(branch)
64
64
  end
65
65
  elh[:attributes][:through] = junction.version_model
66
- elh[:attributes][:junction_our_name] = "#{elh[:attributes][:reverse]}_versioned".to_sym
66
+ elh[:attributes][:junction_our_element] = "#{elh[:attributes][:reverse]}_versioned".to_sym
67
67
  elh[:attributes][:junction_their_element] = "#{elh[:attributes][:junction_their_element]}_versioned".to_sym
68
68
  vname = "#{elh[:name]}_versioned".to_sym
69
69
  vmod.send(elh[:method], vname, el.type.version_model, elh[:attributes])
@@ -34,7 +34,8 @@ module Spider
34
34
  map_types = {
35
35
  Spider::DataTypes::Text => String,
36
36
  Spider::DataTypes::Bool => FalseClass,
37
- Spider::DataTypes::Binary => String
37
+ Spider::DataTypes::Binary => String,
38
+ Spider::DataTypes::FilePath => String
38
39
  }
39
40
  return map_types[klass] if map_types[klass]
40
41
  return klass
@@ -326,6 +326,12 @@ module Spider; module Model
326
326
  end
327
327
  end
328
328
 
329
+ # Remove all elements from self
330
+ def clear
331
+ @objects = []
332
+ @index_lookup.each_key{ |k| @index_lookup[k] = {} }
333
+ end
334
+
329
335
  # Remove when merging
330
336
  alias :map_array :map
331
337
 
@@ -336,13 +342,22 @@ module Spider; module Model
336
342
 
337
343
  # Iterates on objects, loading when needed.
338
344
  def each
345
+ tmp = []
346
+ prev_parents = []
339
347
  self.each_index do |i|
340
348
  obj = @objects[i]
341
349
  prev_parent = obj._parent
342
350
  prev_parent_element = obj._parent_element
343
351
  obj.set_parent(self, nil)
352
+ tmp << obj
353
+ prev_parents << [prev_parent, prev_parent_element]
354
+ end
355
+ tmp.each do |obj|
344
356
  yield obj
345
- obj.set_parent(prev_parent, prev_parent_element)
357
+ end
358
+ tmp.each_index do |i|
359
+ prev_parent, prev_parent_element = prev_parents[i]
360
+ tmp[i].set_parent(prev_parent, prev_parent_element)
346
361
  end
347
362
  end
348
363
 
@@ -406,8 +421,7 @@ module Spider; module Model
406
421
  # Executes the query and fetches the objects; (the next batch if a fetch_window is set).
407
422
  def load
408
423
  return self unless loadable?
409
- @objects = []
410
- @index_lookup.each_key{ |k| @index_lookup[k] = {} }
424
+ clear
411
425
  @loaded = false
412
426
  @loaded_elements = {}
413
427
  return load_next if @fetch_window && !@query.offset
@@ -599,6 +613,10 @@ module Spider; module Model
599
613
  h
600
614
  end
601
615
  end
616
+
617
+ def reject!(&proc)
618
+ @objects.reject!(&proc)
619
+ end
602
620
 
603
621
  def to_s
604
622
  self.map{ |o| o.to_s }.join(', ')
@@ -10,6 +10,8 @@ module Spider; module Model
10
10
  attr_accessor :total_rows
11
11
  # (array) find also the given subclasses of the queried model.
12
12
  attr_reader :polymorphs
13
+ # (bool) if true, the request will be expanded with lazy groups on load
14
+ attr_accessor :expandable
13
15
 
14
16
  def initialize(val=nil, params={})
15
17
  if (val.is_a?(Array))
@@ -20,6 +22,7 @@ module Spider; module Model
20
22
  end
21
23
  @total_rows = params[:total_rows]
22
24
  @polymorphs = {}
25
+ @expandable = true
23
26
  end
24
27
 
25
28
  # TODO: fix/remove?
@@ -73,6 +76,10 @@ module Spider; module Model
73
76
  def with_superclass?
74
77
  @with_superclass
75
78
  end
79
+
80
+ def expandable?
81
+ @expandable
82
+ end
76
83
 
77
84
  end
78
85
 
@@ -11,7 +11,8 @@ module Spider; module Model; module Storage; module Db
11
11
  {
12
12
  :autoincrement => true,
13
13
  :sequences => false,
14
- :transactions => true
14
+ :transactions => true,
15
+ :foreign_keys => false # not implemented
15
16
  }
16
17
  end
17
18
 
@@ -12,7 +12,8 @@ module Spider; module Model; module Storage; module Db
12
12
  @capabilities = {
13
13
  :autoincrement => true,
14
14
  :sequences => false,
15
- :transactions => true
15
+ :transactions => true,
16
+ :foreign_keys => true
16
17
  }
17
18
  @reserved_keywords = superclass.reserved_keywords
18
19
  @safe_conversions = {
@@ -228,6 +229,8 @@ module Spider; module Model; module Storage; module Db
228
229
  value = super(type, value)
229
230
  return value unless value
230
231
  case type.name
232
+ when 'String'
233
+ return value.to_s
231
234
  when 'Date', 'DateTime'
232
235
  return value.strftime("%Y-%m-%dT%H:%M:%S")
233
236
  when 'Fixnum'
@@ -7,9 +7,10 @@ module Spider; module Model; module Storage; module Db
7
7
  @capabilities = {
8
8
  :autoincrement => false,
9
9
  :sequences => true,
10
- :transactions => true
10
+ :transactions => true,
11
+ :foreign_keys => true
11
12
  }
12
- @reserved_keywords = superclass.reserved_keywords + ['oci8_row_num', 'file', 'uid']
13
+ @reserved_keywords = superclass.reserved_keywords + ['oci8_row_num', 'file', 'uid', 'name', 'comment']
13
14
  @safe_conversions = {
14
15
  'CHAR' => ['VARCHAR', 'CLOB'],
15
16
  'VARCHAR' => ['CLOB'],
@@ -24,6 +25,7 @@ module Spider; module Model; module Storage; module Db
24
25
  def self.new_connection(user, pass, dbname, role)
25
26
  conn ||= ::OCI8.new(user, pass, dbname, role)
26
27
  conn.autocommit = true
28
+ conn.non_blocking = true
27
29
  return conn
28
30
  end
29
31
 
@@ -69,19 +71,23 @@ module Spider; module Model; module Storage; module Db
69
71
 
70
72
 
71
73
  def do_start_transaction
74
+ return unless transactions_enabled?
72
75
  connection.autocommit = false
73
76
  end
74
77
 
75
78
  def in_transaction?
79
+ return false unless transactions_enabled?
76
80
  return curr[:conn] && !curr[:conn].autocommit?
77
81
  end
78
82
 
79
83
  def do_commit
84
+ return release unless transactions_enabled?
80
85
  curr[:conn].commit if curr[:conn]
81
86
  release
82
87
  end
83
88
 
84
89
  def do_rollback
90
+ return release unless transactions_enabled?
85
91
  curr[:conn].rollback
86
92
  release
87
93
  end
@@ -108,7 +114,7 @@ module Spider; module Model; module Storage; module Db
108
114
  case type.name
109
115
  when 'Date', 'DateTime'
110
116
  return nil unless value
111
- return value if value.is_a?(Type)
117
+ return value if value.is_a?(type)
112
118
  return value.to_datetime if type == DateTime
113
119
  return value.to_date # FIXME: check what is returned, here we espect an OCI8::Date
114
120
  when 'Spider::DataTypes::Text'
@@ -126,15 +132,15 @@ module Spider; module Model; module Storage; module Db
126
132
  end
127
133
  curr[:last_executed] = [sql, bind_vars]
128
134
  if (Spider.conf.get('storage.db.replace_debug_vars'))
129
- cnt = -1
130
- debug("oci8 executing: "+sql.gsub(/:\d+/){
131
- v = bind_vars[cnt]
132
- dv = debug_vars[cnt+=1]
135
+ debug("oci8 #{connection} executing: "+sql.gsub(/:(\d+)/){
136
+ i = $1.to_i
137
+ v = bind_vars[i-1]
138
+ dv = debug_vars[i-1]
133
139
  v.is_a?(String) ? "'#{dv}'" : dv
134
140
  })
135
141
  else
136
142
  debug_vars_str = debug_vars ? debug_vars.join(', ') : ''
137
- debug("oci8 executing:\n#{sql}\n[#{debug_vars_str}]")
143
+ debug("oci8 #{connection} executing:\n#{sql}\n[#{debug_vars_str}]")
138
144
  end
139
145
  cursor = connection.parse(sql)
140
146
  return cursor if (!cursor || cursor.is_a?(Fixnum))
@@ -152,11 +158,16 @@ module Spider; module Model; module Storage; module Db
152
158
  if (have_result)
153
159
  result = []
154
160
  while (h = cursor.fetch_hash)
161
+ h.each do |key, val|
162
+ if val.respond_to?(:read)
163
+ h[key] = val.read
164
+ end
165
+ end
155
166
  if block_given?
156
- yield h
157
- else
158
- result << h
159
- end
167
+ yield h
168
+ else
169
+ result << h
170
+ end
160
171
  end
161
172
  end
162
173
  if (have_result)
@@ -168,9 +179,14 @@ module Spider; module Model; module Storage; module Db
168
179
  else
169
180
  return res
170
181
  end
182
+ cursor.close
183
+
171
184
  rescue => exc
185
+ curr[:conn].break if curr[:conn]
186
+ rollback! if in_transaction?
187
+ #curr[:conn].logoff
172
188
  release
173
- raise exc
189
+ raise
174
190
  ensure
175
191
  cursor.close if cursor
176
192
  release if curr[:conn] && !in_transaction?
@@ -234,6 +250,7 @@ module Spider; module Model; module Storage; module Db
234
250
  # Spider::Logger.debug("SQL SELECT:")
235
251
  # Spider::Logger.debug(query)
236
252
  bind_vars = query[:bind_vars] || []
253
+ order_on_different_table = false
237
254
  if query[:limit] # Oracle is so braindead
238
255
  replaced_fields = {}
239
256
  replace_cnt = 0
@@ -248,6 +265,7 @@ module Spider; module Model; module Storage; module Db
248
265
  # end
249
266
  transformed = "O#{replace_cnt += 1}"
250
267
  replaced_fields[field.to_s] = transformed
268
+ order_on_different_table = true if field.is_a?(Spider::Model::Storage::Db::Field) && !query[:tables].include?(field.table)
251
269
  if (field.is_a?(Spider::Model::Storage::Db::Field) && field.type == 'CLOB')
252
270
  field = "CAST(#{field} as varchar2(100))"
253
271
  end
@@ -262,7 +280,7 @@ module Spider; module Model; module Storage; module Db
262
280
  where, vals = sql_condition(query)
263
281
  bind_vars += vals
264
282
  sql += "WHERE #{where} " if where && !where.empty?
265
- order = sql_order(query)
283
+ order = sql_order(query, replaced_fields)
266
284
  if (query[:limit])
267
285
  if (query[:offset])
268
286
  limit = "oci8_row_num between :#{curr[:bind_cnt]+=1} and :#{curr[:bind_cnt]+=1}"
@@ -272,14 +290,12 @@ module Spider; module Model; module Storage; module Db
272
290
  limit = "oci8_row_num < :#{curr[:bind_cnt]+=1}"
273
291
  bind_vars << query[:limit] + 1
274
292
  end
275
- replaced_fields.each do |f, repl|
276
- order = order.gsub(f, repl)
277
- end
278
293
  if (!query[:joins].empty?)
294
+ data_tables_sql = order_on_different_table ? tables_sql : query[:tables].join(', ')
279
295
  pk_sql = query[:primary_keys].join(', ')
280
296
  distinct_sql = "SELECT DISTINCT #{pk_sql} FROM #{tables_sql}"
281
297
  distinct_sql += " WHERE #{where}" if where && !where.empty?
282
- data_sql = "SELECT #{keys} FROM #{tables_sql} WHERE #{pk_sql} IN (#{distinct_sql}) order by #{order}"
298
+ data_sql = "SELECT #{keys} FROM #{data_tables_sql} WHERE (#{pk_sql}) IN (#{distinct_sql}) order by #{order}"
283
299
  else
284
300
  data_sql = "#{sql} order by #{order}"
285
301
  end
@@ -296,6 +312,7 @@ module Spider; module Model; module Storage; module Db
296
312
  end
297
313
 
298
314
  def sql_condition_value(key, comp, value, bound_vars=true)
315
+ curr[:bind_cnt] ||= 0
299
316
  if (comp.to_s.downcase == 'ilike')
300
317
  comp = 'like'
301
318
  key = "UPPER(#{key})"
@@ -6,30 +6,39 @@ module Spider; module Model; module Storage; module Db
6
6
  class SQLite < DbStorage
7
7
  @reserved_keywords = superclass.reserved_keywords + []
8
8
  @capabilities = {
9
- :autoincrement => false,
9
+ :autoincrement => true,
10
10
  :sequences => true,
11
- :transactions => true
11
+ :transactions => true,
12
+ :foreign_keys => false
12
13
  }
13
14
 
14
15
  class << self; attr_reader :reserved_kewords; end
15
16
 
17
+ def self.max_connections
18
+ 1
19
+ end
20
+
16
21
  def self.base_types
17
22
  super << Spider::DataTypes::Binary
18
23
  end
19
24
 
20
25
  def self.new_connection(file)
21
- @db = SQLite3::Database.new(file)
22
- @db.results_as_hash = true
23
- return @db
26
+ db = SQLite3::Database.new(file)
27
+ db.results_as_hash = true
28
+ return db
24
29
  end
25
30
 
26
- def connect
27
- @conn = self.class.new_connection(*@connection_params) unless @conn
31
+ def self.connection_alive?(conn)
32
+ !conn.closed?
28
33
  end
29
34
 
30
35
  def release
31
- @conn.close if @conn
32
- @conn = nil
36
+ begin
37
+ #curr[:conn].close
38
+ super
39
+ rescue
40
+ curr[:conn] = nil
41
+ end
33
42
  end
34
43
 
35
44
 
@@ -43,26 +52,30 @@ module Spider; module Model; module Storage; module Db
43
52
  @connection_params = [@file]
44
53
  end
45
54
 
46
- def start_transaction
55
+ def do_start_transaction
56
+ return unless transactions_enabled?
47
57
  connection.transaction
48
58
  end
49
59
 
50
60
  def in_transaction?
51
- @conn && @conn.transaction_active?
61
+ return false unless transactions_enabled?
62
+ return curr[:conn] && curr[:conn].transaction_active?
52
63
  end
53
64
 
54
- def commit
55
- @conn.commit
65
+ def do_commit
66
+ return release unless transactions_enabled?
67
+ curr[:conn].commit if curr[:conn]
56
68
  release
57
69
  end
58
-
59
- def rollback
60
- @conn.rollback
70
+
71
+ def do_rollback
72
+ return release unless transactions_enabled?
73
+ curr[:conn].rollback
61
74
  release
62
75
  end
63
-
76
+
64
77
  def assigned_key(key)
65
- @last_insert_row_id
78
+ curr[:last_insert_row_id]
66
79
  end
67
80
 
68
81
  def value_for_save(type, value, save_mode)
@@ -81,9 +94,9 @@ module Spider; module Model; module Storage; module Db
81
94
  debug("sqlite executing:\n#{sql}\n[#{debug_vars}]")
82
95
 
83
96
  result = connection.execute(sql, *bind_vars)
84
- @last_insert_row_id = connection.last_insert_row_id
97
+ curr[:last_insert_row_id] = connection.last_insert_row_id
85
98
  result.extend(StorageResult)
86
- @last_result = result
99
+ curr[:last_result] = result
87
100
  if block_given?
88
101
  result.each{ |row| yield row }
89
102
  else
@@ -97,8 +110,7 @@ module Spider; module Model; module Storage; module Db
97
110
 
98
111
  def prepare(sql)
99
112
  debug("sqlite preparing: #{sql}")
100
- connect unless connected?
101
- return @conn.prepare(sql)
113
+ return connection.prepare(sql)
102
114
  end
103
115
 
104
116
  def execute_statement(stmt, *bind_vars)
@@ -106,10 +118,10 @@ module Spider; module Model; module Storage; module Db
106
118
  end
107
119
 
108
120
  def total_rows
109
- return nil unless @last_query
110
- q = @last_query
121
+ return nil unless curr[:last_query]
122
+ q = curr[:last_query]
111
123
  unless (q[:offset] || q[:limit])
112
- return @last_result ? @last_result.length : nil
124
+ return curr[:last_result] ? curr[:last_result].length : nil
113
125
  end
114
126
  q[:offset] = q[:limit] = nil
115
127
  q[:keys] = ["COUNT(*) AS N"]
@@ -117,6 +129,10 @@ module Spider; module Model; module Storage; module Db
117
129
  return res[0]['N']
118
130
  end
119
131
 
132
+ #############################################################
133
+ # SQL methods #
134
+ #############################################################
135
+
120
136
  ##############################################################
121
137
  # Methods to get information from the db #
122
138
  ##############################################################
@@ -127,17 +143,35 @@ module Spider; module Model; module Storage; module Db
127
143
 
128
144
  def describe_table(table)
129
145
  columns = {}
130
- stmt = prepare("select * from #{table}")
131
- stmt.columns.each_index do |index|
132
- field = stmt.columns[index]
133
- columns[field] ||= {}
134
- if (stmt.types[index] =~ /([^\(]+)(?:\((\d+)\))?/)
135
- columns[field][:type] = $1
136
- columns[field][:length] = $2.to_i if $2
146
+ primary_keys = []
147
+ res = execute("PRAGMA table_info('#{table}')")
148
+ res.each do |row|
149
+ name = row['name']
150
+ type = row['type']
151
+ length = nil
152
+ precision = nil
153
+ if type =~ /(.+)\((.+)\)/
154
+ type = $1
155
+ length = $2
156
+ end
157
+ if length && length.include?(",")
158
+ length, precision = length.split(',')
137
159
  end
160
+ length = length.to_i if length
161
+ precision = precision.to_i if length
162
+ primary_keys << name if row['pk'] == "1"
163
+ columns[name] = {:type => type, :length => length, :precision => precision}
138
164
  end
139
- stmt.close
140
- return {:columns => columns}
165
+ # stmt.columns.each_index do |index|
166
+ # field = stmt.columns[index]
167
+ # columns[field] ||= {}
168
+ # if (stmt.types[index] =~ /([^\(]+)(?:\((\d+)\))?/)
169
+ # columns[field][:type] = $1
170
+ # columns[field][:length] = $2.to_i if $2
171
+ # end
172
+ # end
173
+ # stmt.close
174
+ return {:columns => columns, :primary_keys => primary_keys}
141
175
  end
142
176
 
143
177
  def table_exists?(table)
@@ -37,7 +37,7 @@ module Spider; module Model; module Storage; module Db; module Connectors
37
37
  end
38
38
 
39
39
  def parse_url(url)
40
- # adapter//<username:password>@<dsn>
40
+ # adapter://<username:password>@<dsn>
41
41
  if (url =~ /(.+):\/\/(?:(.+):(.+)@)?(.+)/)
42
42
  @adapter = $1
43
43
  @user = $2