lafcadio 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/lafcadio_schema +28 -26
- data/lib/lafcadio.rb +3 -3
- data/lib/lafcadio.rb~ +1 -1
- data/lib/lafcadio/domain.rb +29 -35
- data/lib/lafcadio/domain.rb~ +35 -42
- data/lib/lafcadio/mock.rb +37 -15
- data/lib/lafcadio/mock.rb~ +59 -36
- data/lib/lafcadio/objectField.rb +31 -20
- data/lib/lafcadio/objectField.rb~ +163 -142
- data/lib/lafcadio/objectStore.rb +125 -58
- data/lib/lafcadio/objectStore.rb~ +242 -177
- data/lib/lafcadio/query.rb +98 -95
- data/lib/lafcadio/query.rb~ +96 -95
- data/lib/lafcadio/schema.rb +4 -4
- data/lib/lafcadio/schema.rb~ +13 -17
- data/lib/lafcadio/test.rb +33 -7
- data/lib/lafcadio/test.rb~ +146 -20
- data/lib/lafcadio/util.rb +27 -11
- data/lib/lafcadio/util.rb~ +27 -43
- metadata +3 -7
- data/lib/lafcadio/dateTime.rb~ +0 -93
- data/lib/lafcadio/depend.rb~ +0 -8
- data/lib/lafcadio/objectStore.rb.~1.64.~ +0 -766
- data/lib/lafcadio/test/testconfig.dat~ +0 -13
data/lib/lafcadio/query.rb
CHANGED
@@ -32,7 +32,7 @@
|
|
32
32
|
# qry = Query.infer(
|
33
33
|
# SKU,
|
34
34
|
# :order_by => [ :standardPrice, :salePrice ],
|
35
|
-
# :order_by_order =>
|
35
|
+
# :order_by_order => :desc
|
36
36
|
# ) { |s| s.sku.nil? }
|
37
37
|
# qry.to_sql # => "select * from skus where skus.sku is null order by
|
38
38
|
# standardPrice, salePrice desc"
|
@@ -93,8 +93,10 @@
|
|
93
93
|
# # => "select * from users where fname like '%a'"
|
94
94
|
# fname_contains_a = User.get { |user| user.fname.like( /a/ ) }
|
95
95
|
# # => "select * from users where fname like '%a%'"
|
96
|
+
# james_or_jones = User.get { |user| user.lname.like( /J..es/ ) }
|
97
|
+
# # => "select * from users where lname like 'J__es'"
|
96
98
|
# Please note that although we're using the Regexp operators here, these aren't
|
97
|
-
# full-fledged regexps. Only
|
99
|
+
# full-fledged regexps. Only ^, $, and . work for this.
|
98
100
|
#
|
99
101
|
# == Compound conditions: <tt>&</tt> and <tt>|</tt>
|
100
102
|
# invoices = Invoice.get { |inv|
|
@@ -146,14 +148,13 @@ module Lafcadio
|
|
146
148
|
# Infers a query from a block. The first required argument is the domain
|
147
149
|
# class. Other optional arguments should be passed in hash form:
|
148
150
|
# [:order_by] An array of fields to order the results by.
|
149
|
-
# [:order_by_order] Possible values are
|
150
|
-
# to Query::DESC.
|
151
|
+
# [:order_by_order] Possible values are :asc or :desc. Defaults to :desc.
|
151
152
|
# qry = Query.infer( User ) { |u| u.lname.equals( 'Hwang' ) }
|
152
153
|
# qry.to_sql # => "select * from users where users.lname = 'Hwang'"
|
153
154
|
# qry = Query.infer(
|
154
155
|
# SKU,
|
155
156
|
# :order_by => [ :standardPrice, :salePrice ],
|
156
|
-
# :order_by_order =>
|
157
|
+
# :order_by_order => :desc
|
157
158
|
# ) { |s| s.sku.nil? }
|
158
159
|
# qry.to_sql # => "select * from skus where skus.sku is null order by
|
159
160
|
# standardPrice, salePrice desc"
|
@@ -163,29 +164,25 @@ module Lafcadio
|
|
163
164
|
end
|
164
165
|
|
165
166
|
def self.Or( *conditions ) #:nodoc:
|
166
|
-
conditions <<
|
167
|
+
conditions << :or
|
167
168
|
CompoundCondition.new( *conditions)
|
168
169
|
end
|
169
170
|
|
170
|
-
|
171
|
-
|
171
|
+
attr_reader :domain_class, :condition, :include, :limit, :order_by
|
172
|
+
attr_accessor :order_by_order
|
172
173
|
|
173
|
-
|
174
|
-
attr_accessor :order_by, :order_by_order
|
175
|
-
|
176
|
-
def initialize(domain_class, pk_id_or_condition = nil, opts = {} ) #:nodoc:
|
174
|
+
def initialize(domain_class, opts = {} ) #:nodoc:
|
177
175
|
@domain_class, @opts = domain_class, opts
|
178
176
|
( @condition, @order_by, @limit ) = [ nil, nil, nil ]
|
179
|
-
if
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
@condition = Query::Equals.new(
|
184
|
-
:pk_id, pk_id_or_condition, domain_class
|
185
|
-
)
|
186
|
-
end
|
177
|
+
if ( cond = opts[:condition] )
|
178
|
+
@condition = cond
|
179
|
+
elsif ( pk_id = opts[:pk_id] )
|
180
|
+
@condition = Query::Equals.new( :pk_id, pk_id, domain_class )
|
187
181
|
end
|
188
|
-
@
|
182
|
+
if ( @include = opts[:include] )
|
183
|
+
@include = [ @include ] unless @include.is_a?( Array )
|
184
|
+
end
|
185
|
+
@order_by_order = :asc
|
189
186
|
end
|
190
187
|
|
191
188
|
# Returns a new query representing the condition of the current query and
|
@@ -195,7 +192,7 @@ module Lafcadio
|
|
195
192
|
# qry = qry.and { |u| u.fname.equals( 'Francis' ) }
|
196
193
|
# qry.to_sql # => "select * from users where (users.lname = 'Hwang' and
|
197
194
|
# users.fname = 'Francis')"
|
198
|
-
def and( &action ); compound(
|
195
|
+
def and( &action ); compound( :and, action ); end
|
199
196
|
|
200
197
|
def collect( coll ) #:nodoc:
|
201
198
|
if @opts[:group_functions] == [:count]
|
@@ -248,10 +245,21 @@ module Lafcadio
|
|
248
245
|
@limit = limit.is_a?( Fixnum ) ? 0..limit-1 : limit
|
249
246
|
end
|
250
247
|
|
251
|
-
def limit_clause #:nodoc:
|
252
|
-
|
248
|
+
def limit_clause( db ) #:nodoc:
|
249
|
+
if @limit
|
250
|
+
case db
|
251
|
+
when 'Mysql'
|
252
|
+
"limit #{ @limit.begin }, #{ @limit.end - @limit.begin + 1 }"
|
253
|
+
when 'Pg'
|
254
|
+
limit_clause = "limit #{ @limit.end - @limit.begin + 1 }"
|
255
|
+
limit_clause += " offset #{ @limit.begin }" if @limit.begin > 0
|
256
|
+
limit_clause
|
257
|
+
end
|
258
|
+
end
|
253
259
|
end
|
254
260
|
|
261
|
+
def one_pk_id?; @condition and @condition.one_pk_id?; end
|
262
|
+
|
255
263
|
# Returns a new query representing the condition of the current query and
|
256
264
|
# the new inferred query.
|
257
265
|
# qry = Query.infer( User ) { |u| u.lname.equals( 'Hwang' ) }
|
@@ -259,7 +267,11 @@ module Lafcadio
|
|
259
267
|
# qry = qry.or { |u| u.fname.equals( 'Francis' ) }
|
260
268
|
# qry.to_sql # => "select * from users where (users.lname = 'Hwang' or
|
261
269
|
# users.fname = 'Francis')"
|
262
|
-
def or( &action ); compound(
|
270
|
+
def or( &action ); compound( :or, action ); end
|
271
|
+
|
272
|
+
def order_by=( ob )
|
273
|
+
@order_by = ( ob.is_a?( Array ) ? ob.map { |f| f.to_s } : ob.to_s ) if ob
|
274
|
+
end
|
263
275
|
|
264
276
|
def order_clause #:nodoc:
|
265
277
|
if @order_by
|
@@ -267,7 +279,7 @@ module Lafcadio
|
|
267
279
|
@domain_class.field( f_name.to_s ).db_field_name
|
268
280
|
}.join( ', ' )
|
269
281
|
clause = "order by #{ field_str } "
|
270
|
-
clause += @order_by_order ==
|
282
|
+
clause += @order_by_order == :asc ? 'asc' : 'desc'
|
271
283
|
clause
|
272
284
|
end
|
273
285
|
end
|
@@ -282,7 +294,7 @@ module Lafcadio
|
|
282
294
|
dobj.send order_by
|
283
295
|
end
|
284
296
|
}
|
285
|
-
objects.reverse! if order_by_order ==
|
297
|
+
objects.reverse! if order_by_order == :desc
|
286
298
|
objects = objects[limit] if limit
|
287
299
|
objects
|
288
300
|
end
|
@@ -301,32 +313,38 @@ module Lafcadio
|
|
301
313
|
|
302
314
|
def tables #:nodoc:
|
303
315
|
concrete_classes = domain_class.self_and_concrete_superclasses.reverse
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
316
|
+
sql = ''
|
317
|
+
dclass = nil
|
318
|
+
until concrete_classes.empty?
|
319
|
+
prev_dclass = dclass
|
320
|
+
dclass = concrete_classes.shift
|
321
|
+
if sql == ''
|
322
|
+
sql = dclass.table_name
|
323
|
+
else
|
324
|
+
sql += " inner join #{ dclass.table_name } on #{ sql_primary_key_field( prev_dclass ) } = #{ sql_primary_key_field( dclass ) }"
|
325
|
+
end
|
326
|
+
end
|
327
|
+
if @include
|
328
|
+
@include.each do |include_sym|
|
329
|
+
field = dclass.field include_sym
|
330
|
+
included_dclass = field.linked_type
|
331
|
+
sql += " left outer join #{ included_dclass.table_name } on #{ dclass.table_name }.#{ field.db_field_name } = #{ sql_primary_key_field( included_dclass ) }"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
sql
|
308
335
|
end
|
309
336
|
|
310
|
-
def to_sql
|
337
|
+
def to_sql( db = 'Mysql' )
|
311
338
|
clauses = [ "select #{ fields }", "from #{ tables }" ]
|
312
339
|
clauses << where_clause if where_clause
|
313
340
|
clauses << order_clause if order_clause
|
314
|
-
clauses << limit_clause if limit_clause
|
341
|
+
clauses << limit_clause( db ) if limit_clause( db )
|
315
342
|
clauses.join ' '
|
316
343
|
end
|
317
344
|
|
318
345
|
def where_clause #:nodoc:
|
319
|
-
concrete_classes = domain_class.self_and_concrete_superclasses.reverse
|
320
346
|
where_clauses = []
|
321
|
-
|
322
|
-
if i < concrete_classes.size - 1
|
323
|
-
join_clause = sql_primary_key_field( domain_class ) + ' = ' +
|
324
|
-
sql_primary_key_field( concrete_classes[i+1] )
|
325
|
-
where_clauses << join_clause
|
326
|
-
else
|
327
|
-
where_clauses << @condition.to_sql if @condition
|
328
|
-
end
|
329
|
-
}
|
347
|
+
where_clauses << @condition.to_sql if @condition
|
330
348
|
!where_clauses.empty? ? 'where ' + where_clauses.join( ' and ' ) : nil
|
331
349
|
end
|
332
350
|
|
@@ -376,32 +394,24 @@ module Lafcadio
|
|
376
394
|
end
|
377
395
|
|
378
396
|
def not; Query::Not.new( self ); end
|
397
|
+
|
398
|
+
def one_pk_id?; self.is_a?( Equals ) and primary_key_field?; end
|
379
399
|
|
380
400
|
def primary_key_field?; 'pk_id' == @fieldName; end
|
381
401
|
|
382
|
-
def query; Query.new( @domain_class, self ); end
|
402
|
+
def query; Query.new( @domain_class, :condition => self ); end
|
383
403
|
|
384
404
|
def to_condition; self; end
|
385
405
|
end
|
386
406
|
|
387
407
|
class Compare < Condition #:nodoc:
|
388
|
-
|
389
|
-
LESS_THAN_OR_EQUAL = 2
|
390
|
-
GREATER_THAN_OR_EQUAL = 3
|
391
|
-
GREATER_THAN = 4
|
392
|
-
|
393
|
-
@@comparators = {
|
394
|
-
LESS_THAN => '<',
|
395
|
-
LESS_THAN_OR_EQUAL => '<=',
|
396
|
-
GREATER_THAN_OR_EQUAL => '>=',
|
397
|
-
GREATER_THAN => '>'
|
398
|
-
}
|
408
|
+
@@comparators = { :lt => '<', :lte => '<=', :gte => '>=', :gt => '>' }
|
399
409
|
|
400
410
|
@@mockComparators = {
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
411
|
+
:lt => Proc.new { |d1, d2| d1 < d2 },
|
412
|
+
:lte => Proc.new { |d1, d2| d1 <= d2 },
|
413
|
+
:gte => Proc.new { |d1, d2| d1 >= d2 },
|
414
|
+
:gt => Proc.new { |d1, d2| d1 > d2 }
|
405
415
|
}
|
406
416
|
|
407
417
|
def initialize(fieldName, searchTerm, domain_class, compareType)
|
@@ -431,15 +441,12 @@ module Lafcadio
|
|
431
441
|
end
|
432
442
|
|
433
443
|
class CompoundCondition < Condition #:nodoc:
|
434
|
-
AND = 1
|
435
|
-
OR = 2
|
436
|
-
|
437
444
|
def initialize( *args )
|
438
|
-
if( [
|
445
|
+
if( [ :and, :or ].include?( args.last ) )
|
439
446
|
@compound_type = args.last
|
440
447
|
args.pop
|
441
448
|
else
|
442
|
-
@compound_type =
|
449
|
+
@compound_type = :and
|
443
450
|
end
|
444
451
|
@conditions = args.map { |arg|
|
445
452
|
arg.respond_to?( :to_condition ) ? arg.to_condition : arg
|
@@ -448,7 +455,7 @@ module Lafcadio
|
|
448
455
|
end
|
449
456
|
|
450
457
|
def dobj_satisfies?(anObj)
|
451
|
-
if @compound_type ==
|
458
|
+
if @compound_type == :and
|
452
459
|
@conditions.inject( true ) { |result, cond|
|
453
460
|
result && cond.dobj_satisfies?( anObj )
|
454
461
|
}
|
@@ -460,25 +467,25 @@ module Lafcadio
|
|
460
467
|
end
|
461
468
|
|
462
469
|
def implied_by?( other_condition )
|
463
|
-
@compound_type ==
|
470
|
+
@compound_type == :or && @conditions.any? { |cond|
|
464
471
|
cond.implies?( other_condition )
|
465
472
|
}
|
466
473
|
end
|
467
474
|
|
468
475
|
def implies?( other_condition )
|
469
476
|
super( other_condition ) or (
|
470
|
-
@compound_type ==
|
477
|
+
@compound_type == :and and @conditions.any? { |cond|
|
471
478
|
cond.implies? other_condition
|
472
479
|
}
|
473
480
|
) or (
|
474
|
-
@compound_type ==
|
481
|
+
@compound_type == :or and @conditions.all? { |cond|
|
475
482
|
cond.implies? other_condition
|
476
483
|
}
|
477
484
|
)
|
478
485
|
end
|
479
486
|
|
480
487
|
def to_sql
|
481
|
-
booleanString = @compound_type ==
|
488
|
+
booleanString = @compound_type == :and ? 'and' : 'or'
|
482
489
|
subSqlStrings = @conditions.collect { |cond| cond.to_sql }
|
483
490
|
"(#{ subSqlStrings.join(" #{ booleanString } ") })"
|
484
491
|
end
|
@@ -500,7 +507,10 @@ module Lafcadio
|
|
500
507
|
if ( classField = self.domain_class.field( fieldName ) )
|
501
508
|
ObjectFieldImpostor.new( self, classField )
|
502
509
|
else
|
503
|
-
|
510
|
+
msg = "undefined method `" + fieldName +
|
511
|
+
"' for #<DomainObjectImpostor::" +
|
512
|
+
'#{ domain_class.name }' + ">"
|
513
|
+
raise( NoMethodError, msg )
|
504
514
|
end
|
505
515
|
end
|
506
516
|
|
@@ -574,16 +584,16 @@ module Lafcadio
|
|
574
584
|
class Include < CompoundCondition #:nodoc:
|
575
585
|
def initialize( field_name, search_term, domain_class )
|
576
586
|
begin_cond = Like.new(
|
577
|
-
field_name, search_term + ',', domain_class,
|
587
|
+
field_name, search_term + ',', domain_class, :post_only
|
578
588
|
)
|
579
589
|
mid_cond = Like.new(
|
580
590
|
field_name, ',' + search_term + ',', domain_class
|
581
591
|
)
|
582
592
|
end_cond = Like.new(
|
583
|
-
field_name, ',' + search_term, domain_class,
|
593
|
+
field_name, ',' + search_term, domain_class, :pre_only
|
584
594
|
)
|
585
595
|
only_cond = Equals.new( field_name, search_term, domain_class )
|
586
|
-
super( begin_cond, mid_cond, end_cond, only_cond,
|
596
|
+
super( begin_cond, mid_cond, end_cond, only_cond, :or )
|
587
597
|
end
|
588
598
|
end
|
589
599
|
|
@@ -593,7 +603,7 @@ module Lafcadio
|
|
593
603
|
unless args.size == 1
|
594
604
|
h = args.last
|
595
605
|
@order_by = h[:order_by]
|
596
|
-
@order_by_order = ( h[:order_by_order] or
|
606
|
+
@order_by_order = ( h[:order_by_order] or :asc )
|
597
607
|
@limit = h[:limit]
|
598
608
|
end
|
599
609
|
end
|
@@ -601,7 +611,7 @@ module Lafcadio
|
|
601
611
|
def execute
|
602
612
|
impostor = DomainObjectImpostor.impostor @domain_class
|
603
613
|
condition = @action.call( impostor ).to_condition
|
604
|
-
query = Query.new( @domain_class, condition )
|
614
|
+
query = Query.new( @domain_class, :condition => condition )
|
605
615
|
query.order_by = @order_by
|
606
616
|
query.order_by_order = @order_by_order
|
607
617
|
query.limit = @limit
|
@@ -610,12 +620,8 @@ module Lafcadio
|
|
610
620
|
end
|
611
621
|
|
612
622
|
class Like < Condition #:nodoc:
|
613
|
-
PRE_AND_POST = 1
|
614
|
-
PRE_ONLY = 2
|
615
|
-
POST_ONLY = 3
|
616
|
-
|
617
623
|
def initialize(
|
618
|
-
fieldName, searchTerm, domain_class, matchType =
|
624
|
+
fieldName, searchTerm, domain_class, matchType = :pre_and_post
|
619
625
|
)
|
620
626
|
if searchTerm.is_a? Regexp
|
621
627
|
searchTerm = process_regexp searchTerm
|
@@ -637,36 +643,37 @@ module Lafcadio
|
|
637
643
|
|
638
644
|
def process_regexp( searchTerm )
|
639
645
|
if searchTerm.source =~ /^\^(.*)/
|
640
|
-
@matchType =
|
646
|
+
@matchType = :post_only
|
641
647
|
$1
|
642
648
|
elsif searchTerm.source =~ /(.*)\$$/
|
643
|
-
@matchType =
|
649
|
+
@matchType = :pre_only
|
644
650
|
$1
|
645
651
|
else
|
646
|
-
@matchType =
|
652
|
+
@matchType = :pre_and_post
|
647
653
|
searchTerm.source
|
648
654
|
end
|
649
655
|
end
|
650
656
|
|
651
657
|
def regexp
|
652
|
-
if @matchType ==
|
658
|
+
if @matchType == :pre_and_post
|
653
659
|
Regexp.new( @searchTerm, Regexp::IGNORECASE )
|
654
|
-
elsif @matchType ==
|
660
|
+
elsif @matchType == :pre_only
|
655
661
|
Regexp.new( @searchTerm.to_s + "$", Regexp::IGNORECASE )
|
656
|
-
elsif @matchType ==
|
662
|
+
elsif @matchType == :post_only
|
657
663
|
Regexp.new( "^" + @searchTerm, Regexp::IGNORECASE )
|
658
664
|
end
|
659
665
|
end
|
660
666
|
|
661
667
|
def to_sql
|
662
|
-
withWildcards = @searchTerm
|
663
|
-
if @matchType ==
|
668
|
+
withWildcards = @searchTerm.clone
|
669
|
+
if @matchType == :pre_and_post
|
664
670
|
withWildcards = "%" + withWildcards + "%"
|
665
|
-
elsif @matchType ==
|
671
|
+
elsif @matchType == :pre_only
|
666
672
|
withWildcards = "%" + withWildcards
|
667
|
-
elsif @matchType ==
|
673
|
+
elsif @matchType == :post_only
|
668
674
|
withWildcards += "%"
|
669
675
|
end
|
676
|
+
withWildcards.gsub!( /(\\?\.)/ ) { |m| m.size == 1 ? "_" : "." }
|
670
677
|
"#{ db_field_name } like '#{ withWildcards }'"
|
671
678
|
end
|
672
679
|
end
|
@@ -712,11 +719,7 @@ module Lafcadio
|
|
712
719
|
|
713
720
|
class ObjectFieldImpostor #:nodoc:
|
714
721
|
def self.comparators
|
715
|
-
{
|
716
|
-
'lt' => Compare::LESS_THAN, 'lte' => Compare::LESS_THAN_OR_EQUAL,
|
717
|
-
'gte' => Compare::GREATER_THAN_OR_EQUAL,
|
718
|
-
'gt' => Compare::GREATER_THAN
|
719
|
-
}
|
722
|
+
{ 'lt' => :lt, 'lte' => :lte, 'gte' => :gte, 'gt' => :gt }
|
720
723
|
end
|
721
724
|
|
722
725
|
attr_reader :class_field
|
data/lib/lafcadio/query.rb~
CHANGED
@@ -32,7 +32,7 @@
|
|
32
32
|
# qry = Query.infer(
|
33
33
|
# SKU,
|
34
34
|
# :order_by => [ :standardPrice, :salePrice ],
|
35
|
-
# :order_by_order =>
|
35
|
+
# :order_by_order => :desc
|
36
36
|
# ) { |s| s.sku.nil? }
|
37
37
|
# qry.to_sql # => "select * from skus where skus.sku is null order by
|
38
38
|
# standardPrice, salePrice desc"
|
@@ -108,7 +108,7 @@
|
|
108
108
|
# }
|
109
109
|
# # => "select * from invoices where (hours = 40 or rate = 50 or client = 99)"
|
110
110
|
# Note that both compound operators can be nested:
|
111
|
-
# invoices =
|
111
|
+
# invoices = Invoice.get { |inv|
|
112
112
|
# inv.hours.equals( 40 ) &
|
113
113
|
# ( inv.rate.equals( 50 ) | inv.client.equals( client99 ) )
|
114
114
|
# }
|
@@ -146,14 +146,13 @@ module Lafcadio
|
|
146
146
|
# Infers a query from a block. The first required argument is the domain
|
147
147
|
# class. Other optional arguments should be passed in hash form:
|
148
148
|
# [:order_by] An array of fields to order the results by.
|
149
|
-
# [:order_by_order] Possible values are
|
150
|
-
# to Query::DESC.
|
149
|
+
# [:order_by_order] Possible values are :asc or :desc. Defaults to :desc.
|
151
150
|
# qry = Query.infer( User ) { |u| u.lname.equals( 'Hwang' ) }
|
152
151
|
# qry.to_sql # => "select * from users where users.lname = 'Hwang'"
|
153
152
|
# qry = Query.infer(
|
154
153
|
# SKU,
|
155
154
|
# :order_by => [ :standardPrice, :salePrice ],
|
156
|
-
# :order_by_order =>
|
155
|
+
# :order_by_order => :desc
|
157
156
|
# ) { |s| s.sku.nil? }
|
158
157
|
# qry.to_sql # => "select * from skus where skus.sku is null order by
|
159
158
|
# standardPrice, salePrice desc"
|
@@ -163,29 +162,25 @@ module Lafcadio
|
|
163
162
|
end
|
164
163
|
|
165
164
|
def self.Or( *conditions ) #:nodoc:
|
166
|
-
conditions <<
|
165
|
+
conditions << :or
|
167
166
|
CompoundCondition.new( *conditions)
|
168
167
|
end
|
169
168
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
attr_reader :domain_class, :condition, :limit
|
174
|
-
attr_accessor :order_by, :order_by_order
|
169
|
+
attr_reader :domain_class, :condition, :include, :limit, :order_by
|
170
|
+
attr_accessor :order_by_order
|
175
171
|
|
176
|
-
def initialize(domain_class,
|
172
|
+
def initialize(domain_class, opts = {} ) #:nodoc:
|
177
173
|
@domain_class, @opts = domain_class, opts
|
178
174
|
( @condition, @order_by, @limit ) = [ nil, nil, nil ]
|
179
|
-
if
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
end
|
175
|
+
if ( cond = opts[:condition] )
|
176
|
+
@condition = cond
|
177
|
+
elsif ( pk_id = opts[:pk_id] )
|
178
|
+
@condition = Query::Equals.new( :pk_id, pk_id, domain_class )
|
179
|
+
end
|
180
|
+
if ( @include = opts[:include] )
|
181
|
+
@include = [ @include ] unless @include.is_a?( Array )
|
187
182
|
end
|
188
|
-
@order_by_order =
|
183
|
+
@order_by_order = :asc
|
189
184
|
end
|
190
185
|
|
191
186
|
# Returns a new query representing the condition of the current query and
|
@@ -195,7 +190,7 @@ module Lafcadio
|
|
195
190
|
# qry = qry.and { |u| u.fname.equals( 'Francis' ) }
|
196
191
|
# qry.to_sql # => "select * from users where (users.lname = 'Hwang' and
|
197
192
|
# users.fname = 'Francis')"
|
198
|
-
def and( &action ); compound(
|
193
|
+
def and( &action ); compound( :and, action ); end
|
199
194
|
|
200
195
|
def collect( coll ) #:nodoc:
|
201
196
|
if @opts[:group_functions] == [:count]
|
@@ -248,10 +243,21 @@ module Lafcadio
|
|
248
243
|
@limit = limit.is_a?( Fixnum ) ? 0..limit-1 : limit
|
249
244
|
end
|
250
245
|
|
251
|
-
def limit_clause #:nodoc:
|
252
|
-
|
246
|
+
def limit_clause( db ) #:nodoc:
|
247
|
+
if @limit
|
248
|
+
case db
|
249
|
+
when 'Mysql'
|
250
|
+
"limit #{ @limit.begin }, #{ @limit.end - @limit.begin + 1 }"
|
251
|
+
when 'Pg'
|
252
|
+
limit_clause = "limit #{ @limit.end - @limit.begin + 1 }"
|
253
|
+
limit_clause += " offset #{ @limit.begin }" if @limit.begin > 0
|
254
|
+
limit_clause
|
255
|
+
end
|
256
|
+
end
|
253
257
|
end
|
254
258
|
|
259
|
+
def one_pk_id?; @condition and @condition.one_pk_id?; end
|
260
|
+
|
255
261
|
# Returns a new query representing the condition of the current query and
|
256
262
|
# the new inferred query.
|
257
263
|
# qry = Query.infer( User ) { |u| u.lname.equals( 'Hwang' ) }
|
@@ -259,7 +265,11 @@ module Lafcadio
|
|
259
265
|
# qry = qry.or { |u| u.fname.equals( 'Francis' ) }
|
260
266
|
# qry.to_sql # => "select * from users where (users.lname = 'Hwang' or
|
261
267
|
# users.fname = 'Francis')"
|
262
|
-
def or( &action ); compound(
|
268
|
+
def or( &action ); compound( :or, action ); end
|
269
|
+
|
270
|
+
def order_by=( ob )
|
271
|
+
@order_by = ( ob.is_a?( Array ) ? ob.map { |f| f.to_s } : ob.to_s ) if ob
|
272
|
+
end
|
263
273
|
|
264
274
|
def order_clause #:nodoc:
|
265
275
|
if @order_by
|
@@ -267,7 +277,7 @@ module Lafcadio
|
|
267
277
|
@domain_class.field( f_name.to_s ).db_field_name
|
268
278
|
}.join( ', ' )
|
269
279
|
clause = "order by #{ field_str } "
|
270
|
-
clause += @order_by_order ==
|
280
|
+
clause += @order_by_order == :asc ? 'asc' : 'desc'
|
271
281
|
clause
|
272
282
|
end
|
273
283
|
end
|
@@ -282,7 +292,7 @@ module Lafcadio
|
|
282
292
|
dobj.send order_by
|
283
293
|
end
|
284
294
|
}
|
285
|
-
objects.reverse! if order_by_order ==
|
295
|
+
objects.reverse! if order_by_order == :desc
|
286
296
|
objects = objects[limit] if limit
|
287
297
|
objects
|
288
298
|
end
|
@@ -301,32 +311,38 @@ module Lafcadio
|
|
301
311
|
|
302
312
|
def tables #:nodoc:
|
303
313
|
concrete_classes = domain_class.self_and_concrete_superclasses.reverse
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
314
|
+
sql = ''
|
315
|
+
dclass = nil
|
316
|
+
until concrete_classes.empty?
|
317
|
+
prev_dclass = dclass
|
318
|
+
dclass = concrete_classes.shift
|
319
|
+
if sql == ''
|
320
|
+
sql = dclass.table_name
|
321
|
+
else
|
322
|
+
sql += " inner join #{ dclass.table_name } on #{ sql_primary_key_field( prev_dclass ) } = #{ sql_primary_key_field( dclass ) }"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
if @include
|
326
|
+
@include.each do |include_sym|
|
327
|
+
field = dclass.field include_sym
|
328
|
+
included_dclass = field.linked_type
|
329
|
+
sql += " left outer join #{ included_dclass.table_name } on #{ dclass.table_name }.#{ field.db_field_name } = #{ sql_primary_key_field( included_dclass ) }"
|
330
|
+
end
|
331
|
+
end
|
332
|
+
sql
|
308
333
|
end
|
309
334
|
|
310
|
-
def to_sql
|
335
|
+
def to_sql( db = 'Mysql' )
|
311
336
|
clauses = [ "select #{ fields }", "from #{ tables }" ]
|
312
337
|
clauses << where_clause if where_clause
|
313
338
|
clauses << order_clause if order_clause
|
314
|
-
clauses << limit_clause if limit_clause
|
339
|
+
clauses << limit_clause( db ) if limit_clause( db )
|
315
340
|
clauses.join ' '
|
316
341
|
end
|
317
342
|
|
318
343
|
def where_clause #:nodoc:
|
319
|
-
concrete_classes = domain_class.self_and_concrete_superclasses.reverse
|
320
344
|
where_clauses = []
|
321
|
-
|
322
|
-
if i < concrete_classes.size - 1
|
323
|
-
join_clause = sql_primary_key_field( domain_class ) + ' = ' +
|
324
|
-
sql_primary_key_field( concrete_classes[i+1] )
|
325
|
-
where_clauses << join_clause
|
326
|
-
else
|
327
|
-
where_clauses << @condition.to_sql if @condition
|
328
|
-
end
|
329
|
-
}
|
345
|
+
where_clauses << @condition.to_sql if @condition
|
330
346
|
!where_clauses.empty? ? 'where ' + where_clauses.join( ' and ' ) : nil
|
331
347
|
end
|
332
348
|
|
@@ -376,32 +392,24 @@ module Lafcadio
|
|
376
392
|
end
|
377
393
|
|
378
394
|
def not; Query::Not.new( self ); end
|
395
|
+
|
396
|
+
def one_pk_id?; self.is_a?( Equals ) and primary_key_field?; end
|
379
397
|
|
380
398
|
def primary_key_field?; 'pk_id' == @fieldName; end
|
381
399
|
|
382
|
-
def query; Query.new( @domain_class, self ); end
|
400
|
+
def query; Query.new( @domain_class, :condition => self ); end
|
383
401
|
|
384
402
|
def to_condition; self; end
|
385
403
|
end
|
386
404
|
|
387
405
|
class Compare < Condition #:nodoc:
|
388
|
-
|
389
|
-
LESS_THAN_OR_EQUAL = 2
|
390
|
-
GREATER_THAN_OR_EQUAL = 3
|
391
|
-
GREATER_THAN = 4
|
392
|
-
|
393
|
-
@@comparators = {
|
394
|
-
LESS_THAN => '<',
|
395
|
-
LESS_THAN_OR_EQUAL => '<=',
|
396
|
-
GREATER_THAN_OR_EQUAL => '>=',
|
397
|
-
GREATER_THAN => '>'
|
398
|
-
}
|
406
|
+
@@comparators = { :lt => '<', :lte => '<=', :gte => '>=', :gt => '>' }
|
399
407
|
|
400
408
|
@@mockComparators = {
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
409
|
+
:lt => Proc.new { |d1, d2| d1 < d2 },
|
410
|
+
:lte => Proc.new { |d1, d2| d1 <= d2 },
|
411
|
+
:gte => Proc.new { |d1, d2| d1 >= d2 },
|
412
|
+
:gt => Proc.new { |d1, d2| d1 > d2 }
|
405
413
|
}
|
406
414
|
|
407
415
|
def initialize(fieldName, searchTerm, domain_class, compareType)
|
@@ -431,15 +439,12 @@ module Lafcadio
|
|
431
439
|
end
|
432
440
|
|
433
441
|
class CompoundCondition < Condition #:nodoc:
|
434
|
-
AND = 1
|
435
|
-
OR = 2
|
436
|
-
|
437
442
|
def initialize( *args )
|
438
|
-
if( [
|
443
|
+
if( [ :and, :or ].include?( args.last ) )
|
439
444
|
@compound_type = args.last
|
440
445
|
args.pop
|
441
446
|
else
|
442
|
-
@compound_type =
|
447
|
+
@compound_type = :and
|
443
448
|
end
|
444
449
|
@conditions = args.map { |arg|
|
445
450
|
arg.respond_to?( :to_condition ) ? arg.to_condition : arg
|
@@ -448,7 +453,7 @@ module Lafcadio
|
|
448
453
|
end
|
449
454
|
|
450
455
|
def dobj_satisfies?(anObj)
|
451
|
-
if @compound_type ==
|
456
|
+
if @compound_type == :and
|
452
457
|
@conditions.inject( true ) { |result, cond|
|
453
458
|
result && cond.dobj_satisfies?( anObj )
|
454
459
|
}
|
@@ -460,25 +465,25 @@ module Lafcadio
|
|
460
465
|
end
|
461
466
|
|
462
467
|
def implied_by?( other_condition )
|
463
|
-
@compound_type ==
|
468
|
+
@compound_type == :or && @conditions.any? { |cond|
|
464
469
|
cond.implies?( other_condition )
|
465
470
|
}
|
466
471
|
end
|
467
472
|
|
468
473
|
def implies?( other_condition )
|
469
474
|
super( other_condition ) or (
|
470
|
-
@compound_type ==
|
475
|
+
@compound_type == :and and @conditions.any? { |cond|
|
471
476
|
cond.implies? other_condition
|
472
477
|
}
|
473
478
|
) or (
|
474
|
-
@compound_type ==
|
479
|
+
@compound_type == :or and @conditions.all? { |cond|
|
475
480
|
cond.implies? other_condition
|
476
481
|
}
|
477
482
|
)
|
478
483
|
end
|
479
484
|
|
480
485
|
def to_sql
|
481
|
-
booleanString = @compound_type ==
|
486
|
+
booleanString = @compound_type == :and ? 'and' : 'or'
|
482
487
|
subSqlStrings = @conditions.collect { |cond| cond.to_sql }
|
483
488
|
"(#{ subSqlStrings.join(" #{ booleanString } ") })"
|
484
489
|
end
|
@@ -500,7 +505,10 @@ module Lafcadio
|
|
500
505
|
if ( classField = self.domain_class.field( fieldName ) )
|
501
506
|
ObjectFieldImpostor.new( self, classField )
|
502
507
|
else
|
503
|
-
|
508
|
+
msg = "undefined method `" + fieldName +
|
509
|
+
"' for #<DomainObjectImpostor::" +
|
510
|
+
'#{ domain_class.name }' + ">"
|
511
|
+
raise( NoMethodError, msg )
|
504
512
|
end
|
505
513
|
end
|
506
514
|
|
@@ -574,16 +582,16 @@ module Lafcadio
|
|
574
582
|
class Include < CompoundCondition #:nodoc:
|
575
583
|
def initialize( field_name, search_term, domain_class )
|
576
584
|
begin_cond = Like.new(
|
577
|
-
field_name, search_term + ',', domain_class,
|
585
|
+
field_name, search_term + ',', domain_class, :post_only
|
578
586
|
)
|
579
587
|
mid_cond = Like.new(
|
580
588
|
field_name, ',' + search_term + ',', domain_class
|
581
589
|
)
|
582
590
|
end_cond = Like.new(
|
583
|
-
field_name, ',' + search_term, domain_class,
|
591
|
+
field_name, ',' + search_term, domain_class, :pre_only
|
584
592
|
)
|
585
593
|
only_cond = Equals.new( field_name, search_term, domain_class )
|
586
|
-
super( begin_cond, mid_cond, end_cond, only_cond,
|
594
|
+
super( begin_cond, mid_cond, end_cond, only_cond, :or )
|
587
595
|
end
|
588
596
|
end
|
589
597
|
|
@@ -593,7 +601,7 @@ module Lafcadio
|
|
593
601
|
unless args.size == 1
|
594
602
|
h = args.last
|
595
603
|
@order_by = h[:order_by]
|
596
|
-
@order_by_order = ( h[:order_by_order] or
|
604
|
+
@order_by_order = ( h[:order_by_order] or :asc )
|
597
605
|
@limit = h[:limit]
|
598
606
|
end
|
599
607
|
end
|
@@ -601,7 +609,7 @@ module Lafcadio
|
|
601
609
|
def execute
|
602
610
|
impostor = DomainObjectImpostor.impostor @domain_class
|
603
611
|
condition = @action.call( impostor ).to_condition
|
604
|
-
query = Query.new( @domain_class, condition )
|
612
|
+
query = Query.new( @domain_class, :condition => condition )
|
605
613
|
query.order_by = @order_by
|
606
614
|
query.order_by_order = @order_by_order
|
607
615
|
query.limit = @limit
|
@@ -610,12 +618,8 @@ module Lafcadio
|
|
610
618
|
end
|
611
619
|
|
612
620
|
class Like < Condition #:nodoc:
|
613
|
-
PRE_AND_POST = 1
|
614
|
-
PRE_ONLY = 2
|
615
|
-
POST_ONLY = 3
|
616
|
-
|
617
621
|
def initialize(
|
618
|
-
fieldName, searchTerm, domain_class, matchType =
|
622
|
+
fieldName, searchTerm, domain_class, matchType = :pre_and_post
|
619
623
|
)
|
620
624
|
if searchTerm.is_a? Regexp
|
621
625
|
searchTerm = process_regexp searchTerm
|
@@ -637,36 +641,37 @@ module Lafcadio
|
|
637
641
|
|
638
642
|
def process_regexp( searchTerm )
|
639
643
|
if searchTerm.source =~ /^\^(.*)/
|
640
|
-
@matchType =
|
644
|
+
@matchType = :post_only
|
641
645
|
$1
|
642
646
|
elsif searchTerm.source =~ /(.*)\$$/
|
643
|
-
@matchType =
|
647
|
+
@matchType = :pre_only
|
644
648
|
$1
|
645
649
|
else
|
646
|
-
@matchType =
|
650
|
+
@matchType = :pre_and_post
|
647
651
|
searchTerm.source
|
648
652
|
end
|
649
653
|
end
|
650
654
|
|
651
655
|
def regexp
|
652
|
-
if @matchType ==
|
656
|
+
if @matchType == :pre_and_post
|
653
657
|
Regexp.new( @searchTerm, Regexp::IGNORECASE )
|
654
|
-
elsif @matchType ==
|
658
|
+
elsif @matchType == :pre_only
|
655
659
|
Regexp.new( @searchTerm.to_s + "$", Regexp::IGNORECASE )
|
656
|
-
elsif @matchType ==
|
660
|
+
elsif @matchType == :post_only
|
657
661
|
Regexp.new( "^" + @searchTerm, Regexp::IGNORECASE )
|
658
662
|
end
|
659
663
|
end
|
660
664
|
|
661
665
|
def to_sql
|
662
|
-
withWildcards = @searchTerm
|
663
|
-
if @matchType ==
|
666
|
+
withWildcards = @searchTerm.clone
|
667
|
+
if @matchType == :pre_and_post
|
664
668
|
withWildcards = "%" + withWildcards + "%"
|
665
|
-
elsif @matchType ==
|
669
|
+
elsif @matchType == :pre_only
|
666
670
|
withWildcards = "%" + withWildcards
|
667
|
-
elsif @matchType ==
|
671
|
+
elsif @matchType == :post_only
|
668
672
|
withWildcards += "%"
|
669
673
|
end
|
674
|
+
withWildcards.gsub!( /(\\?\.)/ ) { |m| m.size == 1 ? "_" : "." }
|
670
675
|
"#{ db_field_name } like '#{ withWildcards }'"
|
671
676
|
end
|
672
677
|
end
|
@@ -712,11 +717,7 @@ module Lafcadio
|
|
712
717
|
|
713
718
|
class ObjectFieldImpostor #:nodoc:
|
714
719
|
def self.comparators
|
715
|
-
{
|
716
|
-
'lt' => Compare::LESS_THAN, 'lte' => Compare::LESS_THAN_OR_EQUAL,
|
717
|
-
'gte' => Compare::GREATER_THAN_OR_EQUAL,
|
718
|
-
'gt' => Compare::GREATER_THAN
|
719
|
-
}
|
720
|
+
{ 'lt' => :lt, 'lte' => :lte, 'gte' => :gte, 'gt' => :gt }
|
720
721
|
end
|
721
722
|
|
722
723
|
attr_reader :class_field
|