amalgalite 0.10.1-x86-mingw32

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.
Files changed (100) hide show
  1. data/HISTORY +201 -0
  2. data/LICENSE +29 -0
  3. data/README +51 -0
  4. data/bin/amalgalite-pack +126 -0
  5. data/examples/a.rb +9 -0
  6. data/examples/blob.rb +88 -0
  7. data/examples/bootstrap.rb +36 -0
  8. data/examples/define_aggregate.rb +75 -0
  9. data/examples/define_function.rb +104 -0
  10. data/examples/gem-db.rb +94 -0
  11. data/examples/gems.db +0 -0
  12. data/examples/require_me.rb +11 -0
  13. data/examples/requires.rb +42 -0
  14. data/examples/schema-info.rb +34 -0
  15. data/ext/amalgalite/amalgalite3.c +290 -0
  16. data/ext/amalgalite/amalgalite3.h +151 -0
  17. data/ext/amalgalite/amalgalite3_blob.c +240 -0
  18. data/ext/amalgalite/amalgalite3_constants.c +221 -0
  19. data/ext/amalgalite/amalgalite3_database.c +1148 -0
  20. data/ext/amalgalite/amalgalite3_requires_bootstrap.c +210 -0
  21. data/ext/amalgalite/amalgalite3_statement.c +639 -0
  22. data/ext/amalgalite/extconf.rb +36 -0
  23. data/ext/amalgalite/gen_constants.rb +130 -0
  24. data/ext/amalgalite/sqlite3.c +106729 -0
  25. data/ext/amalgalite/sqlite3.h +5626 -0
  26. data/ext/amalgalite/sqlite3_options.h +4 -0
  27. data/ext/amalgalite/sqlite3ext.h +380 -0
  28. data/gemspec.rb +60 -0
  29. data/lib/amalgalite.rb +43 -0
  30. data/lib/amalgalite/1.8/amalgalite3.so +0 -0
  31. data/lib/amalgalite/1.9/amalgalite3.so +0 -0
  32. data/lib/amalgalite/aggregate.rb +67 -0
  33. data/lib/amalgalite/blob.rb +186 -0
  34. data/lib/amalgalite/boolean.rb +42 -0
  35. data/lib/amalgalite/busy_timeout.rb +47 -0
  36. data/lib/amalgalite/column.rb +97 -0
  37. data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
  38. data/lib/amalgalite/database.rb +947 -0
  39. data/lib/amalgalite/function.rb +61 -0
  40. data/lib/amalgalite/index.rb +43 -0
  41. data/lib/amalgalite/packer.rb +226 -0
  42. data/lib/amalgalite/paths.rb +70 -0
  43. data/lib/amalgalite/profile_tap.rb +131 -0
  44. data/lib/amalgalite/progress_handler.rb +21 -0
  45. data/lib/amalgalite/requires.rb +120 -0
  46. data/lib/amalgalite/schema.rb +191 -0
  47. data/lib/amalgalite/sqlite3.rb +6 -0
  48. data/lib/amalgalite/sqlite3/constants.rb +80 -0
  49. data/lib/amalgalite/sqlite3/database/function.rb +48 -0
  50. data/lib/amalgalite/sqlite3/database/status.rb +68 -0
  51. data/lib/amalgalite/sqlite3/status.rb +60 -0
  52. data/lib/amalgalite/sqlite3/version.rb +37 -0
  53. data/lib/amalgalite/statement.rb +414 -0
  54. data/lib/amalgalite/table.rb +90 -0
  55. data/lib/amalgalite/taps.rb +2 -0
  56. data/lib/amalgalite/taps/console.rb +27 -0
  57. data/lib/amalgalite/taps/io.rb +71 -0
  58. data/lib/amalgalite/trace_tap.rb +35 -0
  59. data/lib/amalgalite/type_map.rb +63 -0
  60. data/lib/amalgalite/type_maps/default_map.rb +167 -0
  61. data/lib/amalgalite/type_maps/storage_map.rb +40 -0
  62. data/lib/amalgalite/type_maps/text_map.rb +22 -0
  63. data/lib/amalgalite/version.rb +37 -0
  64. data/lib/amalgalite/view.rb +26 -0
  65. data/spec/aggregate_spec.rb +169 -0
  66. data/spec/amalgalite_spec.rb +4 -0
  67. data/spec/blob_spec.rb +81 -0
  68. data/spec/boolean_spec.rb +23 -0
  69. data/spec/busy_handler.rb +165 -0
  70. data/spec/database_spec.rb +494 -0
  71. data/spec/default_map_spec.rb +87 -0
  72. data/spec/function_spec.rb +94 -0
  73. data/spec/integeration_spec.rb +111 -0
  74. data/spec/packer_spec.rb +60 -0
  75. data/spec/paths_spec.rb +28 -0
  76. data/spec/progress_handler_spec.rb +105 -0
  77. data/spec/requires_spec.rb +23 -0
  78. data/spec/rtree_spec.rb +71 -0
  79. data/spec/schema_spec.rb +120 -0
  80. data/spec/spec_helper.rb +27 -0
  81. data/spec/sqlite3/constants_spec.rb +65 -0
  82. data/spec/sqlite3/database_status_spec.rb +36 -0
  83. data/spec/sqlite3/status_spec.rb +18 -0
  84. data/spec/sqlite3/version_spec.rb +14 -0
  85. data/spec/sqlite3_spec.rb +53 -0
  86. data/spec/statement_spec.rb +161 -0
  87. data/spec/storage_map_spec.rb +41 -0
  88. data/spec/tap_spec.rb +59 -0
  89. data/spec/text_map_spec.rb +23 -0
  90. data/spec/type_map_spec.rb +17 -0
  91. data/spec/version_spec.rb +15 -0
  92. data/tasks/announce.rake +43 -0
  93. data/tasks/config.rb +107 -0
  94. data/tasks/distribution.rake +77 -0
  95. data/tasks/documentation.rake +32 -0
  96. data/tasks/extension.rake +141 -0
  97. data/tasks/rspec.rake +33 -0
  98. data/tasks/rubyforge.rake +59 -0
  99. data/tasks/utils.rb +80 -0
  100. metadata +237 -0
