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
@@ -8,13 +8,25 @@ module Spider; module DataTypes
8
8
  class Decimal < BigDecimal
9
9
  include DataType
10
10
 
11
- maps_back_to superclass
11
+ #maps_back_to superclass
12
12
 
13
13
  take_attributes :scale
14
14
 
15
- def set(value)
16
- @val = BigDecimal.new(value.to_s).round(attributes[:scale] || 2)
15
+ def self.from_value(value)
16
+ return nil if value.nil?
17
+ super(value.to_s)
17
18
  end
19
+
20
+ def prepare
21
+ self.class.from_value(self.round(attributes[:scale] || 2))
22
+ end
23
+
24
+ def to_s(s=nil)
25
+ s ||= "#{attributes[:scale]}F"
26
+ super(s)
27
+ end
28
+
29
+
18
30
 
19
31
  end
20
32
 
@@ -0,0 +1,50 @@
1
+ require 'pathname'
2
+
3
+ module Spider; module DataTypes
4
+
5
+ class FilePath < ::Pathname
6
+ include DataType
7
+ maps_to String
8
+
9
+ take_attributes :base_path, :uploadable
10
+
11
+ def self.from_value(value)
12
+ return nil if value.to_s.empty?
13
+ super
14
+ end
15
+
16
+ def map(mapper_type)
17
+ val = nil
18
+ if attributes[:base_path]
19
+ begin
20
+ val = self.relative_path_from(Pathname.new(attributes[:base_path]))
21
+ rescue ArgumentError
22
+ val = self
23
+ end
24
+ else
25
+ val = self
26
+ end
27
+ val.to_s
28
+ end
29
+
30
+ def prepare
31
+ if attributes[:base_path]
32
+ self.new(Pathname.new(attributes[:base_path]) + self)
33
+ else
34
+ self
35
+ end
36
+ end
37
+
38
+ def format(format_type = :normal)
39
+ return super unless attributes[:base_path]
40
+ if format_type == :long || format_type == :full
41
+ self.to_s
42
+ else
43
+ self.relative_path_from(Pathname.new(attributes[:base_path])).to_s
44
+ end
45
+ end
46
+
47
+
48
+ end
49
+
50
+ end; end
@@ -22,10 +22,6 @@ module Spider; module DataTypes
22
22
  YAML::dump(self)
23
23
  end
24
24
 
25
- def map_back(mapper_type, val)
26
- YAML::load(val).extend(SerializedMixin)
27
- end
28
-
29
25
  end
30
26
 
31
27
 
@@ -1,4 +1,4 @@
1
- require "uuid"
1
+ require "uuidtools"
2
2
 
3
3
  module Spider; module DataTypes
4
4
 
@@ -12,7 +12,7 @@ module Spider; module DataTypes
12
12
  end
13
13
 
14
14
  # format :short returns just the first part
15
- def format(type)
15
+ def format(type = :normal)
16
16
  if (type == :short)
17
17
  return self.to_s.split('-')[0]
18
18
  end
@@ -20,7 +20,7 @@ module Spider; module DataTypes
20
20
  end
21
21
 
22
22
  def self.generate
23
- ::UUID.new.generate
23
+ UUIDTools::UUID.random_create.to_s
24
24
  end
25
25
 
26
26
  end
@@ -6,6 +6,7 @@ require 'spiderfw/model/datatypes/binary'
6
6
  require 'spiderfw/model/datatypes/password'
7
7
  require 'spiderfw/model/datatypes/uuid'
8
8
  require 'spiderfw/model/datatypes/serialized_object'
9
+ require 'spiderfw/model/datatypes/file_path'
9
10
 
10
11
 
11
12
  module Spider
@@ -30,10 +30,19 @@ module Spider; module Model
30
30
  true
31
31
  end
32
32
 
33
+ def _set_dates(bool=nil)
34
+ @_set_dates = true if @_set_dates == nil
35
+ @_set_dates = bool if bool != nil
36
+ @_set_dates
37
+ end
38
+
39
+
33
40
  with_mapper do
34
41
  def before_save(obj, mode)
