Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
Update
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
7 / 7
19
100.00% covered (success)
100.00%
1 / 1
 renderOptions
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
4
 table
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 renderTable
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 limit
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 renderSetPart
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 sql
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
6
 run
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php declare(strict_types=1);
2/*
3 * This file is part of Aplus Framework Database Library.
4 *
5 * (c) Natan Felles <natanfelles@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10namespace Framework\Database\Manipulation;
11
12use Closure;
13use InvalidArgumentException;
14use LogicException;
15
16/**
17 * Class Update.
18 *
19 * @see https://mariadb.com/kb/en/update/
20 *
21 * @package database
22 */
23class Update extends Statement
24{
25    use Traits\Join;
26    use Traits\Set;
27    use Traits\Where;
28    use Traits\OrderBy;
29
30    /**
31     * Convert errors to warnings, which will not stop inserts of additional rows.
32     *
33     * @see https://mariadb.com/kb/en/insert-ignore/
34     *
35     * @var string
36     */
37    public const OPT_IGNORE = 'IGNORE';
38    /**
39     * @see https://mariadb.com/kb/en/high_priority-and-low_priority/
40     *
41     * @var string
42     */
43    public const OPT_LOW_PRIORITY = 'LOW_PRIORITY';
44
45    protected function renderOptions() : ?string
46    {
47        if ( ! $this->hasOptions()) {
48            return null;
49        }
50        $options = $this->sql['options'];
51        foreach ($options as &$option) {
52            $input = $option;
53            $option = \strtoupper($option);
54            if ( ! \in_array($option, [
55                static::OPT_IGNORE,
56                static::OPT_LOW_PRIORITY,
57            ], true)) {
58                throw new InvalidArgumentException("Invalid option: {$input}");
59            }
60        }
61        unset($option);
62        $options = \implode(' ', $options);
63        return " {$options}";
64    }
65
66    /**
67     * Sets the table references.
68     *
69     * @param array<string,Closure|string>|Closure|string $reference
70     * @param array<string,Closure|string>|Closure|string ...$references
71     *
72     * @return static
73     */
74    public function table(
75        array | Closure | string $reference,
76        array | Closure | string ...$references
77    ) : static {
78        $this->sql['table'] = [];
79        foreach ([$reference, ...$references] as $reference) {
80            $this->sql['table'][] = $reference;
81        }
82        return $this;
83    }
84
85    protected function renderTable() : string
86    {
87        if ( ! isset($this->sql['table'])) {
88            throw new LogicException('Table references must be set');
89        }
90        $tables = [];
91        foreach ($this->sql['table'] as $table) {
92            $tables[] = $this->renderAliasedIdentifier($table);
93        }
94        return ' ' . \implode(', ', $tables);
95    }
96
97    /**
98     * Sets the LIMIT clause.
99     *
100     * @param int $limit
101     *
102     * @see https://mariadb.com/kb/en/limit/
103     *
104     * @return static
105     */
106    public function limit(int $limit) : static
107    {
108        return $this->setLimit($limit);
109    }
110
111    protected function renderSetPart() : string
112    {
113        if ( ! $this->hasSet()) {
114            throw new LogicException('SET statement must be set');
115        }
116        return $this->renderSet();
117    }
118
119    /**
120     * Renders the UPDATE statement.
121     *
122     * @return string
123     */
124    public function sql() : string
125    {
126        $sql = 'UPDATE' . \PHP_EOL;
127        $part = $this->renderOptions();
128        if ($part) {
129            $sql .= $part . \PHP_EOL;
130        }
131        $sql .= $this->renderTable() . \PHP_EOL;
132        $part = $this->renderJoin();
133        if ($part) {
134            $sql .= $part . \PHP_EOL;
135        }
136        $sql .= $this->renderSetPart() . \PHP_EOL;
137        $part = $this->renderWhere();
138        if ($part) {
139            $sql .= $part . \PHP_EOL;
140        }
141        $part = $this->renderOrderBy();
142        if ($part) {
143            $sql .= $part . \PHP_EOL;
144        }
145        $part = $this->renderLimit();
146        if ($part) {
147            $sql .= $part . \PHP_EOL;
148        }
149        return $sql;
150    }
151
152    /**
153     * Runs the UPDATE statement.
154     *
155     * @return int|string The number of affected rows
156     */
157    public function run() : int|string
158    {
159        return $this->database->exec($this->sql());
160    }
161}