amalgalite 0.1.0

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