amalgalite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/HISTORY +4 -0
  2. data/LICENSE +31 -0
  3. data/README +28 -0
  4. data/ext/amalgalite3.c +191 -0
  5. data/ext/amalgalite3.h +97 -0
  6. data/ext/amalgalite3_constants.c +179 -0
  7. data/ext/amalgalite3_database.c +458 -0
  8. data/ext/amalgalite3_statement.c +546 -0
  9. data/ext/gen_constants.rb +114 -0
  10. data/ext/mkrf_conf.rb +6 -0
  11. data/ext/sqlite3.c +87003 -0
  12. data/ext/sqlite3.h +5638 -0
  13. data/ext/sqlite3_options.h +4 -0
  14. data/ext/sqlite3ext.h +362 -0
  15. data/gemspec.rb +50 -0
  16. data/lib/amalgalite.rb +28 -0
  17. data/lib/amalgalite/blob.rb +14 -0
  18. data/lib/amalgalite/boolean.rb +42 -0
  19. data/lib/amalgalite/column.rb +83 -0
  20. data/lib/amalgalite/database.rb +505 -0
  21. data/lib/amalgalite/index.rb +27 -0
  22. data/lib/amalgalite/paths.rb +70 -0
  23. data/lib/amalgalite/profile_tap.rb +130 -0
  24. data/lib/amalgalite/schema.rb +90 -0
  25. data/lib/amalgalite/sqlite3.rb +4 -0
  26. data/lib/amalgalite/sqlite3/constants.rb +48 -0
  27. data/lib/amalgalite/sqlite3/version.rb +38 -0
  28. data/lib/amalgalite/statement.rb +307 -0
  29. data/lib/amalgalite/table.rb +34 -0
  30. data/lib/amalgalite/taps/console.rb +27 -0
  31. data/lib/amalgalite/taps/io.rb +71 -0
  32. data/lib/amalgalite/trace_tap.rb +35 -0
  33. data/lib/amalgalite/type_map.rb +60 -0
  34. data/lib/amalgalite/type_maps/default_map.rb +153 -0
  35. data/lib/amalgalite/type_maps/storage_map.rb +41 -0
  36. data/lib/amalgalite/type_maps/text_map.rb +23 -0
  37. data/lib/amalgalite/version.rb +32 -0
  38. data/lib/amalgalite/view.rb +24 -0
  39. data/spec/amalgalite_spec.rb +4 -0
  40. data/spec/boolean_spec.rb +26 -0
  41. data/spec/database_spec.rb +222 -0
  42. data/spec/default_map_spec.rb +85 -0
  43. data/spec/integeration_spec.rb +111 -0
  44. data/spec/paths_spec.rb +28 -0
  45. data/spec/schema_spec.rb +46 -0
  46. data/spec/spec_helper.rb +25 -0
  47. data/spec/sqlite3/constants_spec.rb +25 -0
  48. data/spec/sqlite3/version_spec.rb +14 -0
  49. data/spec/sqlite3_spec.rb +34 -0
  50. data/spec/statement_spec.rb +116 -0
  51. data/spec/storage_map_spec.rb +41 -0
  52. data/spec/tap_spec.rb +59 -0
  53. data/spec/text_map_spec.rb +23 -0
  54. data/spec/type_map_spec.rb +17 -0
  55. data/spec/version_spec.rb +9 -0
  56. data/tasks/announce.rake +38 -0
  57. data/tasks/config.rb +108 -0
  58. data/tasks/distribution.rake +38 -0
  59. data/tasks/documentation.rake +31 -0
  60. data/tasks/extension.rake +45 -0
  61. data/tasks/rspec.rake +32 -0
  62. data/tasks/rubyforge.rake +48 -0
  63. data/tasks/utils.rb +80 -0
  64. metadata +165 -0
