Completed
Branch master (00332a)
by Eugene
05:11
created

Client::executeQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
ccs 5
cts 5
cp 1
crap 1
1
<?php
2
3
/**
4
 * This file is part of the Tarantool Client package.
5
 *
6
 * (c) Eugene Leonovich <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Tarantool\Client;
15
16
use Tarantool\Client\Connection\StreamConnection;
17
use Tarantool\Client\Exception\RequestFailed;
18
use Tarantool\Client\Handler\DefaultHandler;
19
use Tarantool\Client\Handler\Handler;
20
use Tarantool\Client\Handler\MiddlewareHandler;
21
use Tarantool\Client\Middleware\AuthenticationMiddleware;
22
use Tarantool\Client\Middleware\Middleware;
23
use Tarantool\Client\Middleware\RetryMiddleware;
24
use Tarantool\Client\Packer\PackerFactory;
25
use Tarantool\Client\Request\CallRequest;
26
use Tarantool\Client\Request\EvaluateRequest;
27
use Tarantool\Client\Request\ExecuteRequest;
28
use Tarantool\Client\Request\PingRequest;
29
use Tarantool\Client\Request\PrepareRequest;
30
use Tarantool\Client\Schema\Criteria;
31
use Tarantool\Client\Schema\Space;
32
33
final class Client
34
{
35
    /** @var Handler */
36
    private $handler;
37
38
    /** @var array<array-key, Space> */
39
    private $spaces = [];
40
41 495
    public function __construct(Handler $handler)
42
    {
43 495
        $this->handler = $handler;
44 495
    }
45
46
    public static function fromDefaults() : self
47
    {
48
        return new self(new DefaultHandler(
49
            StreamConnection::createTcp(),
50
            PackerFactory::create()
51
        ));
52
    }
53
54 3
    public static function fromOptions(array $options) : self
55
    {
56 3
        $connectionOptions = [];
57 3
        if (isset($options['connect_timeout'])) {
58
            $connectionOptions['connect_timeout'] = $options['connect_timeout'];
59
        }
60 3
        if (isset($options['socket_timeout'])) {
61
            $connectionOptions['socket_timeout'] = $options['socket_timeout'];
62
        }
63 3
        if (isset($options['tcp_nodelay'])) {
64
            $connectionOptions['tcp_nodelay'] = $options['tcp_nodelay'];
65
        }
66 3
        if (isset($options['persistent'])) {
67
            $connectionOptions['persistent'] = $options['persistent'];
68
        }
69
70 3
        $connection = StreamConnection::create($options['uri'] ?? StreamConnection::DEFAULT_URI, $connectionOptions);
71 3
        $handler = new DefaultHandler($connection, PackerFactory::create());
72
73 3
        if (isset($options['max_retries']) && 0 !== $options['max_retries']) {
74 3
            $handler = MiddlewareHandler::create($handler, RetryMiddleware::linear($options['max_retries']));
75
        }
76 3
        if (isset($options['username'])) {
77 3
            $handler = MiddlewareHandler::create($handler, new AuthenticationMiddleware($options['username'], $options['password'] ?? ''));
78
        }
79
80 3
        return new self($handler);
81
    }
82
83
    public static function fromDsn(string $dsn) : self
84
    {
85
        $dsn = Dsn::parse($dsn);
86
87
        $connectionOptions = [];
88
        if (null !== $timeout = $dsn->getInt('connect_timeout')) {
89
            $connectionOptions['connect_timeout'] = $timeout;
90
        }
91
        if (null !== $timeout = $dsn->getInt('socket_timeout')) {
92
            $connectionOptions['socket_timeout'] = $timeout;
93
        }
94
        if (null !== $tcpNoDelay = $dsn->getBool('tcp_nodelay')) {
95
            $connectionOptions['tcp_nodelay'] = $tcpNoDelay;
96
        }
97
        if (null !== $persistent = $dsn->getBool('persistent')) {
98
            $connectionOptions['persistent'] = $persistent;
99
        }
100
101
        $connection = $dsn->isTcp()
102
            ? StreamConnection::createTcp($dsn->getConnectionUri(), $connectionOptions)
103
            : StreamConnection::createUds($dsn->getConnectionUri(), $connectionOptions);
104
105
        $handler = new DefaultHandler($connection, PackerFactory::create());
106
107
        if ($maxRetries = $dsn->getInt('max_retries')) {
108
            $handler = MiddlewareHandler::create($handler, RetryMiddleware::linear($maxRetries));
109
        }
110
        if ($username = $dsn->getUsername()) {
111
            $handler = MiddlewareHandler::create($handler, new AuthenticationMiddleware($username, $dsn->getPassword() ?? ''));
112
        }
113
114
        return new self($handler);
115
    }
