Passed
Push — dev ( bae50f...820ac9 )
by Def
33:33 queued 29:55
created

DMLQueryBuilder::resetSequence()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4.0466

Importance

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