rhubarb 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,8 @@
1
+ version 0.2.7
2
+
3
+ * Fix for reference-valued hash-style positional parameters in
4
+ custom queries. Fix for Red Hat BZ 618493.
5
+
1
6
  version 0.2.6
2
7
 
3
8
  * Rhubarb now supports starting arbitrary Ruby objects to fields
data/Rakefile CHANGED
@@ -109,6 +109,7 @@ end
109
109
  Spec::Rake::SpecTask.new(:rcov) do |spec|
110
110
  spec.libs << 'lib' << 'spec'
111
111
  spec.pattern = 'spec/**/*_spec.rb'
112
+ spec.rcov_opts << "-x" << "/usr/lib" << "-x" << ".gem"
112
113
  spec.rcov = true
113
114
  end
114
115
 
@@ -127,6 +128,7 @@ begin
127
128
  Rcov::RcovTask.new do |test|
128
129
  test.libs << 'test'
129
130
  test.pattern = 'test/**/test_*.rb'
131
+ test.rcov_opts << "-x" << "/usr/lib" << "-x" << ".gem"
130
132
  test.verbose = true
131
133
  end
132
134
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.6
1
+ 0.2.7
@@ -55,7 +55,7 @@ module Rhubarb
55
55
  arg_hash = arg_hash.dup
56
56
  valid_cols = self.colnames.intersection arg_hash.keys
57
57
  select_criteria = valid_cols.map {|col| "#{col.to_s} = #{col.inspect}"}.join(" AND ")
58
- arg_hash.each {|k,v| arg_hash[k] = v.row_id if v.respond_to? :row_id}
58
+ arg_hash.each {|key,val| arg_hash[key] = val.row_id if val.respond_to? :row_id}
59
59
  db.do_query("select * from #{table_name} where #{select_criteria} order by row_id", arg_hash) {|tup| results << self.new(tup) }
60
60
  results
61
61
  end
@@ -75,7 +75,7 @@ module Rhubarb
75
75
  arg_hash = arg_hash.dup
76
76
  valid_cols = self.colnames.intersection arg_hash.keys
77
77
  select_criteria = valid_cols.map {|col| "#{col.to_s} = #{col.inspect}"}.join(" AND ")
78
- arg_hash.each {|k,v| arg_hash[k] = v.row_id if v.respond_to? :row_id}
78
+ arg_hash.each {|key,val| arg_hash[key] = val.row_id if val.respond_to? :row_id}
79
79
  db.do_query("DELETE FROM #{table_name} WHERE #{select_criteria}", arg_hash)
80
80
  end
81
81
 
@@ -92,7 +92,16 @@ module Rhubarb
92
92
  klass.class_eval do
93
93
  define_method name.to_s do |*args|
94
94
  # handle reference parameters
95
- args = args.map {|arg| Util::rhubarb_fk_identity(arg)}
95
+ if args.size == 1 && args[0].is_a?(Hash)
96
+ args[0].each do |k,v|
97
+ args[0][k] = Util::rhubarb_fk_identity(v)
98
+ end
99
+ else
100
+ args = args.map do |arg|
101
+ raise RuntimeError.new("Hash-valued positional parameters may only appear as named positional parameters.") if arg.is_a?(Hash)
102
+ Util::rhubarb_fk_identity(arg)
103
+ end
104
+ end
96
105
 
97
106
  results = []
98
107
  db.do_query(processed_query, args) {|tup| results << self.new(tup)}
@@ -124,7 +133,7 @@ module Rhubarb
124
133
  set_method_name = "#{cname}=".to_sym
125
134
 
126
135
  # does this column reference another table?
127
- rf = quals.find {|q| q.class == Reference}
136
+ rf = quals.find {|qual| qual.class == Reference}
128
137
  if rf
129
138
  self.refs[cname] = rf
130
139
  end
@@ -154,7 +163,8 @@ module Rhubarb
154
163
  define_method get_method_name do
155
164
  freshen
156
165
  return nil unless @tuple
157
- out_xform ? out_xform.call(@tuple[cname.to_s]) : @tuple[cname.to_s]
166
+ result = @tuple[cname.to_s]
167
+ out_xform ? out_xform.call(result) : result
158
168
  end
159
169
 
160
170
  if not rf
@@ -39,24 +39,22 @@ module Rhubarb
39
39
  group_by_clause = "GROUP BY " + args[:group_by].join(", ")
40
40
  where_clause = "WHERE " + select_clauses.join(" AND ")
