Test Failed
Pull Request — master (#176)
by Wilmer
07:30 queued 03:32
created

DMLQueryBuilder::insertWithReturningPks()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 3
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Sqlite;
6
7
use JsonException;
8
use Throwable;
9
use Yiisoft\Db\Constraint\Constraint;
10
use Yiisoft\Db\Exception\Exception;
11
use Yiisoft\Db\Exception\InvalidArgumentException;
12
use Yiisoft\Db\Exception\InvalidConfigException;
13
use Yiisoft\Db\Exception\NotSupportedException;
14
use Yiisoft\Db\Expression\Expression;
15
use Yiisoft\Db\Expression\ExpressionInterface;
16
use Yiisoft\Db\Query\QueryInterface;
17
use Yiisoft\Db\QueryBuilder\AbstractDMLQueryBuilder;
18
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
19
use Yiisoft\Db\Schema\QuoterInterface;
20
use Yiisoft\Db\Schema\SchemaInterface;
21
22
use function implode;
23
use function ltrim;
24
use function reset;
25
26
final class DMLQueryBuilder extends AbstractDMLQueryBuilder
27
{
28 490
    public function __construct(
29
        QueryBuilderInterface $queryBuilder,
30
        private QuoterInterface $quoter,
31
        private SchemaInterface $schema
32
    ) {
33 490
        parent::__construct($queryBuilder, $quoter, $schema);
34
    }
35
36
    /**
37
     * @throws ExceptionInvalidArgumentException
38
     * @throws InvalidConfigException
39 5
     * @throws NotSupportedException
40
     */
41 5
    public function insertWithReturningPks(string $table, QueryInterface|array $columns, array &$params = []): string
42
    {
43 5
        throw new NotSupportedException(__METHOD__ . '() is not supported by this DBMS.');
44 1
    }
45
46
    /**
47 4
     * @throws Exception
48
     * @throws Throwable
49 4
     */
50 1
    public function resetSequence(string $tableName, int|string $value = null): string
51
    {
52
        $table = $this->schema->getTableSchema($tableName);
53 3
54
        if ($table === null) {
55 3
            throw new InvalidArgumentException("Table not found: '$tableName'.");
56 2
        }
57
58 3
        $sequenceName = $table->getSequenceName();
59 3
60 3
        if ($sequenceName === null) {
61
            throw new InvalidArgumentException("There is not sequence associated with table '$tableName'.'");
62
        }
63 3
64
        $tableName = $this->quoter->quoteTableName($tableName);
65
66
        if ($value !== null) {
67
            $value = "'" . ((int) $value - 1) . "'";
68
        } else {
69 34
            $pk = $table->getPrimaryKey();
70
            $key = $this->quoter->quoteColumnName(reset($pk));
71
            $value = '(SELECT MAX(' . $key . ') FROM ' . $tableName . ')';
72
        }
73
74
        return 'UPDATE sqlite_sequence SET seq=' . $value . " WHERE name='" . $table->getName() . "'";
75
    }
76 34
77
    /**
78
     * @throws Exception
79
     * @throws InvalidArgumentException
80
     * @throws InvalidConfigException
81
     * @throws JsonException
82
     * @throws NotSupportedException
83 34
     */
84 34
    public function upsert(
85 34
        string $table,
86 34
        QueryInterface|array $insertColumns,
87 34
        bool|array $updateColumns,
88 34
        array &$params
89
    ): string {
90 34
        /** @psalm-var Constraint[] $constraints */
91 2
        $constraints = [];
92
93
        /**
94
         * @psalm-var string[] $insertNames
95
         * @psalm-var string[] $updateNames
96
         * @psalm-var array<string, ExpressionInterface|string>|bool $updateColumns
97 32
         */
98
        [$uniqueNames, $insertNames, $updateNames] = $this->prepareUpsertColumns(
99 32
            $table,
100 32
            $insertColumns,
101 32
            $updateColumns,
102 32
            $constraints
103
        );
104 32
105 12
        if (empty($uniqueNames)) {
106
            return $this->insert($table, $insertColumns, $params);
107
        }
108 20
109 20
        /** @psalm-var string[] $placeholders */
110
        [, $placeholders, $values, $params] = $this->prepareInsertValues($table, $insertColumns, $params);
111 20
112 20
        $insertSql = 'INSERT OR IGNORE INTO '
113
            . $this->quoter->quoteTableName($table)
114 20
            . (!empty($insertNames) ? ' (' . implode(', ', $insertNames) . ')' : '')
115 20
            . (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : "$values");
116 20
117 20
        if ($updateColumns === false) {
0 ignored issues
show
introduced by
The condition $updateColumns === false is always false.
Loading history...
118
            return $insertSql;
119 20
        }
120
121
        $updateCondition = ['or'];
122 20
        $quotedTableName = $this->quoter->quoteTableName($table);
123 10
124 10
        foreach ($constraints as $constraint) {
125 8
            $constraintCondition = ['and'];
126
            /** @psalm-var string[] $columnNames */
127 8
            $columnsNames = $constraint->getColumnNames();
128 8
            foreach ($columnsNames as $name) {
129
                $quotedName = $this->quoter->quoteColumnName($name);
130 8
                $constraintCondition[] = "$quotedTableName.$quotedName=(SELECT $quotedName FROM `EXCLUDED`)";
131
            }
132
            $updateCondition[] = $constraintCondition;
133
        }
134 20
135 2
        if ($updateColumns === true) {
0 ignored issues
show
introduced by
The condition $updateColumns === true is always false.
Loading history...
136
            $updateColumns = [];
137
            foreach ($updateNames as $name) {
138
                $quotedName = $this->quoter->quoteColumnName($name);
139 18
140 18
                if (strrpos($quotedName, '.') === false) {
141 18
                    $quotedName = "(SELECT $quotedName FROM `EXCLUDED`)";
142 10
                }
143 18
                $updateColumns[$name] = new Expression($quotedName);
144 18
            }
145
        }
146 18
147
        if ($updateColumns === []) {
148
            return $insertSql;
149
        }
150
151
        /** @psalm-var array $params */
152
        $updateSql = 'WITH "EXCLUDED" ('
153
            . implode(', ', $insertNames)
154
            . ') AS (' . (!empty($placeholders)
155
                ? 'VALUES (' . implode(', ', $placeholders) . ')'
156
                : ltrim("$values", ' ')) . ') ' .
157
                $this->update($table, $updateColumns, $updateCondition, $params);
158
159
        return "$updateSql; $insertSql;";
160
    }
161
}
162