@@ -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,46 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite'
6
+ require 'amalgalite/schema'
7
+
8
+ describe Amalgalite::Schema do
9
+ before(:each) do
10
+ @schema = IO.read( SpecInfo.test_schema_file )
11
+ @iso_db_file = SpecInfo.make_iso_db
12
+ @iso_db = Amalgalite::Database.new( SpecInfo.make_iso_db )
13
+ end
14
+
15
+ after(:each) do
16
+ File.unlink SpecInfo.test_db if File.exist?( SpecInfo.test_db )
17
+ @iso_db.close
18
+ File.unlink @iso_db_file if File.exist?( @iso_db_file )
19
+ end
20
+
21
+ it "loads the schema of a database" do
22
+ schema = @iso_db.schema
23
+ schema.tables.size.should == 2
24
+ end
25
+
26
+ it "loads the views in the database" do
27
+ sql = "CREATE VIEW v1 AS SELECT c.name, c.two_letter, s.name, s.subdivision FROM country AS c JOIN subcountry AS s ON c.two_letter = s.country"
28
+ @iso_db.execute( sql )
29
+ @iso_db.schema.views.size.should == 1
30
+ @iso_db.schema.views["v1"].sql.should == sql
31
+ end
32
+
33
+ it "loads the tables and columns" do
34
+ @iso_db.schema.tables.size.should == 2
35
+ ct = @iso_db.schema.tables['country']
36
+ ct.name.should == "country"
37
+ ct.columns.size.should == 3
38
+ ct.indexes.size.should == 2
39
+
40
+ ct.columns['two_letter'].should be_primary_key
41
+ ct.columns['name'].should_not be_nullable
42
+ ct.columns['name'].should be_not_null_constraint
43
+ ct.columns['name'].should_not be_has_default_value
44
+ ct.columns['id'].should_not be_auto_increment
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite'
6
+
7
+ class SpecInfo
8
+ class << self
9
+ def test_db
10
+ @test_db ||= File.expand_path(File.join(File.dirname(__FILE__), "test.db"))
11
+ end
12
+
13
+ def test_schema_file
14
+ @test_schema_file ||= File.expand_path(File.join(File.dirname(__FILE__),"iso-3166-schema.sql"))
15
+ end
16
+
17
+ def make_iso_db
18
+ @iso_db ||= File.expand_path(File.join(File.dirname(__FILE__), "iso-3166.db"))
19
+ @new_is_db = File.expand_path(File.join(File.dirname(__FILE__), "iso-3166-testing.db"))
20
+ FileUtils.cp @iso_db, @new_is_db
21
+ return @new_is_db
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),%w[ .. spec_helper.rb ]))
2
+
3
+ require 'amalgalite/sqlite3/constants'
4
+
5
+ describe Amalgalite::SQLite3::Constants do
6
+
7
+ it "has Open constants" do
8
+ Amalgalite::SQLite3::Constants::Open::READONLY.should > 0
9
+ end
10
+
11
+ it "has DataType constants" do
12
+ Amalgalite::SQLite3::Constants::DataType::BLOB.should > 0
13
+ end
14
+
15
+ it "has ResultCode constants" do
16
+ Amalgalite::SQLite3::Constants::ResultCode::OK.should == 0
17
+ end
18
+
19
+ it "can return the constant from a number" do
20
+ c = Amalgalite::SQLite3::Constants::ResultCode.from_int( 21 )
21
+ c.should == "MISUSE"
22
+ end
23
+
24
+
25
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),"..","spec_helper.rb"))
2
+ require 'amalgalite/sqlite3/version'
3
+
4
+ describe "Amalgalite::SQLite3::Version" do
5
+ it "should have the sqlite3 version" do
6
+ Amalgalite::SQLite3::VERSION.should =~ /\d\.\d\.\d/
7
+ Amalgalite::SQLite3::Version.to_s.should =~ /\d\.\d\.\d/
8
+ Amalgalite::SQLite3::Version.to_i.should == 3005009
9
+ Amalgalite::SQLite3::Version::MAJOR.should == 3
10
+ Amalgalite::SQLite3::Version::MINOR.should == 5
11
+ Amalgalite::SQLite3::Version::RELEASE.should == 9
12
+ Amalgalite::SQLite3::Version.to_a.should have(3).items
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),"spec_helper.rb"))
2
+ require 'amalgalite/sqlite3'
3
+
4
+ describe "Amalgalite::SQLite3" do
5
+ it "says if SQLite3 is in threadsafe mode or not" do
6
+ Amalgalite::SQLite3.threadsafe?.should == true
7
+ end
8
+
9
+ it "knows if an SQL statement is complete" do
10
+ Amalgalite::SQLite3.complete?("SELECT * FROM sometable;").should == true
11
+ Amalgalite::SQLite3.complete?("SELECT * FROM sometable;", :utf16 => true).should == true
12
+ end
13
+
14
+ it "knows if an SQL statement is not complete" do
15
+ Amalgalite::SQLite3.complete?("SELECT * FROM sometable ").should == false
16
+ Amalgalite::SQLite3.complete?("SELECT * FROM sometable WHERE ", :utf16 => true).should == false
17
+ end
18
+
19
+ it "knows how much memory it has used" do
20
+ Amalgalite::SQLite3.memory_used.should >= 0
21
+ end
22
+
23
+ it "knows the maximum amount of memory it has used so far" do
24
+ Amalgalite::SQLite3.memory_highwater_mark.should >= 0
25
+ end
26
+
27
+ it "can reset it maximum memory usage counter" do
28
+ Amalgalite::SQLite3.memory_highwater_mark_reset!.should >= 0
29
+ end
30
+
31
+ it "can produce random data" do
32
+ Amalgalite::SQLite3.randomness( 42 ).size.should == 42
33
+ end
34
+ end
@@ -0,0 +1,116 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite'
6
+
7
+ describe Amalgalite::Statement do
8
+ before(:each) do
9
+ @db = Amalgalite::Database.new( SpecInfo.test_db )
10
+ @schema_sql = IO.read( SpecInfo.test_schema_file )
11
+ @iso_db_file = SpecInfo.make_iso_db
12
+ @iso_db = Amalgalite::Database.new( SpecInfo.make_iso_db )
13
+ end
14
+
15
+ after(:each) do
16
+ @db.close
17
+ File.unlink SpecInfo.test_db if File.exist?( SpecInfo.test_db )
18
+
19
+ @iso_db.close
20
+ File.unlink @iso_db_file if File.exist?( @iso_db_file )
21
+ end
22
+
23
+ it "a statement has a copy of the sql it was prepared with" do
24
+ stmt = @db.prepare( "SELECT strftime('%Y-%m-%d %H:%M:%S', 'now')")
25
+ stmt.sql.should == "SELECT strftime('%Y-%m-%d %H:%M:%S', 'now')"
26
+ stmt.close
27
+ end
28
+
29
+ it "steps through results" do
30
+ now = Time.new.utc.strftime("%Y-%m-%d %H:%M")
31
+ @db.prepare( "SELECT strftime('%Y-%m-%d %H:%M', 'now') as now") do |stmt|
32
+ stmt.should_not == nil
33
+ stmt.each do |row|
34
+ row['now'].should == now
35
+ end
36
+ end
37
+ end
38
+
39
+ it "can prepare a statement without a block" do
40
+ stmt = @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two")
41
+ rs = stmt.execute( ":two" => "JP" )
42
+ rs.size.should == 1
43
+ stmt.close
44
+ end
45
+
46
+ it "knows how many parameters are in the statement" do
47
+ @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two") do |stmt|
48
+ stmt.check_parameter_count!( 1 ).should == 1
49
+ end
50
+ end
51
+
52
+ it "raises an error if there are not enough parameters are passed in a statement" do
53
+ @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two") do |stmt|
54
+ lambda{ stmt.execute }.should raise_error( Amalgalite::Error )
55
+ end
56
+ end
57
+
58
+
59
+ it "can run a query with a named parameter" do
60
+ @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two") do |stmt|
61
+ all_rows = stmt.execute( ":two" => "JP" )
62
+ all_rows.size.should == 1
63
+ all_rows.first['name'].should == "Japan"
64
+ end
65
+ end
66
+
67
+ it "it can execute a query with a named parameter and yield the rows" do
68
+ @iso_db.prepare("SELECT * FROM country WHERE id = @id ORDER BY name") do |stmt|
69
+ rows = []
70
+ stmt.execute( "@id" => 891 ) do |row|
71
+ rows << row
72
+ end
73
+ rows.size.should == 2
74
+ rows.last['name'].should == "Yugoslavia"
75
+ rows.first['two_letter'].should == "CS"
76
+ end
77
+ end
78
+
79
+ it "binds a integer variable correctly" do
80
+ @iso_db.prepare("SELECT * FROM country WHERE id = ? ORDER BY name ") do |stmt|
81
+ all_rows = stmt.execute( 891 )
82
+ all_rows.size.should == 2
83
+ all_rows.last['name'].should == "Yugoslavia"
84
+ all_rows.first['two_letter'].should == "CS"
85
+ end
86
+ end
87
+
88
+ it "raises and error if an invaliding binding is attempted" do
89
+ @iso_db.prepare("SELECT * FROM country WHERE id = :somevar ORDER BY name ") do |stmt|
90
+ lambda{ stmt.execute( "blah" => 42 ) }.should raise_error(Amalgalite::Error)
91
+ end
92
+ end
93
+
94
+ it "can reset the statement to the state it was before executing" do
95
+ stmt = @iso_db.prepare("SELECT * FROM country WHERE id = :somevar ORDER BY name ")
96
+ stmt.reset_and_clear_bindings!
97
+ stmt.close
98
+ end
99
+
100
+ it "can execute a single sql command and say if there is remaining sql to execute" do
101
+ db = Amalgalite::Database.new( SpecInfo.test_db )
102
+ stmt = @db.prepare( @schema_sql )
103
+ stmt.execute
104
+ stmt.remaining_sql.size.should > 0
105
+ stmt.close
106
+ end
107
+
108
+ it "has index based access to the result set" do
109
+ @iso_db.prepare("SELECT * FROM country WHERE id = ? ORDER BY name ") do |stmt|
110
+ all_rows = stmt.execute( 891 )
111
+ all_rows.size.should == 2
112
+ all_rows.last.first.should == "Yugoslavia"
113
+ all_rows.first[1].should == "CS"
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite/type_maps/storage_map'
6
+
7
+ describe Amalgalite::TypeMaps::StorageMap do
8
+ before(:each) do
9
+ @map = Amalgalite::TypeMaps::StorageMap.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 ).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
+ describe "#result_value_of" do
37
+ it "returns the original object for everything passed in" do
38
+ @map.result_value_of( "doesn't matter", 42 ).should == 42
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite'
6
+ require 'amalgalite/trace_tap'
7
+ require 'amalgalite/profile_tap'
8
+ require 'amalgalite/taps/console'
9
+ require 'stringio'
10
+
11
+ describe Amalgalite::TraceTap do
12
+ it "wraps up an object and delegates the 'trace' method to a method on that object" do
13
+ s = StringIO.new
14
+ tt = ::Amalgalite::TraceTap.new( s, 'puts' )
15
+ tt.trace('test trace')
16
+ s.string.should == "test trace\n"
17
+ end
18
+
19
+ it "raises an error if an the wrapped object does not respond to the indicated method" do
20
+ lambda{ ::Amalgalite::TraceTap.new( Object.new ) }.should raise_error( Amalgalite::Error )
21
+ end
22
+ end
23
+
24
+ describe Amalgalite::ProfileTap do
25
+ it "raises an error if an the wrapped object does not respond to the indicated method" do
26
+ lambda{ ::Amalgalite::ProfileTap.new( Object.new ) }.should raise_error( Amalgalite::Error )
27
+ end
28
+ end
29
+
30
+ describe Amalgalite::Taps::StringIO do
31
+ it "dumps profile information" do
32
+ s = ::Amalgalite::Taps::StringIO.new
33
+ s.profile( 'test', 42 )
34
+ s.dump_profile
35
+ s.string.should == "42 : test\ntest[test] => sum: 42, sumsq: 1764, n: 1, mean: 42.000000, stddev: 0.000000, min: 42, max: 42\n"
36
+ end
37
+
38
+ it "has a stdout tap" do
39
+ s = ::Amalgalite::Taps::Stdout.new
40
+ end
41
+
42
+ it "has a stderr tap" do
43
+ s = ::Amalgalite::Taps::Stderr.new
44
+ end
45
+ end
46
+
47
+ describe Amalgalite::ProfileSampler do
48
+ it "aggregates samples" do
49
+ s = Amalgalite::ProfileSampler.new( 'test1' )
50
+ s.sample( 42 )
51
+ s.sample( 84 )
52
+ s.sample( 21 )
53
+ h = s.to_h
54
+ h['min'].should == 21
55
+ h['max'].should == 84
56
+ h['mean'].should == 49
57
+ h['n'].should == 3
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite/type_maps/text_map'
6
+
7
+ describe Amalgalite::TypeMaps::TextMap do
8
+ before(:each) do
9
+ @map = Amalgalite::TypeMaps::TextMap.new
10
+ end
11
+
12
+ describe "#bind_type_of" do
13
+ it "returnes text for everything" do
14
+ @map.bind_type_of( 3.14 ).should == ::Amalgalite::SQLite3::Constants::DataType::TEXT
15
+ end
16
+ end
17
+
18
+ describe "#result_value_of" do
19
+ it "returns the string value of the object for everything passed in" do
20
+ @map.result_value_of( "doesn't matter", 42 ).should == "42"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite/type_map'
6
+
7
+ describe Amalgalite::TypeMap do
8
+ it "#bind_type_of raises NotImplemented error" do
9
+ tm = Amalgalite::TypeMap.new
10
+ lambda { tm.bind_type_of( Object.new ) }.should raise_error( NotImplementedError )
11
+ end
12
+
13
+ it "#result_value_of raises NotImplemented error" do
14
+ tm = Amalgalite::TypeMap.new
15
+ lambda { tm.result_value_of( "foo", Object.new ) }.should raise_error( NotImplementedError )
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),"spec_helper.rb"))
2
+ require 'amalgalite/version'
3
+
4
+ describe "Amalgalite::Version" do
5
+ it "should have a version string" do
6
+ Amalgalite::Version.to_s.should =~ /\d+\.\d+\.\d+/
7
+ Amalgalite::VERSION.should =~ /\d+\.\d+\.\d+/
8
+ end
9
+ end