libsql 0.1.0-x64-mingw-ucrt
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +60 -0
- data/HISTORY.md +6 -0
- data/LICENSE +31 -0
- data/Manifest.txt +96 -0
- data/README.md +59 -0
- data/Rakefile +28 -0
- data/TODO.md +57 -0
- data/examples/a.rb +9 -0
- data/examples/blob.rb +106 -0
- data/examples/define_aggregate.rb +75 -0
- data/examples/define_function.rb +104 -0
- data/examples/fts5.rb +152 -0
- data/examples/gem-db.rb +94 -0
- data/examples/schema-info.rb +34 -0
- data/ext/libsql/c/extconf.rb +86 -0
- data/ext/libsql/c/gen_constants.rb +353 -0
- data/ext/libsql/c/libsql_blob.c +240 -0
- data/ext/libsql/c/libsql_constants.c +1518 -0
- data/ext/libsql/c/libsql_database.c +1188 -0
- data/ext/libsql/c/libsql_ext.c +383 -0
- data/ext/libsql/c/libsql_ext.h +149 -0
- data/ext/libsql/c/libsql_statement.c +649 -0
- data/ext/libsql/c/notes.txt +134 -0
- data/ext/libsql/c/sqlite3.c +247030 -0
- data/ext/libsql/c/sqlite3.h +13436 -0
- data/lib/libsql/3.1/libsql_ext.so +0 -0
- data/lib/libsql/3.2/libsql_ext.so +0 -0
- data/lib/libsql/aggregate.rb +73 -0
- data/lib/libsql/blob.rb +186 -0
- data/lib/libsql/boolean.rb +42 -0
- data/lib/libsql/busy_timeout.rb +47 -0
- data/lib/libsql/column.rb +99 -0
- data/lib/libsql/csv_table_importer.rb +75 -0
- data/lib/libsql/database.rb +933 -0
- data/lib/libsql/function.rb +61 -0
- data/lib/libsql/index.rb +43 -0
- data/lib/libsql/memory_database.rb +15 -0
- data/lib/libsql/paths.rb +80 -0
- data/lib/libsql/profile_tap.rb +131 -0
- data/lib/libsql/progress_handler.rb +21 -0
- data/lib/libsql/schema.rb +225 -0
- data/lib/libsql/sqlite3/constants.rb +95 -0
- data/lib/libsql/sqlite3/database/function.rb +48 -0
- data/lib/libsql/sqlite3/database/status.rb +68 -0
- data/lib/libsql/sqlite3/libsql_version.rb +32 -0
- data/lib/libsql/sqlite3/status.rb +60 -0
- data/lib/libsql/sqlite3/version.rb +55 -0
- data/lib/libsql/sqlite3.rb +7 -0
- data/lib/libsql/statement.rb +421 -0
- data/lib/libsql/table.rb +91 -0
- data/lib/libsql/taps/console.rb +27 -0
- data/lib/libsql/taps/io.rb +74 -0
- data/lib/libsql/taps.rb +2 -0
- data/lib/libsql/trace_tap.rb +35 -0
- data/lib/libsql/type_map.rb +63 -0
- data/lib/libsql/type_maps/default_map.rb +166 -0
- data/lib/libsql/type_maps/storage_map.rb +38 -0
- data/lib/libsql/type_maps/text_map.rb +21 -0
- data/lib/libsql/version.rb +8 -0
- data/lib/libsql/view.rb +26 -0
- data/lib/libsql-ruby.rb +1 -0
- data/lib/libsql.rb +51 -0
- data/spec/aggregate_spec.rb +158 -0
- data/spec/blob_spec.rb +78 -0
- data/spec/boolean_spec.rb +24 -0
- data/spec/busy_handler.rb +157 -0
- data/spec/data/iso-3166-country.txt +242 -0
- data/spec/data/iso-3166-schema.sql +22 -0
- data/spec/data/iso-3166-subcountry.txt +3995 -0
- data/spec/data/make-iso-db.sh +12 -0
- data/spec/database_spec.rb +505 -0
- data/spec/default_map_spec.rb +92 -0
- data/spec/function_spec.rb +78 -0
- data/spec/integeration_spec.rb +97 -0
- data/spec/iso_3166_database.rb +58 -0
- data/spec/json_spec.rb +24 -0
- data/spec/libsql_spec.rb +4 -0
- data/spec/paths_spec.rb +28 -0
- data/spec/progress_handler_spec.rb +91 -0
- data/spec/rtree_spec.rb +66 -0
- data/spec/schema_spec.rb +131 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/sqlite3/constants_spec.rb +108 -0
- data/spec/sqlite3/database_status_spec.rb +36 -0
- data/spec/sqlite3/libsql_version_spec.rb +16 -0
- data/spec/sqlite3/status_spec.rb +22 -0
- data/spec/sqlite3/version_spec.rb +28 -0
- data/spec/sqlite3_spec.rb +53 -0
- data/spec/statement_spec.rb +168 -0
- data/spec/storage_map_spec.rb +38 -0
- data/spec/tap_spec.rb +57 -0
- data/spec/text_map_spec.rb +20 -0
- data/spec/type_map_spec.rb +14 -0
- data/spec/version_spec.rb +8 -0
- data/tasks/custom.rake +134 -0
- data/tasks/default.rake +257 -0
- data/tasks/extension.rake +29 -0
- data/tasks/this.rb +208 -0
- metadata +329 -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
|
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
|