From ca119fe402ff85ff414ea7a27dc711dfbffb5d64 Mon Sep 17 00:00:00 2001
From: Nikita Chernykh <n.chernykh@iqdev.digital>
Date: Fri, 29 Sep 2023 09:47:38 +0500
Subject: [PATCH] EscapeDependence | Refactor

---
 composer.json                                 |  3 +-
 .../Converter/CriteriaToEsRequest.php         | 41 +++++-------
 .../Converter/EsResponseToResult.php          | 25 ++++---
 src/ElasticSearch/Criteria.php                |  2 +-
 .../Document/ProductDocument.php              | 14 ++--
 .../Document/Property/AttrType.php            | 30 ---------
 .../Document/Property/Property.php            | 22 +++++++
 .../Document/Property/PropertyType.php        | 38 ++---------
 src/ElasticSearch/Document/Property/Type.php  | 13 ----
 .../{ => Collection}/FacetCollection.php      |  3 +-
 .../Collection/FacetResultCollection.php      | 18 +++++
 src/ElasticSearch/Facet/Facet.php             | 37 +++--------
 src/ElasticSearch/Facet/FacetCategory.php     | 22 -------
 src/ElasticSearch/Facet/FacetFactory.php      | 23 +++++++
 src/ElasticSearch/Facet/FacetKeyword.php      | 27 --------
 src/ElasticSearch/Facet/FacetNumber.php       | 23 -------
 src/ElasticSearch/Facet/FacetResult.php       | 31 +++++++++
 src/ElasticSearch/Facet/FacetType.php         |  9 +++
 src/ElasticSearch/Facet/FacetTypeEnum.php     |  9 ---
 src/ElasticSearch/Facet/NewFacet.php          | 15 -----
 src/ElasticSearch/Facet/Type/BaseFacet.php    | 18 +++++
 .../Facet/Type/FacetListType.php              |  7 --
 .../Facet/Type/FacetRangeType.php             |  7 --
 src/ElasticSearch/Facet/Type/FacetType.php    |  7 --
 src/ElasticSearch/Facet/Type/KeywordFacet.php | 19 ++++++
 src/ElasticSearch/Facet/Type/NumberFacet.php  | 19 ++++++
 .../{ => Collection}/FilterCollection.php     |  3 +-
 .../FilterGroupCollection.php                 |  5 +-
 .../{ => Collection}/PostFilterCollection.php |  2 +-
 .../QueryFilterCollection.php                 |  2 +-
 .../Filter/{ => Value}/FilterKeyword.php      |  4 +-
 .../Filter/{ => Value}/FilterNumber.php       |  4 +-
 .../Indexer/BaseIndexProvider.php             | 20 ++++--
 src/ElasticSearch/Order/Order.php             | 33 ++++------
 src/ElasticSearch/Order/OrderAscType.php      |  8 ---
 src/ElasticSearch/Order/OrderDescType.php     |  8 ---
 src/ElasticSearch/Order/OrderDirection.php    |  9 +++
 src/ElasticSearch/Order/OrderFactory.php      | 25 +++++++
 src/ElasticSearch/Order/OrderField.php        |  7 --
 src/ElasticSearch/Order/OrderType.php         | 13 ----
 src/ElasticSearch/Order/Type/BaseOrder.php    | 16 +++++
 .../KeywordPropertyOrder.php}                 | 19 ++++--
 .../NumberPropertyOrder.php}                  | 19 ++++--
 src/ElasticSearch/Result.php                  |  8 +--
 tests/Filter/AggsTest.php                     | 12 ++--
 tests/Filter/CommonRangeKeywordsTest.php      | 12 ++--
 tests/Filter/KeywordsTest.php                 | 10 +--
 tests/Filter/QueryAndPostFilterTest.php       | 12 ++--
 tests/Filter/QueryTest.php                    | 12 ++--
 tests/Filter/RangeTest.php                    | 10 +--
 tests/Filter/SearchItemsTest.php              | 10 +--
 tests/Filter/SortTest.php                     | 65 ++++++++-----------
 tests/Helpers/FormatData.php                  |  8 +--
 tests/Helpers/TestIndexProvider.php           | 20 ++++--
 54 files changed, 410 insertions(+), 448 deletions(-)
 delete mode 100644 src/ElasticSearch/Document/Property/AttrType.php
 create mode 100644 src/ElasticSearch/Document/Property/Property.php
 delete mode 100644 src/ElasticSearch/Document/Property/Type.php
 rename src/ElasticSearch/Facet/{ => Collection}/FacetCollection.php (80%)
 create mode 100644 src/ElasticSearch/Facet/Collection/FacetResultCollection.php
 delete mode 100644 src/ElasticSearch/Facet/FacetCategory.php
 create mode 100644 src/ElasticSearch/Facet/FacetFactory.php
 delete mode 100644 src/ElasticSearch/Facet/FacetKeyword.php
 delete mode 100644 src/ElasticSearch/Facet/FacetNumber.php
 create mode 100644 src/ElasticSearch/Facet/FacetResult.php
 create mode 100644 src/ElasticSearch/Facet/FacetType.php
 delete mode 100644 src/ElasticSearch/Facet/FacetTypeEnum.php
 delete mode 100644 src/ElasticSearch/Facet/NewFacet.php
 create mode 100644 src/ElasticSearch/Facet/Type/BaseFacet.php
 delete mode 100644 src/ElasticSearch/Facet/Type/FacetListType.php
 delete mode 100644 src/ElasticSearch/Facet/Type/FacetRangeType.php
 delete mode 100644 src/ElasticSearch/Facet/Type/FacetType.php
 create mode 100644 src/ElasticSearch/Facet/Type/KeywordFacet.php
 create mode 100644 src/ElasticSearch/Facet/Type/NumberFacet.php
 rename src/ElasticSearch/Filter/{ => Collection}/FilterCollection.php (92%)
 rename src/ElasticSearch/Filter/{ => Collection}/FilterGroupCollection.php (90%)
 rename src/ElasticSearch/Filter/{ => Collection}/PostFilterCollection.php (56%)
 rename src/ElasticSearch/Filter/{ => Collection}/QueryFilterCollection.php (56%)
 rename src/ElasticSearch/Filter/{ => Value}/FilterKeyword.php (80%)
 rename src/ElasticSearch/Filter/{ => Value}/FilterNumber.php (77%)
 delete mode 100644 src/ElasticSearch/Order/OrderAscType.php
 delete mode 100644 src/ElasticSearch/Order/OrderDescType.php
 create mode 100644 src/ElasticSearch/Order/OrderDirection.php
 create mode 100644 src/ElasticSearch/Order/OrderFactory.php
 delete mode 100644 src/ElasticSearch/Order/OrderField.php
 delete mode 100644 src/ElasticSearch/Order/OrderType.php
 create mode 100644 src/ElasticSearch/Order/Type/BaseOrder.php
 rename src/ElasticSearch/Order/{OrderKeywordProperty.php => Type/KeywordPropertyOrder.php} (54%)
 rename src/ElasticSearch/Order/{OrderNumberProperty.php => Type/NumberPropertyOrder.php} (55%)