35
- obj.obj_created = DateTime.now if mode == :insert
36
- obj.obj_modified = DateTime.now if obj.modified?
42
+ if obj._set_dates
43
+ obj.obj_created = DateTime.now if mode == :insert
44
+ obj.obj_modified = DateTime.now if obj.modified?
45
+ end
37
46
  super
38
47
  end
39
48
  end
@@ -39,7 +39,7 @@ module Spider; module Model; module Mappers
39
39
  end
40
40
 
41
41
  def save_all(root) #:nodoc:
42
- @storage.start_transaction if @storage.supports_transactions?
42
+ @storage.start_transaction
43
43
  super
44
44
  @storage.commit
45
45
  end
@@ -80,7 +80,7 @@ module Spider; module Model; module Mappers
80
80
  end
81
81
 
82
82
  # Save preprocessing
83
- def prepare_save(obj, save_mode, request=nil) #:nodoc:
83
+ def prepare_save(obj, save_mode) #:nodoc:
84
84
  values = {}
85
85
  obj.no_autoload do
86
86
  @model.each_element do |element|
@@ -105,6 +105,7 @@ module Spider; module Model; module Mappers
105
105
  key_value = element_val.get(key.name)
106
106
  end
107
107
  store_key = schema.foreign_key_field(element.name, key.name)
108
+ next if store_key.is_a?(FieldExpression)
108
109
  values[store_key] = map_save_value(key_type, key_value, save_mode)
109
110
  end
110
111
  else
@@ -330,15 +331,15 @@ module Spider; module Model; module Mappers
330
331
  elements.each do |el|
331
332
  element = @model.elements[el.to_sym]
332
333
  next if !element || !element.type || element.integrated?
333
- if (!element.model?)
334
+ if !element.model?
334
335
  field = schema.field(el)
335
336
  unless seen_fields[field.name]
336
337
  keys << field
337
338
  primary_keys << field if model_pks.include?(el)
338
339
  seen_fields[field.name] = true
339
340
  end
340
- elsif (!element.attributes[:junction])
341
- if (schema.has_foreign_fields?(el))
341
+ elsif !element.attributes[:junction]
342
+ if schema.has_foreign_fields?(el)
342
343
  element.model.primary_keys.each do |key|
343
344
  field = schema.foreign_key_field(el, key.name)
344
345
  raise "Can't find a foreign key field for key #{key.name} of element #{el} of model #{@model}" unless field
@@ -423,18 +424,37 @@ module Spider; module Model; module Mappers
423
424
  # FIXME: document
424
425
  def prepare_joins(joins) # :nodoc:
425
426
  h = {}
427
+ left_joins = []
426
428
  joins.each do |join|
427
429
  h[join[:from]] ||= {}
428
430
  cur = (h[join[:from]][join[:to]] ||= [])
429
431
  has_join = false
430
432
  cur.each do |cur_join|
431
433
  if (cur_join[:keys] == join[:keys] && cur_join[:conditions] == join[:conditions])
434
+ cur_join[:type] = :left if join[:type] == :left
432
435
  has_join = true
433
436
  break
434
437
  end
435
438
  end
439
+ left_joins << join if join[:type] == :left
436
440
  h[join[:from]][join[:to]] << join unless has_join
437
441
  end
442
+ while left_joins.length > 0
443
+ new_left_joins = []
444
+ left_joins.each do |lj|
445
+ if h[lj[:to]]
446
+ h[lj[:to]].each_key do |to|
447
+ h[lj[:to]][to].each do |j|
448
+ unless j[:type] == :left
449
+ new_left_joins << j
450
+ j[:type] = :left
451
+ end
452
+ end
453
+ end
454
+ end
455
+ end
456
+ left_joins = new_left_joins
457
+ end
438
458
  return h
439
459
  end
440
460
 
@@ -454,11 +474,12 @@ module Spider; module Model; module Mappers
454
474
  # FIXME: move to mapper
455
475
  model = condition.polymorph ? condition.polymorph : @model
456
476
  model_schema = model.mapper.schema
477
+ cond = {}
457
478
  # debugger if condition.polymorph
