spiderfw 0.5.10 → 0.5.11
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.
- 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]
|