lafcadio 0.6.1 → 0.6.2
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/lib/lafcadio.rb +1 -1
- data/lib/lafcadio.rb~ +1 -1
- data/lib/lafcadio/domain.rb +4 -4
- data/lib/lafcadio/domain.rb~ +639 -0
- data/lib/lafcadio/objectField.rb +1 -1
- data/lib/lafcadio/objectField.rb~ +561 -0
- data/lib/lafcadio/objectStore.rb +1 -1
- data/lib/lafcadio/objectStore.rb~ +754 -0
- data/lib/lafcadio/query.rb +3 -16
- data/lib/lafcadio/query.rb~ +583 -0
- metadata +6 -2
data/lib/lafcadio/query.rb
CHANGED
@@ -145,7 +145,8 @@ module Lafcadio
|
|
145
145
|
|
146
146
|
def order_clause
|
147
147
|
if @order_by
|
148
|
-
|
148
|
+
order_by_field = @domain_class.get_field( @order_by )
|
149
|
+
clause = "order by #{ order_by_field.db_field_name } "
|
149
150
|
clause += @order_by_order == ASC ? 'asc' : 'desc'
|
150
151
|
clause
|
151
152
|
end
|
@@ -209,21 +210,7 @@ module Lafcadio
|
|
209
210
|
|
210
211
|
def db_field_name; get_field.db_table_and_field_name; end
|
211
212
|
|
212
|
-
def get_field
|
213
|
-
a_domain_class = @domain_class
|
214
|
-
field = nil
|
215
|
-
while ( a_domain_class < DomainObject ) && !field
|
216
|
-
field = a_domain_class.get_class_field( @fieldName )
|
217
|
-
a_domain_class = a_domain_class.superclass
|
218
|
-
end
|
219
|
-
if field
|
220
|
-
field
|
221
|
-
else
|
222
|
-
errStr = "Couldn't find field \"#{ @fieldName }\" in " +
|
223
|
-
"#{ @domain_class } domain class"
|
224
|
-
raise( MissingError, errStr, caller )
|
225
|
-
end
|
226
|
-
end
|
213
|
+
def get_field; @domain_class.get_field( @fieldName ); end
|
227
214
|
|
228
215
|
def query; Query.new( @domain_class, self ); end
|
229
216
|
|
@@ -0,0 +1,583 @@
|
|
1
|
+
# = Overview
|
2
|
+
# By passing a block to ObjectStore, you can write complex, ad-hoc queries in
|
3
|
+
# Ruby. This involves a few more keystrokes than writing raw SQL, but also makes
|
4
|
+
# it easier to change queries at runtime, and these queries can also be fully
|
5
|
+
# tested against the MockObjectStore.
|
6
|
+
# big_invoices = object_store.getInvoices { |inv| inv.rate.gt( 50 ) }
|
7
|
+
# # => "select * from invoices where rate > 50"
|
8
|
+
# This a full-fledged block, so you can pass in values from the calling context.
|
9
|
+
# date = Date.new( 2004, 1, 1 )
|
10
|
+
# recent_invoices = object_store.getInvoices { |inv| inv.date.gt( date ) }
|
11
|
+
# # => "select * from invoices where date > '2004-01-01'"
|
12
|
+
#
|
13
|
+
# = Query operators
|
14
|
+
# You can compare fields either to simple values, or to other fields in the same
|
15
|
+
# table.
|
16
|
+
# paid_immediately = object_store.getInvoices { |inv|
|
17
|
+
# inv.date.equals( inv.paid )
|
18
|
+
# }
|
19
|
+
# # => "select * from invoices where date = paid"
|
20
|
+
#
|
21
|
+
# == Numerical comparisons: +lt+, +lte+, +gte+, +gt+
|
22
|
+
# +lt+, +lte+, +gte+, and +gt+ stand for "less than", "less than or equal",
|
23
|
+
# "greater than or equal", and "greater than", respectively.
|
24
|
+
# tiny_invoices = object_store.getInvoices { |inv| inv.rate.lte( 25 ) }
|
25
|
+
# # => "select * from invoices where rate <= 25"
|
26
|
+
# These comparators work on fields that contain numbers, dates, and even
|
27
|
+
# references to other domain objects.
|
28
|
+
# for_1st_ten_clients = object_store.getInvoices { |inv|
|
29
|
+
# inv.client.lte( 10 )
|
30
|
+
# }
|
31
|
+
# # => "select * from invoices where client <= 10"
|
32
|
+
#
|
33
|
+
# == Equality: +equals+
|
34
|
+
# full_week_invs = object_store.getInvoices { |inv| inv.hours.equals( 40 ) }
|
35
|
+
# # => "select * from invoices where hours = 40"
|
36
|
+
# If you're comparing to a domain object you should pass in the object itself.
|
37
|
+
# client = object_store.getClient( 99 )
|
38
|
+
# invoices = object_store.getInvoices { |inv| inv.client.equals( client ) }
|
39
|
+
# # => "select * from invoices where client = 99"
|
40
|
+
#
|
41
|
+
# == Inclusion: +in+
|
42
|
+
# first_three_invs = object_store.getInvoices { |inv| inv.pk_id.in( 1, 2, 3 ) }
|
43
|
+
# # => "select * from invoices where pk_id in ( 1, 2, 3 )"
|
44
|
+
#
|
45
|
+
# == Text comparison: +like+
|
46
|
+
# fname_starts_with_a = object_store.getUsers { |user|
|
47
|
+
# user.fname.like( /^a/ )
|
48
|
+
# }
|
49
|
+
# # => "select * from users where fname like 'a%'"
|
50
|
+
# fname_ends_with_a = object_store.getUsers { |user|
|
51
|
+
# user.fname.like( /a$/ )
|
52
|
+
# }
|
53
|
+
# # => "select * from users where fname like '%a'"
|
54
|
+
# fname_contains_a = object_store.getUsers { |user|
|
55
|
+
# user.fname.like( /a/ )
|
56
|
+
# }
|
57
|
+
# # => "select * from users where fname like '%a%'"
|
58
|
+
# Please note that although we're using the Regexp operators here, these aren't
|
59
|
+
# full-fledged regexps. Only ^ and $ work for this.
|
60
|
+
#
|
61
|
+
# == Compound conditions: <tt>Query.And</tt> and <tt>Query.Or</tt>
|
62
|
+
# invoices = object_store.getInvoices { |inv|
|
63
|
+
# Query.And( inv.hours.equals( 40 ), inv.rate.equals( 50 ) )
|
64
|
+
# }
|
65
|
+
# # => "select * from invoices where (hours = 40 and rate = 50)"
|
66
|
+
# client99 = object_store.getClient( 99 )
|
67
|
+
# invoices = object_store.getInvoices { |inv|
|
68
|
+
# Query.Or( inv.hours.equals( 40 ),
|
69
|
+
# inv.rate.equals( 50 ),
|
70
|
+
# inv.client.equals( client99 ) )
|
71
|
+
# }
|
72
|
+
# # => "select * from invoices where (hours = 40 or rate = 50 or client = 99)"
|
73
|
+
# Note that both compound operators can take 2 or more arguments. Also, they can
|
74
|
+
# be nested:
|
75
|
+
# invoices = object_store.getInvoices { |inv|
|
76
|
+
# Query.And( inv.hours.equals( 40 ),
|
77
|
+
# Query.Or( inv.rate.equals( 50 ),
|
78
|
+
# inv.client.equals( client99 ) ) )
|
79
|
+
# }
|
80
|
+
# # => "select * from invoices where (hours = 40 and
|
81
|
+
# # (rate = 50 or client = 99))"
|
82
|
+
#
|
83
|
+
# == Negation: +not+
|
84
|
+
# invoices = object_store.getInvoices { |inv| inv.rate.equals( 50 ).not }
|
85
|
+
# # => "select * from invoices where rate != 50"
|
86
|
+
|
87
|
+
require 'delegate'
|
88
|
+
|
89
|
+
module Lafcadio
|
90
|
+
class Query
|
91
|
+
def self.And( *conditions ); CompoundCondition.new( *conditions ); end
|
92
|
+
|
93
|
+
def self.infer( domain_class, &action )
|
94
|
+
inferrer = Query::Inferrer.new( domain_class ) { |obj|
|
95
|
+
action.call( obj )
|
96
|
+
}
|
97
|
+
inferrer.execute
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.Or( *conditions )
|
101
|
+
conditions << CompoundCondition::OR
|
102
|
+
CompoundCondition.new( *conditions)
|
103
|
+
end
|
104
|
+
|
105
|
+
ASC = 1
|
106
|
+
DESC = 2
|
107
|
+
|
108
|
+
attr_reader :domain_class, :condition
|
109
|
+
attr_accessor :order_by, :order_by_order, :limit
|
110
|
+
|
111
|
+
def initialize(domain_class, pk_idOrCondition = nil)
|
112
|
+
@domain_class = domain_class
|
113
|
+
( @condition, @order_by, @limit ) = [ nil, nil, nil ]
|
114
|
+
if pk_idOrCondition
|
115
|
+
if pk_idOrCondition.class <= Condition
|
116
|
+
@condition = pk_idOrCondition
|
117
|
+
else
|
118
|
+
@condition = Query::Equals.new( 'pk_id', pk_idOrCondition,
|
119
|
+
domain_class )
|
120
|
+
end
|
121
|
+
end
|
122
|
+
@order_by_order = ASC
|
123
|
+
end
|
124
|
+
|
125
|
+
def and( &action ); compound( CompoundCondition::AND, action ); end
|
126
|
+
|
127
|
+
def compound( comp_type, action )
|
128
|
+
rquery = Query.infer( @domain_class ) { |dobj| action.call( dobj ) }
|
129
|
+
comp_cond = Query::CompoundCondition.new( @condition, rquery.condition,
|
130
|
+
comp_type )
|
131
|
+
comp_cond.query
|
132
|
+
end
|
133
|
+
|
134
|
+
def eql?( other ); other.class <= Query && other.to_sql == to_sql; end
|
135
|
+
|
136
|
+
def fields; '*'; end
|
137
|
+
|
138
|
+
def hash; to_sql.hash; end
|
139
|
+
|
140
|
+
def limit_clause
|
141
|
+
"limit #{ @limit.begin }, #{ @limit.end - @limit.begin + 1 }" if @limit
|
142
|
+
end
|
143
|
+
|
144
|
+
def or( &action ); compound( CompoundCondition::OR, action ); end
|
145
|
+
|
146
|
+
def order_clause
|
147
|
+
if @order_by
|
148
|
+
order_by_field = @domain_class.get_field( @order_by )
|
149
|
+
clause = "order by #{ order_by_field.db_field_name } "
|
150
|
+
clause += @order_by_order == ASC ? 'asc' : 'desc'
|
151
|
+
clause
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def sql_primary_key_field(domain_class)
|
156
|
+
"#{ domain_class.table_name }.#{ domain_class.sql_primary_key_name }"
|
157
|
+
end
|
158
|
+
|
159
|
+
def tables
|
160
|
+
concrete_classes = domain_class.self_and_concrete_superclasses.reverse
|
161
|
+
table_names = concrete_classes.collect { |domain_class|
|
162
|
+
domain_class.table_name
|
163
|
+
}
|
164
|
+
table_names.join( ', ' )
|
165
|
+
end
|
166
|
+
|
167
|
+
def to_sql
|
168
|
+
clauses = [ "select #{ fields }", "from #{ tables }" ]
|
169
|
+
clauses << where_clause if where_clause
|
170
|
+
clauses << order_clause if order_clause
|
171
|
+
clauses << limit_clause if limit_clause
|
172
|
+
clauses.join ' '
|
173
|
+
end
|
174
|
+
|
175
|
+
def where_clause
|
176
|
+
concrete_classes = domain_class.self_and_concrete_superclasses.reverse
|
177
|
+
where_clauses = []
|
178
|
+
concrete_classes.each_with_index { |domain_class, i|
|
179
|
+
if i < concrete_classes.size - 1
|
180
|
+
join_clause = sql_primary_key_field( domain_class ) + ' = ' +
|
181
|
+
sql_primary_key_field( concrete_classes[i+1] )
|
182
|
+
where_clauses << join_clause
|
183
|
+
else
|
184
|
+
where_clauses << @condition.to_sql if @condition
|
185
|
+
end
|
186
|
+
}
|
187
|
+
where_clauses.size > 0 ? 'where ' + where_clauses.join( ' and ' ) : nil
|
188
|
+
end
|
189
|
+
|
190
|
+
class Condition #:nodoc:
|
191
|
+
def Condition.search_term_type
|
192
|
+
Object
|
193
|
+
end
|
194
|
+
|
195
|
+
attr_reader :domain_class
|
196
|
+
|
197
|
+
def initialize(fieldName, searchTerm, domain_class)
|
198
|
+
@fieldName = fieldName
|
199
|
+
@searchTerm = searchTerm
|
200
|
+
unless @searchTerm.class <= self.class.search_term_type
|
201
|
+
raise "Incorrect searchTerm type #{ searchTerm.class }"
|
202
|
+
end
|
203
|
+
@domain_class = domain_class
|
204
|
+
if @domain_class
|
205
|
+
unless @domain_class <= DomainObject
|
206
|
+
raise "Incorrect object type #{ @domain_class.to_s }"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def db_field_name; get_field.db_table_and_field_name; end
|
212
|
+
|
213
|
+
def get_field; @domain_class.get_field( @fieldName ); end
|
214
|
+
|
215
|
+
def query; Query.new( @domain_class, self ); end
|
216
|
+
|
217
|
+
def not
|
218
|
+
Query::Not.new( self )
|
219
|
+
end
|
220
|
+
|
221
|
+
def primary_key_field?; 'pk_id' == @fieldName; end
|
222
|
+
|
223
|
+
def to_condition; self; end
|
224
|
+
end
|
225
|
+
|
226
|
+
class Compare < Condition #:nodoc:
|
227
|
+
LESS_THAN = 1
|
228
|
+
LESS_THAN_OR_EQUAL = 2
|
229
|
+
GREATER_THAN_OR_EQUAL = 3
|
230
|
+
GREATER_THAN = 4
|
231
|
+
|
232
|
+
@@comparators = {
|
233
|
+
LESS_THAN => '<',
|
234
|
+
LESS_THAN_OR_EQUAL => '<=',
|
235
|
+
GREATER_THAN_OR_EQUAL => '>=',
|
236
|
+
GREATER_THAN => '>'
|
237
|
+
}
|
238
|
+
|
239
|
+
@@mockComparators = {
|
240
|
+
LESS_THAN => Proc.new { |d1, d2| d1 < d2 },
|
241
|
+
LESS_THAN_OR_EQUAL => Proc.new { |d1, d2| d1 <= d2 },
|
242
|
+
GREATER_THAN_OR_EQUAL => Proc.new { |d1, d2| d1 >= d2 },
|
243
|
+
GREATER_THAN => Proc.new { |d1, d2| d1 > d2 }
|
244
|
+
}
|
245
|
+
|
246
|
+
def initialize(fieldName, searchTerm, domain_class, compareType)
|
247
|
+
super fieldName, searchTerm, domain_class
|
248
|
+
@compareType = compareType
|
249
|
+
end
|
250
|
+
|
251
|
+
def to_sql
|
252
|
+
if ( get_field.kind_of?( LinkField ) &&
|
253
|
+
!@searchTerm.respond_to?( :pk_id ) )
|
254
|
+
search_val = @searchTerm.to_s
|
255
|
+
else
|
256
|
+
search_val = get_field.value_for_sql( @searchTerm ).to_s
|
257
|
+
end
|
258
|
+
"#{ db_field_name } #{ @@comparators[@compareType] } " + search_val
|
259
|
+
end
|
260
|
+
|
261
|
+
def object_meets(anObj)
|
262
|
+
value = anObj.send @fieldName
|
263
|
+
value = value.pk_id if value.class <= DomainObject
|
264
|
+
if value
|
265
|
+
@@mockComparators[@compareType].call(value, @searchTerm)
|
266
|
+
else
|
267
|
+
false
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
class CompoundCondition < Condition #:nodoc:
|
273
|
+
AND = 1
|
274
|
+
OR = 2
|
275
|
+
|
276
|
+
def initialize(*conditions)
|
277
|
+
if( [ AND, OR ].index(conditions.last) )
|
278
|
+
@compoundType = conditions.last
|
279
|
+
conditions.pop
|
280
|
+
else
|
281
|
+
@compoundType = AND
|
282
|
+
end
|
283
|
+
@conditions = conditions
|
284
|
+
@domain_class = conditions[0].domain_class
|
285
|
+
end
|
286
|
+
|
287
|
+
def object_meets(anObj)
|
288
|
+
if @compoundType == AND
|
289
|
+
@conditions.inject( true ) { |result, cond|
|
290
|
+
result && cond.object_meets( anObj )
|
291
|
+
}
|
292
|
+
else
|
293
|
+
@conditions.inject( false ) { |result, cond|
|
294
|
+
result || cond.object_meets( anObj )
|
295
|
+
}
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def to_sql
|
300
|
+
booleanString = @compoundType == AND ? 'and' : 'or'
|
301
|
+
subSqlStrings = @conditions.collect { |cond| cond.to_sql }
|
302
|
+
"(#{ subSqlStrings.join(" #{ booleanString } ") })"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
class DomainObjectImpostor #:nodoc:
|
307
|
+
attr_reader :domain_class
|
308
|
+
|
309
|
+
def initialize( domain_class )
|
310
|
+
@domain_class = domain_class
|
311
|
+
end
|
312
|
+
|
313
|
+
def method_missing( methId, *args )
|
314
|
+
fieldName = methId.id2name
|
315
|
+
begin
|
316
|
+
classField = @domain_class.get_field( fieldName )
|
317
|
+
ObjectFieldImpostor.new( self, classField )
|
318
|
+
rescue MissingError
|
319
|
+
super( methId, *args )
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
class Equals < Condition #:nodoc:
|
325
|
+
def r_val_string
|
326
|
+
field = get_field
|
327
|
+
if @searchTerm.class <= ObjectField
|
328
|
+
@searchTerm.db_table_and_field_name
|
329
|
+
else
|
330
|
+
begin
|
331
|
+
field.value_for_sql( @searchTerm ).to_s
|
332
|
+
rescue DomainObjectInitError
|
333
|
+
raise(
|
334
|
+
ArgumentError,
|
335
|
+
"Can't query using an uncommitted domain object as a search " +
|
336
|
+
"term.",
|
337
|
+
caller
|
338
|
+
)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def object_meets(anObj)
|
344
|
+
if @searchTerm.class <= ObjectField
|
345
|
+
compare_value = anObj.send( @searchTerm.name )
|
346
|
+
else
|
347
|
+
compare_value = @searchTerm
|
348
|
+
end
|
349
|
+
compare_value == anObj.send( @fieldName )
|
350
|
+
end
|
351
|
+
|
352
|
+
def to_sql
|
353
|
+
sql = "#{ db_field_name } "
|
354
|
+
unless @searchTerm.nil?
|
355
|
+
sql += "= " + r_val_string
|
356
|
+
else
|
357
|
+
sql += "is null"
|
358
|
+
end
|
359
|
+
sql
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
class In < Condition #:nodoc:
|
364
|
+
def self.search_term_type
|
365
|
+
Array
|
366
|
+
end
|
367
|
+
|
368
|
+
def object_meets(anObj)
|
369
|
+
value = anObj.send @fieldName
|
370
|
+
@searchTerm.index(value) != nil
|
371
|
+
end
|
372
|
+
|
373
|
+
def to_sql
|
374
|
+
"#{ db_field_name } in (#{ @searchTerm.join(', ') })"
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
class Include < CompoundCondition
|
379
|
+
def initialize( field_name, search_term, domain_class )
|
380
|
+
begin_cond = Like.new( field_name, search_term + ',', domain_class,
|
381
|
+
Like::POST_ONLY )
|
382
|
+
mid_cond = Like.new( field_name, ',' + search_term + ',',
|
383
|
+
domain_class )
|
384
|
+
end_cond = Like.new( field_name, ',' + search_term, domain_class,
|
385
|
+
Like::PRE_ONLY )
|
386
|
+
only_cond = Equals.new( field_name, search_term, domain_class )
|
387
|
+
super( begin_cond, mid_cond, end_cond, only_cond, OR )
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
class Inferrer #:nodoc:
|
392
|
+
def initialize( domain_class, &action )
|
393
|
+
@domain_class = domain_class; @action = action
|
394
|
+
end
|
395
|
+
|
396
|
+
def execute
|
397
|
+
impostor = DomainObjectImpostor.new( @domain_class )
|
398
|
+
condition = @action.call( impostor ).to_condition
|
399
|
+
query = Query.new( @domain_class, condition )
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
class Like < Condition #:nodoc:
|
404
|
+
PRE_AND_POST = 1
|
405
|
+
PRE_ONLY = 2
|
406
|
+
POST_ONLY = 3
|
407
|
+
|
408
|
+
def initialize(
|
409
|
+
fieldName, searchTerm, domain_class, matchType = PRE_AND_POST)
|
410
|
+
super fieldName, searchTerm, domain_class
|
411
|
+
@matchType = matchType
|
412
|
+
end
|
413
|
+
|
414
|
+
def get_regexp
|
415
|
+
if @matchType == PRE_AND_POST
|
416
|
+
Regexp.new(@searchTerm)
|
417
|
+
elsif @matchType == PRE_ONLY
|
418
|
+
Regexp.new(@searchTerm.to_s + "$")
|
419
|
+
elsif @matchType == POST_ONLY
|
420
|
+
Regexp.new("^" + @searchTerm)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def object_meets(anObj)
|
425
|
+
value = anObj.send @fieldName
|
426
|
+
if value.class <= DomainObject || value.class == DomainObjectProxy
|
427
|
+
value = value.pk_id.to_s
|
428
|
+
end
|
429
|
+
if value.class <= Array
|
430
|
+
(value.index(@searchTerm) != nil)
|
431
|
+
else
|
432
|
+
get_regexp.match(value) != nil
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def to_sql
|
437
|
+
withWildcards = @searchTerm
|
438
|
+
if @matchType == PRE_AND_POST
|
439
|
+
withWildcards = "%" + withWildcards + "%"
|
440
|
+
elsif @matchType == PRE_ONLY
|
441
|
+
withWildcards = "%" + withWildcards
|
442
|
+
elsif @matchType == POST_ONLY
|
443
|
+
withWildcards += "%"
|
444
|
+
end
|
445
|
+
"#{ db_field_name } like '#{ withWildcards }'"
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
class Max < Query #:nodoc:
|
450
|
+
attr_reader :field_name
|
451
|
+
|
452
|
+
def initialize( domain_class, field_name = 'pk_id' )
|
453
|
+
super( domain_class )
|
454
|
+
@field_name = field_name
|
455
|
+
end
|
456
|
+
|
457
|
+
def collect( coll )
|
458
|
+
max = coll.inject( nil ) { |max, d_obj|
|
459
|
+
a_value = d_obj.send( @field_name )
|
460
|
+
( max.nil? || a_value > max ) ? a_value : max
|
461
|
+
}
|
462
|
+
[ max ]
|
463
|
+
end
|
464
|
+
|
465
|
+
def fields
|
466
|
+
"max(#{ @domain_class.get_field( @field_name ).db_field_name })"
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
class Not < Condition #:nodoc:
|
471
|
+
def initialize(unCondition)
|
472
|
+
@unCondition = unCondition
|
473
|
+
end
|
474
|
+
|
475
|
+
def object_meets(obj)
|
476
|
+
!@unCondition.object_meets(obj)
|
477
|
+
end
|
478
|
+
|
479
|
+
def domain_class; @unCondition.domain_class; end
|
480
|
+
|
481
|
+
def to_sql
|
482
|
+
"!(#{ @unCondition.to_sql })"
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
class ObjectFieldImpostor #:nodoc:
|
487
|
+
def self.comparators
|
488
|
+
{
|
489
|
+
'lt' => Compare::LESS_THAN, 'lte' => Compare::LESS_THAN_OR_EQUAL,
|
490
|
+
'gte' => Compare::GREATER_THAN_OR_EQUAL,
|
491
|
+
'gt' => Compare::GREATER_THAN
|
492
|
+
}
|
493
|
+
end
|
494
|
+
|
495
|
+
attr_reader :class_field
|
496
|
+
|
497
|
+
def initialize( domainObjectImpostor, class_field_or_name )
|
498
|
+
@domainObjectImpostor = domainObjectImpostor
|
499
|
+
if class_field_or_name == 'pk_id'
|
500
|
+
@field_name = 'pk_id'
|
501
|
+
else
|
502
|
+
@class_field = class_field_or_name
|
503
|
+
@field_name = class_field_or_name.name
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
def method_missing( methId, *args )
|
508
|
+
methodName = methId.id2name
|
509
|
+
if !ObjectFieldImpostor.comparators.keys.index( methodName ).nil?
|
510
|
+
register_compare_condition( methodName, *args )
|
511
|
+
else
|
512
|
+
super( methId, *args )
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
def register_compare_condition( compareStr, searchTerm)
|
517
|
+
compareVal = ObjectFieldImpostor.comparators[compareStr]
|
518
|
+
Compare.new( @field_name, searchTerm,
|
519
|
+
@domainObjectImpostor.domain_class, compareVal )
|
520
|
+
end
|
521
|
+
|
522
|
+
def equals( searchTerm )
|
523
|
+
Equals.new( @field_name, field_or_field_name( searchTerm ),
|
524
|
+
@domainObjectImpostor.domain_class )
|
525
|
+
end
|
526
|
+
|
527
|
+
def field_or_field_name( search_term )
|
528
|
+
if search_term.class == ObjectFieldImpostor
|
529
|
+
search_term.class_field
|
530
|
+
else
|
531
|
+
search_term
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
def include?( search_term )
|
536
|
+
if @class_field.instance_of?( TextListField )
|
537
|
+
Include.new( @field_name, search_term,
|
538
|
+
@domainObjectImpostor.domain_class )
|
539
|
+
else
|
540
|
+
raise ArgumentError
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
def like( regexp )
|
545
|
+
if regexp.is_a?( Regexp )
|
546
|
+
if regexp.source =~ /^\^(.*)/
|
547
|
+
searchTerm = $1
|
548
|
+
matchType = Query::Like::POST_ONLY
|
549
|
+
elsif regexp.source =~ /(.*)\$$/
|
550
|
+
searchTerm = $1
|
551
|
+
matchType = Query::Like::PRE_ONLY
|
552
|
+
else
|
553
|
+
searchTerm = regexp.source
|
554
|
+
matchType = Query::Like::PRE_AND_POST
|
555
|
+
end
|
556
|
+
Query::Like.new( @field_name, searchTerm,
|
557
|
+
@domainObjectImpostor.domain_class, matchType )
|
558
|
+
else
|
559
|
+
raise(
|
560
|
+
ArgumentError, "#{ @field_name }#like needs to receive a Regexp",
|
561
|
+
caller
|
562
|
+
)
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
def in( *searchTerms )
|
567
|
+
Query::In.new( @field_name, searchTerms,
|
568
|
+
@domainObjectImpostor.domain_class )
|
569
|
+
end
|
570
|
+
|
571
|
+
def to_condition
|
572
|
+
if @class_field.instance_of?( BooleanField )
|
573
|
+
Query::Equals.new( @field_name, true,
|
574
|
+
@domainObjectImpostor.domain_class )
|
575
|
+
else
|
576
|
+
raise
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
def not; to_condition.not; end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|