From defc3c35309ff6a056af7b83d48c6210521955aa 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 780634c57e2db496c87e001121d75d93654ef716 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 1577ea06057913e6d661eaedeb638ed292cb1c80 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 67236c4e1d0dcad962e35859a769a6225666867c 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 10c7afc8e869d3598aa2c5430a117c6b0fbb7b0e 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 5127f038ffee61c6ad4703374b80625cbb1876c9 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