mirror of
https://gitea.invidious.io/iv-org/shard-crystal-sqlite3.git
synced 2024-08-15 00:53:26 +00:00
Documentation and some refactors
This commit is contained in:
parent
d96255d766
commit
d62185867b
10 changed files with 215 additions and 45 deletions
16
README.md
16
README.md
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
SQLite3 bindings for [Crystal](http://crystal-lang.org/).
|
SQLite3 bindings for [Crystal](http://crystal-lang.org/).
|
||||||
|
|
||||||
|
**This is a work in progress.**
|
||||||
|
|
||||||
|
[Documentation](http://manastech.github.io/crystal-sqlite3/)
|
||||||
|
|
||||||
### Projectfile
|
### Projectfile
|
||||||
|
|
||||||
```crystal
|
```crystal
|
||||||
|
@ -9,3 +13,15 @@ deps do
|
||||||
github "manastech/crystal-sqlite3"
|
github "manastech/crystal-sqlite3"
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
require "sqlite3"
|
||||||
|
|
||||||
|
db = SQLite3::Database.new( "data.db" )
|
||||||
|
db.execute("select * from table") do |row|
|
||||||
|
p row
|
||||||
|
end
|
||||||
|
db.close
|
||||||
|
```
|
||||||
|
|
|
@ -61,6 +61,18 @@ describe Database do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "gets column types" do
|
||||||
|
Database.new(":memory:") do |db|
|
||||||
|
db.execute "create table person (name string, age integer)"
|
||||||
|
db.execute %(insert into person values ("foo", 10))
|
||||||
|
stmt = db.prepare("select * from person")
|
||||||
|
stmt.execute
|
||||||
|
stmt.step
|
||||||
|
stmt.types.should eq([Type::TEXT, Type::INTEGER])
|
||||||
|
stmt.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "gets column by name" do
|
it "gets column by name" do
|
||||||
Database.new(":memory:") do |db|
|
Database.new(":memory:") do |db|
|
||||||
db.execute "create table person (name string, age integer)"
|
db.execute "create table person (name string, age integer)"
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
module SQLite3
|
|
||||||
alias ColumnType = Nil | Int64 | Float64 | String | Slice(UInt8)
|
|
||||||
end
|
|
|
@ -1,4 +1,18 @@
|
||||||
|
# The Database class encapsulates single connection to an SQLite3 database. Its usage is very straightforward:
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# require "sqlite3"
|
||||||
|
#
|
||||||
|
# db = SQLite3::Database.new( "data.db" )
|
||||||
|
# db.execute("select * from table") do |row|
|
||||||
|
# p row
|
||||||
|
# end
|
||||||
|
# db.close
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Lower level methods are also provided.
|
||||||
class SQLite3::Database
|
class SQLite3::Database
|
||||||
|
# Creates a new Database object that opens the given file.
|
||||||
def initialize(filename)
|
def initialize(filename)
|
||||||
code = LibSQLite3.open_v2(filename, out @db, (LibSQLite3::Flag::READWRITE | LibSQLite3::Flag::CREATE), nil)
|
code = LibSQLite3.open_v2(filename, out @db, (LibSQLite3::Flag::READWRITE | LibSQLite3::Flag::CREATE), nil)
|
||||||
if code != 0
|
if code != 0
|
||||||
|
@ -7,6 +21,7 @@ class SQLite3::Database
|
||||||
@closed = false
|
@closed = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a new Database object that opens the given file, yields it, and closes it at the end.
|
||||||
def self.new(filename)
|
def self.new(filename)
|
||||||
db = new filename
|
db = new filename
|
||||||
begin
|
begin
|
||||||
|
@ -16,24 +31,52 @@ class SQLite3::Database
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes the given SQL statement. If additional parameters are given, they are treated as bind variables,
|
||||||
|
# and are bound to the placeholders in the query.
|
||||||
|
#
|
||||||
|
# Note that if any of the values passed to this are hashes, then the key/value pairs are each bound separately,
|
||||||
|
# with the key being used as the name of the placeholder to bind the value to.
|
||||||
|
#
|
||||||
|
# Returns an `Array(Array(Value))`.
|
||||||
def execute(sql, *binds)
|
def execute(sql, *binds)
|
||||||
execute(sql, binds)
|
execute(sql, binds)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes the given SQL statement. If additional parameters are given, they are treated as bind variables,
|
||||||
|
# and are bound to the placeholders in the query.
|
||||||
|
#
|
||||||
|
# Note that if any of the values passed to this are hashes, then the key/value pairs are each bound separately,
|
||||||
|
# with the key being used as the name of the placeholder to bind the value to.
|
||||||
|
#
|
||||||
|
# Yields one `Array(Value)` for each result.
|
||||||
def execute(sql, *binds, &block)
|
def execute(sql, *binds, &block)
|
||||||
execute(sql, binds) do |row|
|
execute(sql, binds) do |row|
|
||||||
yield row
|
yield row
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes the given SQL statement. If additional parameters are given, they are treated as bind variables,
|
||||||
|
# and are bound to the placeholders in the query.
|
||||||
|
#
|
||||||
|
# Note that if any of the values passed to this are hashes, then the key/value pairs are each bound separately,
|
||||||
|
# with the key being used as the name of the placeholder to bind the value to.
|
||||||
|
#
|
||||||
|
# Returns an `Array(Array(Value))`.
|
||||||
def execute(sql, binds : Enumerable)
|
def execute(sql, binds : Enumerable)
|
||||||
rows = [] of Array(SQLite3::ColumnType)
|
rows = [] of Array(Value)
|
||||||
execute(sql, binds) do |row|
|
execute(sql, binds) do |row|
|
||||||
rows << row
|
rows << row
|
||||||
end
|
end
|
||||||
rows
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes the given SQL statement. If additional parameters are given, they are treated as bind variables,
|
||||||
|
# and are bound to the placeholders in the query.
|
||||||
|
#
|
||||||
|
# Note that if any of the values passed to this are hashes, then the key/value pairs are each bound separately,
|
||||||
|
# with the key being used as the name of the placeholder to bind the value to.
|
||||||
|
#
|
||||||
|
# Yields one `Array(Value)` for each result.
|
||||||
def execute(sql, binds : Enumerable, &block)
|
def execute(sql, binds : Enumerable, &block)
|
||||||
query(sql, binds) do |result_set|
|
query(sql, binds) do |result_set|
|
||||||
while result_set.next
|
while result_set.next
|
||||||
|
@ -42,10 +85,12 @@ class SQLite3::Database
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A convenience method that returns the first row of a query result.
|
||||||
def get_first_row(sql, *binds)
|
def get_first_row(sql, *binds)
|
||||||
get_first_row(sql, binds)
|
get_first_row(sql, binds)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A convenience method that returns the first row of a query result.
|
||||||
def get_first_row(sql, binds : Enumerable)
|
def get_first_row(sql, binds : Enumerable)
|
||||||
query(sql, binds) do |result_set|
|
query(sql, binds) do |result_set|
|
||||||
if result_set.next
|
if result_set.next
|
||||||
|
@ -56,10 +101,12 @@ class SQLite3::Database
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A convenience method that returns the first value of the first row of a query result.
|
||||||
def get_first_value(sql, *binds)
|
def get_first_value(sql, *binds)
|
||||||
get_first_value(sql, binds)
|
get_first_value(sql, binds)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A convenience method that returns the first value of the first row of a query result.
|
||||||
def get_first_value(sql, binds : Enumerable)
|
def get_first_value(sql, binds : Enumerable)
|
||||||
query(sql, binds) do |result_set|
|
query(sql, binds) do |result_set|
|
||||||
if result_set.next
|
if result_set.next
|
||||||
|
@ -70,42 +117,53 @@ class SQLite3::Database
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a query and gives back a `ResultSet`.
|
||||||
def query(sql, *binds)
|
def query(sql, *binds)
|
||||||
query(sql, binds)
|
query(sql, binds)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a query and yields a `ResultSet` that will be closed at the end of the given block.
|
||||||
def query(sql, *binds, &block)
|
def query(sql, *binds, &block)
|
||||||
query(sql, binds) do |result_set|
|
query(sql, binds) do |result_set|
|
||||||
yield result_set
|
yield result_set
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a query and gives back a `ResultSet`.
|
||||||
def query(sql, binds : Enumerable)
|
def query(sql, binds : Enumerable)
|
||||||
prepare(sql).execute(binds)
|
prepare(sql).execute(binds)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a query and yields a `ResultSet` that will be closed at the end of the given block.
|
||||||
def query(sql, binds : Enumerable, &block)
|
def query(sql, binds : Enumerable, &block)
|
||||||
prepare(sql).execute(binds) do |result_set|
|
prepare(sql).execute(binds) do |result_set|
|
||||||
yield result_set
|
yield result_set
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Prepares an sql statement. Returns a `Statement`.
|
||||||
def prepare(sql)
|
def prepare(sql)
|
||||||
Statement.new(self, sql)
|
Statement.new(self, sql)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Obtains the unique row ID of the last row to be inserted by this Database instance.
|
||||||
|
# This is an `Int64`.
|
||||||
def last_insert_row_id
|
def last_insert_row_id
|
||||||
LibSQLite3.last_insert_rowid(self)
|
LibSQLite3.last_insert_rowid(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Quotes the given string, making it safe to use in an SQL statement.
|
||||||
|
# It replaces all instances of the single-quote character with two single-quote characters.
|
||||||
def quote(string)
|
def quote(string)
|
||||||
string.gsub('\'', "''")
|
string.gsub('\'', "''")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns `true` if this database instance has been closed (see `#close`).
|
||||||
def closed?
|
def closed?
|
||||||
@closed
|
@closed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Closes this database.
|
||||||
def close
|
def close
|
||||||
return if @closed
|
return if @closed
|
||||||
|
|
||||||
|
@ -114,10 +172,12 @@ class SQLite3::Database
|
||||||
LibSQLite3.close_v2(@db)
|
LibSQLite3.close_v2(@db)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
def finalize
|
def finalize
|
||||||
close
|
close
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
def to_unsafe
|
def to_unsafe
|
||||||
@db
|
@db
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
# Exception thrown on invalid SQLite3 operations.
|
||||||
class SQLite3::Exception < ::Exception
|
class SQLite3::Exception < ::Exception
|
||||||
|
# The internal code associated with the failure.
|
||||||
getter code
|
getter code
|
||||||
|
|
||||||
def initialize(db)
|
def initialize(db)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require "./type"
|
||||||
|
|
||||||
@[Link("sqlite3")]
|
@[Link("sqlite3")]
|
||||||
lib LibSQLite3
|
lib LibSQLite3
|
||||||
type SQLite3 = Void*
|
type SQLite3 = Void*
|
||||||
|
@ -31,14 +33,6 @@ lib LibSQLite3
|
||||||
DONE = 101
|
DONE = 101
|
||||||
end
|
end
|
||||||
|
|
||||||
enum Type
|
|
||||||
INTEGER = 1
|
|
||||||
FLOAT = 2
|
|
||||||
BLOB = 4
|
|
||||||
NULL = 5
|
|
||||||
TEXT = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
alias Callback = (Void*, Int32, UInt8**, UInt8**) -> Int32
|
alias Callback = (Void*, Int32, UInt8**, UInt8**) -> Int32
|
||||||
|
|
||||||
fun open = sqlite3_open_v2(filename : UInt8*, db : SQLite3*) : Int32
|
fun open = sqlite3_open_v2(filename : UInt8*, db : SQLite3*) : Int32
|
||||||
|
@ -50,7 +44,7 @@ lib LibSQLite3
|
||||||
fun prepare_v2 = sqlite3_prepare_v2(db : SQLite3, zSql : UInt8*, nByte : Int32, ppStmt : Statement*, pzTail : UInt8**) : Int32
|
fun prepare_v2 = sqlite3_prepare_v2(db : SQLite3, zSql : UInt8*, nByte : Int32, ppStmt : Statement*, pzTail : UInt8**) : Int32
|
||||||
fun step = sqlite3_step(stmt : Statement) : Int32
|
fun step = sqlite3_step(stmt : Statement) : Int32
|
||||||
fun column_count = sqlite3_column_count(stmt : Statement) : Int32
|
fun column_count = sqlite3_column_count(stmt : Statement) : Int32
|
||||||
fun column_type = sqlite3_column_type(stmt : Statement, iCol : Int32) : Int32
|
fun column_type = sqlite3_column_type(stmt : Statement, iCol : Int32) : SQLite3::Type
|
||||||
fun column_int64 = sqlite3_column_int64(stmt : Statement, iCol : Int32) : Int64
|
fun column_int64 = sqlite3_column_int64(stmt : Statement, iCol : Int32) : Int64
|
||||||
fun column_double = sqlite3_column_double(stmt : Statement, iCol : Int32) : Float64
|
fun column_double = sqlite3_column_double(stmt : Statement, iCol : Int32) : Float64
|
||||||
fun column_text = sqlite3_column_text(stmt : Statement, iCol : Int32) : UInt8*
|
fun column_text = sqlite3_column_text(stmt : Statement, iCol : Int32) : UInt8*
|
||||||
|
|
|
@ -1,15 +1,48 @@
|
||||||
|
# The ResultSet object encapsulates the enumerability of a query’s output.
|
||||||
|
# It is a simple cursor over the data that the query returns.
|
||||||
|
#
|
||||||
|
# Typical usage is:
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# require "sqlite3"
|
||||||
|
#
|
||||||
|
# db = SQLite3::Database.new("foo.db")
|
||||||
|
# stmt = db.prepare("select * from person")
|
||||||
|
# result_set = stmt.execute
|
||||||
|
# while result_set.next
|
||||||
|
# p result_set.to_a
|
||||||
|
# end
|
||||||
|
# stmt.close
|
||||||
|
# db.close
|
||||||
|
# ```
|
||||||
class SQLite3::ResultSet
|
class SQLite3::ResultSet
|
||||||
|
# :nodoc:
|
||||||
def initialize(@statement)
|
def initialize(@statement)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the number of columns.
|
||||||
def column_count
|
def column_count
|
||||||
@statement.column_count
|
@statement.column_count
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](index)
|
# Returns the value of a column by index or name.
|
||||||
@statement[index]
|
def [](index_or_name)
|
||||||
|
@statement[index_or_name]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the types of the columns, an `Array(Type)`.
|
||||||
|
def types
|
||||||
|
@statement.types
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the names of the columns, an `Array(String)`.
|
||||||
|
def columns
|
||||||
|
@statement.types
|
||||||
|
end
|
||||||
|
|
||||||
|
# Advances to the next row. Returns `true` if there's a next row,
|
||||||
|
# `false` otherwise. Must be called at least once to advance to the first
|
||||||
|
# row.
|
||||||
def next
|
def next
|
||||||
case @statement.step
|
case @statement.step
|
||||||
when LibSQLite3::Code::ROW
|
when LibSQLite3::Code::ROW
|
||||||
|
@ -21,11 +54,18 @@ class SQLite3::ResultSet
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Closes this result set, closing the associated statement.
|
||||||
def close
|
def close
|
||||||
@statement.close
|
@statement.close
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns `true` if the associated statement is closed.
|
||||||
|
def closed?
|
||||||
|
@statement.closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return the current row's value as an `Array(Value)`.
|
||||||
def to_a
|
def to_a
|
||||||
Array(ColumnType).new(column_count) { |i| self[i] }
|
Array(Value).new(column_count) { |i| self[i] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
# A statement represents a prepared-but-unexecuted SQL query.
|
||||||
class SQLite3::Statement
|
class SQLite3::Statement
|
||||||
|
# :nodoc:
|
||||||
def initialize(@db, sql)
|
def initialize(@db, sql)
|
||||||
check LibSQLite3.prepare_v2(@db, sql, sql.bytesize + 1, out @stmt, nil)
|
check LibSQLite3.prepare_v2(@db, sql, sql.bytesize + 1, out @stmt, nil)
|
||||||
@closed = false
|
@closed = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
def self.new(db, sql)
|
def self.new(db, sql)
|
||||||
statement = new db, sql
|
statement = new db, sql
|
||||||
begin
|
begin
|
||||||
|
@ -13,93 +16,87 @@ class SQLite3::Statement
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
def step
|
def step
|
||||||
LibSQLite3::Code.new LibSQLite3.step(self)
|
LibSQLite3::Code.new LibSQLite3.step(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the number of columns in this statement.
|
||||||
def column_count
|
def column_count
|
||||||
LibSQLite3.column_count(self)
|
LibSQLite3.column_count(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def column_type(index)
|
# Returns the `Type` of the column at the given index.
|
||||||
LibSQLite3::Type.new LibSQLite3.column_type(self, index.to_i32)
|
def column_type(index : Int)
|
||||||
|
LibSQLite3.column_type(self, index.to_i32)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the name of the column at the given index.
|
||||||
def column_name(index)
|
def column_name(index)
|
||||||
String.new LibSQLite3.column_name(self, index.to_i32)
|
String.new LibSQLite3.column_name(self, index.to_i32)
|
||||||
end
|
end
|
||||||
|
|
||||||
def column_int64(index)
|
# Executes this statement with the given binds and returns a `ResultSet`.
|
||||||
LibSQLite3.column_int64(self, index.to_i32)
|
|
||||||
end
|
|
||||||
|
|
||||||
def column_double(index)
|
|
||||||
LibSQLite3.column_double(self, index.to_i32)
|
|
||||||
end
|
|
||||||
|
|
||||||
def column_text(index)
|
|
||||||
LibSQLite3.column_text(self, index.to_i32)
|
|
||||||
end
|
|
||||||
|
|
||||||
def column_blob(index)
|
|
||||||
LibSQLite3.column_blob(self, index.to_i32)
|
|
||||||
end
|
|
||||||
|
|
||||||
def column_bytes(index)
|
|
||||||
LibSQLite3.column_bytes(self, index.to_i32)
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute(*binds)
|
def execute(*binds)
|
||||||
execute binds
|
execute binds
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes this statement with the given binds and yields a `ResultSet` that
|
||||||
|
# will be closed at the end of the block.
|
||||||
def execute(*binds)
|
def execute(*binds)
|
||||||
execute(binds) do |row|
|
execute(binds) do |row|
|
||||||
yield row
|
yield row
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes this statement with a single BLOB bind and returns a `ResultSet`.
|
||||||
def execute(binds : Slice(UInt8))
|
def execute(binds : Slice(UInt8))
|
||||||
reset
|
reset
|
||||||
self[1] = binds
|
self[1] = binds
|
||||||
ResultSet.new self
|
ResultSet.new self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes this statement with the given binds and returns a `ResultSet`.
|
||||||
def execute(binds : Enumerable)
|
def execute(binds : Enumerable)
|
||||||
reset
|
reset
|
||||||
binds.each_with_index(1) do |bind_value, index|
|
# TODO use offset after Crystal 0.6.2
|
||||||
self[index] = bind_value
|
binds.each_with_index do |bind_value, index|
|
||||||
|
self[index + 1] = bind_value
|
||||||
end
|
end
|
||||||
ResultSet.new self
|
ResultSet.new self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes this statement with the given binds and yields a `ResultSet` that
|
||||||
|
# will be closed at the end of the block.
|
||||||
def execute(binds : Enumerable | Slice(UInt8), &block)
|
def execute(binds : Enumerable | Slice(UInt8), &block)
|
||||||
result_set = execute(binds)
|
result_set = execute(binds)
|
||||||
yield result_set
|
yield result_set
|
||||||
close
|
close
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the value of the given column by index (1-based).
|
||||||
def [](index : Int)
|
def [](index : Int)
|
||||||
case type = column_type(index)
|
case type = column_type(index)
|
||||||
when LibSQLite3::Type::INTEGER
|
when Type::INTEGER
|
||||||
column_int64(index)
|
column_int64(index)
|
||||||
when LibSQLite3::Type::FLOAT
|
when Type::FLOAT
|
||||||
column_double(index)
|
column_double(index)
|
||||||
when LibSQLite3::Type::TEXT
|
when Type::TEXT
|
||||||
String.new(column_text(index))
|
String.new(column_text(index))
|
||||||
when LibSQLite3::Type::BLOB
|
when Type::BLOB
|
||||||
blob = column_blob(index)
|
blob = column_blob(index)
|
||||||
bytes = column_bytes(index)
|
bytes = column_bytes(index)
|
||||||
ptr = Pointer(UInt8).malloc(bytes)
|
ptr = Pointer(UInt8).malloc(bytes)
|
||||||
ptr.copy_from(blob, bytes)
|
ptr.copy_from(blob, bytes)
|
||||||
Slice.new(ptr, bytes)
|
Slice.new(ptr, bytes)
|
||||||
when LibSQLite3::Type::NULL
|
when Type::NULL
|
||||||
nil
|
nil
|
||||||
else
|
else
|
||||||
raise "Unknown column type: #{type}"
|
raise "Unknown column type: #{type}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the value of the given column by name.
|
||||||
def [](name : String)
|
def [](name : String)
|
||||||
column_count.times do |i|
|
column_count.times do |i|
|
||||||
if column_name(i) == name
|
if column_name(i) == name
|
||||||
|
@ -109,30 +106,37 @@ class SQLite3::Statement
|
||||||
raise "Unknown column: #{name}"
|
raise "Unknown column: #{name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds the parameter at the given index to an Int.
|
||||||
def []=(index : Int, value : Nil)
|
def []=(index : Int, value : Nil)
|
||||||
check LibSQLite3.bind_null(self, index.to_i32)
|
check LibSQLite3.bind_null(self, index.to_i32)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds the parameter at the given index to an Int32.
|
||||||
def []=(index : Int, value : Int32)
|
def []=(index : Int, value : Int32)
|
||||||
check LibSQLite3.bind_int(self, index.to_i32, value)
|
check LibSQLite3.bind_int(self, index.to_i32, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds the parameter at the given index to an Int64.
|
||||||
def []=(index : Int, value : Int64)
|
def []=(index : Int, value : Int64)
|
||||||
check LibSQLite3.bind_int64(self, index.to_i32, value)
|
check LibSQLite3.bind_int64(self, index.to_i32, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds the parameter at the given index to a Float.
|
||||||
def []=(index : Int, value : Float)
|
def []=(index : Int, value : Float)
|
||||||
check LibSQLite3.bind_double(self, index.to_i32, value.to_f64)
|
check LibSQLite3.bind_double(self, index.to_i32, value.to_f64)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds the parameter at the given index to a String.
|
||||||
def []=(index : Int, value : String)
|
def []=(index : Int, value : String)
|
||||||
check LibSQLite3.bind_text(self, index.to_i32, value, value.bytesize, nil)
|
check LibSQLite3.bind_text(self, index.to_i32, value, value.bytesize, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds the parameter at the given index to a BLOB.
|
||||||
def []=(index : Int, value : Slice(UInt8))
|
def []=(index : Int, value : Slice(UInt8))
|
||||||
check LibSQLite3.bind_blob(self, index.to_i32, value, value.length, nil)
|
check LibSQLite3.bind_blob(self, index.to_i32, value, value.length, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds a named parameter, using the `:AAAA` naming scheme for parameters.
|
||||||
def []=(name : String | Symbol, value)
|
def []=(name : String | Symbol, value)
|
||||||
converted_name = ":#{name}"
|
converted_name = ":#{name}"
|
||||||
index = LibSQLite3.bind_parameter_index(self, converted_name)
|
index = LibSQLite3.bind_parameter_index(self, converted_name)
|
||||||
|
@ -142,20 +146,31 @@ class SQLite3::Statement
|
||||||
self[index] = value
|
self[index] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Binds a hash to this statement (the `index` is ignored).
|
||||||
def []=(index : Int, hash : Hash)
|
def []=(index : Int, hash : Hash)
|
||||||
hash.each do |key, value|
|
hash.each do |key, value|
|
||||||
self[key] = value
|
self[key] = value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the column names of this statement.
|
||||||
def columns
|
def columns
|
||||||
Array.new(column_count) { |i| column_name(i) }
|
Array.new(column_count) { |i| column_name(i) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns an `Array(Type)` of this statement's columns. Note that the statement
|
||||||
|
# must be executed in order for this to return sensible values, otherwise all types
|
||||||
|
# will be NULL.
|
||||||
|
def types
|
||||||
|
Array.new(column_count) { |i| column_type(i) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Reset this statment, allowing to re-execute it with new binds.
|
||||||
def reset
|
def reset
|
||||||
LibSQLite3.reset(self)
|
LibSQLite3.reset(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Closes this statement.
|
||||||
def close
|
def close
|
||||||
raise "Statement already closed" if @closed
|
raise "Statement already closed" if @closed
|
||||||
@closed = true
|
@closed = true
|
||||||
|
@ -163,14 +178,36 @@ class SQLite3::Statement
|
||||||
check LibSQLite3.finalize(self)
|
check LibSQLite3.finalize(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns `true` if this statement is closed. See `#close`.
|
||||||
def closed?
|
def closed?
|
||||||
@closed
|
@closed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
def to_unsafe
|
def to_unsafe
|
||||||
@stmt
|
@stmt
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private def column_int64(index)
|
||||||
|
LibSQLite3.column_int64(self, index.to_i32)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def column_double(index)
|
||||||
|
LibSQLite3.column_double(self, index.to_i32)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def column_text(index)
|
||||||
|
LibSQLite3.column_text(self, index.to_i32)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def column_blob(index)
|
||||||
|
LibSQLite3.column_blob(self, index.to_i32)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def column_bytes(index)
|
||||||
|
LibSQLite3.column_bytes(self, index.to_i32)
|
||||||
|
end
|
||||||
|
|
||||||
private def check(code)
|
private def check(code)
|
||||||
raise Exception.new(@db) unless code == 0
|
raise Exception.new(@db) unless code == 0
|
||||||
end
|
end
|
||||||
|
|
8
src/sqlite3/type.cr
Normal file
8
src/sqlite3/type.cr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Each of the possible types of an SQLite3 column.
|
||||||
|
enum SQLite3::Type
|
||||||
|
INTEGER = 1
|
||||||
|
FLOAT = 2
|
||||||
|
BLOB = 4
|
||||||
|
NULL = 5
|
||||||
|
TEXT = 3
|
||||||
|
end
|
4
src/sqlite3/value.cr
Normal file
4
src/sqlite3/value.cr
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
module SQLite3
|
||||||
|
# All possible values of each column of a row returned by `Database#execute`.
|
||||||
|
alias Value = Nil | Int64 | Float64 | String | Slice(UInt8)
|
||||||
|
end
|
Loading…
Reference in a new issue