rhubarb 0.2.4 → 0.2.5

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,9 @@
1
+ version 0.2.5
2
+
3
+ * Prepared statements are now optional to eliminate a strange bug
4
+ that appears in some environments. If you experience unusual table
5
+ locking errors, try running without prepared statements.
6
+
1
7
  version 0.2.4
2
8
 
3
9
  * More aggressive use of prepared statements, which should result
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.4
1
+ 0.2.5
@@ -49,28 +49,24 @@ module Rhubarb
49
49
  alias find_by_id find
50
50
 
51
51
  def find_by(arg_hash)
52
+ results = []
52
53
  arg_hash = arg_hash.dup
53
54
  valid_cols = self.colnames.intersection arg_hash.keys
54
55
  select_criteria = valid_cols.map {|col| "#{col.to_s} = #{col.inspect}"}.join(" AND ")
55
56
  arg_hash.each {|k,v| arg_hash[k] = v.row_id if v.respond_to? :row_id}
56
- find_by_text = "select * from #{table_name} where #{select_criteria} order by row_id"
57
- find_by_stmt = (db.stmts[find_by_text] ||= db.prepare(find_by_text))
58
- find_by_stmt.execute!(arg_hash).map {|tup| self.new(tup) }
57
+ db.do_query("select * from #{table_name} where #{select_criteria} order by row_id", arg_hash) {|tup| results << self.new(tup) }
58
+ results
59
59
  end
60
60
 
61
61
  # Does what it says on the tin. Since this will allocate an object for each row, it isn't recomended for huge tables.
62
62
  def find_all
63
63
  results = []
64
- find_all_text = "SELECT * from #{table_name}"
65
- find_all_stmt = (db.stmts[find_all_text] ||= db.prepare(find_all_text))
66
- find_all_stmt.execute! {|tup| results << self.new(tup)}
64
+ db.do_query("SELECT * from #{table_name}") {|tup| results << self.new(tup)}
67
65
  results
68
66
  end
69
67
 
70
68
  def delete_all
71
- da_text = "DELETE from #{table_name}"
72
- da_stmt = (db.stmts[da_text] ||= db.prepare(da_text))
73
- da_stmt.execute!
69
+ db.do_query("DELETE from #{table_name}")
74
70
  end
75
71
 
76
72
  def delete_where(arg_hash)
@@ -78,9 +74,7 @@ module Rhubarb
78
74
  valid_cols = self.colnames.intersection arg_hash.keys
79
75
  select_criteria = valid_cols.map {|col| "#{col.to_s} = #{col.inspect}"}.join(" AND ")
80
76
  arg_hash.each {|k,v| arg_hash[k] = v.row_id if v.respond_to? :row_id}
81
- dw_text = "DELETE FROM #{table_name} WHERE #{select_criteria}"
82
- dw_stmt = (db.stmts[dw_text] ||= db.prepare(dw_text))
83
- dw_stmt.execute!(arg_hash)
77
+ db.do_query("DELETE FROM #{table_name} WHERE #{select_criteria}", arg_hash)
84
78
  end
85
79
 
86
80
  # Declares a query method named +name+ and adds it to this class. The query method returns a list of objects corresponding to the rows returned by executing "+SELECT * FROM+ _table_ +WHERE+ _query_" on the database.
@@ -91,15 +85,16 @@ module Rhubarb
91
85
  # Declares a custom query method named +name+, and adds it to this class. The custom query method returns a list of objects corresponding to the rows returned by executing +query+ on the database. +query+ should select all fields (with +SELECT *+). If +query+ includes the string +\_\_TABLE\_\_+, it will be expanded to the table name. Typically, you will want to use +declare\_query+ instead; this method is most useful for self-joins.
92
86
  def declare_custom_query(name, query)
93
87
  klass = (class << self; self end)
88
+ processed_query = query.gsub("__TABLE__", "#{self.table_name}")
89
+
94
90
  klass.class_eval do
95
91
  define_method name.to_s do |*args|
96
92
  # handle reference parameters
97
93
  args = args.map {|arg| Util::rhubarb_fk_identity(arg)}
98
- cq_text = query.gsub("__TABLE__", "#{self.table_name}")
99
- cq_stmt = (db.stmts[cq_text] ||= db.prepare(cq_text))
100
94
 
101
- res = cq_stmt.execute!(args)
102
- res.map {|row| self.new(row) }
95
+ results = []
96
+ db.do_query(processed_query, args) {|tup| results << self.new(tup)}
97
+ results
103
98
  end
104
99
  end
105
100
  end
@@ -136,15 +131,14 @@ module Rhubarb
136
131
  klass = (class << self; self end)
137
132
  klass.class_eval do
138
133
  define_method find_method_name do |arg|
139
- fq_stmt = (self.db.stmts[find_query] ||= db.prepare(find_query))
140
- res = fq_stmt.execute!(arg)
141
- res.map {|row| self.new(row)}
134
+ results = []
135
+ db.do_query(find_query, arg) {|row| results << self.new(row)}
136
+ results
142
137
  end