41
41
  projection = self.colnames - [:created]
42
- join_clause = projection.map do |column|
42
+ join_criteria = projection.map do |column|
43
43
  "__fresh.#{column} = __freshest.#{column}"
44
44
  end
45
45
 
46
46
  projection << "MAX(created) AS __current_version"
47
- join_clause << "__fresh.__current_version = __freshest.created"
47
+ join_criteria << "__fresh.__current_version = __freshest.created"
48
48
 
49
+ join_clause = join_criteria.join(' AND ')
50
+
49
51
  query = "
50
52
  SELECT __freshest.* FROM (
51
53
  SELECT #{projection.to_a.join(', ')} FROM (
52
54
  SELECT * from #{table_name} #{where_clause}
53
55
  ) #{group_by_clause}
54
- ) as __fresh INNER JOIN #{table_name} as __freshest ON
55
- #{join_clause.join(' AND ')}
56
- ORDER BY row_id
57
- "
58
-
56
+ ) as __fresh INNER JOIN #{table_name} as __freshest ON #{join_clause} ORDER BY row_id"
59
57
  self.db.execute(query, query_params).map {|tup| self.new(tup) }
60
58
  end
61
59
  end
62
- end
60
+ end
data/lib/rhubarb/util.rb CHANGED
@@ -27,43 +27,35 @@ module Rhubarb
27
27
  (object.row_id if object.class.ancestors.include? Persisting) || object
28
28
  end
29
29
 
30
- def self.blobify(obj)
31
- blobify_proc.call(obj)
32
- end
33
-
34
30
  def self.blobify_proc
35
- @blobify_proc ||= Proc.new {|x| x.is_a?(SQLite3::Blob) ? x : SQLite3::Blob.new(x)}
31
+ @blobify_proc ||= Proc.new {|obj| obj.is_a?(SQLite3::Blob) ? obj : SQLite3::Blob.new(obj)}
36
32
  end
37
33
 
38
34
  def self.zblobify_proc
39
- @zblobify_proc ||= Proc.new {|x| x.is_a?(SQLite3::Blob) ? x : SQLite3::Blob.new(Zlib::Deflate.deflate(x))}
35
+ @zblobify_proc ||= Proc.new {|obj| obj.is_a?(SQLite3::Blob) ? obj : SQLite3::Blob.new(Zlib::Deflate.deflate(obj))}
40
36
  end
41
37
 
42
38
  def self.dezblobify_proc
43
- @dezblobify_proc ||= Proc.new do |x|
44
- return nil if x.nil? || x == ""
45
- Zlib::Inflate.inflate(x)
39
+ @dezblobify_proc ||= Proc.new do |obj|
40
+ return nil if obj.nil? || obj == ""
41
+ Zlib::Inflate.inflate(obj)
46
42
  end
47
43
  end
48
44
 
49
45
  def self.swizzle_object_proc
50
- @swizzle_object_proc ||= Proc.new do |x|
51
- yamlrepr = x.to_yaml
46
+ @swizzle_object_proc ||= Proc.new do |obj|
47
+ yamlrepr = obj.to_yaml
52
48
  SQLite3::Blob.new(Zlib::Deflate.deflate(yamlrepr, Zlib::BEST_COMPRESSION))
53
49
  end
54
50
  end
55
51
 
56
52
  def self.deswizzle_object_proc
57
- @deswizzle_object_proc ||= Proc.new do |x|
58
- return nil if x.nil? || x == ""
53
+ @deswizzle_object_proc ||= Proc.new do |zy_obj|
54
+ return nil if zy_obj.nil? || zy_obj == ""
59
55
 
60
- z = YAML.load(Zlib::Inflate.inflate(x))
61
- z.freeze
56
+ obj = YAML.load(Zlib::Inflate.inflate(zy_obj))
57
+ obj.freeze
62
58
  end
63
59
  end
64
-
65
- def self.identity_proc
66
- @identity ||= Proc.new {|x| x}
67
- end
68
60
  end
69
61
  end
data/test/test_rhubarb.rb CHANGED
@@ -78,9 +78,11 @@ class ToRef
78
78
  declare_column :foo, :string
79
79
  end
80
80
 
81
- class FromRef
81
+ class FromRef
82
82
  include Rhubarb::Persisting
83
83
  declare_column :t, :integer, references(ToRef, :on_delete=>:cascade)
84
+ declare_query :to_is, "t = ?"
85
+ declare_query :to_is_hash, "t = :t"
84
86
  end