458
479
  condition.each_with_comparison do |k, v, comp|
459
480
  # normalize condition values
460
481
  element = model.elements[k.to_sym]
461
- if (!v.is_a?(Condition) && element.model?)
482
+ if (v && !v.is_a?(Condition) && element.model?)
462
483
  condition.delete(element.name)
463
484
  def set_pks_condition(condition, el, val, prefix)
464
485
  el.model.primary_keys.each do |primary_key|
@@ -469,20 +490,19 @@ module Spider; module Model; module Mappers
469
490
  condition.set(new_prefix, '=', val.get(primary_key).get(primary_key.model.primary_keys[0]))
470
491
  else
471
492
  # FIXME! does not work, the subcondition does not get processed
472
- raise "Subonditions on multiple key elements not supported yet"
473
- set_pks_condition(condition, primary_key, val.get(primary_key), new_prefix)
493
+ raise "Subconditions on multiple key elements not supported yet"
494
+ subcond = Condition.new
495
+ set_pks_condition(subcond, primary_key, val.get(primary_key), new_prefix)
496
+ condition << subcond
474
497
  end
475
498
  else
476
499
  condition.set(new_prefix, '=', val.get(primary_key))
477
500
  end
478
501
  end
479
502
  end
480
- if (v.is_a?(BaseModel))
503
+ if v.is_a?(BaseModel)
481
504
  set_pks_condition(condition, element, v, element.name)
482
- # element.model.primary_keys.each do |primary_key|
483
- # condition.set("#{element.name}.#{primary_key.name}", '=', v.get(primary_key))
484
- # end
485
- elsif (element.model.primary_keys.length == 1 )
505
+ elsif element.model.primary_keys.length == 1
486
506
  new_v = Condition.new
487
507
  if (model.mapper.have_references?(element.name))
488
508
  new_v.set(element.model.primary_keys[0].name, comp, v)
@@ -496,18 +516,15 @@ module Spider; module Model; module Mappers
496
516
  end
497
517
  end
498
518
  bind_values = []
499
- joins = []
500
- cond = {}
519
+ joins = options[:joins] || []
501
520
  remaining_condition = Condition.new # TODO: implement
502
521
  cond[:conj] = condition.conjunction.to_s
503
522
  cond[:values] = []
504
- # FIXME: the allow_left_joins hack will probably not work in the general case
505
- cond[:allow_left_joins] = options[:allow_left_joins] || {}
506
523
  condition.each_with_comparison do |k, v, comp|
507
524
  element = model.elements[k.to_sym]
508
525
  next unless model.mapper.mapped?(element)
509
526
  if (element.model?)
510
- if (model.mapper.have_references?(element.name) && v.select{ |key, value| !element.model.elements[key].primary_key? }.empty?)
527
+ if (v && model.mapper.have_references?(element.name) && v.select{ |key, value| !element.model.elements[key].primary_key? }.empty?)
511
528
  # 1/n <-> 1 with only primary keys
512
529
  element_cond = {:conj => 'AND', :values => []}
513
530
  v.each_with_comparison do |el_k, el_v, el_comp|
@@ -516,24 +533,49 @@ module Spider; module Model; module Mappers
516
533
  op = el_comp
517
534
  field_cond = [field, op, map_condition_value(element.model.elements[el_k.to_sym].type, el_v)]
518
535
  element_cond[:values] << field_cond
519
- if (el_v.nil? && el_comp == '=')
520
- cond[:allow_left_joins][element.model] = true
521
- end
522
536
  end
523
537
  cond[:values] << element_cond
524
538
  else
525
539
  if (element.storage == model.mapper.storage)
526
- join_type = cond[:allow_left_joins][element.model] ? :left : :inner
540
+ if v.nil?
541
+ join_type = comp == '=' ? :left : :inner
542
+ else
543
+ join_type = :inner
544
+ end
527
545
  sub_join = model.mapper.get_join(element, join_type)
