Completed
Push — master ( 43ebed...079015 )
by Eugene
06:22
created

Client   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 206
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 19

Test Coverage

Coverage 88.78%

Importance

Changes 0
Metric Value
dl 0
loc 206
ccs 87
cts 98
cp 0.8878
rs 9.6
c 0
b 0
f 0
wmc 35
lcom 2
cbo 19

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A fromDefaults() 0 7 1
B fromOptions() 0 28 8
B fromDsn() 0 33 8
A withMiddleware() 0 7 1
A getHandler() 0 4 1
A getSpace() 0 10 2
A getSpaceById() 0 8 2
A ping() 0 4 1
A call() 0 5 1
A evaluate() 0 5 1
A execute() 0 4 1
A executeQuery() 0 9 1
A executeUpdate() 0 6 1
A flushSpaces() 0 4 1
A __clone() 0 4 1
A getSpaceIdByName() 0 11 2
A prepare() 0 12 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\Packer;
25
use Tarantool\Client\Packer\PackerFactory;
26
use Tarantool\Client\Request\CallRequest;
27
use Tarantool\Client\Request\EvaluateRequest;
28
use Tarantool\Client\Request\ExecuteRequest;
29
use Tarantool\Client\Request\PingRequest;
30
use Tarantool\Client\Request\PrepareRequest;
31
use Tarantool\Client\Schema\Criteria;
32
use Tarantool\Client\Schema\Space;
33
34
final class Client
35
{
36
    /** @var Handler */
37
    private $handler;
38
39
    /** @var array<array-key, Space> */
40
    private $spaces = [];
41
42 531
    public function __construct(Handler $handler)
43
    {
44 531
        $this->handler = $handler;
45 531
    }
46
47 3
    public static function fromDefaults() : self
48
    {
49 3
        return new self(new DefaultHandler(
50 3
            StreamConnection::createTcp(),
51 3
            PackerFactory::create()
52
        ));
53
    }
54
55 9
    public static function fromOptions(array $options, ?Packer $packer = null) : self
56
    {
57 9
        $connectionOptions = [];
58 9
        if (isset($options['connect_timeout'])) {
59
            $connectionOptions['connect_timeout'] = $options['connect_timeout'];
60
        }
61 9
        if (isset($options['socket_timeout'])) {
62
            $connectionOptions['socket_timeout'] = $options['socket_timeout'];
63
        }
64 9
        if (isset($options['tcp_nodelay'])) {
65
            $connectionOptions['tcp_nodelay'] = $options['tcp_nodelay'];
66
        }
67 9
        if (isset($options['persistent'])) {
68
            $connectionOptions['persistent'] = $options['persistent'];
69
        }
70
71 9
        $connection = StreamConnection::create($options['uri'] ?? StreamConnection::DEFAULT_URI, $connectionOptions);
72 9
        $handler = new DefaultHandler($connection, $packer ?? PackerFactory::create());
73
74 9
        if (isset($options['max_retries']) && 0 !== $options['max_retries']) {
75 3
            $handler = MiddlewareHandler::create($handler, RetryMiddleware::linear($options['max_retries']));
76
        }
77 9
        if (isset($options['username'])) {
78 3
            $handler = MiddlewareHandler::create($handler, new AuthenticationMiddleware($options['username'], $options['password'] ?? ''));
79
        }
80
81 9
        return new self($handler);
82
    }
83
84 6
    public static function fromDsn(string $dsn, ?Packer $packer = null) : self
85
    {
86 6
        $dsn = Dsn::parse($dsn);
87
88 6
        $connectionOptions = [];
89 6
        if (null !== $timeout = $dsn->getInt('connect_timeout')) {
90
            $connectionOptions['connect_timeout'] = $timeout;
91
        }
92 6
        if (null !== $timeout = $dsn->getInt('socket_timeout')) {
93
            $connectionOptions['socket_timeout'] = $timeout;
94
        }
95 6
        if (null !== $tcpNoDelay = $dsn->getBool('tcp_nodelay')) {
96
            $connectionOptions['tcp_nodelay'] = $tcpNoDelay;
97
        }
98 6
        if (null !== $persistent = $dsn->getBool('persistent')) {
99
            $connectionOptions['persistent'] = $persistent;
100
        }
101
102 6
        $connection = $dsn->isTcp()
103 6
            ? StreamConnection::createTcp($dsn->getConnectionUri(), $connectionOptions)
104 6
            : StreamConnection::createUds($dsn->getConnectionUri(), $connectionOptions);
105
106 6
        $handler = new DefaultHandler($connection, $packer ?? PackerFactory::create());
107
108 6
        if ($maxRetries = $dsn->getInt('max_retries')) {
109
            $handler = MiddlewareHandler::create($handler, RetryMiddleware::linear($maxRetries));
110
        }
111 6
        if ($username = $dsn->getUsername()) {
112
            $handler = MiddlewareHandler::create($handler, new AuthenticationMiddleware($username, $dsn->getPassword() ?? ''));
113
        }
114
115 6
        return new self($handler);
116
    }
117
118 6
    public function withMiddleware(Middleware $middleware, Middleware ...$middlewares) : self
119
    {
120 6
        $new = clone $this;
121 6
        $new->handler = MiddlewareHandler::create($new->handler, $middleware, ...$middlewares);
122
123 6
        return $new;
124
    }
125
126 72
    public function getHandler() : Handler
127
    {
128 72
        return $this->handler;
129
    }
130
131 173
    public function getSpace(string $spaceName) : Space
132
    {
133 173
        if (isset($this->spaces[$spaceName])) {
134 3
            return $this->spaces[$spaceName];
135
        }
136
137 173
        $spaceId = $this->getSpaceIdByName($spaceName);
138
139 167
        return $this->spaces[$spaceName] = $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
140
    }
141
142 185
    public function getSpaceById(int $spaceId) : Space
143
    {
144 185
        if (isset($this->spaces[$spaceId])) {
145
            return $this->spaces[$spaceId];
146
        }
147
148 185
        return $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
149
    }
150
151 97
    public function ping() : void
152
    {
153 97
        $this->handler->handle(new PingRequest());
154 16
    }
155
156
    /**
157
     * @param mixed ...$args
158
     */
159 42
    public function call(string $funcName, ...$args) : array
160
    {
161 42
        return $this->handler->handle(new CallRequest($funcName, $args))
162 42
            ->getBodyField(Keys::DATA);
163
    }
164
165
    /**
166
     * @param mixed ...$args
167
     */
168 251
    public function evaluate(string $expr, ...$args) : array
169
    {
170 251
        return $this->handler->handle(new EvaluateRequest($expr, $args))
171 242
            ->getBodyField(Keys::DATA);
172
    }
173
174
    /**
175
     * @param mixed ...$params
176
     */
177 6
    public function execute(string $sql, ...$params) : Response
178
    {
179 6
        return $this->handler->handle(ExecuteRequest::fromSql($sql, $params));
180
    }
181
182
    /**
183
     * @param mixed ...$params
184
     */
185 24
    public function executeQuery(string $sql, ...$params) : SqlQueryResult
186
    {
187 24
        $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params));
