Skip to content

Commit b0a8e0a

Browse files
authored
Refactor Command::insertWithReturningPks() method (#324)
1 parent 4f87e11 commit b0a8e0a

File tree

6 files changed

+102
-282
lines changed

6 files changed

+102
-282
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
- Enh #318, #320: Use `DbArrayHelper::arrange()` instead of `DbArrayHelper::index()` method (@Tigrov)
4646
- New #316: Realize `Schema::loadResultColumn()` method (@Tigrov)
4747
- New #323: Use `DateTimeColumn` class for datetime column types (@Tigrov)
48+
- Enh #324: Refactor `Command::insertWithReturningPks()` method (@Tigrov)
4849

4950
## 1.3.0 March 21, 2024
5051

src/Command.php

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
use Yiisoft\Db\Constant\DataType;
99
use Yiisoft\Db\Constant\PhpType;
1010
use Yiisoft\Db\Driver\Pdo\AbstractPdoCommand;
11+
use Yiisoft\Db\Query\QueryInterface;
1112
use Yiisoft\Db\QueryBuilder\AbstractQueryBuilder;
1213

1314
use function array_keys;
15+
use function array_map;
1416
use function count;
1517
use function implode;
1618
use function strlen;
@@ -21,7 +23,7 @@
2123
*/
2224
final class Command extends AbstractPdoCommand
2325
{
24-
public function insertWithReturningPks(string $table, array $columns): array|false
26+
public function insertWithReturningPks(string $table, array|QueryInterface $columns): array|false
2527
{
2628
$tableSchema = $this->db->getSchema()->getTableSchema($table);
2729
$returnColumns = $tableSchema?->getPrimaryKey() ?? [];
@@ -37,9 +39,9 @@ public function insertWithReturningPks(string $table, array $columns): array|fal
3739
$params = [];
3840
$sql = $this->getQueryBuilder()->insert($table, $columns, $params);
3941

40-
$tableColumns = $tableSchema?->getColumns() ?? [];
42+
/** @var TableSchema $tableSchema */
43+
$tableColumns = $tableSchema->getColumns();
4144
$returnParams = [];
42-
$returning = [];
4345

4446
foreach ($returnColumns as $name) {
4547
$phName = AbstractQueryBuilder::PARAM_PREFIX . (count($params) + count($returnParams));
@@ -49,18 +51,20 @@ public function insertWithReturningPks(string $table, array $columns): array|fal
4951
'value' => '',
5052
];
5153

52-
if (!isset($tableColumns[$name]) || $tableColumns[$name]->getPhpType() !== PhpType::INT) {
54+
$column = $tableColumns[$name];
55+
56+
if ($column->getPhpType() !== PhpType::INT) {
5357
$returnParams[$phName]['dataType'] = PDO::PARAM_STR;
5458
} else {
5559
$returnParams[$phName]['dataType'] = PDO::PARAM_INT;
5660
}
5761

58-
$returnParams[$phName]['size'] = ($tableColumns[$name]?->getSize() ?? 3998) + 2;
59-
60-
$returning[] = $this->db->getQuoter()->quoteColumnName($name);
62+
$returnParams[$phName]['size'] = ($column->getSize() ?? 3998) + 2;
6163
}
6264

63-
$sql .= ' RETURNING ' . implode(', ', $returning) . ' INTO ' . implode(', ', array_keys($returnParams));
65+
$quotedReturnColumns = array_map($this->db->getQuoter()->quoteColumnName(...), $returnColumns);
66+
67+
$sql .= ' RETURNING ' . implode(', ', $quotedReturnColumns) . ' INTO ' . implode(', ', array_keys($returnParams));
6468

6569
$this->setSql($sql)->bindValues($params);
6670
$this->prepare(false);
@@ -72,17 +76,22 @@ public function insertWithReturningPks(string $table, array $columns): array|fal
7276

7377
unset($value);
7478

75-
if (!$this->execute()) {
79+
if ($this->execute() === 0) {
7680
return false;
7781
}
7882

7983
$result = [];
8084

8185
foreach ($returnParams as $value) {
82-
/** @psalm-var mixed */
8386
$result[$value['column']] = $value['value'];
8487
}
8588

89+
if ($this->phpTypecasting) {
90+
foreach ($result as $column => &$value) {
91+
$value = $tableColumns[$column]->phpTypecast($value);
92+
}
93+
}
94+
8695
return $result;
8796
}
8897

src/DMLQueryBuilder.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = [],
4949
return $query . "\nSELECT " . implode(" FROM DUAL UNION ALL\nSELECT ", $values) . ' FROM DUAL';
5050
}
5151

52-
public function insertWithReturningPks(string $table, QueryInterface|array $columns, array &$params = []): string
52+
public function insertWithReturningPks(string $table, array|QueryInterface $columns, array &$params = []): string
5353
{
5454
throw new NotSupportedException(__METHOD__ . ' is not supported by Oracle.');
5555
}
@@ -59,9 +59,9 @@ public function insertWithReturningPks(string $table, QueryInterface|array $colu
5959
*/
6060
public function upsert(
6161
string $table,
62-
QueryInterface|array $insertColumns,
63-
array|bool $updateColumns,
64-
array &$params = []
62+
array|QueryInterface $insertColumns,
63+
array|bool $updateColumns = true,
64+
array &$params = [],
6565
): string {
6666
$constraints = [];
6767

@@ -134,6 +134,15 @@ public function upsert(
134134
return "$mergeSql WHEN MATCHED THEN $updateSql WHEN NOT MATCHED THEN $insertSql";
135135
}
136136

137+
public function upsertWithReturningPks(
138+
string $table,
139+
array|QueryInterface $insertColumns,
140+
array|bool $updateColumns = true,
141+
array &$params = [],
142+
): string {
143+
throw new NotSupportedException(__METHOD__ . ' is not supported by Oracle.');
144+
}
145+
137146
protected function prepareInsertValues(string $table, array|QueryInterface $columns, array $params = []): array
138147
{
139148
if (empty($columns)) {

tests/CommandTest.php

Lines changed: 38 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,9 @@
55
namespace Yiisoft\Db\Oracle\Tests;
66

77
use PHPUnit\Framework\Attributes\DataProviderExternal;
8-
use ReflectionException;
9-
use Throwable;
108
use Yiisoft\Db\Constant\ColumnType;
119
use Yiisoft\Db\Constant\PseudoType;
1210
use Yiisoft\Db\Exception\Exception;
13-
use Yiisoft\Db\Exception\InvalidArgumentException;
14-
use Yiisoft\Db\Exception\InvalidCallException;
15-
use Yiisoft\Db\Exception\InvalidConfigException;
1611
use Yiisoft\Db\Exception\NotSupportedException;
1712
use Yiisoft\Db\Oracle\Column\ColumnBuilder;
1813
use Yiisoft\Db\Oracle\IndexType;
@@ -30,19 +25,13 @@
3025

3126
/**
3227
* @group oracle
33-
*
34-
* @psalm-suppress PropertyNotSetInConstructor
3528
*/
3629
final class CommandTest extends CommonCommandTest
3730
{
3831
use TestTrait;
3932

4033
protected string $upsertTestCharCast = 'CAST([[address]] AS VARCHAR(255))';
4134

42-
/**
43-
* @throws Exception
44-
* @throws InvalidConfigException
45-
*/
4635
public function testAddDefaultValue(): void
4736
{
4837
$db = $this->getConnection();
@@ -108,11 +97,6 @@ public function testBatchInsertWithAutoincrement(): void
10897
$db->close();
10998
}
11099

111-
/**
112-
* @throws Exception
113-
* @throws InvalidConfigException
114-
* @throws Throwable
115-
*/
116100
public function testCLOBStringInsertion(): void
117101
{
118102
$db = $this->getConnection();
@@ -142,11 +126,6 @@ public function testCLOBStringInsertion(): void
142126
$db->close();
143127
}
144128

145-
/**
146-
* @throws Exception
147-
* @throws InvalidConfigException
148-
* @throws Throwable
149-
*/
150129
public function testCreateTable(): void
151130
{
152131
$db = $this->getConnection(true);
@@ -188,11 +167,6 @@ public function testCreateTable(): void
188167
$db->close();
189168
}
190169

191-
/**
192-
* @throws Exception
193-
* @throws InvalidConfigException
194-
* @throws Throwable
195-
*/
196170
public function testCreateView(): void
197171
{
198172
$db = $this->getConnection();
@@ -251,10 +225,6 @@ public function testCreateView(): void
251225
$db->close();
252226
}
253227

254-
/**
255-
* @throws Exception
256-
* @throws InvalidConfigException
257-
*/
258228
public function testDropDefaultValue(): void
259229
{
260230
$db = $this->getConnection();
@@ -288,12 +258,6 @@ public function testDropTableIfExistsWithNonExistTable(): void
288258
$this->markTestSkipped('Oracle doesn\'t support "IF EXISTS" option on drop table.');
289259
}
290260

291-
/**
292-
* @throws Exception
293-
* @throws InvalidConfigException
294-
* @throws ReflectionException
295-
* @throws Throwable
296-
*/
297261
public function testExecuteWithTransaction(): void
298262
{
299263
$db = $this->getConnection(true);
@@ -345,24 +309,12 @@ public function testExecuteWithTransaction(): void
345309
$db->close();
346310
}
347311

348-
/**
349-
* @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\CommandProvider::rawSql
350-
*
351-
* @throws Exception
352-
* @throws InvalidConfigException
353-
* @throws NotSupportedException
354-
*/
312+
#[DataProviderExternal(CommandProvider::class, 'rawSql')]
355313
public function testGetRawSql(string $sql, array $params, string $expectedRawSql): void
356314
{
357315
parent::testGetRawSql($sql, $params, $expectedRawSql);
358316
}
359317

360-
/**
361-
* @throws Exception
362-
* @throws InvalidCallException
363-
* @throws InvalidConfigException
364-
* @throws Throwable
365-
*/
366318
public function testsInsertQueryAsColumnValue(): void
367319
{
368320
$db = $this->getConnection(true);
@@ -399,12 +351,6 @@ public function testsInsertQueryAsColumnValue(): void
399351
$db->close();
400352
}
401353

402-
/**
403-
* @throws Exception
404-
* @throws InvalidCallException
405-
* @throws InvalidConfigException
406-
* @throws Throwable
407-
*/
408354
public function testInsertWithReturningPksWithPrimaryKeyString(): void
409355
{
410356
$db = $this->getConnection();
@@ -451,11 +397,6 @@ public function testInsertWithReturningPksWithPrimaryKeySignedDecimal(): void
451397
$db->close();
452398
}
453399

454-
/**
455-
* @throws Exception
456-
* @throws InvalidConfigException
457-
* @throws Throwable
458-
*/
459400
public function testInsertSelectAlias(): void
460401
{
461402
$db = $this->getConnection();
@@ -510,13 +451,7 @@ public function testInsertSelectAlias(): void
510451
$db->close();
511452
}
512453

513-
/**
514-
* @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\CommandProvider::insertVarbinary
515-
*
516-
* @throws Exception
517-
* @throws InvalidConfigException
518-
* @throws Throwable
519-
*/
454+
#[DataProviderExternal(CommandProvider::class, 'insertVarbinary')]
520455
public function testInsertVarbinary(mixed $expectedData, mixed $testData): void
521456
{
522457
$db = $this->getConnection(true);
@@ -537,12 +472,6 @@ public function testInsertVarbinary(mixed $expectedData, mixed $testData): void
537472
$db->close();
538473
}
539474

540-
/**
541-
* @throws Exception
542-
* @throws InvalidCallException
543-
* @throws InvalidConfigException
544-
* @throws Throwable
545-
*/
546475
public function testNoTablenameReplacement(): void
547476
{
548477
$db = $this->getConnection(true);
@@ -592,13 +521,7 @@ public function testNoTablenameReplacement(): void
592521
$db->close();
593522
}
594523

595-
/**
596-
* @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\CommandProvider::update
597-
*
598-
* @throws Exception
599-
* @throws InvalidConfigException
600-
* @throws Throwable
601-
*/
524+
#[DataProviderExternal(CommandProvider::class, 'update')]
602525
public function testUpdate(
603526
string $table,
604527
array $columns,
@@ -610,25 +533,46 @@ public function testUpdate(
610533
parent::testUpdate($table, $columns, $conditions, $params, $expectedValues, $expectedCount);
611534
}
612535

613-
/**
614-
* @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\CommandProvider::upsert
615-
*
616-
* @throws Exception
617-
* @throws InvalidConfigException
618-
* @throws Throwable
619-
*/
536+
#[DataProviderExternal(CommandProvider::class, 'upsert')]
620537
public function testUpsert(array $firstData, array $secondData): void
621538
{
622539
parent::testUpsert($firstData, $secondData);
623540
}
624541

625-
/**
626-
* @throws InvalidConfigException
627-
* @throws InvalidArgumentException
628-
* @throws NotSupportedException
629-
* @throws Exception
630-
* @throws Throwable
631-
*/
542+
public function testUpsertWithReturningPks(): void
543+
{
544+
$db = $this->getConnection();
545+
$command = $db->createCommand();
546+
547+
$this->expectException(NotSupportedException::class);
548+
$this->expectExceptionMessage('Yiisoft\Db\Oracle\DMLQueryBuilder::upsertWithReturningPks is not supported by Oracle.');
549+
550+
$command->upsertWithReturningPks('{{customer}}', ['name' => 'test_1', 'email' => '[email protected]']);
551+
}
552+
553+
public function testUpsertWithReturningPksEmptyValues()
554+
{
555+
$db = $this->getConnection();
556+
$command = $db->createCommand();
557+
558+
$this->expectException(NotSupportedException::class);
559+
$this->expectExceptionMessage('Yiisoft\Db\Oracle\DMLQueryBuilder::upsertWithReturningPks is not supported by Oracle.');
560+
561+
$command->upsertWithReturningPks('null_values', []);
562+
}
563+
564+
public function testUpsertWithReturningPksWithPhpTypecasting(): void
565+
{
566+
$db = $this->getConnection();
567+
568+
$this->expectException(NotSupportedException::class);
569+
$this->expectExceptionMessage('Yiisoft\Db\Oracle\DMLQueryBuilder::upsertWithReturningPks is not supported by Oracle.');
570+
571+
$db->createCommand()
572+
->withPhpTypecasting()
573+
->upsertWithReturningPks('notauto_pk', ['id_1' => 1, 'id_2' => 2.5, 'type' => 'test1']);
574+
}
575+
632576
public function testQueryScalarWithBlob(): void
633577
{
634578
$db = $this->getConnection(true);

0 commit comments

Comments
 (0)