85
87
 
86
88
  class FreshTestTable
@@ -89,6 +91,16 @@ class FreshTestTable
89
91
  declare_column :fie, :integer
90
92
  declare_column :foe, :integer
91
93
  declare_column :fum, :integer
94
+ declare_column :foo, :integer
95
+ declare_column :bar, :integer
96
+
97
+ def <=>(other)
98
+ [:fie,:foe,:fum,:foo,:bar].each do |msg|
99
+ tmpresult = self.send(msg) <=> other.send(msg)
100
+ return tmpresult unless tmpresult == 0
101
+ end
102
+ return 0
103
+ end
92
104
  end
93
105
 
94
106
  class BlobTestTable
@@ -641,6 +653,10 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
641
653
  assert_equal(tc1, tc1) # equality is reflexive
642
654
  assert_equal(tc1p, tc1) # even after find operations
643
655
  assert_equal(tc1, tc1p) # ... and it should be symmetric
656
+
657
+ assert_equal(tc1.hash, tc1p.hash)
658
+ assert_not_equal(tc2.hash, tc1p.hash)
659
+
644
660
  assert_not_equal(tc1, tc2) # these are not identical
645
661
  assert_not_equal(tc1p, tc2) # even after find operations
646
662
  assert_not_equal(tc2, tc1p) # ... and it should be symmetric
@@ -653,10 +669,29 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
653
669
 
654
670
  def freshness_query_fixture
655
671
  @flist = []
656
-
657
- 0.upto(99) do |x|
658
- @flist << FreshTestTable.create(:fee=>x, :fie=>(x%7), :foe=>(x%11), :fum=>(x%13))
672
+ @fresh_fields = [:fee,:fie,:foe,:fum,:foo,:bar,:created,:updated,:row_id]
673
+ @ffcounts = {:fie=>2, :foe=>3, :fum=>4, :foo=>5, :bar=>6}
674
+
675
+ x = 0
676
+
677
+ 2.times do
678
+ @ffcounts[:fie].times do |fie|
679
+ @ffcounts[:foe].times do |foe|
680
+ @ffcounts[:fum].times do |fum|
681
+ @ffcounts[:foo].times do |foo|
682
+ @ffcounts[:bar].times do |bar|
683
+ row = FreshTestTable.create(:fee=>@flist.size, :fie=>fie, :foe=>foe, :fum=>fum, :foo=>foo, :bar=>bar)
684
+ assert(row != nil)
685
+ @flist << row
686
+ end
687
+ end
688
+ end
689
+ end
690
+ end
659
691
  end
692
+
693
+ @fcount = @flist.size
694
+ @ffcounts[:fee] = @fcount
660
695
  end
661
696
 
662
697
  def test_freshness_query_basic
@@ -665,8 +700,8 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
665
700
  basic = FreshTestTable.find_freshest(:group_by=>[:fee])
666
701
 
667
702
  assert_equal(@flist.size, basic.size)
668
- 0.upto(99) do |x|
669
- [:fee,:fie,:foe,:fum,:created,:updated,:row_id].each do |msg|
703
+ 0.upto(@fcount - 1) do |x|
704
+ @fresh_fields.each do |msg|
670
705
  assert_equal(@flist[x].send(msg), basic[x].send(msg))
671
706
  end
672
707
  end
@@ -680,7 +715,7 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
680
715
 
681
716
  assert_equal(31, basic.size)
682
717
  0.upto(30) do |x|
683
- [:fee,:fie,:foe,:fum,:created,:updated,:row_id].each do |msg|
718
+ @fresh_fields.each do |msg|
684
719
  assert_equal(@flist[x].send(msg), basic[x].send(msg))
685
720
  end
686
721
  end
@@ -690,15 +725,18 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
690
725
  freshness_query_fixture
691
726
  # basic test
692
727
 
693
- basic = FreshTestTable.find_freshest(:group_by=>[:fee], :select_by=>{:fie=>0}, :debug=>true)
728
+ ffc = @ffcounts[:fie]
694
729
 
695
- expected_ct = 99/7 + 1;
730
+ basic = FreshTestTable.find_freshest(:group_by=>[:fee], :select_by=>{:fie=>0}, :debug=>true).sort_by {|x| x.fee}
731
+
732
+ expected_ct = @fcount/ffc
733
+ expected_rows = @flist.select{|tup| tup.fie == 0}.sort_by{|tup| tup.fee}
696
734
 
697
735
  assert_equal(expected_ct, basic.size)
