diff --git a/BibliotecaTypesenseBundle/src/Mapper/CollectionOptions.php b/BibliotecaTypesenseBundle/src/Mapper/CollectionOptions.php new file mode 100644 index 00000000..b27a1401 --- /dev/null +++ b/BibliotecaTypesenseBundle/src/Mapper/CollectionOptions.php @@ -0,0 +1,22 @@ + $this->tokenSeparators, + 'symbols_to_index' => $this->symbolsToIndex, + 'default_sorting_field' => $this->defaultSortingField, + ]; + } +} diff --git a/BibliotecaTypesenseBundle/src/Mapper/CollectionOptionsInterface.php b/BibliotecaTypesenseBundle/src/Mapper/CollectionOptionsInterface.php new file mode 100644 index 00000000..d012cfa4 --- /dev/null +++ b/BibliotecaTypesenseBundle/src/Mapper/CollectionOptionsInterface.php @@ -0,0 +1,8 @@ +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, + 'stem' => $this->stem, + ]); + } + + public function getType(): string + { + return $this->type; + } + + public function getName(): string + { + return $this->name; + } +} diff --git a/BibliotecaTypesenseBundle/src/Mapper/FieldMappingInterface.php b/BibliotecaTypesenseBundle/src/Mapper/FieldMappingInterface.php new file mode 100644 index 00000000..3ea453bb --- /dev/null +++ b/BibliotecaTypesenseBundle/src/Mapper/FieldMappingInterface.php @@ -0,0 +1,22 @@ + + */ + public function toArray(): array; + + /** + * @see DataTypeEnum + * @return string + */ + public function getType(): string; + + public function getName(): string; +} diff --git a/BibliotecaTypesenseBundle/src/Mapper/MapperInterface.php b/BibliotecaTypesenseBundle/src/Mapper/MapperInterface.php index 7c05bbe7..8aba3d56 100644 --- a/BibliotecaTypesenseBundle/src/Mapper/MapperInterface.php +++ b/BibliotecaTypesenseBundle/src/Mapper/MapperInterface.php @@ -4,12 +4,17 @@ interface MapperInterface { - public function getMapping(): Mapping; + public function getMapping(): MappingInterface; /** - * @return \generator> + * Data to index, the key is the field name + * @return \Generator> */ - 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; } diff --git a/BibliotecaTypesenseBundle/src/Mapper/MapperLocator.php b/BibliotecaTypesenseBundle/src/Mapper/MapperLocator.php index 0aec9bb1..d63056c2 100644 --- a/BibliotecaTypesenseBundle/src/Mapper/MapperLocator.php +++ b/BibliotecaTypesenseBundle/src/Mapper/MapperLocator.php @@ -5,14 +5,15 @@ class MapperLocator { /** + * TODO Check if we need to inject the ServiceLocator and lazy load this. * @param iterable $mappers */ - public function __construct(private iterable $mappers) + public function __construct(private readonly iterable $mappers) { } /** - * @return \generator + * @return \Generator */ public function getMappers(): \Generator { @@ -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); diff --git a/BibliotecaTypesenseBundle/src/Mapper/Mapping.php b/BibliotecaTypesenseBundle/src/Mapper/Mapping.php index d41149a4..d3311f21 100644 --- a/BibliotecaTypesenseBundle/src/Mapper/Mapping.php +++ b/BibliotecaTypesenseBundle/src/Mapper/Mapping.php @@ -2,28 +2,27 @@ namespace Biblioteca\TypesenseBundle\Mapper; -use Symfony\Component\OptionsResolver\OptionsResolver; - -class Mapping +class Mapping implements MappingInterface { - public function __construct(private string $name, private array $fields = []) + public function __construct( + private string $name, + /** @var array */ + 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']); - - $data = $optionResolver->resolve($options); - unset($data['optional']); - $this->fields[$name] = $data; + $this->fields[] = $field; return $this; } @@ -33,8 +32,8 @@ public function getName(): string return $this->name; } - public function getCollectionOptions(): array + public function getCollectionOptions(): ?CollectionOptionsInterface { - return []; + return $this->collectionOptions; } } diff --git a/BibliotecaTypesenseBundle/src/Mapper/MappingInterface.php b/BibliotecaTypesenseBundle/src/Mapper/MappingInterface.php new file mode 100644 index 00000000..58109422 --- /dev/null +++ b/BibliotecaTypesenseBundle/src/Mapper/MappingInterface.php @@ -0,0 +1,15 @@ + $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); @@ -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(); } diff --git a/BibliotecaTypesenseBundle/src/Type/DataTypeEnum.php b/BibliotecaTypesenseBundle/src/Type/DataTypeEnum.php new file mode 100644 index 00000000..109505df --- /dev/null +++ b/BibliotecaTypesenseBundle/src/Type/DataTypeEnum.php @@ -0,0 +1,25 @@ +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-> + addField(new FieldMapping( + name: 'id', + type: DataTypeEnum::PRIMARY + )) + ->addField(new FieldMapping( + name: 'title', + type: DataTypeEnum::STRING + )) + ->addField(new FieldMapping( + name: 'sortable_id', + type: DataTypeEnum::INT32 + )) + ->addField(new FieldMapping( + name: 'serie', + type: DataTypeEnum::STRING, + facet: true, + optional: true + )) + ->addField(new FieldMapping( + name: 'summary', + type: DataTypeEnum::STRING, + optional: true + )) + ->addField(new FieldMapping( + name: 'serieIndex', + type: DataTypeEnum::STRING, + optional: true + )) + ->addField(new FieldMapping( + name: 'extension', + type: DataTypeEnum::STRING, + facet: true + )) + ->addField(new FieldMapping( + name: 'authors', + type: DataTypeEnum::STRING_ARRAY, + facet: true + )) + ->addField(new FieldMapping( + name: 'tags', + type: DataTypeEnum::STRING_ARRAY, + facet: true, + optional: true + )) + ; return $mapping; }