diff --git a/composer.json b/composer.json
index 1f0b16f..52d7804 100644
--- a/composer.json
+++ b/composer.json
@@ -32,7 +32,8 @@
     }
   },
   "require-dev": {
-    "phpunit/phpunit": "^9.5"
+    "phpunit/phpunit": "^9.5",
+    "symfony/var-dumper": "^6.3"
   },
   "scripts": {
     "tests": "php ./vendor/bin/phpunit --testdox --verbose"
diff --git a/src/ElasticSearch/Converter/CriteriaToEsRequest.php b/src/ElasticSearch/Converter/CriteriaToEsRequest.php
index c168286..94a7b91 100644
--- a/src/ElasticSearch/Converter/CriteriaToEsRequest.php
+++ b/src/ElasticSearch/Converter/CriteriaToEsRequest.php
@@ -2,8 +2,20 @@
 
 namespace IQDEV\ElasticSearch\Converter;
 
-use IQDEV\ElasticSearch\Filter\PostFilterCollection;
-use IQDEV\ElasticSearch\Filter\QueryFilterCollection;
+use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Document\Property\AttrType;
+use IQDEV\ElasticSearch\Document\Property\PropertyType;
+use IQDEV\ElasticSearch\Filter\Collection\FilterCollection;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
+use IQDEV\ElasticSearch\Filter\Collection\PostFilterCollection;
+use IQDEV\ElasticSearch\Filter\Collection\QueryFilterCollection;
+use IQDEV\ElasticSearch\Filter\Filter;
+use IQDEV\ElasticSearch\Filter\FilterOperator;
+use IQDEV\ElasticSearch\Filter\FilterType;
+use IQDEV\ElasticSearch\Filter\LogicOperator;
+use IQDEV\ElasticSearch\Filter\Value\FilterKeyword;
+use IQDEV\ElasticSearch\Filter\Value\FilterNumber;
+use IQDEV\ElasticSearch\Order\Order;
 use IQDEV\ElasticSearch\Order\OrderField;
 use IQDEV\ElasticSearch\Order\OrderKeywordProperty;
 use IQDEV\ElasticSearch\Order\OrderNumberProperty;
@@ -17,18 +29,6 @@ use IQDEV\ElasticSearch\Search\BoolQuery\Terms;
 use IQDEV\ElasticSearch\Search\Nested;
 use IQDEV\ElasticSearch\Search\Pagination;
 use IQDEV\ElasticSearch\Search\Request;
-use IQDEV\ElasticSearch\Criteria;
-use IQDEV\ElasticSearch\Document\Property\AttrType;
-use IQDEV\ElasticSearch\Document\Property\PropertyType;
-use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterCollection;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterKeyword;
-use IQDEV\ElasticSearch\Filter\FilterNumber;
-use IQDEV\ElasticSearch\Filter\FilterOperator;
-use IQDEV\ElasticSearch\Filter\FilterType;
-use IQDEV\ElasticSearch\Filter\LogicOperator;
-use IQDEV\ElasticSearch\Order\Order;
 
 final class CriteriaToEsRequest
 {
@@ -62,18 +62,7 @@ final class CriteriaToEsRequest
 
         foreach ($criteria->sorting() as $order) {
             /** @var Order $order */
-
-            $direction = $order->orderType();
-
-            if ($order->orderBy() instanceof AttrType) {
-                $request->getSort()->add(new OrderField($order->orderBy(), $direction));
-            } elseif ($order->orderBy() instanceof PropertyType) {
-                if ($order->orderBy()->type() === PropertyType::TYPE_KEYWORD) {
-                    $request->getSort()->add(new OrderKeywordProperty($order->orderBy(), $direction));
-                } elseif ($order->orderBy()->type() === PropertyType::TYPE_NUMBER) {
-                    $request->getSort()->add(new OrderNumberProperty($order->orderBy(), $direction));
-                }
-            }
+            $request->getSort()->add($order);
         }
 
         return $request;
diff --git a/src/ElasticSearch/Converter/EsResponseToResult.php b/src/ElasticSearch/Converter/EsResponseToResult.php
index ee1262c..2b06234 100644
--- a/src/ElasticSearch/Converter/EsResponseToResult.php
+++ b/src/ElasticSearch/Converter/EsResponseToResult.php
@@ -4,12 +4,11 @@ namespace IQDEV\ElasticSearch\Converter;
 
 use Elastic\Elasticsearch\Response\Elasticsearch;
 use IQDEV\ElasticSearch\Document\Product;
-use IQDEV\ElasticSearch\Facet\Facet;
+use IQDEV\ElasticSearch\Facet\FacetType;
+use IQDEV\ElasticSearch\Facet\FacetResult;
 use IQDEV\ElasticSearch\Facet\Item\FacetItemList;
 use IQDEV\ElasticSearch\Facet\Item\FacetItemRange;
 use IQDEV\ElasticSearch\Facet\Item\FacetItemRangeDTO;
-use IQDEV\ElasticSearch\Facet\Type\FacetListType;
-use IQDEV\ElasticSearch\Facet\Type\FacetRangeType;
 use IQDEV\ElasticSearch\Result;
 
 final class EsResponseToResult
@@ -91,7 +90,7 @@ final class EsResponseToResult
             $code = $bucket['key'];
             $valueBucket = $bucket['agg_keyword_facet_value']['buckets'];
 
-            $facet = new Facet(new FacetListType(), $code);
+            $facet = new FacetResult(FacetType::LIST, $code);
 
             foreach ($valueBucket as $value) {
                 $count = 0;
@@ -127,9 +126,9 @@ final class EsResponseToResult
         foreach ($buckets as $bucket) {
             $code = $bucket['key'];
             $workBucket = $bucket['agg_number_facet_value'];
-            $selectedBuket = !empty($bucketsFiltered[$code]) ? $bucketsFiltered[$code] : null;
+            $selectedBucket = !empty($bucketsFiltered[$code]) ? $bucketsFiltered[$code] : null;
 
-            $facet = new Facet(new FacetRangeType(), $code);
+            $facet = new FacetResult(FacetType::RANGE, $code);
             $facetItem = FacetItemRange::create(
                 FacetItemRangeDTO::create(
                     $workBucket['min'],
@@ -137,14 +136,14 @@ final class EsResponseToResult
                     $workBucket['avg'],
                     $workBucket['sum']
                 ),
-                $selectedBuket !== null ? FacetItemRangeDTO::create(
-                    $selectedBuket['min'],
-                    $selectedBuket['max'],
-                    $selectedBuket['avg'],
-                    $selectedBuket['sum']
+                $selectedBucket !== null ? FacetItemRangeDTO::create(
+                    $selectedBucket['min'],
+                    $selectedBucket['max'],
+                    $selectedBucket['avg'],
+                    $selectedBucket['sum']
                 ) : FacetItemRangeDTO::create(),
-                $selectedBuket ? $selectedBuket['count'] : 0,
-                $selectedBuket !== null
+                $selectedBucket ? $selectedBucket['count'] : 0,
+                $selectedBucket !== null
             );
             $facet->products->add($facetItem);
 
diff --git a/src/ElasticSearch/Criteria.php b/src/ElasticSearch/Criteria.php
index 524d590..7b49d6a 100644
--- a/src/ElasticSearch/Criteria.php
+++ b/src/ElasticSearch/Criteria.php
@@ -2,7 +2,7 @@
 
 namespace IQDEV\ElasticSearch;
 
-use IQDEV\ElasticSearch\Filter\FilterCollection;
+use IQDEV\ElasticSearch\Filter\Collection\FilterCollection;
 use IQDEV\ElasticSearch\Order\OrderCollection;
 
 final class Criteria
diff --git a/src/ElasticSearch/Document/ProductDocument.php b/src/ElasticSearch/Document/ProductDocument.php
index 87752e8..fefc014 100644
--- a/src/ElasticSearch/Document/ProductDocument.php
+++ b/src/ElasticSearch/Document/ProductDocument.php
@@ -4,8 +4,8 @@ namespace IQDEV\ElasticSearch\Document;
 
 use IQDEV\ElasticSearch\Config\MappingValidator;
 use IQDEV\ElasticSearch\Configuration;
-use IQDEV\ElasticSearch\Facet\FacetCategory;
-use IQDEV\ElasticSearch\Facet\FacetCollection;
+use IQDEV\ElasticSearch\Facet\Collection\FacetCollection;
+use IQDEV\ElasticSearch\Facet\Facet;
 use IQDEV\ElasticSearch\Helper\ArrayHelper;
 
 class ProductDocument implements Document
@@ -17,11 +17,11 @@ class ProductDocument implements Document
     private array $info = [];
     private bool $skipEmpty = false;
 
-    private FacetCategory $categoryFacet;
+    private Facet $categoryFacet;
 
 
     public function __construct(
-        FacetCategory $categoryFacet
+        Facet $categoryFacet
     )
     {
         $this->keywordFacets = new FacetCollection();
@@ -31,7 +31,7 @@ class ProductDocument implements Document
 
     }
 
-    public static function create(FacetCategory $categoryFacet): self
+    public static function create(Facet $categoryFacet): self
     {
         return new self($categoryFacet);
     }
@@ -45,9 +45,9 @@ class ProductDocument implements Document
     }
 
     /**
-     * @return FacetCategory
+     * @return Facet
      */
-    public function getCategoryFacet(): FacetCategory
+    public function getCategoryFacet(): Facet
     {
         return $this->categoryFacet;
     }
diff --git a/src/ElasticSearch/Document/Property/AttrType.php b/src/ElasticSearch/Document/Property/AttrType.php
deleted file mode 100644
index 246828d..0000000
--- a/src/ElasticSearch/Document/Property/AttrType.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Document\Property;
-
-class AttrType implements Type
-{
-    protected string $key;
-    protected ?string $type;
-
-    public function __construct(string $key, ?string $type = null)
-    {
-        $this->key = $key;
-        $this->type = $type;
-    }
-
-    public function key(): string
-    {
-        return $this->key;
-    }
-
-    public function type(): ?string
-    {
-        return $this->type;
-    }
-
-    public static function types(): array
-    {
-        return [];
-    }
-}
\ No newline at end of file
diff --git a/src/ElasticSearch/Document/Property/Property.php b/src/ElasticSearch/Document/Property/Property.php
new file mode 100644
index 0000000..79cfd35
--- /dev/null
+++ b/src/ElasticSearch/Document/Property/Property.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Document\Property;
+
+class Property
+{
+    public function __construct(
+        protected string $key,
+        protected PropertyType $type = PropertyType::BASE,
+    ) {
+    }
+
+    public function getKey(): string
+    {
+        return $this->key;
+    }
+
+    public function getType(): PropertyType
+    {
+        return $this->type;
+    }
+}
diff --git a/src/ElasticSearch/Document/Property/PropertyType.php b/src/ElasticSearch/Document/Property/PropertyType.php
index f533c51..17476b3 100644
--- a/src/ElasticSearch/Document/Property/PropertyType.php
+++ b/src/ElasticSearch/Document/Property/PropertyType.php
@@ -2,39 +2,9 @@
 
 namespace IQDEV\ElasticSearch\Document\Property;
 
-class PropertyType implements Type
+enum PropertyType
 {
-    protected string $key;
-    protected string $type;
-
-    public const TYPE_NUMBER = 'number';
-    public const TYPE_KEYWORD = 'keyword';
-
-    public function __construct(string $key, string $type = null)
-    {
-        if (!in_array($type, self::types(), true)) {
-            throw new \InvalidArgumentException(sprintf('Invalid type "%s" for property "%s"', $type, $key));
-        }
-
-        $this->key = $key;
-        $this->type = $type;
-    }
-
-    public function key(): string
-    {
-        return $this->key;
-    }
-
-    public function type(): string
-    {
-        return $this->type;
-    }
-
-    public static function types(): array
-    {
-        return [
-            self::TYPE_NUMBER,
-            self::TYPE_KEYWORD,
-        ];
-    }
+    case BASE;
+    case KEYWORD;
+    case NUMBER;
 }
diff --git a/src/ElasticSearch/Document/Property/Type.php b/src/ElasticSearch/Document/Property/Type.php
deleted file mode 100644
index 9469944..0000000
--- a/src/ElasticSearch/Document/Property/Type.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Document\Property;
-
-interface Type
-{
-    public function key(): string;
-
-    public function type(): ?string;
-
-    /** @return string[] */
-    public static function types(): array;
-}
diff --git a/src/ElasticSearch/Facet/FacetCollection.php b/src/ElasticSearch/Facet/Collection/FacetCollection.php
similarity index 80%
rename from src/ElasticSearch/Facet/FacetCollection.php
rename to src/ElasticSearch/Facet/Collection/FacetCollection.php
index d628b75..a257b3a 100644
--- a/src/ElasticSearch/Facet/FacetCollection.php
+++ b/src/ElasticSearch/Facet/Collection/FacetCollection.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Facet;
+namespace IQDEV\ElasticSearch\Facet\Collection;
 
 use IQDEV\ElasticSearch\Esable;
+use IQDEV\ElasticSearch\Facet\Facetable;
 use Ramsey\Collection\AbstractCollection;
 
 final class FacetCollection extends AbstractCollection implements Esable
diff --git a/src/ElasticSearch/Facet/Collection/FacetResultCollection.php b/src/ElasticSearch/Facet/Collection/FacetResultCollection.php
new file mode 100644
index 0000000..3d51f0d
--- /dev/null
+++ b/src/ElasticSearch/Facet/Collection/FacetResultCollection.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Facet\Collection;
+
+use IQDEV\ElasticSearch\Facet\FacetResult;
+use Ramsey\Collection\AbstractCollection;
+
+final class FacetResultCollection extends AbstractCollection
+{
+
+    /**
+     * @inheritDoc
+     */
+    public function getType(): string
+    {
+        return FacetResult::class;
+    }
+}
diff --git a/src/ElasticSearch/Facet/Facet.php b/src/ElasticSearch/Facet/Facet.php
index a0f0228..ecfee8f 100644
--- a/src/ElasticSearch/Facet/Facet.php
+++ b/src/ElasticSearch/Facet/Facet.php
@@ -2,39 +2,18 @@
 
 namespace IQDEV\ElasticSearch\Facet;
 
-use IQDEV\ElasticSearch\Facet\Item\FacetItemCollection;
-use IQDEV\ElasticSearch\Facet\Type\FacetType;
+use IQDEV\ElasticSearch\Document\Property\Property;
 
-class Facet implements Facetable
+abstract class Facet implements Facetable
 {
-    public FacetItemCollection $products;
-
-    protected FacetType $type;
-
-    protected string $code;
-
-    public function __construct(FacetType $type, string $code)
-    {
-        $this->type = $type;
-        $this->code = $code;
-        $this->products = new FacetItemCollection();
-    }
-
-    public function getType(): FacetType
-    {
-        return $this->type;
-    }
-
-    public function getCode(): string
-    {
-        return $this->code;
+    public function __construct(
+        protected Property $property,
+        protected mixed $value,
+    ) {
     }
 
-    public function es(): array
+    public function getProperty(): Property
     {
-        return [
-            'facet_code' => $this->code,
-            'facet_value' => $this->type,
-        ];
+        return $this->property;
     }
 }
diff --git a/src/ElasticSearch/Facet/FacetCategory.php b/src/ElasticSearch/Facet/FacetCategory.php
deleted file mode 100644
index 6e286b1..0000000
--- a/src/ElasticSearch/Facet/FacetCategory.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Facet;
-
-use IQDEV\ElasticSearch\Esable;
-
-final class FacetCategory implements Esable
-{
-    private string $category;
-
-    public function __construct(string $category)
-    {
-        $this->category = $category;
-    }
-
-    public function es(): array
-    {
-        return [
-            'category_id' => $this->category,
-        ];
-    }
-}
diff --git a/src/ElasticSearch/Facet/FacetFactory.php b/src/ElasticSearch/Facet/FacetFactory.php
new file mode 100644
index 0000000..0050837
--- /dev/null
+++ b/src/ElasticSearch/Facet/FacetFactory.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Facet;
+
+use IQDEV\ElasticSearch\Document\Property\Property;
+use IQDEV\ElasticSearch\Document\Property\PropertyType;
+use IQDEV\ElasticSearch\Facet\Type\BaseFacet;
+use IQDEV\ElasticSearch\Facet\Type\KeywordFacet;
+use IQDEV\ElasticSearch\Facet\Type\NumberFacet;
+
+class FacetFactory
+{
+    public static function createFromProperty(Property $property, mixed $value): Facet
+    {
+        match ($property->getType()) {
+            PropertyType::KEYWORD => $facet = new KeywordFacet($property, $value),
+            PropertyType::NUMBER => $facet = new NumberFacet($property, $value),
+            default => $facet = new BaseFacet($property, $value),
+        };
+
+        return $facet;
+    }
+}
diff --git a/src/ElasticSearch/Facet/FacetKeyword.php b/src/ElasticSearch/Facet/FacetKeyword.php
deleted file mode 100644
index 11fd094..0000000
--- a/src/ElasticSearch/Facet/FacetKeyword.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Facet;
-
-final class FacetKeyword implements Facetable
-{
-    private string $key;
-    /** @var string|array<string> */
-    private string|array $value;
-
-    /**
-     * @param string|string[] $value
-     */
-    public function __construct(string $key, string|array $value)
-    {
-        $this->key = $key;
-        $this->value = $value;
-    }
-
-    public function es(): array
-    {
-        return [
-            'facet_code' => $this->key,
-            'facet_value' => $this->value,
-        ];
-    }
-}
diff --git a/src/ElasticSearch/Facet/FacetNumber.php b/src/ElasticSearch/Facet/FacetNumber.php
deleted file mode 100644
index 12bf983..0000000
--- a/src/ElasticSearch/Facet/FacetNumber.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Facet;
-
-final class FacetNumber implements Facetable
-{
-    private string $key;
-    private float $value;
-
-    public function __construct(string $key, float $value)
-    {
-        $this->key = $key;
-        $this->value = $value;
-    }
-
-    public function es(): array
-    {
-        return [
-            'facet_code' => $this->key,
-            'facet_value' => $this->value,
-        ];
-    }
-}
diff --git a/src/ElasticSearch/Facet/FacetResult.php b/src/ElasticSearch/Facet/FacetResult.php
new file mode 100644
index 0000000..66c608f
--- /dev/null
+++ b/src/ElasticSearch/Facet/FacetResult.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Facet;
+
+use IQDEV\ElasticSearch\Facet\Item\FacetItemCollection;
+
+class FacetResult
+{
+    public FacetItemCollection $products;
+
+    protected FacetType $type;
+
+    protected string $code;
+
+    public function __construct(FacetType $type, string $code)
+    {
+        $this->type = $type;
+        $this->code = $code;
+        $this->products = new FacetItemCollection();
+    }
+
+    public function getType(): FacetType
+    {
+        return $this->type;
+    }
+
+    public function getCode(): string
+    {
+        return $this->code;
+    }
+}
diff --git a/src/ElasticSearch/Facet/FacetType.php b/src/ElasticSearch/Facet/FacetType.php
new file mode 100644
index 0000000..9a8f9dd
--- /dev/null
+++ b/src/ElasticSearch/Facet/FacetType.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Facet;
+
+enum FacetType: string
+{
+    case LIST = 'list';
+    case RANGE = 'range';
+}
diff --git a/src/ElasticSearch/Facet/FacetTypeEnum.php b/src/ElasticSearch/Facet/FacetTypeEnum.php
deleted file mode 100644
index e0491c7..0000000
--- a/src/ElasticSearch/Facet/FacetTypeEnum.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Facet;
-
-enum FacetTypeEnum: string
-{
-    case KEYWORD = 'keyword';
-    case NUMBER = 'number';
-}
diff --git a/src/ElasticSearch/Facet/NewFacet.php b/src/ElasticSearch/Facet/NewFacet.php
deleted file mode 100644
index cc08955..0000000
--- a/src/ElasticSearch/Facet/NewFacet.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace IQDEV\ElasticSearch\Facet;
-
-class NewFacet implements Facetable
-{
-    protected FacetTypeEnum $type;
-
-    public function es(): array
-    {
-        return [];
-    }
-}
diff --git a/src/ElasticSearch/Facet/Type/BaseFacet.php b/src/ElasticSearch/Facet/Type/BaseFacet.php
new file mode 100644
index 0000000..690f0ed
--- /dev/null
+++ b/src/ElasticSearch/Facet/Type/BaseFacet.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Facet\Type;
+
+use IQDEV\ElasticSearch\Facet\Facet;
+
+final class BaseFacet extends Facet
+{
+    /**
+     * @inheritDoc
+     */
+    public function es(): array
+    {
+        return [
+            $this->property->getKey() => $this->value,
+        ];
+    }
+}
diff --git a/src/ElasticSearch/Facet/Type/FacetListType.php b/src/ElasticSearch/Facet/Type/FacetListType.php
deleted file mode 100644
index fc393aa..0000000
--- a/src/ElasticSearch/Facet/Type/FacetListType.php
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Facet\Type;
-
-class FacetListType implements FacetType
-{
-}
\ No newline at end of file
diff --git a/src/ElasticSearch/Facet/Type/FacetRangeType.php b/src/ElasticSearch/Facet/Type/FacetRangeType.php
deleted file mode 100644
index 344e2c8..0000000
--- a/src/ElasticSearch/Facet/Type/FacetRangeType.php
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Facet\Type;
-
-class FacetRangeType implements FacetType
-{
-}
diff --git a/src/ElasticSearch/Facet/Type/FacetType.php b/src/ElasticSearch/Facet/Type/FacetType.php
deleted file mode 100644
index 5ec289c..0000000
--- a/src/ElasticSearch/Facet/Type/FacetType.php
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Facet\Type;
-
-interface FacetType
-{
-}
diff --git a/src/ElasticSearch/Facet/Type/KeywordFacet.php b/src/ElasticSearch/Facet/Type/KeywordFacet.php
new file mode 100644
index 0000000..ffc1aac
--- /dev/null
+++ b/src/ElasticSearch/Facet/Type/KeywordFacet.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Facet\Type;
+
+use IQDEV\ElasticSearch\Facet\Facet;
+
+final class KeywordFacet extends Facet
+{
+    /**
+     * @inheritDoc
+     */
+    public function es(): array
+    {
+        return [
+            'facet_code' => $this->property->getKey(),
+            'facet_value' => (string) $this->value,
+        ];
+    }
+}
diff --git a/src/ElasticSearch/Facet/Type/NumberFacet.php b/src/ElasticSearch/Facet/Type/NumberFacet.php
new file mode 100644
index 0000000..43e4c8e
--- /dev/null
+++ b/src/ElasticSearch/Facet/Type/NumberFacet.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Facet\Type;
+
+use IQDEV\ElasticSearch\Facet\Facet;
+
+final class NumberFacet extends Facet
+{
+    /**
+     * @inheritDoc
+     */
+    public function es(): array
+    {
+        return [
+            'facet_code' => $this->property->getKey(),
+            'facet_value' => (float) $this->value,
+        ];
+    }
+}
diff --git a/src/ElasticSearch/Filter/FilterCollection.php b/src/ElasticSearch/Filter/Collection/FilterCollection.php
similarity index 92%
rename from src/ElasticSearch/Filter/FilterCollection.php
rename to src/ElasticSearch/Filter/Collection/FilterCollection.php
index 7bb1d49..69fc460 100644
--- a/src/ElasticSearch/Filter/FilterCollection.php
+++ b/src/ElasticSearch/Filter/Collection/FilterCollection.php
@@ -1,7 +1,8 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Filter;
+namespace IQDEV\ElasticSearch\Filter\Collection;
 
+use IQDEV\ElasticSearch\Filter\LogicOperator;
 use Ramsey\Collection\AbstractCollection;
 
 /**
diff --git a/src/ElasticSearch/Filter/FilterGroupCollection.php b/src/ElasticSearch/Filter/Collection/FilterGroupCollection.php
similarity index 90%
rename from src/ElasticSearch/Filter/FilterGroupCollection.php
rename to src/ElasticSearch/Filter/Collection/FilterGroupCollection.php
index 5bbce1e..9f6c8ad 100644
--- a/src/ElasticSearch/Filter/FilterGroupCollection.php
+++ b/src/ElasticSearch/Filter/Collection/FilterGroupCollection.php
@@ -1,7 +1,10 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Filter;
+namespace IQDEV\ElasticSearch\Filter\Collection;
 
+use IQDEV\ElasticSearch\Filter\Filter;
+use IQDEV\ElasticSearch\Filter\FilterType;
+use IQDEV\ElasticSearch\Filter\LogicOperator;
 use Ramsey\Collection\AbstractCollection;
 
 /**
diff --git a/src/ElasticSearch/Filter/PostFilterCollection.php b/src/ElasticSearch/Filter/Collection/PostFilterCollection.php
similarity index 56%
rename from src/ElasticSearch/Filter/PostFilterCollection.php
rename to src/ElasticSearch/Filter/Collection/PostFilterCollection.php
index 8b677a7..482c5d5 100644
--- a/src/ElasticSearch/Filter/PostFilterCollection.php
+++ b/src/ElasticSearch/Filter/Collection/PostFilterCollection.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Filter;
+namespace IQDEV\ElasticSearch\Filter\Collection;
 
 class PostFilterCollection extends FilterCollection
 {
diff --git a/src/ElasticSearch/Filter/QueryFilterCollection.php b/src/ElasticSearch/Filter/Collection/QueryFilterCollection.php
similarity index 56%
rename from src/ElasticSearch/Filter/QueryFilterCollection.php
rename to src/ElasticSearch/Filter/Collection/QueryFilterCollection.php
index aa700cc..96258d2 100644
--- a/src/ElasticSearch/Filter/QueryFilterCollection.php
+++ b/src/ElasticSearch/Filter/Collection/QueryFilterCollection.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Filter;
+namespace IQDEV\ElasticSearch\Filter\Collection;
 
 class QueryFilterCollection extends FilterCollection
 {
diff --git a/src/ElasticSearch/Filter/FilterKeyword.php b/src/ElasticSearch/Filter/Value/FilterKeyword.php
similarity index 80%
rename from src/ElasticSearch/Filter/FilterKeyword.php
rename to src/ElasticSearch/Filter/Value/FilterKeyword.php
index d3edd61..90c83b5 100644
--- a/src/ElasticSearch/Filter/FilterKeyword.php
+++ b/src/ElasticSearch/Filter/Value/FilterKeyword.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Filter;
+namespace IQDEV\ElasticSearch\Filter\Value;
+
+use IQDEV\ElasticSearch\Filter\FilterValue;
 
 class FilterKeyword implements FilterValue
 {
diff --git a/src/ElasticSearch/Filter/FilterNumber.php b/src/ElasticSearch/Filter/Value/FilterNumber.php
similarity index 77%
rename from src/ElasticSearch/Filter/FilterNumber.php
rename to src/ElasticSearch/Filter/Value/FilterNumber.php
index 7a9dc75..d793ea6 100644
--- a/src/ElasticSearch/Filter/FilterNumber.php
+++ b/src/ElasticSearch/Filter/Value/FilterNumber.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Filter;
+namespace IQDEV\ElasticSearch\Filter\Value;
+
+use IQDEV\ElasticSearch\Filter\FilterValue;
 
 class FilterNumber implements FilterValue
 {
diff --git a/src/ElasticSearch/Indexer/BaseIndexProvider.php b/src/ElasticSearch/Indexer/BaseIndexProvider.php
index 83df733..dcce508 100644
--- a/src/ElasticSearch/Indexer/BaseIndexProvider.php
+++ b/src/ElasticSearch/Indexer/BaseIndexProvider.php
@@ -4,8 +4,9 @@ namespace IQDEV\ElasticSearch\Indexer;
 
 use IQDEV\ElasticSearch\Configuration;
 use IQDEV\ElasticSearch\Document\ProductDocument;
-use IQDEV\ElasticSearch\Facet\FacetCategory;
-use IQDEV\ElasticSearch\Facet\FacetKeyword;
+use IQDEV\ElasticSearch\Document\Property\Property;
+use IQDEV\ElasticSearch\Document\Property\PropertyType;
+use IQDEV\ElasticSearch\Facet\FacetFactory;
 
 class BaseIndexProvider implements IndexProvider
 {
@@ -23,14 +24,21 @@ class BaseIndexProvider implements IndexProvider
     public function get(): \Generator
     {
         foreach ($this->products as $product) {
-            $document = new ProductDocument(new FacetCategory($product['category']));
+            $document = new ProductDocument(
+                FacetFactory::createFromProperty(new Property('category_id', PropertyType::BASE), $product['category'])
+            );
+
             $document->setAdditionData($product['data'] ?? []);
             foreach ($product['properties'] as $type => $values) {
-                foreach ($values as $key => $prop) {
+                foreach ($values as $key => $value) {
                     if ($type === 'number') {
-                        $document->getNumberFacets()->add(new FacetKeyword($key, $prop));
+                        $document->getNumberFacets()->add(
+                            FacetFactory::createFromProperty(new Property($key, PropertyType::NUMBER), $value)
+                        );
                     } else {
-                        $document->getKeywordFacets()->add(new FacetKeyword($key, $prop));
+                        $document->getKeywordFacets()->add(
+                            FacetFactory::createFromProperty(new Property($key, PropertyType::KEYWORD), $value)
+                        );
                     }
                 }
             }
diff --git a/src/ElasticSearch/Order/Order.php b/src/ElasticSearch/Order/Order.php
index 82d4ac8..0560011 100644
--- a/src/ElasticSearch/Order/Order.php
+++ b/src/ElasticSearch/Order/Order.php
@@ -2,39 +2,30 @@
 
 namespace IQDEV\ElasticSearch\Order;
 
+use IQDEV\ElasticSearch\Document\Property\Property;
 use IQDEV\ElasticSearch\Esable;
-use IQDEV\ElasticSearch\Document\Property\Type;
 
-class Order implements Esable
+abstract class Order implements Esable
 {
-    public Type $by;
-    public OrderType $direction;
-    public array $properties;
-
-    public function __construct(Type $by, OrderType $direction, array $properties = [])
-    {
-        $this->by = $by;
-        $this->direction = $direction;
-        $this->properties = $properties;
-    }
-
-    public function es(): array
-    {
-        return array_merge([$this->by->key() => $this->direction::getType()], $this->properties);
+    public function __construct(
+        protected Property $property,
+        protected OrderDirection $direction,
+        protected array $additionalParams = [],
+    ) {
     }
 
-    public function orderBy(): Type
+    public function getProperty(): Property
     {
-        return $this->by;
+        return $this->property;
     }
 
-    public function orderType(): OrderType
+    public function getDirection(): OrderDirection
     {
         return $this->direction;
     }
 
-    public function orderProperties(): array
+    public function getAdditionalParams(): array
     {
-        return $this->properties;
+        return $this->additionalParams;
     }
 }
diff --git a/src/ElasticSearch/Order/OrderAscType.php b/src/ElasticSearch/Order/OrderAscType.php
deleted file mode 100644
index 69b8f08..0000000
--- a/src/ElasticSearch/Order/OrderAscType.php
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Order;
-
-class OrderAscType extends OrderType
-{
-    protected static string $code = 'asc';
-}
diff --git a/src/ElasticSearch/Order/OrderDescType.php b/src/ElasticSearch/Order/OrderDescType.php
deleted file mode 100644
index 775fa3c..0000000
--- a/src/ElasticSearch/Order/OrderDescType.php
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Order;
-
-class OrderDescType extends OrderType
-{
-    protected static string $code = 'desc';
-}
diff --git a/src/ElasticSearch/Order/OrderDirection.php b/src/ElasticSearch/Order/OrderDirection.php
new file mode 100644
index 0000000..a5f4b75
--- /dev/null
+++ b/src/ElasticSearch/Order/OrderDirection.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Order;
+
+enum OrderDirection: string
+{
+    case ASC = 'asc';
+    case DESC = 'desc';
+}
diff --git a/src/ElasticSearch/Order/OrderFactory.php b/src/ElasticSearch/Order/OrderFactory.php
new file mode 100644
index 0000000..5764491
--- /dev/null
+++ b/src/ElasticSearch/Order/OrderFactory.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Order;
+
+use IQDEV\ElasticSearch\Document\Property\Property;
+use IQDEV\ElasticSearch\Document\Property\PropertyType;
+use IQDEV\ElasticSearch\Order\Type\BaseOrder;
+use IQDEV\ElasticSearch\Order\Type\KeywordPropertyOrder;
+use IQDEV\ElasticSearch\Order\Type\NumberPropertyOrder;
+
+class OrderFactory
+{
+    public static function createByProperty(
+        Property $property,
+        OrderDirection $direction,
+    ): Order {
+        match ($property->getType()) {
+            PropertyType::KEYWORD => $order = new KeywordPropertyOrder($property, $direction),
+            PropertyType::NUMBER => $order = new NumberPropertyOrder($property, $direction),
+            default => $order = new BaseOrder($property, $direction),
+        };
+
+        return $order;
+    }
+}
diff --git a/src/ElasticSearch/Order/OrderField.php b/src/ElasticSearch/Order/OrderField.php
deleted file mode 100644
index ba56650..0000000
--- a/src/ElasticSearch/Order/OrderField.php
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Order;
-
-class OrderField extends Order
-{
-}
diff --git a/src/ElasticSearch/Order/OrderType.php b/src/ElasticSearch/Order/OrderType.php
deleted file mode 100644
index 979e079..0000000
--- a/src/ElasticSearch/Order/OrderType.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-namespace IQDEV\ElasticSearch\Order;
-
-abstract class OrderType
-{
-    protected static string $code;
-
-    public static function getType(): string
-    {
-        return static::$code;
-    }
-}
diff --git a/src/ElasticSearch/Order/Type/BaseOrder.php b/src/ElasticSearch/Order/Type/BaseOrder.php
new file mode 100644
index 0000000..3af2417
--- /dev/null
+++ b/src/ElasticSearch/Order/Type/BaseOrder.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace IQDEV\ElasticSearch\Order\Type;
+
+use IQDEV\ElasticSearch\Order\Order;
+
+class BaseOrder extends Order
+{
+    public function es(): array
+    {
+        return array_merge(
+            [$this->property->getKey() => $this->direction->value],
+            $this->additionalParams
+        );
+    }
+}
diff --git a/src/ElasticSearch/Order/OrderKeywordProperty.php b/src/ElasticSearch/Order/Type/KeywordPropertyOrder.php
similarity index 54%
rename from src/ElasticSearch/Order/OrderKeywordProperty.php
rename to src/ElasticSearch/Order/Type/KeywordPropertyOrder.php
index f0ae3e1..eee8fe5 100644
--- a/src/ElasticSearch/Order/OrderKeywordProperty.php
+++ b/src/ElasticSearch/Order/Type/KeywordPropertyOrder.php
@@ -1,29 +1,34 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Order;
+namespace IQDEV\ElasticSearch\Order\Type;
 
-class OrderKeywordProperty extends Order
+use IQDEV\ElasticSearch\Order\Order;
+
+class KeywordPropertyOrder extends Order
 {
     public function es(): array
     {
         $order = [
-            'order' => $this->direction::getType(),
+            'order' => $this->direction->value,
             'nested' => [
                 'path' => 'search_data',
                 'filter' => [
                     'bool' => [
                         'must' => [
                             'term' => [
-                                'search_data.keyword_facet.facet_code' => $this->by->key(),
-                            ]
+                                'search_data.keyword_facet.facet_code' => $this->property->getKey(),
+                            ],
                         ],
                     ],
                 ],
             ],
         ];
-        $order = array_merge($order, $this->properties);
+
         return [
-            'search_data.keyword_facet.facet_value' => $order,
+            'search_data.keyword_facet.facet_value' => array_merge(
+                $order,
+                $this->additionalParams
+            ),
         ];
     }
 }
diff --git a/src/ElasticSearch/Order/OrderNumberProperty.php b/src/ElasticSearch/Order/Type/NumberPropertyOrder.php
similarity index 55%
rename from src/ElasticSearch/Order/OrderNumberProperty.php
rename to src/ElasticSearch/Order/Type/NumberPropertyOrder.php
index b6a1401..6a918a4 100644
--- a/src/ElasticSearch/Order/OrderNumberProperty.php
+++ b/src/ElasticSearch/Order/Type/NumberPropertyOrder.php
@@ -1,29 +1,34 @@
 <?php
 
-namespace IQDEV\ElasticSearch\Order;
+namespace IQDEV\ElasticSearch\Order\Type;
 
-class OrderNumberProperty extends Order
+use IQDEV\ElasticSearch\Order\Order;
+
+class NumberPropertyOrder extends Order
 {
     public function es(): array
     {
         $order = [
-            'order' => $this->direction::getType(),
+            'order' => $this->direction->value,
             'nested' => [
                 'path' => 'search_data',
                 'filter' => [
                     'bool' => [
                         'must' => [
                             'term' => [
-                                'search_data.number_facet.facet_code' => $this->by->key(),
-                            ]
+                                'search_data.number_facet.facet_code' => $this->property->getKey(),
+                            ],
                         ],
                     ],
                 ],
             ],
         ];
-        $order = array_merge($order, $this->properties);
+
         return [
-            'search_data.number_facet.facet_value' => $order,
+            'search_data.number_facet.facet_value' => array_merge(
+                $order,
+                $this->additionalParams
+            ),
         ];
     }
 }
diff --git a/src/ElasticSearch/Result.php b/src/ElasticSearch/Result.php
index 54bc776..09885ef 100644
--- a/src/ElasticSearch/Result.php
+++ b/src/ElasticSearch/Result.php
@@ -3,18 +3,18 @@
 namespace IQDEV\ElasticSearch;
 
 use IQDEV\ElasticSearch\Document\ProductCollection;
-use IQDEV\ElasticSearch\Facet\FacetCollection;
+use IQDEV\ElasticSearch\Facet\Collection\FacetResultCollection;
 
 class Result
 {
     private ProductCollection $products;
-    private FacetCollection $facets;
+    private FacetResultCollection $facets;
     private int $total = 0;
 
     public function __construct()
     {
         $this->products = new ProductCollection();
-        $this->facets = new FacetCollection();
+        $this->facets = new FacetResultCollection();
     }
 
     public function setTotal(int $total): void
@@ -32,7 +32,7 @@ class Result
         return $this->products;
     }
 
-    public function getFacets(): FacetCollection
+    public function getFacets(): FacetResultCollection
     {
         return $this->facets;
     }
diff --git a/tests/Filter/AggsTest.php b/tests/Filter/AggsTest.php
index 163be9a..b4b5275 100644
--- a/tests/Filter/AggsTest.php
+++ b/tests/Filter/AggsTest.php
@@ -2,19 +2,19 @@
 
 namespace IQDEV\ElasticSearchTests\Filter;
 
-use IQDEV\ElasticSearchTests\AbstractTestCase;
-use IQDEV\ElasticSearchTests\Helpers\FormatData;
-use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
 use IQDEV\ElasticSearch\Filter\Field;
 use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterKeyword;
-use IQDEV\ElasticSearch\Filter\FilterNumber;
 use IQDEV\ElasticSearch\Filter\FilterOperator;
 use IQDEV\ElasticSearch\Filter\FilterType;
 use IQDEV\ElasticSearch\Filter\LogicOperator;
+use IQDEV\ElasticSearch\Filter\Value\FilterKeyword;
+use IQDEV\ElasticSearch\Filter\Value\FilterNumber;
 use IQDEV\ElasticSearch\Query\SearchQuery;
+use IQDEV\ElasticSearchTests\AbstractTestCase;
+use IQDEV\ElasticSearchTests\Helpers\FormatData;
+use IQDEV\ElasticSearchTests\Service\SearchClient;
 
 /**
  * Тестирование агрегирующих функций
diff --git a/tests/Filter/CommonRangeKeywordsTest.php b/tests/Filter/CommonRangeKeywordsTest.php
index 4bcc8fd..3495804 100644
--- a/tests/Filter/CommonRangeKeywordsTest.php
+++ b/tests/Filter/CommonRangeKeywordsTest.php
@@ -2,17 +2,17 @@
 
 namespace IQDEV\ElasticSearchTests\Filter;
 
-use IQDEV\ElasticSearchTests\AbstractTestCase;
-use IQDEV\ElasticSearchTests\Helpers\FormatData;
-use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
 use IQDEV\ElasticSearch\Filter\Field;
 use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterKeyword;
-use IQDEV\ElasticSearch\Filter\FilterNumber;
 use IQDEV\ElasticSearch\Filter\FilterOperator;
+use IQDEV\ElasticSearch\Filter\Value\FilterKeyword;
+use IQDEV\ElasticSearch\Filter\Value\FilterNumber;
 use IQDEV\ElasticSearch\Query\SearchQuery;
+use IQDEV\ElasticSearchTests\AbstractTestCase;
+use IQDEV\ElasticSearchTests\Helpers\FormatData;
+use IQDEV\ElasticSearchTests\Service\SearchClient;
 
 class CommonRangeKeywordsTest extends AbstractTestCase
 {
diff --git a/tests/Filter/KeywordsTest.php b/tests/Filter/KeywordsTest.php
index df62a19..c56a3c8 100644
--- a/tests/Filter/KeywordsTest.php
+++ b/tests/Filter/KeywordsTest.php
@@ -2,17 +2,17 @@
 
 namespace IQDEV\ElasticSearchTests\Filter;
 
-use IQDEV\ElasticSearchTests\AbstractTestCase;
-use IQDEV\ElasticSearchTests\Helpers\FormatData;
-use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
 use IQDEV\ElasticSearch\Filter\Field;
 use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterKeyword;
 use IQDEV\ElasticSearch\Filter\FilterOperator;
 use IQDEV\ElasticSearch\Filter\FilterType;
+use IQDEV\ElasticSearch\Filter\Value\FilterKeyword;
 use IQDEV\ElasticSearch\Query\SearchQuery;
+use IQDEV\ElasticSearchTests\AbstractTestCase;
+use IQDEV\ElasticSearchTests\Helpers\FormatData;
+use IQDEV\ElasticSearchTests\Service\SearchClient;
 
 class KeywordsTest extends AbstractTestCase
 {
diff --git a/tests/Filter/QueryAndPostFilterTest.php b/tests/Filter/QueryAndPostFilterTest.php
index 9ea7ecc..b7f24c9 100644
--- a/tests/Filter/QueryAndPostFilterTest.php
+++ b/tests/Filter/QueryAndPostFilterTest.php
@@ -2,19 +2,19 @@
 
 namespace IQDEV\ElasticSearchTests\Filter;
 
-use IQDEV\ElasticSearchTests\AbstractTestCase;
-use IQDEV\ElasticSearchTests\Helpers\FormatData;
-use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
 use IQDEV\ElasticSearch\Filter\Field;
 use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterKeyword;
-use IQDEV\ElasticSearch\Filter\FilterNumber;
 use IQDEV\ElasticSearch\Filter\FilterOperator;
 use IQDEV\ElasticSearch\Filter\FilterType;
 use IQDEV\ElasticSearch\Filter\LogicOperator;
+use IQDEV\ElasticSearch\Filter\Value\FilterKeyword;
+use IQDEV\ElasticSearch\Filter\Value\FilterNumber;
 use IQDEV\ElasticSearch\Query\SearchQuery;
+use IQDEV\ElasticSearchTests\AbstractTestCase;
+use IQDEV\ElasticSearchTests\Helpers\FormatData;
+use IQDEV\ElasticSearchTests\Service\SearchClient;
 
 class QueryAndPostFilterTest extends AbstractTestCase
 {
diff --git a/tests/Filter/QueryTest.php b/tests/Filter/QueryTest.php
index 2db833a..6a017db 100644
--- a/tests/Filter/QueryTest.php
+++ b/tests/Filter/QueryTest.php
@@ -3,18 +3,18 @@
 namespace IQDEV\ElasticSearchTests\Filter;
 
 use IQDEV\ElasticSearch\Converter\CriteriaToEsRequest;
-use IQDEV\ElasticSearchTests\AbstractTestCase;
-use IQDEV\ElasticSearchTests\Helpers\FormatData;
-use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
 use IQDEV\ElasticSearch\Filter\Field;
 use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterKeyword;
-use IQDEV\ElasticSearch\Filter\FilterNumber;
 use IQDEV\ElasticSearch\Filter\FilterOperator;
 use IQDEV\ElasticSearch\Filter\FilterType;
+use IQDEV\ElasticSearch\Filter\Value\FilterKeyword;
+use IQDEV\ElasticSearch\Filter\Value\FilterNumber;
 use IQDEV\ElasticSearch\Query\SearchQuery;
+use IQDEV\ElasticSearchTests\AbstractTestCase;
+use IQDEV\ElasticSearchTests\Helpers\FormatData;
+use IQDEV\ElasticSearchTests\Service\SearchClient;
 
 /**
  * Тестирование агрегирующих функций
diff --git a/tests/Filter/RangeTest.php b/tests/Filter/RangeTest.php
index 9c9b032..3f0a3e3 100644
--- a/tests/Filter/RangeTest.php
+++ b/tests/Filter/RangeTest.php
@@ -2,16 +2,16 @@
 
 namespace IQDEV\ElasticSearchTests\Filter;
 
-use IQDEV\ElasticSearchTests\AbstractTestCase;
-use IQDEV\ElasticSearchTests\Helpers\FormatData;
-use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
 use IQDEV\ElasticSearch\Filter\Field;
 use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterNumber;
 use IQDEV\ElasticSearch\Filter\FilterOperator;
+use IQDEV\ElasticSearch\Filter\Value\FilterNumber;
 use IQDEV\ElasticSearch\Query\SearchQuery;
+use IQDEV\ElasticSearchTests\AbstractTestCase;
+use IQDEV\ElasticSearchTests\Helpers\FormatData;
+use IQDEV\ElasticSearchTests\Service\SearchClient;
 
 class RangeTest extends AbstractTestCase
 {
diff --git a/tests/Filter/SearchItemsTest.php b/tests/Filter/SearchItemsTest.php
index 5327213..c1119af 100644
--- a/tests/Filter/SearchItemsTest.php
+++ b/tests/Filter/SearchItemsTest.php
@@ -2,17 +2,17 @@
 
 namespace IQDEV\ElasticSearchTests\Filter;
 
-use IQDEV\ElasticSearchTests\AbstractTestCase;
-use IQDEV\ElasticSearchTests\Helpers\FormatData;
-use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
+use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection;
 use IQDEV\ElasticSearch\Filter\Field;
 use IQDEV\ElasticSearch\Filter\Filter;
-use IQDEV\ElasticSearch\Filter\FilterGroupCollection;
-use IQDEV\ElasticSearch\Filter\FilterKeyword;
 use IQDEV\ElasticSearch\Filter\FilterOperator;
 use IQDEV\ElasticSearch\Filter\FilterType;
+use IQDEV\ElasticSearch\Filter\Value\FilterKeyword;
 use IQDEV\ElasticSearch\Query\SearchQuery;
+use IQDEV\ElasticSearchTests\AbstractTestCase;
+use IQDEV\ElasticSearchTests\Helpers\FormatData;
+use IQDEV\ElasticSearchTests\Service\SearchClient;
 
 class SearchItemsTest extends AbstractTestCase
 {
diff --git a/tests/Filter/SortTest.php b/tests/Filter/SortTest.php
index 9d4b445..3ba6b7f 100644
--- a/tests/Filter/SortTest.php
+++ b/tests/Filter/SortTest.php
@@ -2,17 +2,14 @@
 
 namespace IQDEV\ElasticSearchTests\Filter;
 
-use IQDEV\ElasticSearch\Order\OrderAscType;
-use IQDEV\ElasticSearch\Order\OrderDescType;
-use IQDEV\ElasticSearch\Order\OrderKeywordProperty;
-use IQDEV\ElasticSearch\Order\OrderNumberProperty;
+use IQDEV\ElasticSearch\Document\Property\Property;
+use IQDEV\ElasticSearch\Order\OrderDirection;
+use IQDEV\ElasticSearch\Order\OrderFactory;
 use IQDEV\ElasticSearchTests\AbstractTestCase;
 use IQDEV\ElasticSearchTests\Helpers\FormatData;
 use IQDEV\ElasticSearchTests\Service\SearchClient;
 use IQDEV\ElasticSearch\Criteria;
-use IQDEV\ElasticSearch\Document\Property\AttrType;
 use IQDEV\ElasticSearch\Document\Property\PropertyType;
-use IQDEV\ElasticSearch\Order\Order;
 use IQDEV\ElasticSearch\Query\SearchQuery;
 
 class SortTest extends AbstractTestCase
@@ -26,10 +23,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new Order(
-            new AttrType('category_id'),
-            new OrderAscType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('category_id'), OrderDirection::ASC)
+        );
 
         $q = new SearchQuery($criteria);
 
@@ -62,10 +58,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new Order(
-            new AttrType('category_id'),
-            new OrderDescType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('category_id'), OrderDirection::DESC)
+        );
 
         $q = new SearchQuery($criteria);
 
@@ -98,10 +93,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new OrderKeywordProperty(
-            new PropertyType('color', PropertyType::TYPE_KEYWORD),
-            new OrderAscType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('color', PropertyType::KEYWORD), OrderDirection::ASC)
+        );
 
         $q = new SearchQuery($criteria);
 
@@ -134,10 +128,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new OrderKeywordProperty(
-            new PropertyType('color', PropertyType::TYPE_KEYWORD),
-            new OrderDescType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('color', PropertyType::KEYWORD), OrderDirection::DESC)
+        );
 
         $q = new SearchQuery($criteria);
 
@@ -170,10 +163,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new OrderNumberProperty(
-            new PropertyType('price', PropertyType::TYPE_NUMBER),
-            new OrderAscType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('price', PropertyType::NUMBER), OrderDirection::ASC)
+        );
 
         $q = new SearchQuery($criteria);
 
@@ -206,10 +198,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new OrderNumberProperty(
-            new PropertyType('price', PropertyType::TYPE_NUMBER),
-            new OrderDescType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('price', PropertyType::NUMBER), OrderDirection::DESC)
+        );
 
         $q = new SearchQuery($criteria);
 
@@ -242,10 +233,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new Order(
-            new PropertyType('size', PropertyType::TYPE_KEYWORD),
-            new OrderAscType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('size', PropertyType::KEYWORD), OrderDirection::ASC)
+        );
 
         $q = new SearchQuery($criteria);
 
@@ -278,10 +268,9 @@ class SortTest extends AbstractTestCase
     {
         $criteria = new Criteria();
 
-        $criteria->sorting()->add(new Order(
-            new PropertyType('size', PropertyType::TYPE_KEYWORD),
-            new OrderDescType(),
-        ));
+        $criteria->sorting()->add(
+            OrderFactory::createByProperty(new Property('size', PropertyType::KEYWORD), OrderDirection::DESC)
+        );
 
         $q = new SearchQuery($criteria);
 
diff --git a/tests/Helpers/FormatData.php b/tests/Helpers/FormatData.php
index 7914eed..233bcce 100644
--- a/tests/Helpers/FormatData.php
+++ b/tests/Helpers/FormatData.php
@@ -3,11 +3,9 @@
 namespace IQDEV\ElasticSearchTests\Helpers;
 
 use IQDEV\ElasticSearch\Document\Product;
-use IQDEV\ElasticSearch\Facet\Facet;
+use IQDEV\ElasticSearch\Facet\FacetResult;
 use IQDEV\ElasticSearch\Facet\Item\FacetItemList;
 use IQDEV\ElasticSearch\Facet\Item\FacetItemRange;
-use IQDEV\ElasticSearch\Facet\Type\FacetListType;
-use IQDEV\ElasticSearch\Facet\Type\FacetRangeType;
 use IQDEV\ElasticSearch\Result;
 
 class FormatData
@@ -28,11 +26,11 @@ class FormatData
         $aResult         = ['facets' => []];
         $aResult['hits'] = static::formatData($result)['hits'];
         foreach ($result->getFacets() as $facet) {
-            /** @var Facet $facet */
+            /** @var FacetResult $facet */
             $dataFacet = [
                 'code' => $facet->getCode(),
                 'label' => null, // $facet->getLabel(),
-                'type' => $facet->getType() instanceof FacetRangeType ? 'range' : ($facet->getType() instanceof FacetListType ? 'list' : null),
+                'type' => $facet->getType()->value,
                 'items' => [
                     'list' => [],
                     'range' => []
diff --git a/tests/Helpers/TestIndexProvider.php b/tests/Helpers/TestIndexProvider.php
index 89761f0..070d24c 100644
--- a/tests/Helpers/TestIndexProvider.php
+++ b/tests/Helpers/TestIndexProvider.php
@@ -4,9 +4,9 @@ namespace IQDEV\ElasticSearchTests\Helpers;
 
 use IQDEV\ElasticSearch\Configuration;
 use IQDEV\ElasticSearch\Document\ProductDocument;
-use IQDEV\ElasticSearch\Facet\FacetCategory;
-use IQDEV\ElasticSearch\Facet\FacetKeyword;
-use IQDEV\ElasticSearch\Facet\FacetNumber;
+use IQDEV\ElasticSearch\Document\Property\Property;
+use IQDEV\ElasticSearch\Document\Property\PropertyType;
+use IQDEV\ElasticSearch\Facet\FacetFactory;
 use IQDEV\ElasticSearch\Indexer\AddIndex;
 use IQDEV\ElasticSearch\Indexer\DeleteIndex;
 use IQDEV\ElasticSearch\Indexer\IndexProvider;
@@ -30,7 +30,9 @@ class TestIndexProvider implements IndexProvider
     public function get(): \Generator
     {
         foreach ($this->products as $product) {
-            $document = new ProductDocument(new FacetCategory($product['category']));
+            $document = new ProductDocument(
+                FacetFactory::createFromProperty(new Property('category_id', PropertyType::BASE), $product['category'])
+            );
             //todo по-хорошему нужны базовые классы, которые будут описывать свойства
             // и формировать структуру для последующей обработки
 
@@ -46,11 +48,15 @@ class TestIndexProvider implements IndexProvider
             $document->setAdditionData($data);
 
             if (isset($product['properties'])) {
-                foreach ($product['properties'] as $key => $prop) {
+                foreach ($product['properties'] as $key => $value) {
                     if ($key === 'price') {
-                        $document->getNumberFacets()->add(new FacetNumber($key, $prop));
+                        $document->getNumberFacets()->add(
+                            FacetFactory::createFromProperty(new Property($key, PropertyType::NUMBER), $value)
+                        );
                     } else {
-                        $document->getKeywordFacets()->add(new FacetKeyword($key, $prop));
+                        $document->getKeywordFacets()->add(
+                            FacetFactory::createFromProperty(new Property($key, PropertyType::KEYWORD), $value)
+                        );
                     }
                 }
             }
-- 
GitLab