spiderfw 0.5.10 → 0.5.11
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/Rakefile +4 -1
- data/VERSION +1 -0
- data/apps/core/auth/controllers/login_controller.rb +10 -1
- data/apps/core/auth/controllers/mixins/auth_helper.rb +4 -2
- data/apps/core/auth/views/login.shtml +1 -1
- data/apps/core/components/_init.rb +1 -1
- data/apps/core/components/public/css/spider.css +0 -1
- data/apps/core/components/public/js/jquery/plugins/jquery.form.js +2 -1
- data/apps/core/components/public/js/list.js +14 -126
- data/apps/core/components/public/js/plugins/plugin.js +7 -0
- data/apps/core/components/public/js/plugins/sortable.js +124 -0
- data/apps/core/components/public/js/spider.js +212 -51
- data/apps/core/components/widgets/list/list.shtml +1 -0
- data/apps/core/components/widgets/table/table.rb +1 -1
- data/apps/core/components/widgets/table/table.shtml +3 -3
- data/apps/core/components/widgets/tabs/tabs.rb +70 -22
- data/apps/core/components/widgets/tabs/tabs.shtml +8 -2
- data/apps/core/forms/widgets/inputs/file_input/file_input.rb +4 -1
- data/data/locale/it/LC_MESSAGES/cms.mo +0 -0
- data/data/locale/it/LC_MESSAGES/spider.mo +0 -0
- data/data/locale/it/LC_MESSAGES/spider_files.mo +0 -0
- data/data/locale/it/LC_MESSAGES/spider_images.mo +0 -0
- data/lib/spiderfw.rb +3 -1
- data/lib/spiderfw/config/configuration.rb +3 -1
- data/lib/spiderfw/controller/controller.rb +8 -0
- data/lib/spiderfw/controller/mixins/static_content.rb +14 -2
- data/lib/spiderfw/controller/mixins/visual.rb +25 -25
- data/lib/spiderfw/controller/page_controller.rb +3 -0
- data/lib/spiderfw/controller/request.rb +4 -1
- data/lib/spiderfw/controller/session.rb +7 -6
- data/lib/spiderfw/create.rb +10 -1
- data/lib/spiderfw/model/base_model.rb +104 -57
- data/lib/spiderfw/model/condition.rb +9 -1
- data/lib/spiderfw/model/data_type.rb +15 -0
- data/lib/spiderfw/model/datatypes/uuid.rb +5 -0
- data/lib/spiderfw/model/extended_models/managed.rb +2 -2
- data/lib/spiderfw/model/mappers/db_mapper.rb +46 -21
- data/lib/spiderfw/model/mappers/mapper.rb +34 -8
- data/lib/spiderfw/model/mixins/list.rb +2 -0
- data/lib/spiderfw/model/mixins/tree.rb +2 -1
- data/lib/spiderfw/model/mixins/versioned.rb +12 -9
- data/lib/spiderfw/model/model.rb +72 -0
- data/lib/spiderfw/model/query_set.rb +7 -0
- data/lib/spiderfw/model/storage/base_storage.rb +5 -1
- data/lib/spiderfw/model/storage/db/adapters/mysql.rb +5 -2
- data/lib/spiderfw/model/storage/db/adapters/oci8.rb +9 -3
- data/lib/spiderfw/model/storage/db/db_storage.rb +8 -5
- data/lib/spiderfw/model/sync.rb +12 -6
- data/lib/spiderfw/requires.rb +1 -0
- data/lib/spiderfw/templates/blocks/parent_context.rb +26 -0
- data/lib/spiderfw/templates/blocks/widget.rb +17 -7
- data/lib/spiderfw/templates/layout.rb +11 -1
- data/lib/spiderfw/templates/template.rb +36 -3
- data/lib/spiderfw/templates/template_blocks.rb +36 -26
- data/lib/spiderfw/utils/annotations.rb +2 -1
- data/lib/spiderfw/utils/thread_out.rb +15 -0
- data/lib/spiderfw/widget/widget.rb +58 -16
- data/spider.gemspec +3 -0
- metadata +143 -48
data/lib/spiderfw/create.rb
CHANGED
@@ -39,6 +39,15 @@ module Spider
|
|
39
39
|
raise RuntimeError, "Folder #{dest_path} already exists" if File.exist?(dest_path)
|
40
40
|
FileUtils.mkdir_p(dest_path)
|
41
41
|
erb_binding ||= binding
|
42
|
+
if File.exists?("#{source_path}/.dirs")
|
43
|
+
File.readlines("#{source_path}/.dirs").each do |dir|
|
44
|
+
dir.strip!
|
45
|
+
replacements.each do |search, replace|
|
46
|
+
dir.gsub!(search, replace)
|
47
|
+
end
|
48
|
+
FileUtils.mkdir_p(dest_path+'/'+dir)
|
49
|
+
end
|
50
|
+
end
|
42
51
|
Find.find(source_path) do |sp|
|
43
52
|
next if sp == source_path
|
44
53
|
sp =~ /\/([^\/]+)$/
|
@@ -49,7 +58,7 @@ module Spider
|
|
49
58
|
dp.gsub!(search, replace)
|
50
59
|
end
|
51
60
|
if (File.directory?(sp))
|
52
|
-
FileUtils.mkdir(dest_path+'/'+dp)
|
61
|
+
FileUtils.mkdir(dest_path+'/'+dp) unless File.directory?(dest_path+'/'+dp)
|
53
62
|
else
|
54
63
|
dst = File.new(dest_path+'/'+dp, 'w')
|
55
64
|
res = ERB.new(IO.read(sp)).result(erb_binding)
|
@@ -93,6 +93,10 @@ module Spider; module Model
|
|
93
93
|
subclass.instance_variable_set("@extended_models", @extended_models.clone) if @extended_models
|
94
94
|
end
|
95
95
|
|
96
|
+
def self.subclasses
|
97
|
+
@subclasses || []
|
98
|
+
end
|
99
|
+
|
96
100
|
# Returns the parent Spider::App of the module
|
97
101
|
def self.app
|
98
102
|
return @app if @app
|
@@ -103,12 +107,6 @@ module Spider; module Model
|
|
103
107
|
@app = app
|
104
108
|
end
|
105
109
|
|
106
|
-
# Returns an instance of the Model with #autoload set to false
|
107
|
-
def self.static(value=nil)
|
108
|
-
obj = self.new(value)
|
109
|
-
obj.autoload = false
|
110
|
-
return obj
|
111
|
-
end
|
112
110
|
|
113
111
|
#######################################
|
114
112
|
# Model definition methods #
|
@@ -163,6 +161,8 @@ module Spider; module Model
|
|
163
161
|
# :computed_from:: (array of symbols) the element is not mapped; its value is computed
|
164
162
|
# by the class from the given elements.
|
165
163
|
# :unmapped:: (bool) the element is not mapped.
|
164
|
+
# :sortable:: (bool or Array of symbols) specifies that an unmapped element can be used for sorting.
|
165
|
+
# The model must provide a meaningful order using the prepare_query method.
|
166
166
|
# :check:: (a Proc, or a Regexp, or a Hash of messages => Regexp|Proc). See #check
|
167
167
|
# :through:: (a BaseModel subclass) model representing the many to many relationship.
|
168
168
|
# :read_only:: (bool) hint to the UI that the element should not be user modifiable.
|
@@ -170,6 +170,8 @@ module Spider; module Model
|
|
170
170
|
# :condition:: (hash or Condition) Restricts an association always adding the condition.
|
171
171
|
# :order:: (true or Fixnum) When doing queries, sort by this element. More than one element can have the
|
172
172
|
# :order attribute; if it is a Fixnum, it will mean the position in the ordering.
|
173
|
+
# :default:: (Proc or value) default value for the element. If it is a Proc, it will be passed
|
174
|
+
# the object.
|
173
175
|
#
|
174
176
|
# Other attributes may be used by DataTypes (see #DataType::ClassMethods.take_attributes), and other code.
|
175
177
|
# See also Element.
|
@@ -210,6 +212,10 @@ module Spider; module Model
|
|
210
212
|
if (attributes[:condition] && !attributes[:condition].is_a?(Condition))
|
211
213
|
attributes[:condition] = Condition.new(attributes[:condition])
|
212
214
|
end
|
215
|
+
if attributes[:computed_from] && !attributes[:computed_from].is_a?(Enumerable)
|
216
|
+
attributes[:computed_from] = [attributes[:computed_from]]
|
217
|
+
end
|
218
|
+
type.set_element_attributes(attributes) if type < Spider::DataType
|
213
219
|
|
214
220
|
|
215
221
|
orig_type = type
|
@@ -220,7 +226,7 @@ module Spider; module Model
|
|
220
226
|
(attributes[:has_single_reverse] == false || !attributes[:reverse] || (!type.elements[attributes[:reverse]] || type.elements[attributes[:reverse]].multiple?))))
|
221
227
|
attributes[:anonymous_model] = true
|
222
228
|
attributes[:owned] = true unless attributes[:owned] != nil
|
223
|
-
first_model = self.first_definer(name)
|
229
|
+
first_model = self.first_definer(name, type)
|
224
230
|
assoc_type_name = Spider::Inflector.camelize(name)
|
225
231
|
create_junction = true
|
226
232
|
if (attributes[:through])
|
@@ -266,6 +272,10 @@ module Spider; module Model
|
|
266
272
|
orig_type.referenced_by_junctions << [assoc_type, other_name]
|
267
273
|
attributes[:keep_junction] = true if (attributes[:through] && attributes[:keep_junction] != false)
|
268
274
|
attributes[:association_type] = assoc_type
|
275
|
+
if attributes[:polymorph]
|
276
|
+
assoc_type.elements[attributes[:junction_their_element]].attributes[:polymorph] = attributes[:polymorph]
|
277
|
+
attributes.delete(:polymorph)
|
278
|
+
end
|
269
279
|
end
|
270
280
|
|
271
281
|
@elements[name] = Element.new(name, type, attributes)
|
@@ -282,8 +292,14 @@ module Spider; module Model
|
|
282
292
|
attributes[:reverse] ||= attributes[:add_reverse][:name]
|
283
293
|
rev = attributes[:add_reverse].merge(:reverse => name, :added_reverse => true,
|
284
294
|
:delete_cascade => attributes[:reverse_delete_cascade])
|
285
|
-
rev[:through] = assoc_type if assoc_type
|
286
295
|
rev_name = rev.delete(:name)
|
296
|
+
if assoc_type
|
297
|
+
rev[:junction] = true
|
298
|
+
rev[:keep_junction] = false
|
299
|
+
rev[:through] = assoc_type
|
300
|
+
rev[:junction_their_element] = self_name
|
301
|
+
rev[:junction_our_element] = other_name
|
302
|
+
end
|
287
303
|
orig_type.element(rev_name, self, rev)
|
288
304
|
end
|
289
305
|
elsif (attributes[:add_multiple_reverse])
|
@@ -293,6 +309,7 @@ module Spider; module Model
|
|
293
309
|
:added_reverse => true, :delete_cascade => attributes[:reverse_delete_cascade])
|
294
310
|
rev_name = rev.delete(:name)
|
295
311
|
if assoc_type
|
312
|
+
rev[:junction] = true
|
296
313
|
rev[:through] = assoc_type
|
297
314
|
rev[:junction_their_element] = self_name
|
298
315
|
rev[:junction_our_element] = other_name
|
@@ -304,7 +321,7 @@ module Spider; module Model
|
|
304
321
|
# if attributes[:primary_key]
|
305
322
|
# attributes[:lazy] = true
|
306
323
|
# els
|
307
|
-
if (type < BaseModel && attributes[:multiple])
|
324
|
+
if (type < BaseModel && (attributes[:multiple] || attributes[:polymorph]))
|
308
325
|
# FIXME: we can load eagerly single relations if we can do a join
|
309
326
|
attributes[:lazy] = true
|
310
327
|
else
|
@@ -370,9 +387,18 @@ module Spider; module Model
|
|
370
387
|
if !val && element.model? && (element.multiple? || element.attributes[:extended_model])
|
371
388
|
val = instance_variable_set(ivar, instantiate_element(name))
|
372
389
|
end
|
390
|
+
if !val && element.attributes[:default]
|
391
|
+
if element.attributes[:default].is_a?(Proc)
|
392
|
+
val = element.attributes[:default].call(self)
|
393
|
+
else
|
394
|
+
val = element.attributes[:default]
|
395
|
+
end
|
396
|
+
end
|
373
397
|
val.set_parent(self, name) if element.model? && val && !val._parent # FIXME!!!
|
374
398
|
return val
|
375
399
|
end
|
400
|
+
|
401
|
+
alias_method :"#{name}?", name if type <= Spider::DataTypes::Bool
|
376
402
|
|
377
403
|
#instance_variable_setter
|
378
404
|
element_methods.send(:define_method, "#{name}=") do |val|
|
@@ -634,9 +660,7 @@ module Spider; module Model
|
|
634
660
|
pk_name = @elements[:id] ? :"id_#{self.short_name.downcase}" : :id
|
635
661
|
element(pk_name, Fixnum, :autoincrement => true, :local_pk => true, :hidden => true)
|
636
662
|
end
|
637
|
-
|
638
|
-
model.polymorphic(self, :through => integrated_name)
|
639
|
-
end
|
663
|
+
model.polymorphic(self, :through => integrated_name)
|
640
664
|
end
|
641
665
|
|
642
666
|
# Externalizes the superclass elements making the superclass an external integrated element.
|
@@ -644,7 +668,6 @@ module Spider; module Model
|
|
644
668
|
# * :name (symbol) name of the created element
|
645
669
|
# * :delete_cascade (bool) delete cascade the superclass instance
|
646
670
|
# * :no_local_pk (bool) do not define an id for this class
|
647
|
-
# * :add_polymorphic (bool) notify the superclass that it is extended, making polymorphic queries possible
|
648
671
|
def self.class_table_inheritance(params={})
|
649
672
|
self.extend_model(superclass, params)
|
650
673
|
end
|
@@ -757,6 +780,10 @@ module Spider; module Model
|
|
757
780
|
_(@label_plural || self.name || '')
|
758
781
|
end
|
759
782
|
|
783
|
+
def self.auto_primary_keys?
|
784
|
+
self.primary_keys.select{ |k| !k.autogenerated? }.empty?
|
785
|
+
end
|
786
|
+
|
760
787
|
########################################################
|
761
788
|
# Methods returning information about the elements #
|
762
789
|
########################################################
|
@@ -791,13 +818,13 @@ module Spider; module Model
|
|
791
818
|
|
792
819
|
# Returns the model actually defining element_name; that could be the model
|
793
820
|
# itself, a superclass, or an integrated model.
|
794
|
-
def self.first_definer(element_name)
|
795
|
-
if (@extended_models && @extended_models[self.superclass] && self.superclass.elements[element_name])
|
796
|
-
return self.superclass.first_definer(element_name)
|
821
|
+
def self.first_definer(element_name, type)
|
822
|
+
if (@extended_models && @extended_models[self.superclass] && self.superclass.elements[element_name] && self.superclass.elements[element_name].type == type)
|
823
|
+
return self.superclass.first_definer(element_name, type)
|
797
824
|
end
|
798
825
|
if (self.attributes[:integrated_models])
|
799
826
|
self.attributes[:integrated_models].keys.each do |mod|
|
800
|
-
return mod.first_definer(element_name) if (mod.elements[element_name])
|
827
|
+
return mod.first_definer(element_name, type) if (mod.elements[element_name] && mod.elements[element_name].type == type)
|
801
828
|
end
|
802
829
|
end
|
803
830
|
return self
|
@@ -939,7 +966,9 @@ module Spider; module Model
|
|
939
966
|
# Executes #self.where, returning the first result.
|
940
967
|
# See #self.where for parameter syntax.
|
941
968
|
def self.load(*params, &proc)
|
942
|
-
|
969
|
+
qs = self.where(*params, &proc)
|
970
|
+
qs.limit = 1
|
971
|
+
return qs[0]
|
943
972
|
end
|
944
973
|
|
945
974
|
# Returns a queryset without conditions
|
@@ -1018,31 +1047,41 @@ module Spider; module Model
|
|
1018
1047
|
@_has_values = true
|
1019
1048
|
Spider::Model.unit_of_work.add(self) if (Spider::Model.unit_of_work)
|
1020
1049
|
end
|
1021
|
-
if
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1050
|
+
set_values(values) if values
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
# Returns an instance of the Model with #autoload set to false
|
1054
|
+
def self.static(values=nil)
|
1055
|
+
obj = self.new
|
1056
|
+
obj.autoload = false
|
1057
|
+
obj.set_values(values) if values
|
1058
|
+
return obj
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
def set_values(values)
|
1062
|
+
if (values.is_a? Hash)
|
1063
|
+
values.keys.select{ |k|
|
1064
|
+
k = k.name if k.is_a?(Element)
|
1065
|
+
self.class.elements[k.to_sym] && self.class.elements[k.to_sym].primary_key?
|
1066
|
+
}.each do |k|
|
1067
|
+
set!(k, values[k])
|
1068
|
+
end
|
1069
|
+
values.each do |key, val|
|
1070
|
+
set!(key, val)
|
1071
|
+
end
|
1072
|
+
elsif (values.is_a? BaseModel)
|
1073
|
+
values.each_val do |name, val|
|
1074
|
+
set(name, val) if self.class.has_element?(name)
|
1045
1075
|
end
|
1076
|
+
elsif (values.is_a? Array)
|
1077
|
+
self.class.primary_keys.each_index do |i|
|
1078
|
+
set(self.class.primary_keys[i], values[i])
|
1079
|
+
end
|
1080
|
+
# Single unset key, single value
|
1081
|
+
elsif ((empty_keys = self.class.primary_keys.select{ |key| !element_has_value?(key) }).length == 1)
|
1082
|
+
set(empty_keys[0], values)
|
1083
|
+
else
|
1084
|
+
raise ArgumentError, "Don't know how to construct a #{self.class} from #{values.inspect}"
|
1046
1085
|
end
|
1047
1086
|
end
|
1048
1087
|
|
@@ -1067,7 +1106,7 @@ module Spider; module Model
|
|
1067
1106
|
val = element.type.new
|
1068
1107
|
val.autoload = autoload?
|
1069
1108
|
end
|
1070
|
-
end
|
1109
|
+
end
|
1071
1110
|
return prepare_child(name, val)
|
1072
1111
|
end
|
1073
1112
|
|
@@ -1077,18 +1116,24 @@ module Spider; module Model
|
|
1077
1116
|
element = self.class.elements[name]
|
1078
1117
|
if (element.model?)
|
1079
1118
|
# convert between junction and real type if needed
|
1080
|
-
if
|
1081
|
-
obj.
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1119
|
+
if element.attributes[:junction]
|
1120
|
+
if obj.is_a?(QuerySet)
|
1121
|
+
obj.no_autoload do
|
1122
|
+
if (element.attributes[:keep_junction] && obj.model == element.type)
|
1123
|
+
qs = QuerySet.new(element.model)
|
1124
|
+
obj.each{ |el_obj|
|
1125
|
+
qs << {element.reverse => self, element.attributes[:junction_their_element] => el_obj}
|
1126
|
+
}
|
1127
|
+
obj = qs
|
1128
|
+
elsif (!element.attributes[:keep_junction] && obj.model == element.model)
|
1129
|
+
qs = QuerySet.new(element.type, obj.map{ |el_obj| el_obj.get(element.attributes[:junction_their_element])})
|
1130
|
+
obj = qs
|
1131
|
+
end
|
1132
|
+
end
|
1133
|
+
else
|
1134
|
+
if (!element.attributes[:keep_junction] && obj.class == element.model)
|
1135
|
+
obj = obj.get(element.attributes[:junction_their_element])
|
1136
|
+
end
|
1092
1137
|
end
|
1093
1138
|
end
|
1094
1139
|
self.class.elements_array.select{ |el| el.attributes[:fixed] }.each do |el|
|
@@ -1268,6 +1313,8 @@ module Spider; module Model
|
|
1268
1313
|
get(element.integrated_from).set_loaded_value(element.integrated_from_element, value)
|
1269
1314
|
else
|
1270
1315
|
value = prepare_child(element.name, value)
|
1316
|
+
current = instance_variable_get("@#{element_name}")
|
1317
|
+
current.set_parent(nil, nil) if current && current.is_a?(BaseModel)
|
1271
1318
|
instance_variable_set("@#{element_name}", value)
|
1272
1319
|
end
|
1273
1320
|
value.loaded = true if (value.is_a?(QuerySet))
|
@@ -1333,8 +1380,8 @@ module Spider; module Model
|
|
1333
1380
|
# not contain all of the current model's elements.
|
1334
1381
|
def subclass(model)
|
1335
1382
|
obj = model.new
|
1336
|
-
elements_array.each do |el|
|
1337
|
-
obj.set(el, self.get(el)) if element_has_value?(el)
|
1383
|
+
self.class.elements_array.each do |el|
|
1384
|
+
obj.set(el, self.get(el)) if element_has_value?(el) && model.elements[el.name]
|
1338
1385
|
end
|
1339
1386
|
return obj
|
1340
1387
|
end
|
@@ -294,7 +294,11 @@ module Spider; module Model
|
|
294
294
|
|
295
295
|
# True if there are no comparisons and no subconditions.
|
296
296
|
def empty?
|
297
|
-
return
|
297
|
+
return false unless super
|
298
|
+
@subconditions.each do |sub|
|
299
|
+
return false unless sub.empty?
|
300
|
+
end
|
301
|
+
return true
|
298
302
|
end
|
299
303
|
|
300
304
|
alias :hash_replace :replace # :nodoc:
|
@@ -390,6 +394,10 @@ module Spider; module Model
|
|
390
394
|
return ConditionElement.new(name, @condition_context)
|
391
395
|
end
|
392
396
|
|
397
|
+
def id
|
398
|
+
return ConditionElement.new(:id, @condition_context)
|
399
|
+
end
|
400
|
+
|
393
401
|
def AND(&proc)
|
394
402
|
@condition_context = []
|
395
403
|
instance_eval(&proc)
|
@@ -45,6 +45,21 @@ module Spider
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
# Tells the class that this type generates the element's value automatically
|
49
|
+
def autogenerated
|
50
|
+
@autogenerated = true
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns whether the given element is autogenerated
|
54
|
+
def auto?(element)
|
55
|
+
@autogenerated && element.attributes[:auto]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Is called by the BaseModel when creating an element of this type. Can modify the element's attributes.
|
59
|
+
def set_element_attributes(attributes)
|
60
|
+
attributes[:auto] = true unless attributes[:auto] == false
|
61
|
+
end
|
62
|
+
|
48
63
|
end
|
49
64
|
|
50
65
|
# Returns the DataType attributes, as set in the Model Element.
|
@@ -6,6 +6,7 @@ module Spider; module DataTypes
|
|
6
6
|
|
7
7
|
class UUID < String
|
8
8
|
include DataType
|
9
|
+
autogenerated
|
9
10
|
|
10
11
|
def map(mapper_type)
|
11
12
|
self.to_s
|
@@ -22,6 +23,10 @@ module Spider; module DataTypes
|
|
22
23
|
def self.generate
|
23
24
|
UUIDTools::UUID.random_create.to_s
|
24
25
|
end
|
26
|
+
|
27
|
+
def self.auto_value
|
28
|
+
generate
|
29
|
+
end
|
25
30
|
|
26
31
|
end
|
27
32
|
|
@@ -18,8 +18,8 @@ module Spider; module Model
|
|
18
18
|
:read_only => true,
|
19
19
|
:element_position => 0
|
20
20
|
}
|
21
|
-
element :obj_created, DateTime, :hidden => true
|
22
|
-
element :obj_modified, DateTime, :hidden => true
|
21
|
+
element :obj_created, DateTime, :label => _('Created'), :hidden => true
|
22
|
+
element :obj_modified, DateTime, :label => _('Modified'), :hidden => true
|
23
23
|
|
24
24
|
|
25
25
|
def assign_id(val) #:nodoc:
|
@@ -86,8 +86,10 @@ module Spider; module Model; module Mappers
|
|
86
86
|
@model.each_element do |element|
|
87
87
|
next if !mapped?(element) || element.integrated?
|
88
88
|
next if save_mode == :update && !obj.element_modified?(element)
|
89
|
-
if (save_mode == :insert
|
90
|
-
|
89
|
+
if (save_mode == :insert)
|
90
|
+
if element.attributes[:autoincrement] && !schema.attributes(element.name)[:autoincrement]
|
91
|
+
obj.set(element.name, @storage.sequence_next(schema.sequence(element.name)))
|
92
|
+
end
|
91
93
|
end
|
92
94
|
if (!element.multiple?)
|
93
95
|
next if (save_mode == :update && element.primary_key?)
|
@@ -332,9 +334,9 @@ module Spider; module Model; module Mappers
|
|
332
334
|
next if !element || !element.type || element.integrated?
|
333
335
|
if !element.model?
|
334
336
|
field = schema.field(el)
|
337
|
+
primary_keys << field if model_pks.include?(el)
|
335
338
|
unless seen_fields[field.name]
|
336
339
|
keys << field
|
337
|
-
primary_keys << field if model_pks.include?(el)
|
338
340
|
seen_fields[field.name] = true
|
339
341
|
end
|
340
342
|
elsif !element.attributes[:junction]
|
@@ -342,9 +344,9 @@ module Spider; module Model; module Mappers
|
|
342
344
|
element.model.primary_keys.each do |key|
|
343
345
|
field = schema.foreign_key_field(el, key.name)
|
344
346
|
raise "Can't find a foreign key field for key #{key.name} of element #{el} of model #{@model}" unless field
|
347
|
+
primary_keys << field if model_pks.include?(el)
|
345
348
|
unless seen_fields[field.name]
|
346
349
|
keys << field
|
347
|
-
primary_keys << field if model_pks.include?(el)
|
348
350
|
seen_fields[field.name] = true
|
349
351
|
end
|
350
352
|
end
|
@@ -409,7 +411,7 @@ module Spider; module Model; module Mappers
|
|
409
411
|
return {
|
410
412
|
:query_type => :select,
|
411
413
|
:keys => keys,
|
412
|
-
:primary_keys => primary_keys,
|
414
|
+
:primary_keys => primary_keys.uniq,
|
413
415
|
:tables => tables,
|
414
416
|
:condition => condition,
|
415
417
|
:joins => joins,
|
@@ -480,24 +482,40 @@ module Spider; module Model; module Mappers
|
|
480
482
|
cond[:conj] = condition.conjunction.to_s
|
481
483
|
cond[:values] = []
|
482
484
|
|
483
|
-
|
484
|
-
|
485
|
-
|
485
|
+
|
486
|
+
|
487
|
+
def get_join_info(model, condition)
|
488
|
+
join_info = {}
|
489
|
+
condition.each_with_comparison do |k, v, comp|
|
486
490
|
next unless k.respond_to?(:to_sym)
|
487
491
|
element = model.elements[k.to_sym]
|
488
492
|
next unless element
|
489
493
|
next unless model.mapper.mapped?(element)
|
490
494
|
next unless element.model?
|
491
|
-
|
492
|
-
|
495
|
+
join_info[k.to_s] = true if !v.nil? || comp != '='
|
496
|
+
if v.is_a?(Spider::Model::Condition)
|
497
|
+
el_join_info = get_join_info(element.model, v)
|
498
|
+
el_join_info.each do |jk, jv|
|
499
|
+
join_info["#{k}.#{jk}"] = jv
|
500
|
+
end
|
501
|
+
end
|
493
502
|
end
|
503
|
+
condition.subconditions.each do |sub_cond|
|
504
|
+
sub_join_info = get_join_info(model, sub_cond)
|
505
|
+
if condition.conjunction == :or
|
506
|
+
join_info.each_key do |k|
|
507
|
+
join_info.delete(k) unless sub_join_info[k]
|
508
|
+
end
|
509
|
+
else
|
510
|
+
join_info.merge!(sub_join_info)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
join_info
|
494
514
|
end
|
495
515
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
get_not_nil(@model, condition, not_nil)
|
500
|
-
end
|
516
|
+
join_info = options[:join_info]
|
517
|
+
join_info ||= get_join_info(@model, condition)
|
518
|
+
|
501
519
|
|
502
520
|
condition.each_with_comparison do |k, v, comp|
|
503
521
|
if k.is_a?(QueryFuncs::Function)
|
@@ -509,6 +527,12 @@ module Spider; module Model; module Mappers
|
|
509
527
|
element = model.elements[k.to_sym]
|
510
528
|
next unless model.mapper.mapped?(element)
|
511
529
|
if (element.model?)
|
530
|
+
el_join_info = {}
|
531
|
+
join_info.each do |jk, jv|
|
532
|
+
if jk.index(k.to_s+'.') == 0
|
533
|
+
el_join_info[jk[k.to_s.length..-1]] = jv
|
534
|
+
end
|
535
|
+
end
|
512
536
|
if (v && model.mapper.have_references?(element.name) && v.select{ |key, value|
|
513
537
|
!element.model.elements[key] || !element.model.elements[key].primary_key? }.empty?)
|
514
538
|
# 1/n <-> 1 with only primary keys
|
@@ -523,7 +547,7 @@ module Spider; module Model; module Mappers
|
|
523
547
|
cond[:values] << element_cond
|
524
548
|
else
|
525
549
|
if (element.storage == model.mapper.storage)
|
526
|
-
join_type =
|
550
|
+
join_type = join_info[element.name.to_s] ? :inner : :left
|
527
551
|
sub_join = model.mapper.get_join(element, join_type)
|
528
552
|
# FIXME! cleanup, and apply the check to joins acquired in other places, too (maybe pass the current joins to get_join)
|
529
553
|
existent = joins.select{ |j| j[:to] == sub_join[:to] }
|
@@ -542,25 +566,26 @@ module Spider; module Model; module Mappers
|
|
542
566
|
sub_join[:as] = "#{sub_join[:to]}#{j_cnt}" if j_cnt
|
543
567
|
joins << sub_join unless had_join
|
544
568
|
|
545
|
-
if v.nil? && comp == '='
|
569
|
+
if v.nil? && comp == '='
|
570
|
+
el_model_schema = model_schema
|
546
571
|
element_cond = {:conj => 'AND', :values => []}
|
547
572
|
if model.mapper.have_references?(element.name)
|
548
573
|
el_name = element.name
|
549
574
|
el_model = element.model
|
550
575
|
else
|
551
576
|
el_model = element.type
|
552
|
-
|
577
|
+
el_model_schema = element.model.mapper.schema
|
553
578
|
el_name = element.attributes[:junction_their_element]
|
554
579
|
end
|
555
580
|
el_model.primary_keys.each do |k|
|
556
|
-
field =
|
581
|
+
field = el_model_schema.qualified_foreign_key_field(el_name, k.name)
|
557
582
|
field_cond = [field, comp, map_condition_value(element.model.elements[k.name].type, nil)]
|
558
583
|
element_cond[:values] << field_cond
|
559
584
|
end
|
560
585
|
cond[:values] << element_cond
|
561
586
|
elsif v
|
562
587
|
v = element.model.mapper.preprocess_condition(v)
|
563
|
-
sub_condition, sub_joins = element.mapper.prepare_condition(v, :table => sub_join[:as], :joins => joins, :
|
588
|
+
sub_condition, sub_joins = element.mapper.prepare_condition(v, :table => sub_join[:as], :joins => joins, :join_info => el_join_info)
|
564
589
|
sub_condition[:table] = sub_join[:as] if sub_join[:as]
|
565
590
|
joins = sub_joins
|
566
591
|
cond[:values] << sub_condition
|
@@ -587,7 +612,7 @@ module Spider; module Model; module Mappers
|
|
587
612
|
sub_sqls = []
|
588
613
|
sub_bind_values = []
|
589
614
|
condition.subconditions.each do |sub|
|
590
|
-
sub_res = self.prepare_condition(sub, :joins => joins, :
|
615
|
+
sub_res = self.prepare_condition(sub, :joins => joins, :join_info => join_info)
|
591
616
|
cond[:values] << sub_res[0]
|
592
617
|
joins = sub_res[1]
|
593
618
|
remaining_condition += sub_res[2]
|