143
138
 
144
139
  define_method find_first_method_name do |arg|
145
- fq_stmt = (self.db.stmts[find_query] ||= db.prepare(find_query))
146
140
  result = nil
147
- fq_stmt.execute!(arg) {|row| result = self.new(row) ; break }
141
+ db.do_query(find_query, arg) {|row| result = self.new(row) ; break }
148
142
  result
149
143
  end
150
144
  end
@@ -235,8 +229,8 @@ module Rhubarb
235
229
  end
236
230
 
237
231
  create_text = "insert into #{table_name} (#{colspec}) values (#{valspec})"
238
- create_stmt = (self.db.stmts[create_text] ||= db.prepare(create_text))
239
- create_stmt.execute!(new_row)
232
+ db.do_query(create_text, new_row)
233
+
240
234
  res = find(db.last_insert_row_id)
241
235
 
242
236
  res
@@ -297,8 +291,9 @@ module Rhubarb
297
291
 
298
292
  def find_tuple(tid)
299
293
  ft_text = "select * from #{table_name} where row_id = ?"
300
- ft_stmt = (self.db.stmts[ft_text] ||= db.prepare(ft_text))
301
- return ft_stmt.execute!(tid)[0]
294
+ result = nil
295
+ db.do_query(ft_text, tid) {|tup| result = tup; break}
296
+ result
302
297
  end
303
298
 
304
299
  include FindFreshest
@@ -10,10 +10,29 @@
10
10
  #
11
11
  # http://www.apache.org/licenses/LICENSE-2.0
12
12
 
13
- module Rhubarb
13
+ module Rhubarb
14
+
14
15
  module Persistence
16
+ module UsePreparedStatements
17
+ def do_query(stmt, *args, &blk)
18
+ the_stmt = (self.stmts[stmt] ||= self.prepare(stmt))
19
+ the_stmt.execute!(args, &blk)
20
+ end
21
+ end
22
+
23
+ module EschewPreparedStatements
24
+ def do_query(stmt, *args, &blk)
25
+ execute(stmt, args, &blk)
26
+ end
27
+ end
28
+
15
29
  class DbCollection < Hash
16
30
  alias orig_set []=
31
+ attr_accessor :use_prepared_stmts
32
+
33
+ def initialize
34
+ self.use_prepared_stmts = true
35
+ end
17
36
 
18
37
  def []=(key,db)
19
38
  setup_db(db) if db
@@ -31,12 +50,23 @@ module Rhubarb
31
50
  @rhubarb_stmts
32
51
  end
33
52
  end
53
+
54
+ if @use_prepared_stmts
55
+ class << db
56
+ include UsePreparedStatements
57
+ end
58
+ else
59
+ class << db
60
+ include EschewPreparedStatements
61
+ end
62
+ end
34
63
  end
35
64
  end
36
65
 
37
66
  @dbs = DbCollection.new
38
67
 
39
- def self.open(filename, which=:default)
68
+ def self.open(filename, which=:default, usePrepared=true)
69
+ dbs.use_prepared_stmts = usePrepared
40
70
  dbs[which] = SQLite3::Database.new(filename)
41
71
  end
42
72
 
@@ -62,9 +62,7 @@ module Rhubarb
62
62
  # Deletes the row corresponding to this object from the database;
63
63
  # invalidates =self= and any other objects backed by this row
64
64
  def delete
65
- delete_text = "delete from #{self.class.table_name} where row_id = ?"
66
- delete_stmt = (self.db.stmts[delete_text] ||= self.db.prepare(delete_text))
67
- delete_stmt.execute!(@row_id)
65
+ db.do_query("delete from #{self.class.table_name} where row_id = ?", @row_id)
68
66
  mark_dirty
69
67
  @tuple = nil
70
68
  @row_id = nil
@@ -121,9 +119,7 @@ module Rhubarb
121
119
  def update(attr_name, value)
122
120
  mark_dirty
123
121
 
124
- update_text = "update #{self.class.table_name} set #{attr_name} = ?, updated = ? where row_id = ?"
125
- update_stmt = (self.db.stmts[update_text] ||= self.db.prepare(update_text))
126
- update_stmt.execute!(value, Util::timestamp, @row_id)
122
+ db.do_query("update #{self.class.table_name} set #{attr_name} = ?, updated = ? where row_id = ?", value, Util::timestamp, @row_id)
127
123
  end
128
124
 
129
125
  # Resolve any fields that reference other tables, replacing row ids with referred objects
data/ruby-rhubarb.spec.in CHANGED
@@ -48,11 +48,17 @@ rm -rf %{buildroot}
48
48
  %{ruby_sitelib}/rhubarb/persistence.rb
49
49
 
50
50
  %changelog
51
+ * Wed Apr 14 2010 willb <willb@redhat> - 0.2.5-1.0
52
+ - Updated to version 0.2.5
53
+
54
+ * Wed Apr 7 2010 willb <willb@redhat> - 0.2.4-1.0
55
+ - Updated to version 0.2.4
56
+
51
57
  * Thu Feb 25 2010 willb <willb@redhat> - 0.2.3-1.0