116
117 6
    public function withMiddleware(Middleware $middleware, Middleware ...$middlewares) : self
118
    {
119 6
        $new = clone $this;
120 6
        $new->handler = MiddlewareHandler::create($new->handler, $middleware, ...$middlewares);
121
122 6
        return $new;
123
    }
124
125 51
    public function getHandler() : Handler
126
    {
127 51
        return $this->handler;
128
    }
129
130 173
    public function getSpace(string $spaceName) : Space
131
    {
132 173
        if (isset($this->spaces[$spaceName])) {
133 3
            return $this->spaces[$spaceName];
134
        }
135
136 173
        $spaceId = $this->getSpaceIdByName($spaceName);
137
138 167
        return $this->spaces[$spaceName] = $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
139
    }
140
141 185
    public function getSpaceById(int $spaceId) : Space
142
    {
143 185
        if (isset($this->spaces[$spaceId])) {
144
            return $this->spaces[$spaceId];
145
        }
146
147 185
        return $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
148
    }
149
150 97
    public function ping() : void
151
    {
152 97
        $this->handler->handle(new PingRequest());
153 16
    }
154
155
    /**
156
     * @param mixed ...$args
157
     */
158 42
    public function call(string $funcName, ...$args) : array
159
    {
160 42
        return $this->handler->handle(new CallRequest($funcName, $args))
161 42
            ->getBodyField(Keys::DATA);
162
    }
163
164
    /**
165
     * @param mixed ...$args
166
     */
167 239
    public function evaluate(string $expr, ...$args) : array
168
    {
169 239
        return $this->handler->handle(new EvaluateRequest($expr, $args))
170 230
            ->getBodyField(Keys::DATA);
171
    }
172
173
    /**
174
     * @param mixed ...$params
175
     */
176 6
    public function execute(string $sql, ...$params) : Response
177
    {
178 6
        return $this->handler->handle(ExecuteRequest::fromSql($sql, $params));
179
    }
180
181
    /**
182
     * @param mixed ...$params
183
     */
184 21
    public function executeQuery(string $sql, ...$params) : SqlQueryResult
185
    {
186 21
        $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params));
187
188 21
        return new SqlQueryResult(
189 21
            $response->getBodyField(Keys::DATA),
190 21
            $response->getBodyField(Keys::METADATA)
191
        );
192
    }
193
194
    /**
195
     * @param mixed ...$params
196
     */
197 9
    public function executeUpdate(string $sql, ...$params) : SqlUpdateResult
198
    {
199 9
        $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params));
200
201 9
        return new SqlUpdateResult($response->getBodyField(Keys::SQL_INFO));
202
    }
203
204
    public function prepare(string $sql) : PreparedStatement
205
    {
206
        $response = $this->handler->handle(PrepareRequest::fromSql($sql));
207
208
        return new PreparedStatement(
209
            $this->handler,
210
            $response->getBodyField(Keys::STMT_ID),
211
            $response->getBodyField(Keys::BIND_COUNT),
212
            $response->getBodyField(Keys::BIND_METADATA),
213
            $response->tryGetBodyField(Keys::METADATA, [])
214
        );
215
    }
216
217 6
    public function flushSpaces() : void
218
    {
219 6
        $this->spaces = [];
220 6
    }
221
222 6
    public function __clone()
223
    {
224 6
        $this->spaces = [];
225 6
    }
226
227 173
    private function getSpaceIdByName(string $spaceName) : int
228
    {
229 173
        $schema = $this->getSpaceById(Space::VSPACE_ID);
230 173
        $data = $schema->select(Criteria::key([$spaceName])->andIndex(Space::VSPACE_NAME_INDEX));
231
232 173
        if ($data) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
233 167
            return $data[0][0];
234
        }
235
236 6
        throw RequestFailed::unknownSpace($spaceName);
237
    }
238
}
239