amalgalite 0.10.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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