528
- joins << sub_join
529
- element.model.mapper.prepare_query_condition(v)
546
+ # FIXME! cleanup, and apply the check to joins acquired in other places, too (maybe pass the current joins to get_join)
547
+ existent = joins.select{ |j| j[:to] == sub_join[:to] }
548
+ j_cnt = nil
549
+ had_join = false
550
+ existent.each do |j|
551
+ if sub_join[:to] == j[:to] && sub_join[:keys] == j[:keys] && sub_join[:conditions] == j[:conditions]
552
+ j[:type] = :left if sub_join[:type] == :left
553
+ sub_join = j
554
+ had_join = true
555
+ break
556
+ else
557
+ j_cnt ||= 0; j_cnt += 1
558
+ end
559
+ end
560
+ sub_join[:as] = "#{sub_join[:to]}#{j_cnt}" if j_cnt
561
+ joins << sub_join unless had_join
530
562
 
531
- sub_condition, sub_joins = element.mapper.prepare_condition(v, :table => sub_join[:as], :allow_left_joins => cond[:allow_left_joins])
532
- sub_condition[:table] = sub_join[:as] if sub_join[:as]
533
- joins += sub_joins
563
+ if v.nil? && comp == '='
564
+ element_cond = {:conj => 'AND', :values => []}
565
+ element.model.primary_keys.each do |k|
566
+ field = model_schema.qualified_foreign_key_field(element.name, k.name)
567
+ field_cond = [field, comp, map_condition_value(element.model.elements[k.name].type, nil)]
568
+ element_cond[:values] << field_cond
569
+ end
570
+ cond[:values] << element_cond
571
+ elsif v
572
+ element.model.mapper.prepare_query_condition(v)
573
+ sub_condition, sub_joins = element.mapper.prepare_condition(v, :table => sub_join[:as], :joins => joins)
574
+ sub_condition[:table] = sub_join[:as] if sub_join[:as]
575
+ joins = sub_joins
576
+ cond[:values] << sub_condition
577
+ end
534
578
 
535
- cond[:values] << sub_condition
536
- cond[:allow_left_joins].merge!(sub_condition[:allow_left_joins])
537
579
  else
538
580
  remaining_condition ||= Condition.new
539
581
  remaining_condition.set(k, comp, v)
@@ -555,14 +597,14 @@ module Spider; module Model; module Mappers
555
597
  sub_sqls = []
556
598
  sub_bind_values = []
557
599
  condition.subconditions.each do |sub|
558
- sub_res = self.prepare_condition(sub, :allow_left_joins => cond[:allow_left_joins])
600
+ sub_res = self.prepare_condition(sub, :joins => joins)
559
601
  cond[:values] << sub_res[0]
560
- joins += sub_res[1]
602
+ joins = sub_res[1]
561
603
  remaining_condition += sub_res[2]
562
604
  end
563
605
  return [cond, joins, remaining_condition]
564
606
  end
565
-
607
+
566
608
  # Figures out a join for element. Returns join hash description, i.e. :
567
609
  # join = {
568
610
  # :type => :inner|:outer|...,
@@ -587,7 +629,10 @@ module Spider; module Model; module Mappers
587
629
  else
588
630
  el_field = element.mapper.schema.field(key.name)
589
631
  end
590
- keys[schema.foreign_key_field(element.name, key.name)] = el_field
632
+
633
+ fk = schema.foreign_key_field(element.name, key.name)
634
+ fk = fk.expression if fk.is_a?(FieldExpression)
635
+ keys[fk] = el_field
591
636
  # FIXME: works with models as primary keys through a hack in the field method of db_schema,
592
637
  # assuming the model has only one key. the correct way would be to get another join
593
638
  end
@@ -617,12 +662,13 @@ module Spider; module Model; module Mappers
617
662
  our_field = schema.field(key.name)
618
663
  end
619
664
  keys[our_field] = element.mapper.schema.foreign_key_field(element.reverse, key.name)
665
+ keys[our_field] = keys[our_field].expression if keys[our_field].is_a?(FieldExpression)
620
666
  end
621
667
  if (element.condition)
622
668
  condition, condition_joins, condition_remaining = element.mapper.prepare_condition(element.condition)
623
669
  end
