ShardingInsertQuery::ignore()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Bdf\Prime\Sharding\Query;
4
5
use BadMethodCallException;
6
use Bdf\Prime\Connection\ConnectionInterface;
7
use Bdf\Prime\Connection\Result\ResultSetInterface;
8
use Bdf\Prime\Query\CompilableClause;
9
use Bdf\Prime\Query\Compiler\CompilerInterface;
10
use Bdf\Prime\Query\Compiler\Preprocessor\DefaultPreprocessor;
11
use Bdf\Prime\Query\Compiler\Preprocessor\PreprocessorInterface;
12
use Bdf\Prime\Query\Contract\Cachable;
13
use Bdf\Prime\Query\Contract\Query\InsertQueryInterface;
14
use Bdf\Prime\Query\Contract\WriteOperation;
15
use Bdf\Prime\Query\Custom\BulkInsert\BulkInsertQuery;
16
use Bdf\Prime\Query\Extension\CachableTrait;
17
use Bdf\Prime\Sharding\Extension\ShardPicker;
18
use Bdf\Prime\Sharding\ShardingConnection;
19
20
/**
21
 * Handle INSERT operations on Sharding connection set
22
 * The shard will be choosed using inserted data value, and the operation will be delegated to the shard connection
23
 *
24
 * @implements InsertQueryInterface<ShardingConnection>
25
 */
