@@ -190,7 +190,7 @@ def to_ruby(timezone = nil, prune_sql: false)
190
190
end
191
191
end
192
192
193
- def self . _to_ruby ( exp , context_type , tz )
193
+ def self . _to_ruby ( exp , context_type , tz , obj_name : :rec )
194
194
return exp unless exp . kind_of? ( Hash )
195
195
196
196
operator = exp . keys . first
@@ -200,29 +200,29 @@ def self._to_ruby(exp, context_type, tz)
200
200
201
201
case operator
202
202
when "equal" , "=" , "<" , ">" , ">=" , "<=" , "!="
203
- operands = operands2rubyvalue ( operator , op_args , context_type )
203
+ operands = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
204
204
clause = operands . join ( " #{ normalize_ruby_operator ( operator ) } " )
205
205
when "before"
206
206
col_type = Target . parse ( col_name ) . column_type if col_name
207
- col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type )
207
+ col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type , :obj_name => obj_name )
208
208
val = op_args [ "value" ]
209
209
clause = ruby_for_date_compare ( col_ruby , col_type , tz , "<" , val )
210
210
when "after"
211
211
col_type = Target . parse ( col_name ) . column_type if col_name
212
- col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type )
212
+ col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type , :obj_name => obj_name )
213
213
val = op_args [ "value" ]
214
214
clause = ruby_for_date_compare ( col_ruby , col_type , tz , nil , nil , ">" , val )
215
215
when "includes all"
216
- operands = operands2rubyvalue ( operator , op_args , context_type )
216
+ operands = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
217
217
clause = "(#{ operands [ 0 ] } & #{ operands [ 1 ] } ) == #{ operands [ 1 ] } "
218
218
when "includes any"
219
- operands = operands2rubyvalue ( operator , op_args , context_type )
219
+ operands = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
220
220
clause = "(#{ operands [ 1 ] } - #{ operands [ 0 ] } ) != #{ operands [ 1 ] } "
221
221
when "includes only" , "limited to"
222
- operands = operands2rubyvalue ( operator , op_args , context_type )
222
+ operands = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
223
223
clause = "(#{ operands [ 0 ] } - #{ operands [ 1 ] } ) == []"
224
224
when "like" , "not like" , "starts with" , "ends with" , "includes"
225
- operands = operands2rubyvalue ( operator , op_args , context_type )
225
+ operands = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
226
226
operands [ 1 ] =
227
227
case operator
228
228
when "starts with"
@@ -235,7 +235,7 @@ def self._to_ruby(exp, context_type, tz)
235
235
clause = operands . join ( " #{ normalize_ruby_operator ( operator ) } " )
236
236
clause = "!(" + clause + ")" if operator == "not like"
237
237
when "regular expression matches" , "regular expression does not match"
238
- operands = operands2rubyvalue ( operator , op_args , context_type )
238
+ operands = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
239
239
240
240
# If it looks like a regular expression, sanitize from forward
241
241
# slashes and interpolation
@@ -255,11 +255,11 @@ def self._to_ruby(exp, context_type, tz)
255
255
end
256
256
clause = operands . join ( " #{ normalize_ruby_operator ( operator ) } " )
257
257
when "and" , "or"
258
- clause = "(" + op_args . collect { |operand | _to_ruby ( operand , context_type , tz ) } . join ( " #{ normalize_ruby_operator ( operator ) } " ) + ")"
258
+ clause = "(" + op_args . collect { |operand | _to_ruby ( operand , context_type , tz , :obj_name => obj_name ) } . join ( " #{ normalize_ruby_operator ( operator ) } " ) + ")"
259
259
when "not" , "!"
260
- clause = normalize_ruby_operator ( operator ) + "(" + _to_ruby ( op_args , context_type , tz ) + ")"
260
+ clause = normalize_ruby_operator ( operator ) + "(" + _to_ruby ( op_args , context_type , tz , :obj_name => obj_name ) + ")"
261
261
when "is null" , "is not null" , "is empty" , "is not empty"
262
- operands = operands2rubyvalue ( operator , op_args , context_type )
262
+ operands = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
263
263
clause = operands . join ( " #{ normalize_ruby_operator ( operator ) } " )
264
264
when "contains"
265
265
op_args [ "tag" ] ||= col_name
@@ -294,14 +294,14 @@ def self._to_ruby(exp, context_type, tz)
294
294
295
295
check =~ /^check(.*)$/
296
296
mode = $1. downcase
297
- clause = "<find><search>" + _to_ruby ( op_args [ "search" ] , context_type , tz ) + "</search>" \
298
- "<check mode=#{ mode } >" + _to_ruby ( op_args [ check ] , context_type , tz ) + "</check></find>"
297
+ clause = "<find><search>" + _to_ruby ( op_args [ "search" ] , context_type , tz , :obj_name => nil ) + "</search>" \
298
+ "<check mode=#{ mode } >" + _to_ruby ( op_args [ check ] , context_type , tz , :obj_name => nil ) + "</check></find>"
299
299
when "key exists"
300
- clause , = operands2rubyvalue ( operator , op_args , context_type )
300
+ clause , = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
301
301
when "value exists"
302
- clause , = operands2rubyvalue ( operator , op_args , context_type )
302
+ clause , = operands2rubyvalue ( operator , op_args , context_type , :obj_name => obj_name )
303
303
when "is"
304
- col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type )
304
+ col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type , :obj_name => obj_name )
305
305
col_type = Target . parse ( col_name ) . column_type
306
306
value = op_args [ "value" ]
307
307
clause = if col_type == :date && !RelativeDatetime . relative? ( value )
@@ -310,7 +310,7 @@ def self._to_ruby(exp, context_type, tz)
310
310
ruby_for_date_compare ( col_ruby , col_type , tz , ">=" , value , "<=" , value )
311
311
end
312
312
when "from"
313
- col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type )
313
+ col_ruby , _value = operands2rubyvalue ( operator , { "field" => col_name } , context_type , :obj_name => obj_name )
314
314
col_type = Target . parse ( col_name ) . column_type
315
315
316
316
start_val , end_val = op_args [ "value" ]
@@ -703,7 +703,7 @@ def self.quote_by(operator, value, column_type = nil)
703
703
end
704
704
end
705
705
706
- def self . operands2rubyvalue ( operator , ops , context_type )
706
+ def self . operands2rubyvalue ( operator , ops , context_type , obj_name : nil )
707
707
if ops [ "field" ]
708
708
if ops [ "field" ] == "<count>"
709
709
[ "<count>" , quote ( ops [ "value" ] , :integer ) ]
@@ -713,6 +713,9 @@ def self.operands2rubyvalue(operator, ops, context_type)
713
713
714
714
[ if context_type == "hash"
715
715
"<value type=#{ col_type } >#{ ops [ "field" ] . split ( "." ) . last . split ( "-" ) . join ( "." ) } </value>"
716
+ elsif obj_name && !virtual_custom_attribute? ( target . column ) && target . associations . empty?
717
+ # TODO: handle value for fields with associations (they could be habtm, has_one, has_many, belongs_to)
718
+ "#{ obj_name } .#{ target . column } "
716
719
else
717
720
"<value ref=#{ target . model . to_s . downcase } , type=#{ col_type } >#{ target . tag_path_with } </value>"
718
721
end , quote_by ( operator , ops [ "value" ] , col_type ) ]
@@ -838,6 +841,10 @@ def self.sanitize_regular_expression(string)
838
841
string . gsub ( %r{\\ */} , "\\ /" ) . gsub ( /\\ *#/ , "\\ #" )
839
842
end
840
843
844
+ def self . virtual_custom_attribute? ( attribute )
845
+ attribute . include? ( CustomAttributeMixin ::CUSTOM_ATTRIBUTES_PREFIX )
846
+ end
847
+
841
848
def self . escape_virtual_custom_attribute ( attribute )
842
849
if attribute . include? ( CustomAttributeMixin ::CUSTOM_ATTRIBUTES_PREFIX )
843
850
uri_parser = URI ::RFC2396_Parser . new
0 commit comments