Skip to content

Commit 23f5933

Browse files
committed
- Changed the behavior of RunnableSelect::fetchRowsLazy: If a $callback-Closure returns NULL will not cause a row to be omitted anymore; Row-by-reference is now possible; If a DBIgnoreRow is returned in a closure, the Row will be omitted now
- Changed the behavior of RunnableSelect::fetchRows: If a $callback-Closure returns NULL will not cause a row to be omitted anymore; Row-by-reference is now possible; If a DBIgnoreRow is returned in a closure, the Row will be omitted now - Added parameter $callback to RunnableSelect::fetchRow
1 parent 3e0fd78 commit 23f5933

File tree

6 files changed

+125
-19
lines changed

6 files changed

+125
-19
lines changed

src/Builder/Helpers/DBIgnoreRow.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
namespace Kir\MySQL\Builder\Helpers;
3+
4+
class DBIgnoreRow {}

src/Builder/Helpers/LazyRowGenerator.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ public function generate(QueryStatement $statement, Closure $callback = null) {
2727
$row = FieldValueConverter::convertValues($row, $columnDefinitions);
2828
}
2929
if($callback !== null) {
30-
$row = call_user_func($callback, $row);
31-
if($row !== null) {
30+
$result = $callback($row);
31+
if($result instanceof DBIgnoreRow) {
32+
// Do nothing in this case
33+
} elseif($result !== null) {
34+
yield $result;
35+
} else {
3236
yield $row;
3337
}
3438
} else {

src/Builder/RunnableSelect.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use Closure;
55
use IteratorAggregate;
6+
use Kir\MySQL\Builder\Helpers\DBIgnoreRow;
67
use Kir\MySQL\Builder\Helpers\FieldTypeProvider;
78
use Kir\MySQL\Builder\Helpers\FieldValueConverter;
89
use Kir\MySQL\Builder\Helpers\LazyRowGenerator;
@@ -68,7 +69,16 @@ public function fetchRows(Closure $callback = null) {
6869
}
6970
}
7071
if($callback !== null) {
71-
$data = array_map($callback, $data);
72+
$resultData = [];
73+
foreach($data as $row) {
74+
$result = $callback($row);
75+
if($result !== null && !($result instanceof DBIgnoreRow)) {
76+
$resultData[] = $result;
77+
} else {
78+
$resultData[] = $row;
79+
}
80+
}
81+
return $resultData;
7282
}
7383
return $data;
7484
});
@@ -88,18 +98,26 @@ public function fetchRowsLazy(Closure $callback = null) {
8898
}
8999

