Skip to content

Commit 2020e75

Browse files
committed
Rename Index::addFromArray + get index Fields as object (stats)
1 parent 6e6157a commit 2020e75

File tree

10 files changed

+155
-20
lines changed

10 files changed

+155
-20
lines changed

.phan/config.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@
337337
'directory_list' => [
338338
'src',
339339
'vendor/predis/predis',
340+
'vendor/sgh/comparable/src'
340341
],
341342

342343
// A list of individual files to include in analysis

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
],
1818
"require": {
1919
"php": ">= 7.1",
20-
"predis/predis": "^1.1"
20+
"predis/predis": "^1.1",
21+
"sgh/comparable": "^1.1"
2122
},
2223
"require-dev": {
2324
"friendsofphp/php-cs-fixer": "^2.16",

phpstan.neon

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
parameters:
22
ignoreErrors:
33
- '#type has no value type specified in iterable type Predis\\Client#'
4-
- '#with no value type specified in iterable type Predis\\Client#'
4+
- '#with no value type specified in iterable type Predis\\Client#'
5+
- message: '#MacFJA\\RedisSearch\\Index\\Builder\\\w+ constructor expects [\w\|]+, bool\|float\|int\|string\|null given#'
6+
path: src/Index/InfoResult.php

src/Helper/DataHelper.php

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
use function is_string;
3333
use MacFJA\RedisSearch\Index\Exception\IndexNotFoundException;
3434
use RuntimeException;
35+
use function settype;
3536
use function sprintf;
3637
use function sscanf;
3738
use function strpos;
3839
use function strtolower;
3940
use Throwable;
41+
use UnexpectedValueException;
4042

4143
class DataHelper
4244
{
@@ -79,20 +81,7 @@ public static function assert(bool $condition, $exception = null, int $deep = 1)
7981
*/
8082
public static function assertArrayOf(array $array, string $type, $exception = null): void
8183
{
82-
switch ($type) {
83-
case 'int':
84-
$type = 'integer';
85-
86-
break;
87-
case 'bool':
88-
$type = 'boolean';
89-
90-
break;
91-
case 'float':
92-
$type = 'double';
93-
94-
break;
95-
}
84+
$type = self::getPhpType($type);
9685
foreach ($array as $item) {
9786
if (in_array($type, ['string', 'boolean', 'integer', 'double'], true)) {
9887
self::assert(gettype($item) === $type, $exception, 2);
@@ -120,4 +109,40 @@ public static function handleRawResult($result): void
120109
throw new IndexNotFoundException();
121110
}
122111
}
112+
113+
/**
114+
* @param null|bool|float|int|string $raw
115+
*
116+
* @return null|bool|float|int|string
117+
*/
118+
public static function nullOrCast($raw, string $cast)
119+
{
120+
if (is_scalar($raw)) {
121+
settype($raw, self::getPhpType($cast, true));
122+
}
123+
124+
return $raw;
125+
}
126+
127+
private static function getPhpType(string $type, bool $exceptionOnUnknown = false): string
128+
{
129+
switch ($type) {
130+
case 'int':
131+
case 'integer':
132+
return 'integer';
133+
case 'bool':
134+
case 'boolean':
135+
return 'boolean';
136+
case 'float':
137+
case 'double':
138+
return 'double';
139+
case 'string':
140+
return 'string';
141+
}
142+
if (true === $exceptionOnUnknown) {
143+
throw new UnexpectedValueException(sprintf('The type "%s" is unknown', $type));
144+
}
145+
146+
return $type;
147+
}
123148
}

src/Helper/RedisHelper.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use function array_filter;
2828
use function array_keys;
2929
use function array_merge;
30+
use function array_shift;
3031
use function assert;
3132
use function count;
3233
use function is_array;
@@ -119,4 +120,19 @@ public static function getPairs(array $notKeyedArray): array
119120

120121
return $keyed;
121122
}
123+
124+
/**
125+
* @param array<float|int|string> $notKeyedArray
126+
*/
127+
public static function getValue(array $notKeyedArray, string $key): ?string
128+
{
129+
while (count($notKeyedArray) > 0) {
130+
$shifted = array_shift($notKeyedArray);
131+
if ($shifted === $key && count($notKeyedArray) > 0) {
132+
return (string) array_shift($notKeyedArray);
133+
}
134+
}
135+
136+
return null;
137+
}
122138
}

src/Index.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use MacFJA\RedisSearch\Index\InfoResult;
3232
use Predis\Client;
3333
use Throwable;
34+
use function trigger_error;
3435
use function uniqid;
3536

3637
class Index
@@ -54,8 +55,23 @@ public function __construct(string $indexKey, Client $redis)
5455
* @param array<string,float|int|string> $properties
5556
*
5657
* @throws Throwable
58+
*
59+
* @deprecated Use `addDocumentFromArray` instead
60+
* @see Index::addDocumentFromArray()
5761
*/
5862
public function addFromArray(array $properties, ?string $hash = null): string
63+
{
64+
trigger_error('The method '.__METHOD__.' is deprecated. Use \MacFJA\RedisSearch\Index::addDocumentFromArray instead.', \E_USER_DEPRECATED);
65+
66+
return $this->addDocumentFromArray($properties, $hash);
67+
}
68+
69+
/**
70+
* @param array<string,float|int|string> $properties
71+
*
72+
* @throws Throwable
73+
*/
74+
public function addDocumentFromArray(array $properties, ?string $hash = null): string
5975
{
6076
DataHelper::assertArrayOf(array_keys($properties), 'string');
6177
DataHelper::assertArrayOf($properties, 'scalar');

src/Index/Builder/AbstractField.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
namespace MacFJA\RedisSearch\Index\Builder;
2323

24+
use function implode;
2425
use MacFJA\RedisSearch\Helper\RedisHelper;
26+
use SGH\Comparable\ComparatorException;
2527

2628
abstract class AbstractField implements Field
2729
{
@@ -88,4 +90,13 @@ public function getQueryParts(): array
8890
'NOINDEX' => $this->noIndex,
8991
]);
9092
}
93+
94+
public function compareTo($object)
95+
{
96+
if (!($object instanceof Field)) {
97+
throw new ComparatorException();
98+
}
99+
100+
return implode(' ', $object->getQueryParts()) <=> implode(' ', $this->getQueryParts());
101+
}
91102
}

