rhubarb 0.2.6 → 0.2.7

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/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