624
670
  join = {
625
- :type => :inner,
671
+ :type => join_type,
626
672
  :from => schema.table,
627
673
  :to => element.mapper.schema.table,
628
674
  :keys => keys,
@@ -654,7 +700,7 @@ module Spider; module Model; module Mappers
654
700
  current_model = el.integrated_from.type
655
701
  el = current_model.elements[el.integrated_from_element]
656
702
  end
657
- if (el.model?) # && can_join?(el)
703
+ if (el.model? && can_join?(el))
658
704
  joins << current_model.mapper.get_join(el)
659
705
  current_model = el.model
660
706
  end
@@ -705,8 +751,14 @@ module Spider; module Model; module Mappers
705
751
  el_joins, el_model, el = get_deep_join(order_element)
706
752
  if (el.model?)
707
753
  # FIXME: integrated elements
708
- el.model.primary_keys.each do |pk|
709
- fields << [el.model.mapper.schema.field(pk.name), direction]
754
+ if !joins.empty?
755
+ el.model.primary_keys.each do |pk|
756
+ fields << [el.model.mapper.schema.field(pk.name), direction]
757
+ end
758
+ else
759
+ el.model.primary_keys.each do |pk|
760
+ fields << [schema.qualified_foreign_key_field(el.name, pk.name), direction]
761
+ end
710
762
  end
711
763
  else
712
764
  field = el_model.mapper.schema.field(el.name)
@@ -761,10 +813,14 @@ module Spider; module Model; module Mappers
761
813
  return @storage.value_for_condition(Model.simplify_type(type), value)
762
814
  end
763
815
 
816
+ def storage_value_to_mapper(type, value)
817
+ storage.value_to_mapper(type, value)
818
+ end
819
+
764
820
  # Converts a storage value back to the corresponding base type or DataType.
765
821
  def map_back_value(type, value)
766
822
  value = value[0] if value.class == Array
767
- value = storage.value_to_mapper(Model.simplify_type(type), value)
823
+ value = storage_value_to_mapper(Model.simplify_type(type), value)
768
824
  if (type < Spider::DataType && type.maps_back_to)
769
825
  type = type.maps_back_to
770
826
  end
@@ -872,6 +928,10 @@ module Spider; module Model; module Mappers
872
928
  return schema
873
929
  end
874
930
 
931
+ def storage_column_type(type, attributes)
932
+ @storage.column_type(type, attributes)
933
+ end
934
+
875
935
  # Autogenerates schema. Returns a DbSchema.
876
936
  def generate_schema(schema=nil)
877
937
  had_schema = schema ? true : false
@@ -901,7 +961,7 @@ module Spider; module Model; module Mappers
901
961
  schema.set_sequence(element.name, @storage.sequence_name("#{schema.table}_#{element.name}"))
902
962
  end
903
963
  end
904
- column_type = element.attributes[:db_column_type] || @storage.column_type(storage_type, element.attributes)
964
+ column_type = element.attributes[:db_column_type] || storage_column_type(storage_type, element.attributes)
905
965
  unless column
906
966
  column_name = element.attributes[:db_column_name] || @storage.column_name(element.name)
907
967
  column = Field.new(schema.table, column_name, column_type)
@@ -1010,13 +1070,13 @@ module Spider; module Model; module Mappers
1010
1070
  table_attributes = {
1011
1071
  :primary_keys => table_schema[:attributes][:primary_keys]
1012
1072
  }
1013
- unless options[:no_foreign_key_constraints]
1073
+ unless options[:no_foreign_key_constraints] || !storage.supports?(:foreign_keys)
1014
1074
  table_attributes[:foreign_key_constraints] = table_schema[:attributes][:foreign_key_constraints] || []
1015
1075
  end
1016
1076
  if @storage.table_exists?(table_name)
1017
- alter_table(table_name, table_schema[:columns], table_attributes, force)
1077
+ alter_table(table_name, table_schema, table_attributes, force)
1018
1078
  else
1019
- create_table(table_name, table_schema[:columns], table_attributes)
1079
+ create_table(table_name, table_schema, table_attributes)
1020
1080
  end
1021
1081
  if (options[:drop_fields])
1022
1082
  current = @storage.describe_table(table_name)[:columns]
@@ -1045,28 +1105,33 @@ module Spider; module Model; module Mappers
1045
1105
  end
1046
1106
 
1047
1107
  # Returns a create table structure description.
1048
- def create_table(table_name, fields, attributes) # :nodoc:
1049
- fields = fields.map{ |name, details| {
1050
- :name => name,
1051
- :type => details[:type],
1052
- :attributes => details[:attributes]
1053
- } }
1108
+ def create_table(table_name, schema, attributes) # :nodoc:
1109
+ fields = schema[:fields_order].map do |f|
1110
+ details = schema[:columns][f.name]
1111
+ {
1112
+ :name => f.name,
1113
+ :type => details[:type],
1114
+ :attributes => details[:attributes]
1115
+ }
1116
+ end
1054
1117
  @storage.create_table({
1055
1118
  :table => table_name,
1056
1119
  :fields => fields,
1057
- :attributes => attributes,
1120
+ :attributes => attributes
1058
1121
  })
1059
1122
  end
1060
1123
 
1061
1124
  # Returns an alter table structure description
1062
- def alter_table(name, fields, attributes, force=nil) # :nodoc:
1125
+ def alter_table(name, schema, attributes, force=nil) # :nodoc:
1063
1126
  current = @storage.describe_table(name)
1064
1127
  current_fields = current[:columns]
1065
1128
  add_fields = []
1066
1129
  alter_fields = []
1067
1130
  all_fields = []
1068
1131
  unsafe = []
1069
- fields.each_key do |field|
1132
+ fields = schema[:columns]
1133
+ schema[:fields_order].each do |f|
1134
+ field = f.name
1070
1135
  field_hash = {
1071
1136
  :name => field,
1072
1137
  :type => fields[field][:type],
@@ -1131,7 +1196,6 @@ module Spider; module Model; module Mappers
1131
1196
  end
1132
1197
 
1133
1198
  # Error raised when a conversion results in a potential data loss.
1134
-
1135
1199
  class SchemaSyncUnsafeConversion < RuntimeError
1136
1200
  attr :fields
1137
1201
  def initialize(fields)
@@ -127,7 +127,9 @@ module Spider; module Model
127
127
  obj.set(el, set_data)
128
128
  end
129
129
  end
130
- raise RequiredError.new(el) if (el.required? && obj.element_modified?(el) && !obj.element_has_value?(el))
130
+ if (el.required? && (mode == :insert || obj.element_modified?(el)) && !obj.element_has_value?(el))
131
+ raise RequiredError.new(el)
132
+ end
131
133
  if (el.unique? && !el.integrated? && obj.element_modified?(el))
132
134
  existent = @model.where(el.name => obj.get(el))
133
135
  if (mode == :insert && existent.length > 0) || (mode == :update && existent.length > 1)
@@ -137,10 +139,7 @@ module Spider; module Model
137
139
  end
138
140
  if (@model.extended_models)
139
141
  @model.extended_models.each do |m, el|
140
- obj.instantiate_element(el) unless obj.get(el)
141
- unless sub = obj.get(el)
142
- raise "Object #{obj} is missing its superclass object for model #{m} (element #{el.name})"
143
- end
142
+ sub = obj.get(el)
144
143
  sub.save if (obj.element_modified?(el) || !obj.primary_keys_set?) && sub.mapper.class.write?
145
144
  end
146
145
  end
@@ -215,6 +214,7 @@ module Spider; module Model
215
214
  save_done(obj, save_mode)
216
215
  end
217
216
  @doing_save_done = false
217
+ true
218
218
  end
219
219
 
220
220
  # Elements that are associated to this one externally.
@@ -261,6 +261,7 @@ module Spider; module Model
261
261
  def save_element_associations(obj, element, mode)
262
262
  our_element = element.attributes[:reverse]
263
263
  val = obj.get(element)
264
+
264
265
  if (element.attributes[:junction])
265
266
  their_element = element.attributes[:junction_their_element]
266
267
  if (val.model != element.model) # dereferenced junction
@@ -288,15 +289,20 @@ module Spider; module Model
288
289
  unless mode == :insert
289
290
  condition = Condition.and
290
291
  condition[our_element] = obj
291
- raise "Can't save without a junction id" unless element.attributes[:junction_id]
292
- val.each do |row|
293
- next unless row_id = row.get(element.attributes[:junction_id])
294
- condition.set(:id, '<>', row_id)
292
+ if element.attributes[:junction_id]
293
+ val.each do |row|
294
+ next unless row_id = row.get(element.attributes[:junction_id])
295
+ condition.set(:id, '<>', row_id)
296
+ end
295
297
  end
296
298
  element.model.mapper.delete(condition)
297
299
  end
298
300
  val.set(our_element, obj)
299
- val.save
301
+ if element.attributes[:junction_id]
302
+ val.save
303
+ else
304
+ val.insert
305
+ end
300
306
  end
301
307
  else
302
308
  if (element.multiple?)
@@ -399,6 +405,13 @@ module Spider; module Model
399
405
  end
400
406
  end
401
407
  end
408
+ @model.referenced_by_junctions.each do |junction, element|
409
+ curr.each do |curr_obj|
410
+ junction_condition = Spider::Model::Condition.new
411
+ junction_condition[element] = curr_obj
412
+ junction.mapper.delete(junction_condition)
413
+ end
414
+ end
402
415
  do_delete(condition, force)
403
416
  vals.each do |obj_vals|
404
417
  obj_vals.each do |el, val|
@@ -504,7 +517,7 @@ module Spider; module Model
504
517
  end
505
518
  if (do_fetch)
506
519
  @model.primary_keys.each{ |key| query.request[key] = true}
507
- expand_request(query.request, set) unless options[:no_expand_request]
520
+ expand_request(query.request, set) unless options[:no_expand_request] || !query.request.expandable?
508
521
  query = prepare_query(query, query_set)
509
522
  query.request.total_rows = true unless query.request.total_rows == false
510
523
  result = fetch(query)
@@ -516,7 +529,7 @@ module Spider; module Model
516
529
  obj.set_loaded_value(element_name, nil)
517
530
  end
518
531
  end
519
- return set
532
+ return false
520
533
  end
521
534
  set.total_rows = result.total_rows if (!was_loaded)
522
535
  result.each do |row|
@@ -778,18 +791,27 @@ module Spider; module Model
778
791
  condition.simplify
779
792
  condition.each_with_comparison do |k, v, c|
780
793
  raise MapperError, "Condition for nonexistent element #{k} on model #{model}" unless element = model.elements[k]
794
+ if (element.attributes[:computed_from]) # FIXME: temp fix
795
+ condition.delete(k)
796
+ condition.set(element.attributes[:computed_from][0], c, v)
797
+ element = model.elements[element.attributes[:computed_from][0]]
798
+ end
781
799
  if (element.integrated?)
782
800
  condition.delete(k)
783
801
  integrated_from = element.integrated_from
784
802
  integrated_from_element = element.integrated_from_element
785
803
  condition.set("#{integrated_from.name}.#{integrated_from_element}", c, v)
786
- elsif (element.junction? && !v.is_a?(BaseModel) && !v.is_a?(Hash)) # conditions on junction id don't make sense
804
+ elsif (element.junction? && !v.is_a?(BaseModel) && !v.is_a?(Hash) && !v.nil?) # conditions on junction id don't make sense
787
805
  condition.delete(k)
788
806
  condition.set("#{k}.#{element.attributes[:junction_their_element]}", c, v)
789
807
  end
790
808
  if (element.type < Spider::DataType && !v.is_a?(element.type))
791
809
  condition.delete(k)
792
- condition.set(k, c, element.type.from_value(v))
810
+ begin
811
+ condition.set(k, c, element.type.from_value(v))
812
+ rescue TypeError => exc
813
+ raise TypeError, "Can't convert #{v} to #{element.type} for element #{k} (#{exc.message})"
814
+ end
793
815
  elsif element.type == DateTime && v && !v.is_a?(Date)
794
816
  condition.delete(k)
795
817
  condition.set(k, c, DateTime.parse(v))