Passed
Pull Request — 2.x (#231)
by
unknown
16:15
created

Table::upsert()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of Cycle ORM package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Database;
13
14
use Cycle\Database\Exception\BuilderException;
15
use Cycle\Database\Query\DeleteQuery;
16
use Cycle\Database\Query\InsertQuery;
17
use Cycle\Database\Query\SelectQuery;
18
use Cycle\Database\Query\UpdateQuery;
19
use Cycle\Database\Query\UpsertQuery;
20
use Cycle\Database\Schema\AbstractTable;
21
22
/**
23
 * Represent table level abstraction with simplified access to SelectQuery associated with such
24
 * table.
25
 *
26
 * @method int avg($identifier) Perform aggregation (AVG) based on column or expression value.
27
 * @method int min($identifier) Perform aggregation (MIN) based on column or expression value.
28
 * @method int max($identifier) Perform aggregation (MAX) based on column or expression value.
29
 * @method int sum($identifier) Perform aggregation (SUM) based on column or expression value.
30
 */
31
final class Table implements TableInterface, \IteratorAggregate, \Countable
32
{
33
    /**
34
     * @param DatabaseInterface $database Parent DBAL database.
35
     *
36 2052
     * @psalm-param non-empty-string $name Table name without prefix.
37
     */
38
    public function __construct(
39
        protected DatabaseInterface $database,
40 2052
        private string $name,
41
    ) {}
42
43
    /**
44
     * Get associated database.
45
     */
46
    public function getDatabase(): DatabaseInterface
47
    {
48
        return $this->database;
49 50
    }
50
51 50
    /**
52
     * Real table name, will include database prefix.
53
     *
54
     * @psalm-return non-empty-string
55
     */
56
    public function getFullName(): string
57 8
    {
58
        return $this->database->getPrefix() . $this->name;
59 8
    }
60
61
    /**
62
     * @psalm-return non-empty-string
63
     */
64
    public function getName(): string
65
    {
66
        return $this->name;
67 8
    }
68
69 8
    /**
70
     * Get modifiable table schema.
71
     */
72
    public function getSchema(): AbstractTable
73
    {
74
        return $this->database
75 2
            ->getDriver(DatabaseInterface::WRITE)
76
            ->getSchemaHandler()
77 2
            ->getSchema(
78
                $this->name,
79
                $this->database->getPrefix(),
80
            );
81
    }
82
83 1974
    /**
84
     * Erase all table data.
85 1974
     */
86 1974
    public function eraseData(): void
87 1974
    {
88 1974
        $this->database
89 1974
            ->getDriver(DatabaseInterface::WRITE)
90 1974
            ->getSchemaHandler()
91
            ->eraseTable($this->getSchema());
92
    }
93
94
    /**
95
     * Insert one fieldset into table and return last inserted id.
96
     *
97 16
     * Example:
98
     * $table->insertOne(["name" => "Wolfy-J", "balance" => 10]);
99 16
     *
100 16
     * @throws BuilderException
101 16
     */
102 16
    public function insertOne(array $rowset = []): int|string|null
103 8
    {
104
        return $this->database
105
            ->insert($this->name)
106
            ->values($rowset)
107
            ->run();
108
    }
109
110
    /**
111
     * Perform batch insert into table, every rowset should have identical amount of values matched
112
     * with column names provided in first argument. Method will return lastInsertID on success.
113 240
     *
114
     * Example:
115 240
     * $table->insertMultiple(["name", "balance"], array(["Bob", 10], ["Jack", 20]))
116 240
     *
117 240
     * @param array $columns Array of columns.
118 240
     * @param array $rowsets Array of rowsets.
119
     */
120
    public function insertMultiple(array $columns = [], array $rowsets = []): void
121
    {
122
        //No return value
123
        $this->database
124
            ->insert($this->name)
125
            ->columns($columns)
126
            ->values($rowsets)
127
            ->run();
128
    }
129
130
    /**
131 110
     * Upsert one fieldset into table and return last inserted id.
132
     *
133
     * Example:
134 110
     * $table->upsertOne(["name" => "Wolfy-J", "balance" => 10]);
135 110
     * $table->upsertOne(["name" => "Wolfy-J", "balance" => 10], 'name');
136 110
     *
137 110
     * @throws BuilderException
138 110
     */
139 102
    public function upsertOne(array $rowset = [], array|string $conflicts = []): int|string|null
140
    {
141
        return $this->database
142
            ->upsert($this->name)
143
            ->conflicts($conflicts)
144 16
            ->values($rowset)
145
            ->run();
146 16
    }
147 16
148
    /**
149
     * Perform batch upsert into table, every rowset should have identical amount of values matched
150
     * with column names provided in first argument. Method will return lastInsertID on success.
151
     *
152
     * Example:
153 376
     * $table->insertMultiple(["name", "balance"], array(["Bob", 10], ["Jack", 20]))
154
     *
155 376
     * @param array $columns Array of columns.
156 376
     * @param array $rowsets Array of rowsets.
157 376
     */
158
    public function upsertMultiple(array $columns = [], array $rowsets = [], array|string $conflicts = []): void
159
    {
160
        $this->database
161
            ->upsert($this->name)
162
            ->conflicts($conflicts)
163
            ->columns($columns)
164
            ->values($rowsets)
165
            ->run();
166
    }
167 32
168
    /**
169 32
     * Get insert builder specific to current table.
170 32
     */
171
    public function insert(): InsertQuery
172
    {
173
        return $this->database
174
            ->insert($this->name);
175
    }
176
177
    /**
178
     * Get upsert builder specific to current table.
179
     */
180 48
    public function upsert(): UpsertQuery
181
    {
182 48
        return $this->database
183 48
            ->upsert($this->name);
184
    }
185
186
    /**
187
     * Get SelectQuery builder with pre-populated from tables.
188
     */
189 222
    public function select(mixed $columns = '*'): SelectQuery
190
    {
191 222
        return $this->database
192
            ->select(\func_num_args() ? \func_get_args() : '*')
193
            ->from($this->name);
194
    }
195
196
    /**
197
     * Get DeleteQuery builder with pre-populated table name. This is NOT table delete method, use
198
     * schema()->drop() for this purposes. If you want to remove all records from table use
199 8
     * Table->truncate() method. Call ->run() to perform query.
200
     *
201 8
     * @param array $where Initial set of where rules specified as array.
202
     */
203
    public function delete(array $where = []): DeleteQuery
204
    {
205
        return $this->database
206
            ->delete($this->name, $where);
207 24
    }
208
209 24
    /**
210
     * Get UpdateQuery builder with pre-populated table name and set of columns to update. Columns
211
     * can be scalar values, Parameter objects or even SQLFragments. Call ->run() to perform query.
212 8
     *
213
     * @param array $values Initial set of columns associated with values.
214 8
     * @param array $where  Initial set of where rules specified as array.
215
     */
216
    public function update(array $values = [], array $where = []): UpdateQuery
217
    {
218
        return $this->database
219
            ->update($this->name, $values, $where);
220
    }
221 8
222
    /**
223 8
     * Count number of records in table.
224
     */
225
    public function count(): int
226
    {
227
        return $this->select()->count();
228
    }
229
230
    /**
231 16
     * Retrieve an external iterator, SelectBuilder will return PDOResult as iterator.
232
     *
233 16
     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
234
     */
235
    public function getIterator(): SelectQuery
236
    {
237
        return $this->select();
238
    }
239
240
    /**
241 8
     * A simple alias for table query without condition (returns array of rows).
242
     */
243 8
    public function fetchAll(): array
244
    {
245
        return $this->select()->fetchAll();
246
    }
247
248
    public function exists(): bool
249
    {
250
        return $this->getSchema()->exists();
251 8
    }
252
253 8
    /**
254
     * Array of columns dedicated to primary index. Attention, this methods will ALWAYS return
255
     * array, even if there is only one primary key.
256
     */
257
    public function getPrimaryKeys(): array
258
    {
259
        return $this->getSchema()->getPrimaryKeys();
260
    }
261 8
262
    /**
263 8
     * Check if table have specified column.
264
     *
265
     * @psalm-param non-empty-string $name Column name.
266
     */
267
    public function hasColumn(string $name): bool
268
    {
269
        return $this->getSchema()->hasColumn($name);
270
    }
271 8
272
    /**
273 8
     * Get all declared columns.
274
     *
275
     * @return ColumnInterface[]
276
     */
277
    public function getColumns(): array
278
    {
279
        return $this->getSchema()->getColumns();
280
    }
281 8
282
    /**
283 8
     * Check if table has index related to set of provided columns. Columns order does matter!
284
     *
285
     */
286
    public function hasIndex(array $columns = []): bool
287
    {
288
        return $this->getSchema()->hasIndex($columns);
289
    }
290 8
291
    /**
292 8
     * Get all table indexes.
293
     *
294
     * @return IndexInterface[]
295
     */
296
    public function getIndexes(): array
297
    {
298
        return $this->getSchema()->getIndexes();
299
    }
300
301
    /**
302
     * Check if table has foreign key related to table column.
303
     *
304
     * @param array $columns Column names.
305
     */
306
    public function hasForeignKey(array $columns): bool
307
    {
308
        return $this->getSchema()->hasForeignKey($columns);
309
    }
310
311
    /**
312
     * Get all table foreign keys.
313
     *
314
     * @return ForeignKeyInterface[]
315
     */
316
    public function getForeignKeys(): array
317
    {
318
        return $this->getSchema()->getForeignKeys();
319
    }
320
321
    /**
322
     * Get list of table names current schema depends on, must include every table linked using
323
     * foreign key or other constraint. Table names MUST include prefixes.
324
     */
325
    public function getDependencies(): array
326
    {
327
        return $this->getSchema()->getDependencies();
328
    }
329
330
    /**
331
     * Bypass call to SelectQuery builder.
332
     *
333
     * @psalm-param non-empty-string $method
334
     *
335
     * @return mixed|SelectQuery
336
     */
337
    public function __call(string $method, array $arguments): mixed
338
    {
339
        return \call_user_func_array([$this->select(), $method], $arguments);
340
    }
341
}
342