188
189 24
        return new SqlQueryResult(
190 24
            $response->getBodyField(Keys::DATA),
191 24
            $response->getBodyField(Keys::METADATA)
192
        );
193
    }
194
195
    /**
196
     * @param mixed ...$params
197
     */
198 9
    public function executeUpdate(string $sql, ...$params) : SqlUpdateResult
199
    {
200 9
        $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params));
201
202 9
        return new SqlUpdateResult($response->getBodyField(Keys::SQL_INFO));
203
    }
204
205 12
    public function prepare(string $sql) : PreparedStatement
206
    {
207 12
        $response = $this->handler->handle(PrepareRequest::fromSql($sql));
208
209 12
        return new PreparedStatement(
210 12
            $this->handler,
211 12
            $response->getBodyField(Keys::STMT_ID),
212 12
            $response->getBodyField(Keys::BIND_COUNT),
213 12
            $response->getBodyField(Keys::BIND_METADATA),
214 12
            $response->tryGetBodyField(Keys::METADATA, [])
215
        );
216
    }
217
218 6
    public function flushSpaces() : void
219
    {
220 6
        $this->spaces = [];
221 6
    }
222
223 6
    public function __clone()
224
    {
225 6
        $this->spaces = [];
226 6
    }
227
228 173
    private function getSpaceIdByName(string $spaceName) : int
229
    {
230 173
        $schema = $this->getSpaceById(Space::VSPACE_ID);
231 173
        $data = $schema->select(Criteria::key([$spaceName])->andIndex(Space::VSPACE_NAME_INDEX));
232
233 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...
234 167
            return $data[0][0];
235
        }
236
237 6
        throw RequestFailed::unknownSpace($spaceName);
238
    }
239
}
240