src/Index/Builder/Field.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
namespace MacFJA\RedisSearch\Index\Builder;
2323

2424
use MacFJA\RedisSearch\PartialQuery;
25+
use SGH\Comparable\Comparable;
2526

26-
interface Field extends PartialQuery
27+
interface Field extends PartialQuery, Comparable
2728
{
2829
public const TYPE_TEXT = 'TEXT';
2930

src/Index/InfoResult.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,18 @@
2121

2222
namespace MacFJA\RedisSearch\Index;
2323

24+
use function array_map;
25+
use function array_shift;
26+
use function in_array;
2427
use MacFJA\RedisSearch\Helper\DataHelper;
28+
use MacFJA\RedisSearch\Helper\RedisHelper;
29+
use MacFJA\RedisSearch\Index\Builder\Field;
30+
use MacFJA\RedisSearch\Index\Builder\GeoField;
31+
use MacFJA\RedisSearch\Index\Builder\NumericField;
32+
use MacFJA\RedisSearch\Index\Builder\TagField;
33+
use MacFJA\RedisSearch\Index\Builder\TextField;
34+
use function sprintf;
35+
use UnexpectedValueException;
2536

2637
class InfoResult
2738
{
@@ -127,6 +138,51 @@ public function getFields(): array
127138
return $this->fields;
128139
}
129140

141+
/**
142+
* @return array<Field>
143+
*/
144+
public function getFieldsAsObject(): array
145+
{
146+
return array_map(function (array $field): Field {
147+
$name = (string) array_shift($field);
148+
array_shift($field); // type
149+
$type = (string) array_shift($field);
150+
151+
switch ($type) {
152+
case 'GEO':
153+
return new GeoField(
154+
$name,
155+
in_array('NOINDEX', $field, true)
156+
);
157+
case 'NUMERIC':
158+
return new NumericField(
159+
$name,
160+
in_array('SORTABLE', $field, true),
161+
in_array('NOINDEX', $field, true)
162+
);
163+
case 'TAG':
164+
return new TagField(
165+
$name,
166+
RedisHelper::getValue($field, 'SEPARATOR'),
167+
in_array('SORTABLE', $field, true),
168+
in_array('NOINDEX', $field, true)
169+
);
170+
case 'TEXT':
171+
return new TextField(
172+
$name,
173+
in_array('NOSTEM', $field, true),
174+
/** @phan-suppress-next-line PhanPartialTypeMismatchArgument */
175+
DataHelper::nullOrCast(RedisHelper::getValue($field, 'WEIGHT'), 'float'),
176+
RedisHelper::getValue($field, 'PHONETIC'),
177+
in_array('SORTABLE', $field, true),
178+
in_array('NOINDEX', $field, true)
179+
);
180+
default:
181+
throw new UnexpectedValueException(sprintf('Unknown field type "%s" for field "%s"', $type, $name));
182+
}
183+
}, $this->fields);
184+
}
185+
130186
public function getDocumentCount(): int
131187
{
132188
return $this->documentCount;

src/Suggestions.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@
3434
use MacFJA\RedisSearch\Suggestion\Result;
3535
use Predis\Client;
3636

37+
/**
38+
* @property-read int $length
39+
*/
3740
class Suggestions
3841
{
3942
/** @var string */
4043
private $dictionaryKey;
4144

42-
/** @var int */
43-
private $length = 0;
45+
/** @var ?int */
46+
private $length;
4447

4548
/** @var Client */
4649
private $redis;
@@ -60,7 +63,7 @@ public function __construct(string $dictionaryKey, Client $redis)
6063
public function __get(string $name)
6164
{
6265
if ('length' === $name) {
63-
return $this->length;
66+
return $this->length ?? $this->length();
6467
}
6568

6669
return;
@@ -76,6 +79,7 @@ public function add(string $suggestion, float $score, bool $increment = false, ?
7679
$command = ['FT.SUGADD', $this->dictionaryKey, $suggestion, $score];
7780
$command = RedisHelper::buildQueryBoolean($command, ['INCR' => $increment]);
7881
$command = RedisHelper::buildQueryNotNull($command, ['PAYLOAD' => $payload]);
82+
/** @phan-suppress-next-line PhanAccessReadOnlyMagicProperty */
7983
$this->length = $this->redis->executeRaw($command);
8084
}
8185

@@ -105,13 +109,15 @@ public function get(string $prefix, bool $fuzzy = false, bool $withScores = fals
105109
public function delete(string $suggestion): bool
106110
{
107111
$removed = (int) $this->redis->executeRaw(['FT.SUGDEL', $this->dictionaryKey, $suggestion]);
112+
/** @phan-suppress-next-line PhanAccessReadOnlyMagicProperty */
108113
$this->length -= $removed;
109114

110115
return 1 === $removed;
111116
}
112117

113118
public function length(): int
114119
{
120+
/** @phan-suppress-next-line PhanAccessReadOnlyMagicProperty */
115121
$this->length = (int) $this->redis->executeRaw(['FT.SUGLEN', $this->dictionaryKey]);
116122

117123
return $this->length;

0 commit comments

Comments
 (0)