52
- * updated to version 0.2.3 from source
58
+ - updated to version 0.2.3 from source
53
59
 
54
60
  * Thu Feb 25 2010 willb <willb@redhat> - 0.2.2-2.0
55
- * removed rubygems include
61
+ - removed rubygems include
56
62
 
57
63
  * Fri Feb 5 2010 <rrat@redhat> - 0.2.0-0.3
58
64
  - Explicitly list files
data/test/test_rhubarb.rb CHANGED
@@ -12,6 +12,7 @@
12
12
  # http://www.apache.org/licenses/LICENSE-2.0
13
13
 
14
14
  require 'helper'
15
+ require 'fileutils'
15
16
 
16
17
  class TestClass
17
18
  include Rhubarb::Persisting
@@ -92,9 +93,21 @@ class BlobTestTable
92
93
  declare_column :info, :blob
93
94
  end
94
95
 
95
- class BackendBasicTests < Test::Unit::TestCase
96
+ class PreparedStmtBackendTests < Test::Unit::TestCase
97
+ def dbfile
98
+ ENV['RHUBARB_TEST_DB'] || ":memory:"
99
+ end
100
+
101
+ def use_prepared
102
+ true
103
+ end
104
+
96
105
  def setup
97
- Rhubarb::Persistence::open(":memory:")
106
+ unless dbfile == ":memory:"
107
+ FileUtils::safe_unlink(dbfile)
108
+ end
109
+
110
+ Rhubarb::Persistence::open(dbfile, :default, use_prepared)
98
111
  klasses = []
99
112
  klasses << TestClass
100
113
  klasses << TestClass2
@@ -216,6 +229,13 @@ class BackendBasicTests < Test::Unit::TestCase
216
229
  end
217
230
  end
218
231
 
232
+ def test_delete_all
233
+ freshness_query_fixture
234
+ assert(FreshTestTable.find_all.size > 0)
235
+ FreshTestTable.delete_all
236
+ assert_equal([], FreshTestTable.find_all)
237
+ end
238
+
219
239
  def test_class_methods
220
240
  ["foo", "bar"].each do |prefix|
221
241
  ["find_by_#{prefix}", "find_first_by_#{prefix}"].each do |m|
@@ -711,3 +731,9 @@ class BackendBasicTests < Test::Unit::TestCase
711
731
  end
712
732
 
713
733
  end
734
+
735
+ class NoPreparedStmtBackendTests < PreparedStmtBackendTests
736
+ def use_prepared
737
+ false
738
+ end
739
+ end
metadata CHANGED
@@ -1,12 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhubarb
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 2
8
- - 4
9
- version: 0.2.4
4
+ version: 0.2.5
10
5
  platform: ruby
11
6
  authors:
12
7
  - William Benton
@@ -14,37 +9,29 @@ autorequire:
14
9
  bindir: bin
15
10
  cert_chain: []
16
11
 
17
- date: 2010-03-23 00:00:00 -05:00
12
+ date: 2010-04-20 00:00:00 -05:00
18
13
  default_executable:
19
14
  dependencies:
20
15
  - !ruby/object:Gem::Dependency
21
16
  name: rspec
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
24
20
  requirements:
25
21
  - - ">="
26
22
  - !ruby/object:Gem::Version
27
- segments:
28
- - 1
29
- - 2
30
- - 9
31
23
  version: 1.2.9
32
- type: :development
33
- version_requirements: *id001
24
+ version:
34
25
  - !ruby/object:Gem::Dependency
35
26
  name: sqlite3-ruby
36
- prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
38
30
  requirements:
39
31
  - - ">="
40
32
  - !ruby/object:Gem::Version
41
- segments:
42
- - 1
43
- - 2
44
- - 2
45
33
  version: 1.2.2
46
- type: :runtime
47
- version_requirements: *id002
34
+ version:
48
35
  description: Rhubarb is a simple object-graph persistence library implemented as a mixin. It also works with the SPQR library for straightforward object publishing over QMF.
49
36
  email: willb@redhat.com
50
37
  executables: []
@@ -88,20 +75,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
75
  requirements:
89
76
  - - ">="
90
77
  - !ruby/object:Gem::Version
91
- segments:
92
- - 0
93
78
  version: "0"
79
+ version:
94
80
  required_rubygems_version: !ruby/object:Gem::Requirement
95
81
  requirements:
96
82
  - - ">="
97
83
  - !ruby/object:Gem::Version
98
- segments:
99
- - 0
100
84
  version: "0"
85
+ version:
101
86
  requirements: []
102
87
 
103
88
  rubyforge_project:
104
- rubygems_version: 1.3.6
89
+ rubygems_version: 1.3.5
105
90
  signing_key:
106
91
  specification_version: 3
107
92
  summary: "Rhubarb: object graph persistence, easy as pie"