From 135f33d9eac82c63a48b14942c8eff647c070410 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Wed, 15 Jun 2016 12:05:12 -0300 Subject: [PATCH] Updated to Crystal 0.18.0 --- shard.yml | 2 +- spec/database_spec.cr | 44 ++++++++++++++++++++++++++++++++++++---- src/sqlite3/database.cr | 30 ++++++++++++++++++++++----- src/sqlite3/statement.cr | 30 +++++++++++++++++++++++---- src/sqlite3/type.cr | 8 ++++---- 5 files changed, 96 insertions(+), 18 deletions(-) diff --git a/shard.yml b/shard.yml index 3f8bbc4..b4ee951 100644 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: sqlite3 -version: 0.3.0 +version: 0.4.0 authors: - Ary Borenszweig diff --git a/spec/database_spec.cr b/spec/database_spec.cr index 612d599..a9aeda2 100644 --- a/spec/database_spec.cr +++ b/spec/database_spec.cr @@ -72,23 +72,31 @@ describe Database do it "executes and selects blob" do rows = with_db(&.execute(%(select X'53514C697465'))) row = rows[0] - cell = row[0] as Slice(UInt8) + cell = row[0].as(Slice(UInt8)) cell.to_a.should eq([0x53, 0x51, 0x4C, 0x69, 0x74, 0x65]) end it "executes with named bind using symbol" do - with_db(&.execute(%(select :value), {value: "hello"})).should eq([["hello"]]) + with_db(&.execute(%(select :value), {:value => "hello"})).should eq([["hello"]]) end it "executes with named bind using string" do - with_db(&.execute(%(select :value), {"value": "hello"})).should eq([["hello"]]) + with_db(&.execute(%(select :value), {"value" => "hello"})).should eq([["hello"]]) + end + + it "executes with named bind using named argument" do + with_db(&.execute(%(select :value), {value: "hello"})).should eq([["hello"]]) + end + + it "executes with named bind using named arguments" do + with_db(&.execute(%(select :value), value: "hello")).should eq([["hello"]]) end it "executes with bind blob" do ary = UInt8[0x53, 0x51, 0x4C, 0x69, 0x74, 0x65] rows = with_db(&.execute(%(select cast(? as BLOB)), Slice.new(ary.to_unsafe, ary.size))) row = rows[0] - cell = row[0] as Slice(UInt8) + cell = row[0].as(Slice(UInt8)) cell.to_a.should eq(ary) end @@ -113,6 +121,20 @@ describe Database do end end + it "uses named arguments in statement execute" do + Database.new(":memory:") do |db| + db.execute "create table person (name string, age integer)" + db.execute %(insert into person values ("foo", 10)) + db.execute %(insert into person values ("bar", 2)) + stmt = db.prepare("select * from person where age > :age") + stmt.execute age: 5 + stmt.step + stmt["age"].should eq(10) + stmt.types.should eq([Type::TEXT, Type::INTEGER]) + stmt.close + end + end + it "gets column by name" do Database.new(":memory:") do |db| db.execute "create table person (name string, age integer)" @@ -126,6 +148,20 @@ describe Database do end end + it "uses named argument in query" do + Database.new(":memory:") do |db| + db.execute "create table person (name string, age integer)" + db.execute %(insert into person values ("foo", 10)) + db.execute %(insert into person values ("bar", 2)) + db.query("select * from person where age > :age", age: 5) do |result_set| + result_set.next.should be_true + result_set["name"].should eq("foo") + result_set["age"].should eq(10) + expect_raises { result_set["lala"] } + end + end + end + it "gets last insert row id" do Database.new(":memory:") do |db| db.execute "create table person (name string, age integer)" diff --git a/src/sqlite3/database.cr b/src/sqlite3/database.cr index bd6e390..5df6dd8 100644 --- a/src/sqlite3/database.cr +++ b/src/sqlite3/database.cr @@ -84,6 +84,10 @@ class SQLite3::Database execute(sql, binds) end + def execute(sql, **binds) + execute(sql, binds) + 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. # @@ -97,6 +101,12 @@ class SQLite3::Database end end + def execute(sql, **binds, &block) + execute(sql, binds) do |row| + yield row + 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. # @@ -104,7 +114,7 @@ class SQLite3::Database # 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 | NamedTuple) rows = [] of Array(Value) execute(sql, binds) do |row| rows << row @@ -119,7 +129,7 @@ class SQLite3::Database # 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 | NamedTuple, &block) query(sql, binds) do |result_set| while result_set.next yield result_set.to_a @@ -149,7 +159,7 @@ class SQLite3::Database 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 | NamedTuple) query(sql, binds) do |result_set| if result_set.next return result_set[0] @@ -172,17 +182,27 @@ class SQLite3::Database end # Executes a query and gives back a `ResultSet`. - def query(sql, binds : Enumerable) + def query(sql, binds : Enumerable | NamedTuple) prepare(sql).execute(binds) 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 | NamedTuple, &block) prepare(sql).execute(binds) do |result_set| yield result_set end end + def query(sql, **binds) + query(sql, binds) + end + + def query(sql, **binds, &block) + query(sql, binds) do |rs| + yield rs + end + end + # Prepares an sql statement. Returns a `Statement`. def prepare(sql) Statement.new(self, sql) diff --git a/src/sqlite3/statement.cr b/src/sqlite3/statement.cr index c87e858..c023a9c 100644 --- a/src/sqlite3/statement.cr +++ b/src/sqlite3/statement.cr @@ -61,22 +61,40 @@ class SQLite3::Statement # Executes this statement with the given binds and returns a `ResultSet`. def execute(binds : Enumerable) reset - # TODO use offset after Crystal 0.6.2 - binds.each_with_index do |bind_value, index| - self[index + 1] = bind_value + binds.each_with_index(1) do |bind_value, index| + self[index] = bind_value + end + ResultSet.new self + end + + # Executes this statement with the given binds and returns a `ResultSet`. + def execute(binds : NamedTuple) + reset + binds.each do |name, bind_value| + self[name] = bind_value end ResultSet.new self 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 | NamedTuple | Slice(UInt8), &block) result_set = execute(binds) yield result_set ensure close end + def execute(**binds) + execute(binds) + end + + def execute(**binds, &block) + execute(binds) do |rs| + yield rs + end + end + # Returns the value of the given column by index (1-based). def [](index : Int) case type = column_type(index) @@ -156,6 +174,10 @@ class SQLite3::Statement end end + def []=(index : Int, tuple : Tuple(String | Symbol, U)) + self[tuple[0]] = tuple[1] + end + # Returns the column names of this statement. def columns Array.new(column_count) { |i| column_name(i) } diff --git a/src/sqlite3/type.cr b/src/sqlite3/type.cr index 4008f39..a4abe0e 100644 --- a/src/sqlite3/type.cr +++ b/src/sqlite3/type.cr @@ -1,8 +1,8 @@ # Each of the possible types of an SQLite3 column. enum SQLite3::Type INTEGER = 1 - FLOAT = 2 - BLOB = 4 - NULL = 5 - TEXT = 3 + FLOAT = 2 + BLOB = 4 + NULL = 5 + TEXT = 3 end