Skip to content

Commit

Permalink
Better types and interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
ragusa87 committed Dec 11, 2024
1 parent 27bfbc6 commit a9209e9
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 35 deletions.
22 changes: 22 additions & 0 deletions BibliotecaTypesenseBundle/src/Mapper/CollectionOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Biblioteca\TypesenseBundle\Mapper;

class CollectionOptions implements CollectionOptionsInterface
{
public function __construct(
public ?string $tokenSeparators = null,
public ?string $symbolsToIndex = null,
public ?string $defaultSortingField = null,
) {
}

public function toArray(): array
{
return [
'token_separators' => $this->tokenSeparators,
'symbols_to_index' => $this->symbolsToIndex,
'default_sorting_field' => $this->defaultSortingField,
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Biblioteca\TypesenseBundle\Mapper;

interface CollectionOptionsInterface
{
public function toArray(): array;
}
61 changes: 61 additions & 0 deletions BibliotecaTypesenseBundle/src/Mapper/FieldMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Biblioteca\TypesenseBundle\Mapper;

use Biblioteca\TypesenseBundle\Type\DataTypeEnum;

class FieldMapping implements FieldMappingInterface
{
public string $type;

public function __construct(
public string $name,
DataTypeEnum|string $type,
public ?bool $facet = null,
public ?bool $optional = null,
public ?bool $drop = null,
public ?bool $index = null,
public ?bool $infix = null,
public ?bool $range_index = null,
public ?bool $sort = null, // Default depends on the type; not assigned here
public ?bool $stem = null,
public ?bool $store = null,
public ?int $num_dim = null,
public ?string $locale = null,
public ?string $reference = null,
public ?string $vec_dist = null,
) {
$this->type = $type instanceof DataTypeEnum ? $type->value : $type;
}

public function toArray(): array
{
return array_filter([
'name' => $this->name,
'type' => $this->type,
'facet' => $this->facet,
'optional' => $this->optional,
'index' => $this->index,
'store' => $this->store,
'sort' => $this->sort,
'infix' => $this->infix,
'locale' => $this->locale,
'num_dim' => $this->num_dim,
'vec_dist' => $this->vec_dist,
'reference' => $this->reference,
'range_index' => $this->range_index,
'drop' => $this->drop,
'stem' => $this->stem,
]);
}

public function getType(): string
{
return $this->type;
}

public function getName(): string
{
return $this->name;
}
}
22 changes: 22 additions & 0 deletions BibliotecaTypesenseBundle/src/Mapper/FieldMappingInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Biblioteca\TypesenseBundle\Mapper;

use Biblioteca\TypesenseBundle\Type\DataTypeEnum;

interface FieldMappingInterface
{
/**
* Field options and value
* @return array<string,mixed>
*/
public function toArray(): array;

/**
* @see DataTypeEnum
* @return string
*/
public function getType(): string;

public function getName(): string;
}
11 changes: 8 additions & 3 deletions BibliotecaTypesenseBundle/src/Mapper/MapperInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@

interface MapperInterface
{
public function getMapping(): Mapping;
public function getMapping(): MappingInterface;

/**
* @return \generator<array<string, mixed>>
* Data to index, the key is the field name
* @return \Generator<array<string, mixed>>
*/
public function getData(): \generator;
public function getData(): \Generator;

/**
* How many data to index. If null, the progression is unknown.
* @return int|null
*/
public function getDataCount(): ?int;
}
10 changes: 3 additions & 7 deletions BibliotecaTypesenseBundle/src/Mapper/MapperLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
class MapperLocator
{
/**
* TODO Check if we need to inject the ServiceLocator and lazy load this.
* @param iterable<MapperInterface> $mappers
*/
public function __construct(private iterable $mappers)
public function __construct(private readonly iterable $mappers)
{
}

/**
* @return \generator<MapperInterface>
* @return \Generator<MapperInterface>
*/
public function getMappers(): \Generator
{
Expand All @@ -21,11 +22,6 @@ public function getMappers(): \Generator
}
}

public function addMapper(MapperInterface $mapper): void
{
$this->mappers[] = $mapper;
}

public function count(): int
{
return count($this->mappers);
Expand Down
32 changes: 20 additions & 12 deletions BibliotecaTypesenseBundle/src/Mapper/Mapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,36 @@

namespace Biblioteca\TypesenseBundle\Mapper;

use Symfony\Component\OptionsResolver\OptionsResolver;
use Biblioteca\TypesenseBundle\Type\DataTypeEnum;

class Mapping
class Mapping implements MappingInterface
{
public function __construct(private string $name, private array $fields = [])
public function __construct(
private string $name,
/** @var array<int, FieldMappingInterface> */
private array $fields = [],
private readonly ?CollectionOptionsInterface $collectionOptions = null)
{
}

/**
* @return FieldMappingInterface[]
*/
public function getFields(): array
{
return $this->fields;
}

public function setField(string $name, array $options): self
public function addField(FieldMappingInterface $field): self
{
$optionResolver = new OptionsResolver();
$optionResolver->setRequired(['name', 'type']);
$optionResolver->setDefined(['facet', 'optional']);
$this->fields[] = $field;

$data = $optionResolver->resolve($options);
unset($data['optional']);
$this->fields[$name] = $data;
return $this;
}

public function add(string $name, DataTypeEnum $type, ?bool $facet = null, ?bool $optional = null): self
{
$this->addField(new FieldMapping(name: $name, type: $type, facet: $facet, optional: $optional));

return $this;
}
Expand All @@ -33,8 +41,8 @@ public function getName(): string
return $this->name;
}

public function getCollectionOptions(): array
public function getCollectionOptions(): ?CollectionOptionsInterface
{
return [];
return $this->collectionOptions;
}
}
15 changes: 15 additions & 0 deletions BibliotecaTypesenseBundle/src/Mapper/MappingInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Biblioteca\TypesenseBundle\Mapper;

interface MappingInterface
{
/**
* @return FieldMappingInterface[]
*/
public function getFields(): array;

public function getName(): string;

public function getCollectionOptions(): ?CollectionOptionsInterface;
}
10 changes: 6 additions & 4 deletions BibliotecaTypesenseBundle/src/PopulateService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
namespace Biblioteca\TypesenseBundle;

use Biblioteca\TypesenseBundle\Client\ClientInterface;
use Biblioteca\TypesenseBundle\Mapper\FieldMappingInterface;
use Biblioteca\TypesenseBundle\Mapper\MapperInterface;
use Biblioteca\TypesenseBundle\Mapper\MappingInterface;
use Typesense\Collection;

class PopulateService
{
public function __construct(
private ClientInterface $client,
private readonly ClientInterface $client,
private readonly string $collectionPrefix = '',
) {
}
Expand All @@ -31,8 +33,8 @@ public function createCollection(MapperInterface $mapper): Collection

$payload = [
'name' => $name,
'fields' => array_values($mapping->getFields()),
...$mapping->getCollectionOptions(),
'fields' => array_map(fn (FieldMappingInterface $mapping) => $mapping->toArray(), $mapping->getFields()),
...$mapping->getCollectionOptions()?->toArray() ?? [],
];

$this->client->getCollections()->create($payload);
Expand All @@ -53,7 +55,7 @@ public function fillCollection(MapperInterface $mapper): \Generator
}
}

private function getMappingName(Mapper\Mapping $mapping): string
private function getMappingName(MappingInterface $mapping): string
{
return $this->collectionPrefix.$mapping->getName();
}
Expand Down
25 changes: 25 additions & 0 deletions BibliotecaTypesenseBundle/src/Type/DataTypeEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Biblioteca\TypesenseBundle\Type;

enum DataTypeEnum: string
{
case PRIMARY = 'primary';
case STRING = 'string';
case STRING_ARRAY = 'string[]';
case INT32 = 'int32';
case INT32_ARRAY = 'int32[]';
case INT64 = 'int64';
case INT64_ARRAY = 'int64[]';
case FLOAT = 'float';
case FLOAT_ARRAY = 'float[]';
case BOOL = 'bool';
case BOOL_ARRAY = 'bool[]';
case GEOPOINT = 'geopoint';
case GEOPOINT_ARRAY = 'geopoint[]';
case OBJECT = 'object';
case OBJECT_ARRAY = 'object[]';
case STRING_CONVERTIBLE = 'string*';
case IMAGE = 'image';
case AUTO = 'auto';
}
57 changes: 48 additions & 9 deletions src/Mapper/BookMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use App\Entity\Book;
use App\Repository\BookRepository;
use Biblioteca\TypesenseBundle\Mapper\FieldMapping;
use Biblioteca\TypesenseBundle\Mapper\MapperInterface;
use Biblioteca\TypesenseBundle\Mapper\Mapping;
use Biblioteca\TypesenseBundle\Type\DataTypeEnum;

class BookMapper implements MapperInterface
{
Expand All @@ -17,15 +19,52 @@ public function __construct(
public function getMapping(): Mapping
{
$mapping = new Mapping('books');
$mapping->setField('id', ['name' => 'id', 'type' => 'primary']);
$mapping->setField('title', ['name' => 'title', 'type' => 'string']);
$mapping->setField('sortable_id', ['name' => 'sortable_id', 'type' => 'int32']);
$mapping->setField('serie', ['name' => 'serie', 'type' => 'string', 'optional' => true, 'facet' => true]);
$mapping->setField('summary', ['name' => 'summary', 'type' => 'string', 'optional' => true]);
$mapping->setField('serieIndex', ['name' => 'serieIndex', 'type' => 'string', 'optional' => true]);
$mapping->setField('extension', ['name' => 'extension', 'type' => 'string', 'facet' => true]);
$mapping->setField('authors', ['name' => 'authors', 'type' => 'string[]', 'facet' => true]);
$mapping->setField('tags', ['name' => 'tags', 'type' => 'string[]', 'facet' => true, 'optional' => true]);
$mapping->
add(
name: 'id',
type: DataTypeEnum::PRIMARY
)
->add(
name: 'title',
type: DataTypeEnum::STRING
)
->add(
name: 'sortable_id',
type: DataTypeEnum::INT32
)
->add(
name: 'serie',
type: DataTypeEnum::STRING,
facet: true,
optional: true
)
->add(
name: 'summary',
type: DataTypeEnum::STRING,
optional: true
)
->add(
name: 'serieIndex',
type: DataTypeEnum::STRING,
optional: true
)
->add(
name: 'extension',
type: DataTypeEnum::STRING,
facet: true
)
->add(
name: 'authors',
type: DataTypeEnum::STRING_ARRAY,
facet: true
)
->add(
name: 'tags',
type: DataTypeEnum::STRING_ARRAY,
facet: true,
optional: true
)
;

return $mapping;
}
Expand Down

0 comments on commit a9209e9

Please sign in to comment.