Skip to content

Commit 41c2bc9

Browse files
committed
Add PG::Result#each_tuple
There's already #stream_each_tuple but the non-streaming counterpart for it was missing.
1 parent 57b127a commit 41c2bc9

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

ext/pg_result.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ static void pgresult_init_fnames(VALUE self)
532532
* res.column_values(1) # ["2"]
533533
* res.each.first # {"a" => "1", "b" => "2", "c" => nil}
534534
* res.each_row.first # ["1", "2", nil]
535+
* res.each_tuple.first # #<PG::Tuple a: "1", b: "2", c: nil>
535536
*
536537
* Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map which is PG::TypeMapAllStrings by default.
537538
* Similarly field names can be retrieved either as strings (default) or as symbols which can be switched per #field_name_type= .
@@ -550,6 +551,7 @@ static void pgresult_init_fnames(VALUE self)
550551
* res.column_values(1) # [2]
551552
* res.each.first # {a: 1, b: 2, c: nil}
552553
* res.each_row.first # [1, 2, nil]
554+
* res.each_tuple.first # #<PG::Tuple a: 1, b: 2, c: nil>
553555
*
554556
* Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
555557
* You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
@@ -1435,6 +1437,32 @@ pgresult_each(VALUE self)
14351437
return self;
14361438
}
14371439

1440+
/*
1441+
* call-seq:
1442+
* res.each_tuple{ |tuple| ... }
1443+
*
1444+
* Yields a PG::Tuple object for each row in the result.
1445+
*
1446+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1447+
* res.each_tuple.first # #<PG::Tuple a: "1", b: "2", c: nil>
1448+
*/
1449+
static VALUE
1450+
pgresult_each_tuple(VALUE self)
1451+
{
1452+
PGresult *result;
1453+
int tuple_num;
1454+
1455+
RETURN_SIZED_ENUMERATOR(self, 0, NULL, pgresult_ntuples_for_enum);
1456+
1457+
result = pgresult_get(self);
1458+
1459+
for(tuple_num = 0; tuple_num < PQntuples(result); tuple_num++) {
1460+
VALUE tuple = pgresult_tuple(self, INT2FIX(tuple_num));
1461+
rb_yield( tuple );
1462+
}
1463+
return self;
1464+
}
1465+
14381466
/*
14391467
* call-seq:
14401468
* res.fields() -> Array
@@ -1802,6 +1830,7 @@ init_pg_result(void)
18021830
rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
18031831
rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
18041832
rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
1833+
rb_define_method(rb_cPGresult, "each_tuple", pgresult_each_tuple, 0);
18051834
rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
18061835
rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
18071836
rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);

spec/pg/result_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@
106106
expect( list ).to eq [['1', '2']]
107107
end
108108

109+
it "yields a row as a PG::Tuple" do
110+
res = @conn.exec("SELECT 2 AS a, NULL AS b")
111+
list = []
112+
res.each_tuple { |r| list << r }
113+
expect( list.map(&:class) ).to eq [PG::Tuple]
114+
expect( list.map(&:to_h) ).to eq([{"a" => "2", "b" => nil}])
115+
end
116+
109117
it "yields a row as an Enumerator" do
110118
res = @conn.exec("SELECT 1 AS a, 2 AS b")
111119
e = res.each_row

0 commit comments

Comments
 (0)