mirror of
https://gitea.invidious.io/iv-org/shard-crystal-sqlite3.git
synced 2024-08-15 00:53:26 +00:00
Merge branch 'feature/5-type-extensibility' into db
This commit is contained in:
commit
186dc01f10
5 changed files with 76 additions and 14 deletions
|
@ -1,7 +1,10 @@
|
||||||
name: sqlite3
|
name: sqlite3
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
db:
|
||||||
|
github: bcardiff/crystal-db
|
||||||
|
|
||||||
authors:
|
authors:
|
||||||
- Ary Borenszweig <aborenszweig@manas.com.ar>
|
- Ary Borenszweig <aborenszweig@manas.com.ar>
|
||||||
- Brian J. Cardiff <bcardiff@manas.com.ar>
|
- Brian J. Cardiff <bcardiff@manas.com.ar>
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ def sqlite_type_for(v)
|
||||||
when String ; "text"
|
when String ; "text"
|
||||||
when Int32, Int64 ; "int"
|
when Int32, Int64 ; "int"
|
||||||
when Float32, Float64; "float"
|
when Float32, Float64; "float"
|
||||||
|
when Time ; "text"
|
||||||
else
|
else
|
||||||
raise "not implemented for #{typeof(v)}"
|
raise "not implemented for #{typeof(v)}"
|
||||||
end
|
end
|
||||||
|
@ -46,6 +47,9 @@ def assert_filename(uri, filename)
|
||||||
SQLite3::Connection.filename(URI.parse(uri)).should eq(filename)
|
SQLite3::Connection.filename(URI.parse(uri)).should eq(filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class NotSupportedType
|
||||||
|
end
|
||||||
|
|
||||||
describe Driver do
|
describe Driver do
|
||||||
it "should register sqlite3 name" do
|
it "should register sqlite3 name" do
|
||||||
DB.driver_class("sqlite3").should eq(SQLite3::Driver)
|
DB.driver_class("sqlite3").should eq(SQLite3::Driver)
|
||||||
|
@ -111,7 +115,7 @@ describe Driver do
|
||||||
|
|
||||||
it "executes and selects blob" do
|
it "executes and selects blob" do
|
||||||
with_db do |db|
|
with_db do |db|
|
||||||
slice = db.scalar(%(select X'53514C697465')) as Slice(UInt8)
|
slice = db.scalar(%(select X'53514C697465')).as(Bytes)
|
||||||
slice.to_a.should eq([0x53, 0x51, 0x4C, 0x69, 0x74, 0x65])
|
slice.to_a.should eq([0x53, 0x51, 0x4C, 0x69, 0x74, 0x65])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -119,7 +123,7 @@ describe Driver do
|
||||||
it "executes with bind blob" do
|
it "executes with bind blob" do
|
||||||
with_db do |db|
|
with_db do |db|
|
||||||
ary = UInt8[0x53, 0x51, 0x4C, 0x69, 0x74, 0x65]
|
ary = UInt8[0x53, 0x51, 0x4C, 0x69, 0x74, 0x65]
|
||||||
slice = db.scalar(%(select cast(? as BLOB)), Slice.new(ary.to_unsafe, ary.size)) as Slice(UInt8)
|
slice = db.scalar(%(select cast(? as BLOB)), Bytes.new(ary.to_unsafe, ary.size)).as(Bytes)
|
||||||
slice.to_a.should eq(ary)
|
slice.to_a.should eq(ary)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -158,7 +162,7 @@ describe Driver do
|
||||||
rs.column_type(0).should eq(String)
|
rs.column_type(0).should eq(String)
|
||||||
rs.column_type(1).should eq(Int64)
|
rs.column_type(1).should eq(Int64)
|
||||||
rs.column_type(2).should eq(Float64)
|
rs.column_type(2).should eq(Float64)
|
||||||
rs.column_type(3).should eq(Slice(UInt8))
|
rs.column_type(3).should eq(Bytes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -190,13 +194,46 @@ describe Driver do
|
||||||
ary = UInt8[0x53, 0x51, 0x4C, 0x69, 0x74, 0x65]
|
ary = UInt8[0x53, 0x51, 0x4C, 0x69, 0x74, 0x65]
|
||||||
|
|
||||||
db.exec "create table table1 (col1 blob)"
|
db.exec "create table table1 (col1 blob)"
|
||||||
db.exec %(insert into table1 values (?)), Slice.new(ary.to_unsafe, ary.size)
|
db.exec %(insert into table1 values (?)), Bytes.new(ary.to_unsafe, ary.size)
|
||||||
|
|
||||||
slice = db.scalar("select cast(col1 as blob) from table1") as Slice(UInt8)
|
slice = db.scalar("select cast(col1 as blob) from table1").as(Bytes)
|
||||||
slice.to_a.should eq(ary)
|
slice.to_a.should eq(ary)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "insert/get value date from table" do
|
||||||
|
with_db do |db|
|
||||||
|
value = Time.new(2016, 7, 22, 15, 0, 0, 0)
|
||||||
|
db.exec "create table table1 (col1 #{sqlite_type_for(value)})"
|
||||||
|
db.exec %(insert into table1 values (?)), value
|
||||||
|
|
||||||
|
db.query "select col1 from table1" do |rs|
|
||||||
|
rs.move_next
|
||||||
|
rs.read(Time).should eq(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
db.query "select col1 from table1" do |rs|
|
||||||
|
rs.move_next
|
||||||
|
rs.read?(Time).should eq(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises on unsupported param types" do
|
||||||
|
with_db do |db|
|
||||||
|
expect_raises Exception, "SQLite3::Statement does not support NotSupportedType params" do
|
||||||
|
db.query "select 1", NotSupportedType.new
|
||||||
|
end
|
||||||
|
# TODO raising exception does not close the connection and pool is exhausted
|
||||||
|
end
|
||||||
|
|
||||||
|
with_db do |db|
|
||||||
|
expect_raises Exception, "SQLite3::Statement does not support NotSupportedType params" do
|
||||||
|
db.exec "select 1", NotSupportedType.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "gets many rows from table" do
|
it "gets many rows from table" do
|
||||||
with_mem_db do |db|
|
with_mem_db do |db|
|
||||||
db.exec "create table person (name string, age integer)"
|
db.exec "create table person (name string, age integer)"
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
require "db"
|
require "db"
|
||||||
require "./sqlite3/**"
|
require "./sqlite3/**"
|
||||||
|
|
||||||
|
module SQLite3
|
||||||
|
DATE_FORMAT = "%F %H:%M:%S.%L"
|
||||||
|
end
|
||||||
|
|
|
@ -22,7 +22,7 @@ class SQLite3::ResultSet < DB::ResultSet
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
{% for t in DB::TYPES %}
|
macro nilable_read_for(t)
|
||||||
def read?(t : {{t}}.class) : {{t}}?
|
def read?(t : {{t}}.class) : {{t}}?
|
||||||
if read_nil?
|
if read_nil?
|
||||||
moving_column { nil }
|
moving_column { nil }
|
||||||
|
@ -30,6 +30,10 @@ class SQLite3::ResultSet < DB::ResultSet
|
||||||
read(t)
|
read(t)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
{% for t in DB::TYPES %}
|
||||||
|
nilable_read_for({{t}})
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
def read(t : String.class) : String
|
def read(t : String.class) : String
|
||||||
|
@ -52,16 +56,22 @@ class SQLite3::ResultSet < DB::ResultSet
|
||||||
moving_column { |col| LibSQLite3.column_double(self, col) }
|
moving_column { |col| LibSQLite3.column_double(self, col) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def read(t : Slice(UInt8).class) : Slice(UInt8)
|
def read(t : Bytes.class) : Bytes
|
||||||
moving_column do |col|
|
moving_column do |col|
|
||||||
blob = LibSQLite3.column_blob(self, col)
|
blob = LibSQLite3.column_blob(self, col)
|
||||||
bytes = LibSQLite3.column_bytes(self, col)
|
bytes = LibSQLite3.column_bytes(self, col)
|
||||||
ptr = Pointer(UInt8).malloc(bytes)
|
ptr = Pointer(UInt8).malloc(bytes)
|
||||||
ptr.copy_from(blob, bytes)
|
ptr.copy_from(blob, bytes)
|
||||||
Slice(UInt8).new(ptr, bytes)
|
Bytes.new(ptr, bytes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read(t : Time.class) : Time
|
||||||
|
Time.parse read(String), SQLite3::DATE_FORMAT
|
||||||
|
end
|
||||||
|
|
||||||
|
nilable_read_for Time
|
||||||
|
|
||||||
def column_count
|
def column_count
|
||||||
LibSQLite3.column_count(self)
|
LibSQLite3.column_count(self)
|
||||||
end
|
end
|
||||||
|
@ -74,7 +84,7 @@ class SQLite3::ResultSet < DB::ResultSet
|
||||||
case LibSQLite3.column_type(self, index)
|
case LibSQLite3.column_type(self, index)
|
||||||
when Type::INTEGER; Int64
|
when Type::INTEGER; Int64
|
||||||
when Type::FLOAT ; Float64
|
when Type::FLOAT ; Float64
|
||||||
when Type::BLOB ; Slice(UInt8)
|
when Type::BLOB ; Bytes
|
||||||
when Type::TEXT ; String
|
when Type::TEXT ; String
|
||||||
when Type::NULL ; Nil
|
when Type::NULL ; Nil
|
||||||
else
|
else
|
||||||
|
|
|
@ -4,7 +4,7 @@ class SQLite3::Statement < DB::Statement
|
||||||
check LibSQLite3.prepare_v2(@connection, sql, sql.bytesize + 1, out @stmt, nil)
|
check LibSQLite3.prepare_v2(@connection, sql, sql.bytesize + 1, out @stmt, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
protected def perform_query(args : Slice(DB::Any))
|
protected def perform_query(args : Enumerable) : DB::ResultSet
|
||||||
LibSQLite3.reset(self)
|
LibSQLite3.reset(self)
|
||||||
args.each_with_index(1) do |arg, index|
|
args.each_with_index(1) do |arg, index|
|
||||||
bind_arg(index, arg)
|
bind_arg(index, arg)
|
||||||
|
@ -12,12 +12,12 @@ class SQLite3::Statement < DB::Statement
|
||||||
ResultSet.new(self)
|
ResultSet.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
protected def perform_exec(args : Slice(DB::Any))
|
protected def perform_exec(args : Enumerable) : DB::ExecResult
|
||||||
rs = perform_query(args)
|
rs = perform_query(args)
|
||||||
rs.move_next
|
rs.move_next
|
||||||
rs.close
|
rs.close
|
||||||
|
|
||||||
rows_affected = LibSQLite3.changes(connection)
|
rows_affected = LibSQLite3.changes(connection).to_i64
|
||||||
last_id = LibSQLite3.last_insert_rowid(connection)
|
last_id = LibSQLite3.last_insert_rowid(connection)
|
||||||
|
|
||||||
DB::ExecResult.new rows_affected, last_id
|
DB::ExecResult.new rows_affected, last_id
|
||||||
|
@ -52,10 +52,18 @@ class SQLite3::Statement < DB::Statement
|
||||||
check LibSQLite3.bind_text(self, index, value, value.bytesize, nil)
|
check LibSQLite3.bind_text(self, index, value, value.bytesize, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
private def bind_arg(index, value : Slice(UInt8))
|
private def bind_arg(index, value : Bytes)
|
||||||
check LibSQLite3.bind_blob(self, index, value, value.size, nil)
|
check LibSQLite3.bind_blob(self, index, value, value.size, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private def bind_arg(index, value : Time)
|
||||||
|
bind_arg(index, value.to_s(SQLite3::DATE_FORMAT))
|
||||||
|
end
|
||||||
|
|
||||||
|
private def bind_arg(index, value)
|
||||||
|
raise "#{self.class} does not support #{value.class} params"
|
||||||
|
end
|
||||||
|
|
||||||
private def check(code)
|
private def check(code)
|
||||||
raise Exception.new(@connection) unless code == 0
|
raise Exception.new(@connection) unless code == 0
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue