From 406f144add9332a942bb06fce1ee52486171a8d9 Mon Sep 17 00:00:00 2001 From: Caio Chassot Date: Wed, 19 Nov 2025 14:15:35 -0300 Subject: [PATCH 1/6] support calling each_hash without block. returns enumerator --- lib/sqlite3/resultset.rb | 1 + test/test_result_set.rb | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/lib/sqlite3/resultset.rb b/lib/sqlite3/resultset.rb index 8af61913..6ecbf7fb 100644 --- a/lib/sqlite3/resultset.rb +++ b/lib/sqlite3/resultset.rb @@ -54,6 +54,7 @@ def each # Provides an internal iterator over the rows of the result set where # each row is yielded as a hash. def each_hash + return enum_for(__method__) unless block_given? while (node = next_hash) yield node end diff --git a/test/test_result_set.rb b/test/test_result_set.rb index 4fc12280..bdde3d64 100644 --- a/test/test_result_set.rb +++ b/test/test_result_set.rb @@ -24,6 +24,12 @@ def test_each_hash assert_equal list[hash["a"] - 1], hash["b"] end rs.close + + rs = @db.prepare("select * from foo").execute + rs.each_hash.to_a do |hash| + assert_equal list[hash["a"] - 1], hash["b"] + end + rs.close end def test_next_hash From f5110f00f6481936789f2674b269e49019021480 Mon Sep 17 00:00:00 2001 From: Caio Chassot Date: Wed, 19 Nov 2025 15:26:59 -0300 Subject: [PATCH 2/6] support calling #each without block. returns enumerator --- lib/sqlite3/resultset.rb | 1 + test/test_integration_resultset.rb | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/sqlite3/resultset.rb b/lib/sqlite3/resultset.rb index 6ecbf7fb..bb8819f4 100644 --- a/lib/sqlite3/resultset.rb +++ b/lib/sqlite3/resultset.rb @@ -46,6 +46,7 @@ def next # Required by the Enumerable mixin. Provides an internal iterator over the # rows of the result set. def each + return enum_for(__method__) unless block_given? while (node = self.next) yield node end diff --git a/test/test_integration_resultset.rb b/test/test_integration_resultset.rb index 531d6154..c7ab9048 100644 --- a/test/test_integration_resultset.rb +++ b/test/test_integration_resultset.rb @@ -117,6 +117,13 @@ def test_each assert_equal 2, called end + def test_each_enum + called = 0 + @result.reset(1, 2) + @result.each.to_a.each { |row| called += 1 } + assert_equal 2, called + end + def test_enumerable @result.reset(1, 2) assert_equal 2, @result.to_a.length @@ -139,7 +146,7 @@ def test_close assert_predicate stmt, :closed? assert_raise(SQLite3::Exception) { result.reset } assert_raise(SQLite3::Exception) { result.next } - assert_raise(SQLite3::Exception) { result.each } + assert_raise(SQLite3::Exception) { result.each.next } assert_raise(SQLite3::Exception) { result.close } assert_raise(SQLite3::Exception) { result.types } assert_raise(SQLite3::Exception) { result.columns } From f91905c37503adf96b6eb40c4868ea44fecc6f59 Mon Sep 17 00:00:00 2001 From: Caio Chassot Date: Sat, 29 Nov 2025 18:26:21 -0300 Subject: [PATCH 3/6] each, each_hash return self when called with block. allows chaining; also update docs --- lib/sqlite3/resultset.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/sqlite3/resultset.rb b/lib/sqlite3/resultset.rb index bb8819f4..e8d7b2b9 100644 --- a/lib/sqlite3/resultset.rb +++ b/lib/sqlite3/resultset.rb @@ -43,22 +43,26 @@ def next @stmt.step end - # Required by the Enumerable mixin. Provides an internal iterator over the - # rows of the result set. + # With a block given, iterates over the rows of the result set, passing each + # to the block. Returns self. + # With no block given, returns a new Enumerator. def each return enum_for(__method__) unless block_given? while (node = self.next) yield node end + self end - # Provides an internal iterator over the rows of the result set where - # each row is yielded as a hash. + # With a block given, iterates over the rows of the result set, passing each + # to the block as a hash. Returns self. + # With no block given, returns a new Enumerator. def each_hash return enum_for(__method__) unless block_given? while (node = next_hash) yield node end + self end # Closes the statement that spawned this result set. From 7e0e90a0a3e9c0d164801233ec3255d659e20475 Mon Sep 17 00:00:00 2001 From: Caio Chassot Date: Sat, 29 Nov 2025 18:30:48 -0300 Subject: [PATCH 4/6] fix test that wasn't doing anything --- test/test_result_set.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_result_set.rb b/test/test_result_set.rb index bdde3d64..02b85691 100644 --- a/test/test_result_set.rb +++ b/test/test_result_set.rb @@ -26,7 +26,7 @@ def test_each_hash rs.close rs = @db.prepare("select * from foo").execute - rs.each_hash.to_a do |hash| + rs.each_hash.to_a.each do |hash| # each_hash without block, to_a confirms enum assert_equal list[hash["a"] - 1], hash["b"] end rs.close From b2d65449391e82a4195a2d435896776af4faf16a Mon Sep 17 00:00:00 2001 From: Caio Chassot Date: Sat, 29 Nov 2025 18:31:34 -0300 Subject: [PATCH 5/6] also test each_hash.next raises when closed --- test/test_integration_resultset.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_integration_resultset.rb b/test/test_integration_resultset.rb index c7ab9048..21e376f7 100644 --- a/test/test_integration_resultset.rb +++ b/test/test_integration_resultset.rb @@ -147,6 +147,7 @@ def test_close assert_raise(SQLite3::Exception) { result.reset } assert_raise(SQLite3::Exception) { result.next } assert_raise(SQLite3::Exception) { result.each.next } + assert_raise(SQLite3::Exception) { result.each_hash.next } assert_raise(SQLite3::Exception) { result.close } assert_raise(SQLite3::Exception) { result.types } assert_raise(SQLite3::Exception) { result.columns } From d9798a9d2d3ad5f36efe9c5ce1431a8f5b102274 Mon Sep 17 00:00:00 2001 From: Caio Chassot Date: Sat, 29 Nov 2025 18:32:46 -0300 Subject: [PATCH 6/6] test each/each_hash return Enumerator w/o block, return self w/ block --- test/test_integration_resultset.rb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/test_integration_resultset.rb b/test/test_integration_resultset.rb index 21e376f7..9c7c312c 100644 --- a/test/test_integration_resultset.rb +++ b/test/test_integration_resultset.rb @@ -113,17 +113,35 @@ def test_next_results_as_hash def test_each called = 0 @result.reset(1, 2) - @result.each { |row| called += 1 } + result = @result.each { |row| called += 1 } + result.reset # reset just to confirm we can chain the method after each + assert_equal @result, result assert_equal 2, called end def test_each_enum + @result.reset(1, 2) + enum = @result.each + assert_instance_of Enumerator, enum + assert_equal 2, enum.to_a.length + end + + def test_each_hash called = 0 @result.reset(1, 2) - @result.each.to_a.each { |row| called += 1 } + result = @result.each_hash { |row| called += 1 } + result.reset + assert_equal @result, result assert_equal 2, called end + def test_each_hash_enum + @result.reset(1, 2) + enum = @result.each_hash + assert_instance_of Enumerator, enum + assert_equal 2, enum.to_a.length + end + def test_enumerable @result.reset(1, 2) assert_equal 2, @result.to_a.length