Skip to content

Commit

Permalink
Implement support for Matej Query Language in recommendation requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
foglcz committed Aug 31, 2018
1 parent 41a1327 commit ebdbbbe
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
## Unreleased
### Changed
- **BC BREAK** | `UserRecommendation` now returns new format of response in `->getData()`, which is a list of `stdClass` instances.
- **BC BREAK** | `UserRecommendation` does not have default filter (was previously set to: `valid_to >= NOW`).
- **BC BREAK** | `UserRecommendation` now uses MQL query language by default for filtering.

### Fixed
- Exceptions occurring during async request now generate rejected promise (as they should) and are no longer thrown directly.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ You can also set more granular options of the recommendation command:

```php
$recommendation = UserRecommendation::create('user-id', 5, 'test-scenario', 1.0, 3600);
$recommendation->setFilters(['valid_to >= NOW']) // Note this filter is present by default
$recommendation->setFilters(['for_recommendation = 1'])
->setMinimalRelevance(UserRecommendation::MINIMAL_RELEVANCE_HIGH)
->enableHardRotation();

Expand Down
22 changes: 21 additions & 1 deletion src/Model/Command/UserRecommendation.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class UserRecommendation extends AbstractCommand implements UserAwareInterface
public const MINIMAL_RELEVANCE_LOW = 'low';
public const MINIMAL_RELEVANCE_MEDIUM = 'medium';
public const MINIMAL_RELEVANCE_HIGH = 'high';
public const FILTER_TYPE_MQL = 'mql';

/** @var string */
protected $filterOperator = 'and';
Expand All @@ -30,7 +31,9 @@ class UserRecommendation extends AbstractCommand implements UserAwareInterface
/** @var string */
private $minimalRelevance = self::MINIMAL_RELEVANCE_LOW;
/** @var string[] */
private $filters = ['valid_to >= NOW'];
private $filters = [];
/** @var string */
private $filterType = self::FILTER_TYPE_MQL;
/** @var string|null */
private $modelName = null;
/** @var string[] */
Expand Down Expand Up @@ -134,6 +137,22 @@ public function setFilters(array $filters): self
return $this;
}

/**
* Specify the filter type being used.
*/
public function setFilterType(string $filterType): self
{
Assertion::typeIdentifier($filterType);
Assertion::choice(
$filterType,
[static::FILTER_TYPE_MQL]
);

$this->filterType = $filterType;

return $this;
}

/**
* Add another response property you want returned. item_id is always returned by Matej.
*/
Expand Down Expand Up @@ -236,6 +255,7 @@ protected function getCommandParameters(): array
'hard_rotation' => $this->hardRotation,
'min_relevance' => $this->minimalRelevance,
'filter' => $this->assembleFiltersString(),
'filter_type' => $this->filterType,
'properties' => $this->responseProperties,
];

Expand Down
29 changes: 20 additions & 9 deletions tests/unit/Model/Command/UserRecommendationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ public function shouldBeInstantiableViaNamedConstructorWithDefaultValues(): void
'rotation_time' => 3600,
'hard_rotation' => false,
'min_relevance' => UserRecommendation::MINIMAL_RELEVANCE_LOW,
'filter' => 'valid_to >= NOW',
'filter' => '',
'filter_type' => UserRecommendation::FILTER_TYPE_MQL,
'properties' => [],
// intentionally no model name ==> should be absent when not used
// when using default model name, parameter "model_name" should be absent.
],
],
$command->jsonSerialize()
Expand Down Expand Up @@ -63,6 +64,7 @@ public function shouldUseCustomParameters(): void
'hard_rotation' => true,
'min_relevance' => UserRecommendation::MINIMAL_RELEVANCE_HIGH,
'filter' => 'foo = bar and baz = ban',
'filter_type' => UserRecommendation::FILTER_TYPE_MQL,
'properties' => [],
'model_name' => $modelName,
],
Expand All @@ -72,26 +74,35 @@ public function shouldUseCustomParameters(): void
}

/** @test */
public function shouldAssembleFilters(): void
public function shouldAssembleMqlFilters(): void
{
$command = UserRecommendation::create('user-id', 333, 'test-scenario', 1.0, 3600);

// Default filter
$this->assertSame('valid_to >= NOW', $command->jsonSerialize()['parameters']['filter']);
$this->assertSame('', $command->jsonSerialize()['parameters']['filter']);

// Add custom filters to the default one
$command->addFilter('foo = bar')
->addFilter('bar = baz');
$command->addFilter("first_string_property = 'bar'")
->addFilter("second_string_property LIKE 'bar%'")
->addFilter("third_string_property NOT LIKE '%bar'")
->addFilter('bool_property = true')
->addFilter('nullable_property IS NULL')
->addFilter("'some_value' in set_property");

$this->assertSame(
'valid_to >= NOW and foo = bar and bar = baz',
"first_string_property = 'bar' and " .
"second_string_property LIKE 'bar%' and " .
"third_string_property NOT LIKE '%bar' and " .
'bool_property = true and ' .
'nullable_property IS NULL and ' .
"'some_value' in set_property",
$command->jsonSerialize()['parameters']['filter']
);

// Overwrite all filters
$command->setFilters(['my_filter = 1', 'other_filter = foo']);
$command->setFilters(['my_filter = 1', 'other_filter IS NULL']);

$this->assertSame('my_filter = 1 and other_filter = foo', $command->jsonSerialize()['parameters']['filter']);
$this->assertSame('my_filter = 1 and other_filter IS NULL', $command->jsonSerialize()['parameters']['filter']);
}

/** @test */
Expand Down

0 comments on commit ebdbbbe

Please sign in to comment.