26
class ShardingInsertQuery extends CompilableClause implements InsertQueryInterface, Cachable
27
{
28
    use CachableTrait;
29
    use ShardPicker;
30
31
    /**
32
     * The DBAL Connection.
33
     *
34
     * @var ShardingConnection
35
     */
36
    private $connection;
37
38
    /**
39
     * @var string
40
     */
41
    private $table;
42
43
    /**
44
     * @var string[]
45
     */
46
    private $columns = [];
47
48
    /**
49
     * @var InsertQueryInterface::MODE_*
50
     */
51
    private $mode = self::MODE_INSERT;
52
53
    /**
54
     * @var array
55
     */
56
    private $values = [];
57
58
    /**
59
     * Queries indexed by shard id
60
     *
61
     * @var BulkInsertQuery[]
62
     */
63
    private $queries = [];
64
65
    /**
66
     * @var BulkInsertQuery|null
67
     */
68
    private $currentQuery;
69
70
71
    /**
72
     * ShardingInsertQuery constructor.
73
     *
74
     * @param ShardingConnection $connection
75
     * @param PreprocessorInterface $preprocessor
76
     */
77 32
    public function __construct(ShardingConnection $connection, PreprocessorInterface $preprocessor = null)
78
    {
79 32
        parent::__construct($preprocessor ?: new DefaultPreprocessor());
80
81 32
        $this->connection = $connection;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public function compiler(): CompilerInterface
88
    {
89
        throw new BadMethodCallException('Cannot directly compile a sharding query');
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95
    public function setCompiler(CompilerInterface $compiler)
0 ignored issues
show
Unused Code introduced by
The parameter $compiler is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

95
    public function setCompiler(/** @scrutinizer ignore-unused */ CompilerInterface $compiler)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
96
    {
97
        throw new BadMethodCallException('Cannot directly compile a sharding query');
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function connection(): ConnectionInterface
104
    {
105
        return $this->connection;
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function on(ConnectionInterface $connection)
112
    {
113
        $this->connection = $connection;
0 ignored issues
show
Documentation Bug introduced by
$connection is of type Bdf\Prime\Connection\ConnectionInterface, but the property $connection was declared to be of type Bdf\Prime\Sharding\ShardingConnection. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
114
        $this->queries = [];
115
        $this->currentQuery = null;
116
117
        return $this;
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 20
    public function from(string $from, ?string $alias = null)
124
    {
125 20
        return $this->into($from);
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function bulk(bool $flag = true)
132
    {
133
        throw new BadMethodCallException('Bulk insert is not (yet ?) supported by sharding connection');
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139 31
    public function into(string $table)
140
    {
141 31
        $this->table = $table;
142
143 31
        foreach ($this->queries as $query) {
144 1
            $query->into($table);
145
        }
146
147 31
        return $this;
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 21
    public function columns(array $columns)
154
    {
155 21
        $this->columns = $columns;
156
157 21
        foreach ($this->queries as $query) {
158 1
            $query->columns($columns);
159
        }
160
161 21
        return $this;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167 30
    public function values(array $data, bool $replace = false)
168
    {
169 30
        $this->values = $data;
170 30
        $this->currentQuery = null;
171
172 30
        $this->currentQuery()->values($data);
173
174 30
        return $this;
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180 22
    public function mode(string $mode)
181
    {
182 22
        $this->mode = $mode;
0 ignored issues
show
Documentation Bug introduced by
It seems like $mode of type string is incompatible with the declared type Bdf\Prime\Query\Contract...ry\InsertQueryInterface of property $mode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
183
184 22
        foreach ($this->queries as $query) {
185 11
            $query->mode($mode);
186
        }
187
188 22
        return $this;
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194 21
    public function ignore(bool $flag = true)
195
    {
196 21
        return $this->mode($flag ? self::MODE_IGNORE : self::MODE_INSERT);
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202 1
    public function replace(bool $flag = true)
203
    {
204 1
        return $this->mode($flag ? self::MODE_REPLACE : self::MODE_INSERT);
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     *
210
     * @return ResultSetInterface<array<string, mixed>>
211
     */
212
    #[WriteOperation]
213 31
    public function execute($columns = null): ResultSetInterface
214
    {
215 31
        $result = $this->currentQuery()->execute($columns);
216
217 30
        if ($result->hasWrite()) {
218 30
            $this->clearCacheOnWrite();
219
        }
220
221 30
        return $result;
222
    }
223
224
    /**
225
     * Get the query associated to the matching sharding
226
     *
227
     * @return BulkInsertQuery
228
     */
229 31
    private function currentQuery()
230
    {
231 31
        if ($this->currentQuery !== null) {
232 30
            return $this->currentQuery;
233
        }
234
235 31
        $shardId = $this->getShardId();
236
237 30
        if (isset($this->queries[$shardId])) {
238 11
            return $this->queries[$shardId];
239
        }
240
241
        /** @var BulkInsertQuery $query */
242 30
        $query = $this->connection->getConnection($shardId)->make(BulkInsertQuery::class, $this->preprocessor());
243
244 30
        $query
245 30
            ->setCache($this->cache)
246 30
            ->into($this->table)
247 30
            ->columns($this->columns)
248 30
            ->mode($this->mode)
0 ignored issues
show
Bug introduced by
$this->mode of type Bdf\Prime\Query\Contract...ry\InsertQueryInterface is incompatible with the type string expected by parameter $mode of Bdf\Prime\Query\Custom\B...BulkInsertQuery::mode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

248
            ->mode(/** @scrutinizer ignore-type */ $this->mode)
Loading history...
249 30
        ;
250
251 30
        return $this->currentQuery = $this->queries[$shardId] = $query;
252
    }
253
254
    /**
255
     * Get the targeted shard ID
256
     *
257
     * @return string
258
     */
259 31
    private function getShardId()
260
    {
261 31
        if ($this->shardId !== null) {
262 2
            return $this->shardId;
263
        }
264
265 29
        $distributionKey = $this->connection->getDistributionKey();
266
267 29
        if (!isset($this->values[$distributionKey])) {
268 1
            throw new \LogicException('The value "'.$distributionKey.'" must be provided for selecting the sharding');
269
        }
270
271 28
        return $this->connection->getShardChoser()->pick($this->values[$distributionKey], $this->connection);
272
    }
273
274
    /**
275
     * {@inheritdoc}
276
     */
277 1
    protected function cacheNamespace(): string
278
    {
279 1
        return $this->connection->getName().':'.$this->table;
280
    }
281
}
282