libsql 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +60 -0
  3. data/HISTORY.md +6 -0
  4. data/LICENSE +31 -0
  5. data/Manifest.txt +96 -0
  6. data/README.md +59 -0
  7. data/Rakefile +28 -0
  8. data/TODO.md +57 -0
  9. data/examples/a.rb +9 -0
  10. data/examples/blob.rb +106 -0
  11. data/examples/define_aggregate.rb +75 -0
  12. data/examples/define_function.rb +104 -0
  13. data/examples/fts5.rb +152 -0
  14. data/examples/gem-db.rb +94 -0
  15. data/examples/schema-info.rb +34 -0
  16. data/ext/libsql/c/extconf.rb +86 -0
  17. data/ext/libsql/c/gen_constants.rb +353 -0
  18. data/ext/libsql/c/libsql_blob.c +240 -0
  19. data/ext/libsql/c/libsql_constants.c +1518 -0
  20. data/ext/libsql/c/libsql_database.c +1188 -0
  21. data/ext/libsql/c/libsql_ext.c +383 -0
  22. data/ext/libsql/c/libsql_ext.h +149 -0
  23. data/ext/libsql/c/libsql_statement.c +649 -0
  24. data/ext/libsql/c/notes.txt +134 -0
  25. data/ext/libsql/c/sqlite3.c +247030 -0
  26. data/ext/libsql/c/sqlite3.h +13436 -0
  27. data/lib/libsql/aggregate.rb +73 -0
  28. data/lib/libsql/blob.rb +186 -0
  29. data/lib/libsql/boolean.rb +42 -0
  30. data/lib/libsql/busy_timeout.rb +47 -0
  31. data/lib/libsql/column.rb +99 -0
  32. data/lib/libsql/csv_table_importer.rb +75 -0
  33. data/lib/libsql/database.rb +933 -0
  34. data/lib/libsql/function.rb +61 -0
  35. data/lib/libsql/index.rb +43 -0
  36. data/lib/libsql/memory_database.rb +15 -0
  37. data/lib/libsql/paths.rb +80 -0
  38. data/lib/libsql/profile_tap.rb +131 -0
  39. data/lib/libsql/progress_handler.rb +21 -0
  40. data/lib/libsql/schema.rb +225 -0
  41. data/lib/libsql/sqlite3/constants.rb +95 -0
  42. data/lib/libsql/sqlite3/database/function.rb +48 -0
  43. data/lib/libsql/sqlite3/database/status.rb +68 -0
  44. data/lib/libsql/sqlite3/libsql_version.rb +32 -0
  45. data/lib/libsql/sqlite3/status.rb +60 -0
  46. data/lib/libsql/sqlite3/version.rb +55 -0
  47. data/lib/libsql/sqlite3.rb +7 -0
  48. data/lib/libsql/statement.rb +421 -0
  49. data/lib/libsql/table.rb +91 -0
  50. data/lib/libsql/taps/console.rb +27 -0
  51. data/lib/libsql/taps/io.rb +74 -0
  52. data/lib/libsql/taps.rb +2 -0
  53. data/lib/libsql/trace_tap.rb +35 -0
  54. data/lib/libsql/type_map.rb +63 -0
  55. data/lib/libsql/type_maps/default_map.rb +166 -0
  56. data/lib/libsql/type_maps/storage_map.rb +38 -0
  57. data/lib/libsql/type_maps/text_map.rb +21 -0
  58. data/lib/libsql/version.rb +8 -0
  59. data/lib/libsql/view.rb +26 -0
  60. data/lib/libsql-ruby.rb +1 -0
  61. data/lib/libsql.rb +51 -0
  62. data/spec/aggregate_spec.rb +158 -0
  63. data/spec/blob_spec.rb +78 -0
  64. data/spec/boolean_spec.rb +24 -0
  65. data/spec/busy_handler.rb +157 -0
  66. data/spec/data/iso-3166-country.txt +242 -0
  67. data/spec/data/iso-3166-schema.sql +22 -0
  68. data/spec/data/iso-3166-subcountry.txt +3995 -0
  69. data/spec/data/make-iso-db.sh +12 -0
  70. data/spec/database_spec.rb +505 -0
  71. data/spec/default_map_spec.rb +92 -0
  72. data/spec/function_spec.rb +78 -0
  73. data/spec/integeration_spec.rb +97 -0
  74. data/spec/iso_3166_database.rb +58 -0
  75. data/spec/json_spec.rb +24 -0
  76. data/spec/libsql_spec.rb +4 -0
  77. data/spec/paths_spec.rb +28 -0
  78. data/spec/progress_handler_spec.rb +91 -0
  79. data/spec/rtree_spec.rb +66 -0
  80. data/spec/schema_spec.rb +131 -0
  81. data/spec/spec_helper.rb +48 -0
  82. data/spec/sqlite3/constants_spec.rb +108 -0
  83. data/spec/sqlite3/database_status_spec.rb +36 -0
  84. data/spec/sqlite3/libsql_version_spec.rb +16 -0
  85. data/spec/sqlite3/status_spec.rb +22 -0
  86. data/spec/sqlite3/version_spec.rb +28 -0
  87. data/spec/sqlite3_spec.rb +53 -0
  88. data/spec/statement_spec.rb +168 -0
  89. data/spec/storage_map_spec.rb +38 -0
  90. data/spec/tap_spec.rb +57 -0
  91. data/spec/text_map_spec.rb +20 -0
  92. data/spec/type_map_spec.rb +14 -0
  93. data/spec/version_spec.rb +8 -0
  94. data/tasks/custom.rake +134 -0
  95. data/tasks/default.rake +257 -0
  96. data/tasks/extension.rake +29 -0
  97. data/tasks/this.rb +208 -0
  98. metadata +325 -0
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'libsql/sqlite3'
3
+ require 'rbconfig'
4
+
5
+ describe "::Libsql::SQLite3::Database::Status" do
6
+ before(:each) do
7
+ @db = ::Libsql::Database.new( "lookaside-test.db" )
8
+ @db.execute(" create table t(a, b)")
9
+ 20.times do |x|
10
+ @db.execute("insert into t(a, b) values (?,?);", x, x+1)
11
+ end
12
+ end
13
+
14
+ after(:each) do
15
+ @db.close
16
+ ::FileUtils.rm_f "lookaside-test.db"
17
+ end
18
+
19
+
20
+ it "knows how much lookaside memory it has used" do
21
+ @db.api.status.lookaside_used.highwater.should be > 0
22
+ @db.api.status.lookaside_used.current.should be >= 0
23
+ end
24
+
25
+ it "can reset the highwater value" do
26
+ stat = @db.api.status.lookaside_used
27
+ before = stat.highwater
28
+ before.should be > 0
29
+
30
+ stat.reset!
31
+ after = stat.highwater
32
+
33
+ after.should eql(0)
34
+ after.should_not eql(before)
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'libsql/sqlite3/libsql_version'
3
+
4
+ describe "::Libsql::SQLite3::LibsqlVersion" do
5
+ it "should have the libsql version" do
6
+ expect(::Libsql::SQLite3::LIBSQL_VERSION).to match(/\d+\.\d+\.\d+/)
7
+ expect(::Libsql::SQLite3::LibsqlVersion.to_s).to match(/\d+\.\d+\.\d+/)
8
+ expect(::Libsql::SQLite3::LibsqlVersion.runtime_version).to match( /\d+\.\d+\.\d+/ )
9
+ expect(::Libsql::SQLite3::LibsqlVersion.compiled_version).to match( /\d+\.\d+\.\d+/ )
10
+
11
+ ::Libsql::SQLite3::LIBSQL_VERSION.should be == "0.2.1"
12
+ ::Libsql::SQLite3::LibsqlVersion.compiled_version.should be == "0.2.1"
13
+ ::Libsql::SQLite3::LibsqlVersion.runtime_version.should be == "0.2.1"
14
+ ::Libsql::SQLite3::LibsqlVersion.to_s.should be == "0.2.1"
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'libsql/sqlite3'
3
+ require 'rbconfig'
4
+
5
+ describe "::Libsql::SQLite3::Status" do
6
+ it "knows how much memory it has used" do
7
+ ::Libsql::SQLite3.status.memory_used.current.should be >= 0
8
+ ::Libsql::SQLite3.status.memory_used.highwater.should be >= 0
9
+ end
10
+
11
+ it "can reset the highwater value" do
12
+ before = ::Libsql::SQLite3.status.memory_used.highwater
13
+ before.should be > 0
14
+
15
+ current = ::Libsql::SQLite3.status.memory_used.current
16
+ ::Libsql::SQLite3.status.memory_used.reset!
17
+ ::Libsql::SQLite3.status.memory_used.highwater.should be == current
18
+
19
+ after = ::Libsql::SQLite3.status.memory_used.highwater
20
+ after.should_not eql(before)
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'libsql/sqlite3/version'
3
+
4
+ describe "::Libsql::SQLite3::Version" do
5
+ it "should have the sqlite3 version" do
6
+ expect(::Libsql::SQLite3::VERSION).to match(/\d+\.\d+\.\d+/)
7
+ expect(::Libsql::SQLite3::Version.to_s).to match( /\d+\.\d+\.\d+/ )
8
+ expect(::Libsql::SQLite3::Version.runtime_version).to match( /\d+\.\d+\.\d+/ )
9
+
10
+ ::Libsql::SQLite3::Version.to_i.should eql(3042000)
11
+ ::Libsql::SQLite3::Version.runtime_version_number.should eql(3042000)
12
+
13
+ ::Libsql::SQLite3::Version::MAJOR.should eql(3)
14
+ ::Libsql::SQLite3::Version::MINOR.should eql(42)
15
+ ::Libsql::SQLite3::Version::RELEASE.should eql(0)
16
+ expect(::Libsql::SQLite3::Version.to_a.size).to eql(3)
17
+
18
+ ::Libsql::SQLite3::Version.compiled_version.should be == "3.42.0"
19
+ ::Libsql::SQLite3::Version.compiled_version_number.should be == 3042000
20
+ ::Libsql::SQLite3::Version.compiled_matches_runtime?.should be == true
21
+ end
22
+
23
+ it "should have the sqlite3 source id" do
24
+ source_id = "2023-03-11 23:21:21 dc9f025dc43cb8008e7d8d644175d8b2d084e602a1513803c40c513d1e99alt1"
25
+ ::Libsql::SQLite3::Version.compiled_source_id.should be == source_id
26
+ ::Libsql::SQLite3::Version.runtime_source_id.should be == source_id
27
+ end
28
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'libsql/sqlite3'
3
+ require 'rbconfig'
4
+
5
+ describe "::Libsql::SQLite3" do
6
+ it "is threadsafe is ruby is compiled with pthread support, in this case that is (#{RbConfig::CONFIG['configure_args'].include?( "--enable-pthread" )})" do
7
+ ::Libsql::SQLite3.threadsafe?.should eql(RbConfig::CONFIG['configure_args'].include?( "--enable-pthread" ))
8
+ end
9
+
10
+ it "knows if an SQL statement is complete" do
11
+ ::Libsql::SQLite3.complete?("SELECT * FROM sometable;").should eql(true)
12
+ #::Libsql::SQLite3.complete?("SELECT * FROM sometable;", :utf16 => true).should eql(true)
13
+ end
14
+
15
+ it "knows if an SQL statement is not complete" do
16
+ ::Libsql::SQLite3.complete?("SELECT * FROM sometable ").should eql(false)
17
+ #::Libsql::SQLite3.complete?("SELECT * FROM sometable WHERE ", :utf16 => true).should eql(false)
18
+ end
19
+
20
+ it "can produce random data" do
21
+ ::Libsql::SQLite3.randomness( 42 ).size.should eql(42)
22
+ end
23
+
24
+ it "has nil for the default sqlite temporary directory" do
25
+ ::Libsql::SQLite3.temp_directory.should eql(nil)
26
+ end
27
+
28
+ it "can set the temporary directory" do
29
+ ::Libsql::SQLite3.temp_directory.should eql(nil)
30
+ ::Libsql::SQLite3.temp_directory = "/tmp/testing"
31
+ ::Libsql::SQLite3.temp_directory.should eql("/tmp/testing")
32
+ ::Libsql::SQLite3.temp_directory = nil
33
+ ::Libsql::SQLite3.temp_directory.should eql(nil)
34
+ end
35
+
36
+ it "can escape quoted strings" do
37
+ ::Libsql::SQLite3.escape( "It's a happy day!" ).should eql("It''s a happy day!")
38
+ end
39
+
40
+ it "can escape a symble into a string" do
41
+ ::Libsql::SQLite3.escape( :stuff ).should eql("stuff")
42
+ ::Libsql::SQLite3.escape( :"stuff'n" ).should eql("stuff''n")
43
+ end
44
+
45
+ it "can quote and escape single quoted strings" do
46
+ ::Libsql::SQLite3.quote( "It's a happy day!" ).should eql("'It''s a happy day!'")
47
+ end
48
+
49
+ it "can quote and escape symbols" do
50
+ ::Libsql::SQLite3.quote( :stuff ).should eql("'stuff'")
51
+ ::Libsql::SQLite3.quote( :"stuff'n" ).should eql("'stuff''n'")
52
+ end
53
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Libsql::Statement do
4
+ before(:each) do
5
+ @db = ::Libsql::Database.new( SpecInfo.test_db )
6
+ end
7
+
8
+ after(:each) do
9
+ @db.close
10
+ end
11
+
12
+ it "a statement has a copy of the sql it was prepared with" do
13
+ stmt = @db.prepare( "SELECT strftime('%Y-%m-%d %H:%M:%S', 'now')")
14
+ stmt.sql.should eql("SELECT strftime('%Y-%m-%d %H:%M:%S', 'now')")
15
+ stmt.close
16
+ end
17
+
18
+ it "steps through results" do
19
+ now = Time.new.utc.strftime("%Y-%m-%d %H:%M")
20
+ @db.prepare( "SELECT strftime('%Y-%m-%d %H:%M', 'now') as now") do |stmt|
21
+ stmt.should_not eql(nil)
22
+ stmt.each do |row|
23
+ row['now'].should eql(now)
24
+ end
25
+ end
26
+ end
27
+
28
+ it "can prepare a statement without a block" do
29
+ stmt = @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two")
30
+ rs = stmt.execute( ":two" => "JP" )
31
+ rs.size.should eql(1)
32
+ stmt.close
33
+ end
34
+
35
+ it "knows how many parameters are in the statement" do
36
+ @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two") do |stmt|
37
+ stmt.check_parameter_count!( 1 ).should eql(1)
38
+ end
39
+ end
40
+
41
+ it "raises an error if there are not enough parameters are passed in a statement" do
42
+ @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two") do |stmt|
43
+ lambda{ stmt.execute }.should raise_error( ::Libsql::Error )
44
+ end
45
+ end
46
+
47
+
48
+ it "can run a query with a named parameter" do
49
+ @iso_db.prepare("SELECT * FROM country WHERE two_letter = :two") do |stmt|
50
+ all_rows = stmt.execute( ":two" => "JP" )
51
+ all_rows.size.should eql(1)
52
+ all_rows.first['name'].should eql("Japan")
53
+ end
54
+ end
55
+
56
+ it "it can execute a query with a named parameter and yield the rows" do
57
+ @iso_db.prepare("SELECT * FROM country WHERE id = @id ORDER BY name") do |stmt|
58
+ rows = []
59
+ stmt.execute( "@id" => 891 ) do |row|
60
+ rows << row
61
+ end
62
+ rows.size.should eql(2)
63
+ rows.last['name'].should eql("Yugoslavia")
64
+ rows.first['two_letter'].should eql("CS")
65
+ end
66
+ end
67
+
68
+ it "can execute the same prepared statement multiple times" do
69
+ @db.execute(" CREATE TABLE t(x,y); ")
70
+ values = {}
71
+ @db.prepare("INSERT INTO t( x, y ) VALUES( $x, $y )" ) do |stmt|
72
+ 20.times do |x|
73
+ y = rand( x )
74
+ stmt.execute( { "$x" => x, "$y" => y } )
75
+ values[x] = y
76
+ end
77
+ end
78
+ c = 0
79
+ @db.execute("SELECT * from t") do |row|
80
+ c += 1
81
+ values[ row['x'] ].should eql(row['y'])
82
+ end
83
+ c.should eql(20)
84
+ end
85
+
86
+ it "expands an array when binding parameters" do
87
+ @db.execute(" CREATE TABLE t(x,y); ")
88
+ values = {}
89
+ @db.prepare( "INSERT INTO t( x, y ) VALUES( ?, ? )") do |stmt|
90
+ 20.times do |x|
91
+ y = rand( x )
92
+ a = [ x, y ]
93
+ stmt.execute( a )
94
+ values[x] = y
95
+ end
96
+ end
97
+ c = 0
98
+ @db.execute("SELECT * from t") do |row|
99
+ c += 1
100
+ values[ row['x'] ].should eql(row['y'])
101
+ end
102
+ c.should eql(20)
103
+
104
+ end
105
+
106
+ it "binds a integer variable correctly" do
107
+ @iso_db.prepare("SELECT * FROM country WHERE id = ? ORDER BY name ") do |stmt|
108
+ all_rows = stmt.execute( 891 )
109
+ all_rows.size.should eql(2)
110
+ all_rows.last['name'].should eql("Yugoslavia")
111
+ all_rows.first['two_letter'].should eql("CS")
112
+ end
113
+ end
114
+
115
+ it "raises and error if an invaliding binding is attempted" do
116
+ @iso_db.prepare("SELECT * FROM country WHERE id = :somevar ORDER BY name ") do |stmt|
117
+ lambda{ stmt.execute( "blah" => 42 ) }.should raise_error(::Libsql::Error)
118
+ end
119
+ end
120
+
121
+ it "can reset the statement to the state it was before executing" do
122
+ stmt = @iso_db.prepare("SELECT * FROM country WHERE id = :somevar ORDER BY name ")
123
+ stmt.reset_and_clear_bindings!
124
+ stmt.close
125
+ end
126
+
127
+ it "can execute a single sql command and say if there is remaining sql to execute" do
128
+ stmt = @db.prepare( @schema )
129
+ stmt.execute
130
+ stmt.remaining_sql.size.should be > 0
131
+ stmt.close
132
+ end
133
+
134
+ it "can select the rowid from the table" do
135
+ db = ::Libsql::Database.new( ":memory:" )
136
+ db.execute( "create table t1(c1,c2,c3)" )
137
+ db.execute("insert into t1(c1,c2,c3) values (1,2,'abc')")
138
+ rows = db.execute( "select rowid,* from t1")
139
+ rows.size.should eql(1)
140
+ rows.first['rowid'].should eql(1)
141
+ rows.first['c1'].should eql(1 )
142
+ rows.first['c3'].should eql('abc')
143
+ end
144
+
145
+ it "shows that the rowid column is rowid column" do
146
+ db = ::Libsql::Database.new( ":memory:" )
147
+ db.execute( "create table t1(c1,c2,c3)" )
148
+ db.execute("insert into t1(c1,c2,c3) values (1,2,'abc')")
149
+ db.prepare( "select oid,* from t1" ) do |stmt|
150
+ stmt.execute
151
+ stmt.should be_using_rowid_column
152
+ end
153
+
154
+ db.prepare( "select * from t1" ) do |stmt|
155
+ stmt.execute
156
+ stmt.should_not be_using_rowid_column
157
+ end
158
+ end
159
+
160
+ it "has index based access to the result set" do
161
+ @iso_db.prepare("SELECT * FROM country WHERE id = ? ORDER BY name ") do |stmt|
162
+ all_rows = stmt.execute( 891 )
163
+ all_rows.size.should eql(2)
164
+ all_rows.last.first.should eql("Yugoslavia")
165
+ all_rows.first[1].should eql("CS")
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'libsql/type_maps/storage_map'
3
+
4
+ describe ::Libsql::TypeMaps::StorageMap do
5
+ before(:each) do
6
+ @map = ::Libsql::TypeMaps::StorageMap.new
7
+ end
8
+
9
+ describe "#bind_type_of" do
10
+
11
+ it "Float is bound to DataType::FLOAT" do
12
+ @map.bind_type_of( 3.14 ).should == ::Libsql::SQLite3::Constants::DataType::FLOAT
13
+ end
14
+
15
+ it "Integer is bound to DataType::INTGER" do
16
+ @map.bind_type_of( 42 ).should == ::Libsql::SQLite3::Constants::DataType::INTEGER
17
+ end
18
+
19
+ it "nil is bound to DataType::NULL" do
20
+ @map.bind_type_of( nil ).should == ::Libsql::SQLite3::Constants::DataType::NULL
21
+ end
22
+
23
+ it "::Libsql::Blob is bound to DataType::BLOB" do
24
+ @map.bind_type_of( ::Libsql::Blob.new( :string => "testing mapping", :column => true ) ).should == ::Libsql::SQLite3::Constants::DataType::BLOB
25
+ end
26
+
27
+ it "everything else is bound to DataType::TEXT" do
28
+ @map.bind_type_of( "everything else" ).should == ::Libsql::SQLite3::Constants::DataType::TEXT
29
+ end
30
+
31
+ end
32
+
33
+ describe "#result_value_of" do
34
+ it "returns the original object for everything passed in" do
35
+ @map.result_value_of( "doesn't matter", 42 ).should == 42
36
+ end
37
+ end
38
+ end
data/spec/tap_spec.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ require 'libsql'
4
+ require 'libsql/trace_tap'
5
+ require 'libsql/profile_tap'
6
+ require 'libsql/taps/console'
7
+ require 'stringio'
8
+
9
+ describe ::Libsql::TraceTap do
10
+ it "wraps up an object and delegates the 'trace' method to a method on that object" do
11
+ s = StringIO.new
12
+ tt = ::Libsql::TraceTap.new( s, 'puts' )
13
+ tt.trace('test trace')
14
+ s.string.should eql("test trace\n")
15
+ end
16
+
17
+ it "raises an error if an the wrapped object does not respond to the indicated method" do
18
+ lambda{ ::Libsql::TraceTap.new( Object.new ) }.should raise_error( ::Libsql::Error )
19
+ end
20
+ end
21
+
22
+ describe ::Libsql::ProfileTap do
23
+ it "raises an error if an the wrapped object does not respond to the indicated method" do
24
+ lambda{ ::Libsql::ProfileTap.new( Object.new ) }.should raise_error( ::Libsql::Error )
25
+ end
26
+ end
27
+
28
+ describe ::Libsql::Taps::StringIO do
29
+ it "dumps profile information" do
30
+ s = ::Libsql::Taps::StringIO.new
31
+ s.profile( 'test', 42 )
32
+ s.dump_profile
33
+ s.string.should eql("42 : test\n[test] => sum: 42, sumsq: 1764, n: 1, mean: 42.000000, stddev: 0.000000, min: 42, max: 42\n")
34
+ end
35
+
36
+ it "has a stdout tap" do
37
+ ::Libsql::Taps::Stdout.new
38
+ end
39
+
40
+ it "has a stderr tap" do
41
+ ::Libsql::Taps::Stderr.new
42
+ end
43
+ end
44
+
45
+ describe ::Libsql::ProfileSampler do
46
+ it "aggregates samples" do
47
+ s = ::Libsql::ProfileSampler.new( 'test1' )
48
+ s.sample( 42 )
49
+ s.sample( 84 )
50
+ s.sample( 21 )
51
+ h = s.to_h
52
+ h['min'].should eql(21)
53
+ h['max'].should eql(84)
54
+ h['mean'].should eql(49.0)
55
+ h['n'].should eql(3)
56
+ end
57
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'libsql/type_maps/text_map'
3
+
4
+ describe ::Libsql::TypeMaps::TextMap do
5
+ before(:each) do
6
+ @map = ::Libsql::TypeMaps::TextMap.new
7
+ end
8
+
9
+ describe "#bind_type_of" do
10
+ it "returnes text for everything" do
11
+ @map.bind_type_of( 3.14 ).should == ::Libsql::SQLite3::Constants::DataType::TEXT
12
+ end
13
+ end
14
+
15
+ describe "#result_value_of" do
16
+ it "returns the string value of the object for everything passed in" do
17
+ @map.result_value_of( "doesn't matter", 42 ).should == "42"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'libsql/type_map'
3
+
4
+ describe ::Libsql::TypeMap do
5
+ it "#bind_type_of raises NotImplemented error" do
6
+ tm = ::Libsql::TypeMap.new
7
+ lambda { tm.bind_type_of( Object.new ) }.should raise_error( NotImplementedError )
8
+ end
9
+
10
+ it "#result_value_of raises NotImplemented error" do
11
+ tm = ::Libsql::TypeMap.new
12
+ lambda { tm.result_value_of( "foo", Object.new ) }.should raise_error( NotImplementedError )
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'libsql/version'
3
+
4
+ describe "::Libsql::VERSION" do
5
+ it "should have a version string" do
6
+ expect(::Libsql::VERSION).to match( /\d+\.\d+\.\d+/ )
7
+ end
8
+ end
data/tasks/custom.rake ADDED
@@ -0,0 +1,134 @@
1
+ #-----------------------------------------------------------------------
2
+ # Custom tasks for this project
3
+ #-----------------------------------------------------------------------
4
+ require 'pathname'
5
+ namespace :util do
6
+ desc "List the sqlite api calls that are not implemented"
7
+ task :todo do
8
+
9
+ not_implementing = %w[
10
+ sqlite3_exec
11
+ sqlite3_open
12
+ sqlite3_os_end
13
+ sqlite3_os_init
14
+ sqlite3_malloc
15
+ sqlite3_realloc
16
+ sqlite3_free
17
+ sqlite3_get_table
18
+ sqlite3_free_table
19
+ sqlite3_key
20
+ sqlite3_rekey
21
+ sqlite3_next_stmt
22
+ sqlite3_release_memory
23
+ sqlite3_sleep
24
+ sqlite3_snprintf
25
+ sqlite3_vmprintf
26
+ sqlite3_strnicmp
27
+ sqlite3_test_control
28
+ sqlite3_unlock_notify
29
+ sqlite3_vfs_find
30
+ sqlite3_vfs_register
31
+ sqlite3_vfs_unregister
32
+ ]
33
+
34
+ sqlite_h = File.join( *%w[ ext libsql c sqlite3.h ] )
35
+ api_todo = {}
36
+ IO.readlines( sqlite_h ).each do |line|
37
+ if line =~ /\ASQLITE_API/ then
38
+ if line !~ /SQLITE_DEPRECATED/ and line !~ /SQLITE_EXPERIMENTAL/ then
39
+ if md = line.match( /(sqlite3_[^(\s]+)\(/ ) then
40
+ next if not_implementing.include?(md.captures[0])
41
+ api_todo[md.captures[0]] = true
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ Dir.glob("ext/libsql/c/libsql*.c").each do |am_file|
48
+ IO.readlines( am_file ).each do |am_line|
49
+ if md = am_line.match( /(sqlite3_[^(\s]+)\(/ ) then
50
+ api_todo.delete( md.captures[0] )
51
+ end
52
+ end
53
+ end
54
+
55
+ puts "#{api_todo.keys.size} functions to still implement"
56
+ puts api_todo.keys.sort.join("\n")
57
+ end
58
+
59
+ desc "Download and integrate the latest version of libsql"
60
+ task :update_libsql, [:version] do |task, args|
61
+ require 'uri'
62
+ require 'open-uri'
63
+
64
+ asset_regex = /\Alibsql-amalgamation-(\d+\.\d+\.\d+)\.tar\.gz\Z/
65
+
66
+ asset = nil
67
+ require 'debug'
68
+
69
+ if args[:version] then
70
+ all_releases_uri = "https://api.github.com/repos/libsql/libsql/releases"
71
+ all_releases_json = ::URI.parse(all_releases_uri).read
72
+ all_releases_parsed = JSON.parse(all_releases_json)
73
+ version_release = all_releases_parsed.find { |p| p['tag_name'] == "libsql-#{args[:version]}" }
74
+ if version_release then
75
+ assets_url = version_release['assets_url']
76
+ assets_json = ::URI.parse(assets_url).read
77
+ assets_parsed = JSON.parse(assets_json)
78
+ asset = assets_parsed.find { |a| a['name'] =~ asset_regex }
79
+ else
80
+ msg = [
81
+ "Unable to find release for `libsql-#{args[:version]}`. Found releases for:"
82
+ ]
83
+ all_releases_parsed.map{ |p| p['tag_name'] }.each do |tag|
84
+ msg << " #{tag}"
85
+ end
86
+
87
+ abort msg.join("\n")
88
+ end
89
+ else
90
+ latest_uri = "https://api.github.com/repos/libsql/libsql/releases/latest"
91
+ latest_json = ::URI.parse(latest_uri).read
92
+ latest_parsed = JSON.parse(latest_json)
93
+ asset = latest_parsed['assets'].find { |a| a['name'] =~ asset_regex }
94
+ end
95
+
96
+ asset_name = asset['name']
97
+ tarball_uri = ::URI.parse(asset['browser_download_url'])
98
+ puts "Downloading from #{tarball_uri}"
99
+ file = "tmp/#{File.basename(tarball_uri.path)}"
100
+ puts " to #{file}"
101
+
102
+ FileUtils.mkdir "tmp" unless File.directory?( "tmp" )
103
+ if File.exist?(file) then
104
+ puts " #{file} already exists.."
105
+ else
106
+ File.open( file, "wb+") do |f|
107
+ tarball_uri.open do |input|
108
+ f.write( input.read )
109
+ end
110
+ end
111
+ end
112
+
113
+ puts "extracting"
114
+ upstream_files = %w[ sqlite3.h sqlite3.c ]
115
+
116
+ require 'rubygems'
117
+ # Using the built in rubygems tar reader since we know it exists
118
+ ::Zlib::GzipReader.open(file) do |gz|
119
+ ::Gem::Package::TarReader.new(gz) do |reader|
120
+ reader.each do |entry|
121
+ next unless entry.file?
122
+ bname = File.basename(entry.full_name)
123
+ if upstream_files.include?(bname) then
124
+ dest_path = File.join( "ext", "libsql", "c", bname )
125
+ puts "updating #{dest_path}"
126
+ File.open(dest_path, "w+") do |dest_file|
127
+ dest_file.write(entry.read)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end