@@ -0,0 +1,87 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite/type_maps/default_map'
6
+
7
+ describe Amalgalite::TypeMaps::DefaultMap do
8
+ before(:each) do
9
+ @map = Amalgalite::TypeMaps::DefaultMap.new
10
+ end
11
+
12
+ describe "#bind_type_of" do
13
+
14
+ it "Float is bound to DataType::FLOAT" do
15
+ @map.bind_type_of( 3.14 ).should == ::Amalgalite::SQLite3::Constants::DataType::FLOAT
16
+ end
17
+
18
+ it "Fixnum is bound to DataType::INTGER" do
19
+ @map.bind_type_of( 42 ).should == ::Amalgalite::SQLite3::Constants::DataType::INTEGER
20
+ end
21
+
22
+ it "nil is bound to DataType::NULL" do
23
+ @map.bind_type_of( nil ).should == ::Amalgalite::SQLite3::Constants::DataType::NULL
24
+ end
25
+
26
+ it "::Amalgalite::Blob is bound to DataType::BLOB" do
27
+ @map.bind_type_of( ::Amalgalite::Blob.new( :column => true, :string => "just a test" ) ).should == ::Amalgalite::SQLite3::Constants::DataType::BLOB
28
+ end
29
+
30
+ it "everything else is bound to DataType::TEXT" do
31
+ @map.bind_type_of( "everything else" ).should == ::Amalgalite::SQLite3::Constants::DataType::TEXT
32
+ end
33
+
34
+ end
35
+
36
+
37
+ describe "#result_value_of" do
38
+
39
+ it "Numeric's are returned" do
40
+ y = 42
41
+ x = @map.result_value_of( "INT", 42 )
42
+ x.object_id.should == y.object_id
43
+ end
44
+
45
+ it "Nil is returned" do
46
+ @map.result_value_of( "NULL", nil ).should == nil
47
+ end
48
+
49
+ it "DateTime is returned for delcared types of 'datetime'" do
50
+ @map.result_value_of( "DaTeTiME", "2008-04-01 23:23:23" ).should be_kind_of(DateTime)
51
+ end
52
+
53
+ it "Date is returned for declared types of 'date'" do
54
+ @map.result_value_of( "date", "2008-04-01 23:42:42" ).should be_kind_of(Date)
55
+ end
56
+
57
+ it "Time is returned for declared types of 'time'" do
58
+ @map.result_value_of( "timestamp", "2008-04-01T23:42:42" ).should be_kind_of(Time)
59
+ end
60
+
61
+ it "Float is returned for declared types of 'double'" do
62
+ @map.result_value_of( "double", "3.14" ).should be_kind_of(Float)
63
+ end
64
+
65
+ it "Integer is returned for declared types of 'int'" do
66
+ @map.result_value_of( "int", "42" ).should be_kind_of(Integer)
67
+ end
68
+
69
+ it "boolean is returned for declared types of 'bool'" do
70
+ @map.result_value_of( "bool", "True" ).should == true
71
+ end
72
+
73
+ it "Blob is returned for declated types of 'blob'" do
74
+ blob = @map.result_value_of( "blob", "stuff")
75
+ blob.to_s.should == "stuff"
76
+ end
77
+
78
+ it "raises and error if an unknown sql type is returned" do
79
+ x = nil
80
+ lambda{ x = @map.result_value_of( "footype", "foo" ) }.should raise_error( ::Amalgalite::Error )
81
+ end
82
+
83
+ it "raises and error if an ruby class is attempted to be mapped" do
84
+ lambda{ @map.result_value_of( "footype", 1..3 ) }.should raise_error( ::Amalgalite::Error )
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,94 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite'
6
+ require 'amalgalite/database'
7
+
8
+ describe "Scalar SQL Functions" do
9
+
10
+ before(:each) do
11
+ @schema = IO.read( SpecInfo.test_schema_file )
12
+ @iso_db_file = SpecInfo.make_iso_db
13
+ @iso_db = Amalgalite::Database.new( SpecInfo.make_iso_db )
14
+ end
15
+
16
+ after(:each) do
17
+ File.unlink SpecInfo.test_db if File.exist?( SpecInfo.test_db )
18
+ @iso_db.close
19
+ File.unlink @iso_db_file if File.exist?( @iso_db_file )
20
+ end
21
+
22
+ it "can define a custom SQL function as a block with 0 params" do
23
+ @iso_db.define_function("foo") do
24
+ "foo"
25
+ end
26
+ r = @iso_db.execute("SELECT foo() AS f");
27
+ r.first['f'].should == "foo"
28
+ end
29
+
30
+ it "has a signature" do
31
+ ::Amalgalite::Function.new( "testing_name", 42 ).signature.should == "testing_name/42"
32
+ end
33
+
34
+ it "can define a custom SQL function as a lambda with 2 param" do
35
+ @iso_db.define_function("foo2", lambda{ |x,y| "foo2 -> #{x} #{y}" } )
36
+ r = @iso_db.execute("SELECT foo2( 'bar', 'baz' ) as f")
37
+ r.first['f'].should == "foo2 -> bar baz"
38
+ end
39
+
40
+ it "can define a custom SQL function as a class with N params" do
41
+ class FunctionTest1 < ::Amalgalite::Function
42
+ def initialize
43
+ super('ftest', -1)
44
+ end
45
+ def call( *args )
46
+ "#{args.length} args #{args.join(', ')}"
47
+ end
48
+ end
49
+
50
+ @iso_db.define_function("ftest1", FunctionTest1.new )
51
+ r = @iso_db.execute("SELECT ftest1(1,2,3,'baz') as f")
52
+ r.first['f'].should == "4 args 1, 2, 3, baz"
53
+ end
54
+
55
+ [ [ 1, lambda { true } ],
56
+ [ 0, lambda { false } ],
57
+ [ nil, lambda { nil } ],
58
+ [ "foo", lambda { "foo" } ],
59
+ [ 42, lambda { 42 } ],
60
+ [ 42.2 , lambda { 42.2 } ], ].each do |expected, func|
61
+ it "returns the appropriate class #{expected.class} " do
62
+ @iso_db.define_function("ctest", func )
63
+ r = @iso_db.execute( "SELECT ctest() AS c" )
64
+ r.first['c'].should == expected
65
+ end
66
+ end
67
+
68
+ it "does not allow outrageous arity" do
69
+ class FunctionTest3 < ::Amalgalite::Function
70
+ def name() "ftest3"; end
71
+ def arity() 128; end
72
+ end
73
+ lambda { @iso_db.define_aggregate("ftest3", FunctionTest3) }.should raise_error( ::Amalgalite::SQLite3::Error, /SQLITE_ERROR .* Library used incorrectly/ )
74
+ end
75
+
76
+ it "raises an error if the function returns a complex Ruby object" do
77
+ l = lambda { Hash.new }
78
+ @iso_db.define_function("htest", l)
79
+ begin
80
+ @iso_db.execute( "SELECT htest() AS h" )
81
+ rescue => e
82
+ e.should be_instance_of( ::Amalgalite::SQLite3::Error )
83
+ e.message.should =~ /Unable to convert ruby object to an SQL function result/
84
+ end
85
+ end
86
+
87
+ it "an error raised during the sql function is handled correctly" do
88
+ @iso_db.define_function( "etest" ) do
89
+ raise "error from within an sql function"
90
+ end
91
+ lambda { @iso_db.execute( "SELECT etest() AS e" ) }.should raise_error( ::Amalgalite::SQLite3::Error, /error from within an sql function/ )
92
+ end
93
+ end
94
+
@@ -0,0 +1,111 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'date'
4
+ require 'time'
5
+
6
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
7
+ require 'amalgalite'
8
+
9
+ describe "Integration specifications" do
10
+ before(:each) do
11
+ @schema = IO.read( SpecInfo.test_schema_file )
12
+ @iso_db_file = SpecInfo.make_iso_db
13
+ @iso_db = Amalgalite::Database.new( SpecInfo.make_iso_db )
14
+ end
15
+
16
+ after(:each) do
17
+ File.unlink SpecInfo.test_db if File.exist?( SpecInfo.test_db )
18
+ @iso_db.close
19
+ File.unlink @iso_db_file if File.exist?( @iso_db_file )
20
+ end
21
+
22
+ describe " - invalid queries" do
23
+ it "raises error with an invalid syntax" do
24
+ lambda{ @iso_db.prepare "SELECT from country" }.should raise_error( ::Amalgalite::SQLite3::Error )
25
+ end
26
+
27
+ it "raises error with invalid table" do
28
+ lambda{ @iso_db.prepare "SELECT * FROM foo" }.should raise_error( ::Amalgalite::SQLite3::Error )
29
+ end
30
+
31
+ it "raises error with invalid column" do
32
+ lambda{ @iso_db.prepare "SELECT foo FROM country" }.should raise_error( ::Amalgalite::SQLite3::Error )
33
+ end
34
+ end
35
+
36
+ describe " - default types conversion" do
37
+
38
+ {
39
+ "datetime" => { :value => DateTime.now, :klass => DateTime },
40
+ "timestamp" => { :value => Time.now, :klass => Time } ,
41
+ "date" => { :value => Date.today, :klass => Date },
42
+ "integer" => { :value => 42, :klass => Fixnum } ,
43
+ "double" => { :value => 3.14, :klass => Float },
44
+ "varchar" => { :value => "foobarbaz", :klass => String },
45
+ "boolean" => { :value => true, :klass => TrueClass },
46
+ "varchar(2)"=> { :value => nil, :klass => NilClass }
47
+ }.each_pair do |sql_type, ruby_info|
48
+ it "converts a ruby obj (#{ruby_info[:value].to_s}) of #{ruby_info[:klass]} to an SQL type of #{sql_type} and back again " do
49
+ db = Amalgalite::Database.new( SpecInfo.test_db )
50
+ db.execute "CREATE TABLE t( c #{sql_type} )"
51
+ db.execute "insert into t (c) values ( ? )", ruby_info[:value]
52
+ rows = db.execute "select * from t"
53
+ rows.first['c'].class.should eql(ruby_info[:klass])
54
+
55
+ if [ DateTime, Time ].include?( ruby_info[:klass] ) then
56
+ rows.first['c'].strftime("%Y-%m-%d %H:%M:%S").should eql(ruby_info[:value].strftime("%Y-%m-%d %H:%M:%S"))
57
+ else
58
+ rows.first['c'].should eql(ruby_info[:value])
59
+ end
60
+ db.close
61
+ end
62
+ end
63
+ end
64
+
65
+ describe " - storage type conversion" do
66
+ {
67
+ "datetime" => { :value => DateTime.now, :result => DateTime.now.strftime("%Y-%m-%dT%H:%M:%S%Z") } ,
68
+ "timestamp" => { :value => Time.now, :result => Time.now.to_s },
69
+ "date" => { :value => Date.today, :result => Date.today.to_s },
70
+ "integer" => { :value => 42, :result => 42 } ,
71
+ "double" => { :value => 3.14, :result => 3.14 } ,
72
+ "varchar" => { :value => "foobarbaz", :result => "foobarbaz" },
73
+ "boolean" => { :value => true, :result => "true" },
74
+ "varchar(2)"=> { :value => nil, :result => nil }
75
+ }.each_pair do |sql_type, ruby_info|
76
+ it "converts a ruby obj (#{ruby_info[:value].to_s}) of class #{ruby_info[:value].class.name} to an SQL type of #{sql_type} and back to a storage type" do
77
+ db = Amalgalite::Database.new( SpecInfo.test_db )
78
+ db.type_map = Amalgalite::TypeMaps::StorageMap.new
79
+ db.execute "CREATE TABLE t( c #{sql_type} )"
80
+ db.execute "insert into t (c) values ( ? )", ruby_info[:value]
81
+ rows = db.execute "select * from t"
82
+ rows.first['c'].should eql(ruby_info[:result])
83
+ db.close
84
+ end
85
+ end
86
+ end
87
+
88
+ describe " - text type conversion" do
89
+ {
90
+ "datetime" => { :value => DateTime.now, :result => DateTime.now.strftime("%Y-%m-%dT%H:%M:%S%Z") } ,
91
+ "timestamp" => { :value => Time.now, :result => Time.now.to_s },
92
+ "date" => { :value => Date.today, :result => Date.today.to_s },
93
+ "integer" => { :value => 42, :result => "42" } ,
94
+ "double" => { :value => 3.14, :result => "3.14" } ,
95
+ "varchar" => { :value => "foobarbaz", :result => "foobarbaz" },
96
+ "boolean" => { :value => true, :result => "true" },
97
+ "varchar(2)"=> { :value => nil, :result => "" }
98
+ }.each_pair do |sql_type, ruby_info|
99
+ it "converts a ruby obj (#{ruby_info[:value].to_s}) of class #{ruby_info[:value].class.name} to an SQL type of #{sql_type} and back to text" do
100
+ db = Amalgalite::Database.new( SpecInfo.test_db )
101
+ db.type_map = Amalgalite::TypeMaps::TextMap.new
102
+ db.execute "CREATE TABLE t( c #{sql_type} )"
103
+ db.execute "insert into t (c) values ( ? )", ruby_info[:value]
104
+ rows = db.execute "select * from t"
105
+ rows.first['c'].should eql(ruby_info[:result])
106
+ db.close
107
+ end
108
+ end
109
+ end
110
+ end
111
+
@@ -0,0 +1,60 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),"spec_helper.rb"))
2
+ require 'amalgalite/packer'
3
+ require 'gemspec'
4
+
5
+ describe "Amalgalite::Packer" do
6
+ before( :each ) do
7
+ @table = Amalgalite::Requires::Bootstrap::DEFAULT_BOOTSTRAP_TABLE
8
+ @packer = Amalgalite::Packer.new( :table_name => @table )
9
+ end
10
+
11
+ after( :each ) do
12
+ FileUtils.rm_f Amalgalite::Requires::Bootstrap::DEFAULT_DB
13
+ end
14
+
15
+ it "does not load the amalgalite/requires file" do
16
+ $LOADED_FEATURES.should_not be_include("amalgalite/requires")
17
+ end
18
+
19
+ it "packs amalgalite into a bootstrap database" do
20
+ @packer.pack( Amalgalite::Packer.amalgalite_require_order )
21
+ db = Amalgalite::Database.new( @packer.dbfile )
22
+ db.schema.tables[ @table ].should_not be_nil
23
+ count = db.execute("SELECT count(1) FROM #{@table}").first
24
+ count.first.should eql(Amalgalite::Packer.amalgalite_require_order.size)
25
+ end
26
+
27
+ it "recreates the table if :drop_table option is given " do
28
+ @packer.pack( Amalgalite::Packer.amalgalite_require_order )
29
+ db = Amalgalite::Database.new( @packer.dbfile )
30
+ db.schema.tables[ @table ].should_not be_nil
31
+ count = db.execute("SELECT count(1) FROM #{@table}").first
32
+ count.first.should eql(Amalgalite::Packer.amalgalite_require_order.size)
33
+
34
+ np = Amalgalite::Packer.new( :drop_table => true, :table_name => @table )
35
+ np.options[ :drop_table ].should eql(true)
36
+ np.check_db( db )
37
+ count = db.execute("SELECT count(1) FROM #{@table}").first
38
+ count.first.should eql(0)
39
+
40
+ end
41
+
42
+ it "compresses the content if told too" do
43
+ @packer.options[ :compressed ] = true
44
+ @packer.pack( Amalgalite::Packer.amalgalite_require_order )
45
+ db = Amalgalite::Database.new( @packer.dbfile )
46
+ orig = IO.read( File.join( File.dirname( __FILE__ ), "..", "lib", "amalgalite.rb" ) )
47
+ zipped = db.execute("SELECT contents FROM #{@table} WHERE filename = 'amalgalite'")
48
+ expanded = Amalgalite::Packer.gunzip( zipped.first['contents'].to_s )
49
+ expanded.should eql(orig)
50
+ end
51
+
52
+ it "has all the lib files in the amalgalite gem" do
53
+ ro = Amalgalite::Packer.amalgalite_require_order
54
+ glist = Amalgalite::GEM_SPEC.files.select { |l| l.index("lib/amalgalite") == 0 }
55
+ glist.map! { |l| l.sub("lib/","") }
56
+ (glist - ro).each do |l|
57
+ l.should_not =~ /amalgalite/
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),"spec_helper.rb"))
2
+
3
+ describe Amalgalite::Paths do
4
+ before(:each) do
5
+ @root_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
6
+ @root_dir += "/"
7
+ end
8
+
9
+ it "root dir should be correct" do
10
+ Amalgalite::Paths.root_dir.should == @root_dir
11
+ end
12
+
13
+ it "config_path should be correct" do
14
+ Amalgalite::Paths.config_path.should == File.join(@root_dir, "config/")
15
+ end
16
+
17
+ it "data path should be correct" do
18
+ Amalgalite::Paths.data_path.should == File.join(@root_dir, "data/")
19
+ end
20
+
21
+ it "lib path should be correct" do
22
+ Amalgalite::Paths.lib_path.should == File.join(@root_dir, "lib/")
23
+ end
24
+
25
+ it "ext path should be correct" do
26
+ Amalgalite::Paths.ext_path.should == File.join(@root_dir, "ext/")
27
+ end
28
+ end
@@ -0,0 +1,105 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
4
+
5
+ require 'amalgalite'
6
+ require 'amalgalite/database'
7
+ class PH < ::Amalgalite::ProgressHandler
8
+ attr_reader :call_count
9
+ def initialize( max = nil )
10
+ @call_count = 0
11
+ @max = max
12
+ end
13
+
14
+ def call
15
+ @call_count += 1
16
+ if @max && ( @call_count >= @max ) then
17
+ return false
18
+ end
19
+ return true
20
+ end
21
+ end
22
+
23
+ def query_thread( db )
24
+ Thread.new( db ) do |db|
25
+ begin
26
+ db.execute("select count(id) from country")
27
+ rescue => e
28
+ had_error = e
29
+ Thread.current[:exception] = e
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "Progress Handlers" do
35
+ before(:each) do
36
+ @db_name = SpecInfo.make_iso_db
37
+ @iso_db = Amalgalite::Database.new( @db_name )
38
+ end
39
+
40
+ after(:each) do
41
+ @iso_db.close
42
+ File.unlink @db_name if File.exist?( @db_name )
43
+ end
44
+
45
+ it "raises NotImplemented if #call is not overwritten" do
46
+ bh = ::Amalgalite::ProgressHandler.new
47
+ lambda { bh.call }.should raise_error( ::NotImplementedError, /The progress handler call\(\) method must be implemented/ )
48
+ end
49
+
50
+ it "can be registered as block" do
51
+ call_count = 0
52
+ @iso_db.progress_handler( 50 ) do ||
53
+ call_count += 1
54
+ true
55
+ end
56
+ qt = query_thread( @iso_db )
57
+ qt.join
58
+ call_count.should > 10
59
+ end
60
+
61
+ it "can be registered as lambda" do
62
+ call_count = 0
63
+ callable = lambda { || call_count += 1; true }
64
+ @iso_db.progress_handler( 42, callable )
65
+ qt = query_thread( @iso_db )
66
+ qt.join
67
+ call_count.should > 10
68
+ end
69
+
70
+ it "can be registered as a class" do
71
+ ph = PH.new
72
+ @iso_db.progress_handler( 5, ph )
73
+ qt = query_thread( @iso_db )
74
+ qt.join
75
+ ph.call_count.should > 100
76
+ end
77
+
78
+ it "behaves like #interrupt! if returning a false value" do
79
+ ph = PH.new( 25 )
80
+ @iso_db.progress_handler( 5, ph )
81
+ qt = query_thread( @iso_db )
82
+ qt.join
83
+ ph.call_count.should eql(25)
84
+ qt[:exception].should be_instance_of( ::Amalgalite::SQLite3::Error )
85
+ @iso_db.api.last_error_code.should == 9
86
+ @iso_db.api.last_error_message.should =~ /interrupted/
87
+ qt[:exception].message.should =~ /interrupted/
88
+ end
89
+
90
+ it "cannot register a block with the wrong arity" do
91
+ lambda do
92
+ @iso_db.define_progress_handler { |x,y| puts "What!" }
93
+ end.should raise_error( ::Amalgalite::Database::ProgressHandlerError, /A progress handler expects 0 arguments, not 2/)
94
+ end
95
+
96
+ it "can remove a progress handler" do
97
+ ph = PH.new
98
+ @iso_db.progress_handler( 5, ph )
99
+ @iso_db.remove_progress_handler
100
+ qt = query_thread( @iso_db )
101
+ qt.join
102
+ ph.call_count.should eql(0)
103
+ qt[:exception].should be_nil
104
+ end
105
+ end