698
736
 
699
737
  0.upto(expected_ct - 1) do |x|
700
- [:fee,:fie,:foe,:fum,:created,:updated,:row_id].each do |msg|
701
- assert_equal(@flist[x*7].send(msg), basic[x].send(msg))
738
+ @fresh_fields.each do |msg|
739
+ assert_equal(expected_rows[x].send(msg), basic[x].send(msg))
702
740
  end
703
741
  end
704
742
  end
@@ -706,26 +744,56 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
706
744
  def test_freshness_query_group_single
707
745
  freshness_query_fixture
708
746
  # more basic tests
709
- pairs = {:fie=>7,:foe=>11,:fum=>13}
747
+ pairs = @ffcounts.dup
748
+ pairs.delete(:fee)
749
+
710
750
  pairs.each do |col,ct|
711
751
  basic = FreshTestTable.find_freshest(:group_by=>[col])
712
752
  assert_equal(ct,basic.size)
713
753
 
714
754
  expected_objs = {}
715
755
 
716
- 99.downto(99-ct+1) do |x|
717
- expected_objs[x%ct] = @flist[x]
756
+ needed_vals = Set[*(0..ct).to_a]
757
+
758
+ @flist.reverse_each do |row|
759
+ break if needed_vals.empty?
760
+
761
+ colval = row.send(col)
762
+ if needed_vals.include? colval
763
+ expected_objs[colval] = row
764
+ needed_vals.delete(colval)
765
+ end
718
766
  end
719
767
 
720
768
  basic.each do |row|
721
769
  res = expected_objs[row.send(col)]
722
- [:fee,:fie,:foe,:fum,:created,:updated,:row_id].each do |msg|
770
+ puts expected_objs.keys.inspect if res.nil?
771
+ @fresh_fields.each do |msg|
723
772
  assert_equal(res.send(msg), row.send(msg))
724
773
  end
725
774
  end
726
775
  end
727
776
  end
728
777
 
778
+ def test_freshness_query_group_powerset
779
+ freshness_query_fixture
780
+ # more basic tests
781
+
782
+ pairs = @ffcounts.dup
783
+ pairs.delete(:fee)
784
+ pairs_powerset = pairs.to_a.inject([[]]){|c,y|r=[];c.each{|i|r<<i;r<<i+[y]};r}.map {|h| h.transpose}
785
+ pairs_powerset.shift
786
+
787
+ pairs_powerset.each do |cols,cts|
788
+ expected_ct = cts.inject(1){|x,acc| acc * x}
789
+ basic = FreshTestTable.find_freshest(:group_by=>cols)
790
+
791
+ assert_equal(expected_ct,basic.size)
792
+
793
+ # XXX: test identities, too
794
+ end
795
+ end
796
+
729
797
  def test_blob_data
730
798
  words = %w{the quick brown fox jumps over a lazy dog now is time for all good men to come aid party jackdaws love my big sphinx of quartz}
731
799
  text = ""
@@ -799,6 +867,25 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
799
867
  assert_equal thing, ott.obj
800
868
  end
801
869
  end
870
+
871
+ [true, false].each do |create_uses_rowid|
872
+ [true, false].each do |lookup_uses_rowid|
873
+ [true, false].each do |to_is_hash|
874
+
875
+ define_method("test_reference_params_in_#{to_is_hash ? "hashed_" : ""}custom_queries_#{create_uses_rowid ? "createUsesRowID" : "createUsesObject"}_#{lookup_uses_rowid ? "lookupUsesRowID" : "lookupUsesObject"}".to_sym) do
876
+ to_refs = %w{foo bar blah}.map {|s| ToRef.create(:foo=>s)}
877
+ to_refs.each {}
878
+ to_refs.each {|tr| FromRef.create(:t=>create_uses_rowid ? tr.row_id : tr)}
879
+
880
+ to_refs.each do |tr|
881
+ frs = to_is_hash ? FromRef.to_is_hash(:t=>lookup_uses_rowid ? tr.row_id : tr) : FromRef.to_is(lookup_uses_rowid ? tr.row_id : tr)
882
+ assert_equal frs.size, 1
883
+ assert_equal frs[0].t, tr
884
+ end
885
+ end
886
+ end
887
+ end
888
+ end
802
889
  end
803
890
 
804
891
  class NoPreparedStmtBackendTests < PreparedStmtBackendTests
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhubarb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Benton
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-04-28 00:00:00 -05:00
12
+ date: 2010-08-31 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency