require 'pathname' require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper' describe "DataObjects::Sqlite3" do include Sqlite3SpecHelpers it "should raise error on bad connection string" do pending # lambda { DataObjects::Connection.new("sqlite3:///ac0d9iopalmsdcasd/asdc9pomasd/test.db") }.should raise_error("unable to open database file") end if JRUBY it "should accept either DO or JDBC style URLs on JRuby" do pending @connection = DataObjects::Connection.new("jdbc:sqlite:test.db") # note the sqlite not sqlite3! @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db") end end end NOW = DateTime.now describe "DataObjects::Sqlite3::Result" do include Sqlite3SpecHelpers before(:all) do @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db") end before do class ::Person; end end after :all do @connection.close end after do Object.send(:remove_const, :Person) end it "should raise an error for a bad query" do command = @connection.create_command("INSER INTO table_which_doesnt_exist (id) VALUES (1)") lambda { command.execute_non_query }.should raise_error(Sqlite3Error, /near "INSER": syntax error/) command = @connection.create_command("INSERT INTO table_which_doesnt_exist (id) VALUES (1)") lambda { command.execute_non_query }.should raise_error(Sqlite3Error, /no such table: table_which_doesnt_exist/) command = @connection.create_command("SELECT * FROM table_which_doesnt_exist") lambda { command.execute_reader }.should raise_error(Sqlite3Error, /no such table: table_which_doesnt_exist/) end it "should return the affected rows and insert_id" do command = @connection.create_command("DROP TABLE users") command.execute_non_query rescue nil command = @connection.create_command("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, type TEXT, age INTEGER, created_at DATETIME, balance DECIMAL default '0.00')") result = command.execute_non_query command = @connection.create_command("INSERT INTO users (name) VALUES ('test')") result = command.execute_non_query result.insert_id.should == 1 result.to_i.should == 1 end it "should do a reader query" do command = @connection.create_command("SELECT * FROM users") reader = command.execute_reader lambda { reader.values }.should raise_error(Sqlite3Error, /Reader is not initialized/) while ( reader.next! ) lambda { reader.values }.should_not raise_error reader.values.should be_a_kind_of(Array) end lambda { reader.values }.should raise_error(Sqlite3Error, /Reader is not initialized/) reader.close end it "should do a parameterized reader query" do command = @connection.create_command("SELECT * FROM users WHERE id = ?") reader = command.execute_reader(1) reader.next! reader.values[0].should == 1 reader.next! lambda { reader.values }.should raise_error(Sqlite3Error, /Reader is not initialized/) reader.close end it "should do a custom typecast reader" do command = @connection.create_command("SELECT name, id FROM users") command.set_types [String, String] reader = command.execute_reader while ( reader.next! ) reader.fields.should == ["name", "id"] reader.values.each { |v| v.should be_a_kind_of(String) } end reader.close end it "should handle a null value" do id = insert("INSERT INTO users (name) VALUES (NULL)") select("SELECT name from users WHERE name is null") do |reader| reader.values[0].should == nil end end it "should not convert empty strings to null" do id = insert("INSERT INTO users (name) VALUES ('')") select("SELECT name FROM users WHERE id = ?", [String], id) do |reader| reader.values.first.should == '' end end it "should raise an error when you pass too many or too few types for the expected result set" do lambda { select("SELECT name, id FROM users", [String, Integer, String]) }.should raise_error(Sqlite3Error, /Field-count mismatch. Expected 3 fields, but the query yielded 2/) end it "should do a custom typecast reader with Class" do id = insert("INSERT INTO users (name, age, type) VALUES (?, ?, ?)", 'Sam', 30, Person) select("SELECT name, age, type FROM users WHERE id = ?", [String, Integer, Class], id) do |reader| reader.fields.should == ["name", "age", "type"] reader.values.should == ["Sam", 30, Person] end exec("DELETE FROM users WHERE id = ?", id) end [ NOW.strftime('%Y-%m-%dT%H:%M:%S'), NOW.strftime('%Y-%m-%d %H:%M:%S') ].each do |raw_value| it "should return #{NOW.to_s} using the LOCAL timezone when typecasting '#{raw_value}'" do # Insert a timezone-less DateTime into the DB id = insert("INSERT INTO users (name, age, type, created_at) VALUES (?, ?, ?, ?)", 'Sam', 30, Person, raw_value) select("SELECT created_at FROM users WHERE id = ?", [DateTime], id) do |reader| reader.values.last.to_s.should == NOW.to_s end exec("DELETE FROM users WHERE id = ?", id) end end it "should not blow up when an empty string for a timestamp is used" do id = insert("INSERT INTO users (name, age, type, created_at) VALUES (?, ?, ?, ?)", 'Sam', 30, Person, "") select("SELECT created_at FROM users WHERE id = ?", [DateTime], id) do |reader| reader.values.last.should == nil end end it "should return DateTimes using the same timezone that was used to insert it" do pending "improved support for timezone checking" dates = [ NOW, NOW.new_offset( (-11 * 3600).to_r / 86400), # GMT -11:00 NOW.new_offset( (-9 * 3600 + 10 * 60).to_r / 86400), # GMT -9:10 NOW.new_offset( (-8 * 3600).to_r / 86400), # GMT -08:00 NOW.new_offset( (+3 * 3600).to_r / 86400), # GMT +03:00 NOW.new_offset( (+5 * 3600 + 30 * 60).to_r / 86400) # GMT +05:30 (New Delhi) ] dates.each do |date| id = insert("INSERT INTO users (name, age, type, created_at) VALUES (?, ?, ?, ?)", 'Sam', 30, Person, date) select("SELECT created_at FROM users WHERE id = ?", [DateTime], id) do |reader| reader.values.last.year.should == date.year reader.values.last.month.should == date.month reader.values.last.day.should == date.day reader.values.last.hour.should == date.hour reader.values.last.min.should == date.min reader.values.last.sec.should == date.sec reader.values.last.zone.should == date.zone end exec("DELETE FROM users WHERE id = ?", id) end end it "should return a BigDecimal" do pending "We need to introduce something like Proxy for typeasting where each SQL type will have _rules_ of casting" if JRUBY balance = BigDecimal.new('10000000000.00') #looks like inserting BigDecimals is not implemented in SQLITE's jdbc driver http://zentus.com/sqlitejdbc/src/src/org/sqlite/Unused.java id = insert("INSERT INTO users (name, age, type, created_at, balance) VALUES (?, ?, ?, ?, ?)", 'Scott', 27, Person, DateTime.now, balance) select("SELECT balance FROM users WHERE id = ?", [BigDecimal], id) do |reader| reader.values.last.should == balance end end unless JRUBY describe "quoting" do before do @connection.create_command("DROP TABLE IF EXISTS sail_boats").execute_non_query @connection.create_command("CREATE TABLE sail_boats ( id INTEGER PRIMARY KEY, name VARCHAR(50), port VARCHAR(50), notes VARCHAR(50), vintage BOOLEAN )").execute_non_query command = @connection.create_command("INSERT INTO sail_boats (id, name, port, name, vintage) VALUES (?, ?, ?, ?, ?)") command.execute_non_query(1, "A", "C", "Fortune Pig!", false) command.execute_non_query(2, "B", "B", "Happy Cow!", true) command.execute_non_query(3, "C", "A", "Spoon", true) end after do @connection.create_command("DROP TABLE sail_boats").execute_non_query end it "should quote a String" do command = @connection.create_command("INSERT INTO users (name) VALUES (?)") result = command.execute_non_query("John Doe") result.to_i.should == 1 end it "should quote multiple values" do command = @connection.create_command("INSERT INTO users (name, age) VALUES (?, ?)") result = command.execute_non_query("Sam Smoot", 1) result.to_i.should == 1 end it "should handle boolean columns gracefully" do command = @connection.create_command("INSERT INTO sail_boats (id, name, port, name, vintage) VALUES (?, ?, ?, ?, ?)") result = command.execute_non_query(4, "Scooner", "Port au Prince", "This is one gangster boat!", true) result.to_i.should == 1 end it "should quote an Array" do command = @connection.create_command("SELECT id, notes FROM sail_boats WHERE (id IN ?)") reader = command.execute_reader([1, 2, 3]) i = 1 while(reader.next!) reader.values[0].should == i i += 1 end end it "should quote an Array with NULL values returned" do command = @connection.create_command("SELECT id, NULL AS notes FROM sail_boats WHERE (id IN ?)") reader = command.execute_reader([1, 2, 3]) i = 1 while(reader.next!) reader.values[0].should == i i += 1 end end it "should quote an Array with NULL values returned AND set_types called" do command = @connection.create_command("SELECT id, NULL AS notes FROM sail_boats WHERE (id IN ?)") command.set_types [ Integer, String ] reader = command.execute_reader([1, 2, 3]) i = 1 while(reader.next!) reader.values[0].should == i i += 1 end end end # describe "quoting" end end