90100
/**
101+
* @param Closure|null $callback
91102
* @return string[]
103+
* @throws \Exception
92104
*/
93-
public function fetchRow() {
94-
return $this->createTempStatement(function (QueryStatement $statement) {
105+
public function fetchRow(Closure $callback = null) {
106+
return $this->createTempStatement(function (QueryStatement $statement) use ($callback) {
95107
$row = $statement->fetch(\PDO::FETCH_ASSOC);
96108
if(!is_array($row)) {
97-
return array();
109+
return [];
98110
}
99111
if($this->preserveTypes) {
100112
$columnDefinitions = FieldTypeProvider::getFieldTypes($statement);
101113
$row = FieldValueConverter::convertValues($row, $columnDefinitions);
102114
}
115+
if($callback !== null) {
116+
$result = $callback($row);
117+
if($result !== null) {
118+
$row = $result;
119+
}
120+
}
103121
return $row;
104122
});
105123
}

tests/Builder/SelectTest.php

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -248,68 +248,61 @@ public function testOptionalExpressions() {
248248
$opt = new OptionalDBFilterMap($filter);
249249

250250
$query = TestSelect::create()
251-
->distinct()
252251
->field('t.field')
253252
->from('t', 'test')
254253
->where($opt('t.field=?', ['filter', 'name']))
255254
->asString();
256255

257-
$this->assertEquals("SELECT DISTINCT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field='aaa')\n", $query);
256+
$this->assertEquals("SELECT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field='aaa')\n", $query);
258257

259258
$query = TestSelect::create()
260-
->distinct()
261259
->field('t.field')
262260
->from('t', 'test')
263261
->where($opt('t.field=?', 'filter.name'))
264262
->asString();
265263

266-
$this->assertEquals("SELECT DISTINCT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field='aaa')\n", $query);
264+
$this->assertEquals("SELECT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field='aaa')\n", $query);
267265

268266
$query = TestSelect::create()
269-
->distinct()
270267
->field('t.field')
271268
->from('t', 'test')
272269
->where($opt('t.field=?', ['filter', 'age']))
273270
->asString();
274271

275-
$this->assertEquals("SELECT DISTINCT\n\tt.field\nFROM\n\ttest t\n", $query);
272+
$this->assertEquals("SELECT\n\tt.field\nFROM\n\ttest t\n", $query);
276273

277274
$query = TestSelect::create()
278-
->distinct()
279275
->field('t.field')
280276
->from('t', 'test')
281277
->where($opt('t.field IN (?)', ['filter', 'ids']))
282278
->asString();
283279

284-
$this->assertEquals("SELECT DISTINCT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field IN ('1', '2', '3'))\n", $query);
280+
$this->assertEquals("SELECT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field IN ('1', '2', '3'))\n", $query);
285281

286282
$query = TestSelect::create()
287-
->distinct()
288283
->field('t.field')
289284
->from('t', 'test')
290285
->where($opt('t.field=?', ['filter', 'empty']))
291286
->asString();
292287

293-
$this->assertEquals("SELECT DISTINCT\n\tt.field\nFROM\n\ttest t\n", $query);
288+
$this->assertEquals("SELECT\n\tt.field\nFROM\n\ttest t\n", $query);
294289
}
295290

296291
public function testRequired() {
297292
$filter = ['filter' => ['name' => 'aaa']];
298293
$req = new RequiredDBFilterMap($filter);
299294

300295
$query = TestSelect::create()
301-
->distinct()
302296
->field('t.field')
303297
->from('t', 'test')
304298
->where($req('t.field=?', ['filter', 'name']))
305299
->asString();
306300

307-
$this->assertEquals("SELECT DISTINCT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field='aaa')\n", $query);
301+
$this->assertEquals("SELECT\n\tt.field\nFROM\n\ttest t\nWHERE\n\t(t.field='aaa')\n", $query);
308302

309303
$this->setExpectedException('Kir\\MySQL\\Builder\\Expr\\RequiredValueNotFoundException');
310304

311305
TestSelect::create()
312-
->distinct()
313306
->field('t.field')
314307
->from('t', 'test')
315308
->where($req('t.field=?', 'filter.id'))

tests/Databases/MySQLTest.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use Kir\FakePDO\EventHandlers\RegistryEventHandler;
55
use Kir\FakePDO\FakePDO;
6+
use Kir\MySQL\Builder\SelectTest\TestSelect;
67

78
class MySQLTest extends \PHPUnit_Framework_TestCase {
89
/** @var TestDB */
@@ -117,4 +118,89 @@ public function testOuterNestedTransaction() {
117118
$mysql->transactionRollback();
118119
$mysql->transactionRollback();
119120
}
121+
122+
public function testFetchRow() {
123+
// Closure w/o return, but with reference
124+
$row = TestSelect::create()
125+
->field('t.id')
126+
->from('t', 'test#test1')
127+
->where('t.id=?', 1)
128+
->fetchRow(function (array &$row) {
129+
$row['test'] = 10;
130+
});
131+
$this->assertEquals(['id' => 1, 'test' => 10], $row);
132+
133+
// Closure with return
134+
$row = TestSelect::create()
135+
->field('t.id')
136+
->from('t', 'test#test1')
137+
->where('t.id=?', 1)
138+
->fetchRow(function (array $row) {
139+
$row['test'] = 10;
140+
return $row;
141+
});
142+
$this->assertEquals(['id' => 1, 'test' => 10], $row);
143+
}
144+
145+
public function testFetchRows() {
146+
// Closure w/o return, but with reference
147+
$rows = TestSelect::create()
148+
->field('t.id')
149+
->from('t', 'test#test1')
150+
->where('t.id=?', 1)
151+
->fetchRows(function (array &$row) {
152+
$row['test'] = 10;
153+
});
154+
155+
$this->assertEquals([['id' => 1, 'test' => 10]], $rows);
156+
157+
// Closure with return
158+
$rows = TestSelect::create()
159+
->field('t.id')
160+
->from('t', 'test#test1')
161+
->where('t.id=?', 1)
162+
->fetchRows(function (array $row) {
163+
$row['test'] = 10;
164+
return $row;
165+
});
166+
167+
$this->assertEquals([['id' => 1, 'test' => 10]], $rows);
168+
}
169+
170+
public function testFetchRowsLazy() {
171+
// Closure w/o return, but with reference
172+
$rows = TestSelect::create()
173+
->field('t.id')
174+
->from('t', 'test#test1')
175+
->where('t.id=?', 1)
176+
->fetchRowsLazy(function (array &$row) {
177+
$row['test'] = 10;
178+
});
179+
$rows = iterator_to_array($rows);
180+
$this->assertEquals([['id' => 1, 'test' => 10]], $rows);
181+
182+
// Closure with return
183+
$rows = TestSelect::create()
184+
->field('t.id')
185+
->from('t', 'test#test1')
186+
->where('t.id=?', 1)
187+
->fetchRowsLazy(function (array $row) {
188+
$row['test'] = 10;
189+
return $row;
190+
});
191+
$rows = iterator_to_array($rows);
192+
$this->assertEquals([['id' => 1, 'test' => 10]], $rows);
193+
194+
// IgnoredRow
195+
$rows = TestSelect::create()
196+
->field('t.id')
197+
->from('t', 'test#test1')
198+
->where('t.id=?', 1)
199+
->fetchRowsLazy(function (array $row) {
200+
$row['test'] = 10;
201+
return $row;
202+
});
203+
$rows = iterator_to_array($rows);
204+
$this->assertEquals([['id' => 1, 'test' => 10]], $rows);
205+
}
120206
}

tests/Databases/TestDB.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public function __construct() {
2929
parent::__construct($this->pdo);
3030
$this->aliasRegistry = new AliasRegistry();
3131
$this->getAliasRegistry()->add('travis', 'travis_test.');
32+
$this->getAliasRegistry()->add('test', 'travis_test.');
3233
}
3334

3435
/**

0 commit comments

Comments
 (0)