diff --git a/README.md b/README.md index 0dcf831..39c2bb5 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,8 @@ $qb->bind('your data', 'your-bind-id') - [Subqueries](docs/core-concepts/subqueries.md): how to create subqueries, joins etc. - Core Concepts - [Terminology](docs/core-concepts/terminology.md): definitions of terms used in the documentation - - [Data binding](docs/core-concepts/data-binding.md): How to inject external data and collections + - [Data binding](docs/core-concepts/data-binding.md): How to inject external data and collections + - [Predicates](docs/core-concepts/predicates.md): How to use predicates in filter clauses and functions - [Subqueries](docs/core-concepts/subqueries.md): Subquery creation ## References & resources diff --git a/docs/api/functions.md b/docs/api/functions.md index 6f7f140..3108bd6 100644 --- a/docs/api/functions.md +++ b/docs/api/functions.md @@ -20,8 +20,16 @@ $qb->for('i', '1..100') ## ArangoSearch functions | Description | AQL Function | | :-------------------- | :-------------------------------------------------------------------------------------------- | -| analyzer(string|array $leftOperand, $comparisonOperand, $rightOperand, $analyzer) | [ANALYZER(expr, analyzer)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#analyzer) | -| boost(string|array $leftOperand, $comparisonOperand, $rightOperand, $analyzer) | [BOOST(expr, boost)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#boost) | +| analyzer($leftOperand, $comparisonOperand, $rightOperand, $analyzer) | [ANALYZER(expr, analyzer)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#analyzer) | +| bm25($doc, $k = null,$b = null) | [BM25(doc, k, b)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#bm25) | +| boost($leftOperand, $comparisonOperand, $rightOperand, $analyzer) | [BOOST(expr, boost)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#boost) | +| exists($path,$type = null) | [EXISTS(path)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#exists) | +| inRange($path, $low, $high, $includeLow, $includeHigh) | [IN_RANGE(path, low, high, includeLow, includeHigh)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#in_range) | +| levenshteinMatch($path, $target, $distance, $transpositions, $maxTerms, $prefix) | [LEVENSHTEIN_MATCH(path, target, distance, transpositions, maxTerms, prefix)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#levenshtein_match) | +| like($path, $search)| [LIKE(path, search)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#like) | +| nGramMatch($path, $target, $threshold, $analyzer) | [NGRAM_MATCH(path, target, threshold, analyzer)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#ngram_match) | +| phrase(path, $phrasePart1, $skipTokens1, ... $phrasePartN, $skipTokensN ], $analyzer) | [PHRASE(path, [ phrasePart1, skipTokens1, ... phrasePartN, skipTokensN ], analyzer)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#phrase) | +| tfidf($doc, $normalize) | [TFIDF(doc, normalize)](https://www.arangodb.com/docs/stable/aql/functions-arangosearch.html#tfidf) | ## Array functions diff --git a/docs/core-concepts/predicates.md b/docs/core-concepts/predicates.md new file mode 100644 index 0000000..8b062b5 --- /dev/null +++ b/docs/core-concepts/predicates.md @@ -0,0 +1,101 @@ +# Using predicates +Predicates are conditional expressions that return a boolean on evaluation. +Commonly written as `$leftOperand $comparisonOperator $rightOperand` for example: `true !== false` + +Predicates are used by the following clauses: filter, prune and search; +as well as functions such as: analyzer and boost. + +## Singular predicates +You can use the following syntax' to build predicates: + +### Basic: +`$leftOperand, $comparisonOperator, $rightOperand` + +**Example: find active users** +```php +$qb->for('u', 'users')->filter('u.active', '==', true)->return('u'); +``` +resolves to : +```aql +FOR u IN users FILTER u.active == true RETURN u +``` + +### without the rightOperand +When you exclude the rightOperand a null value will be assumed. +`$leftOperand, $comparisonOperator` resolves to `$leftOperand $comparisonOperator null` + +**Example: find users that don't have their age set.** +```php +$qb->for('u', 'users')->filter('u.age', '==')->return('u'); +``` +resolves to : +```aql +FOR u IN users FILTER u.active == null RETURN u +``` + +### leftOperand only +When just supplying the leftOperand the operator and rightOperand will be left blank. +This useful to resolve the result of a function or subquery. + +Note that other values such as arrays or scalars always resolve to tru +**Example: find users that have their age set.** +```php +$qb->for('u', 'users')->filter('u.age')->return('u'); +``` +resolves to : +```aql +FOR u IN users FILTER u.active RETURN u +``` + +## Predicate groups +You can combine multiple predicates by grouping them in arrays. +**Example: get users whose age is between 17 and 68.** +```php +$qb->for('u', 'users') + ->filter([ + ['u.age', '>=', 18], + ['u.age', '<=', 67] + ]) + ->return('u'); +``` +resolves to : +```aql +FOR u IN users FILTER u.age >= 18 AND u.age <= 67 RETURN u +``` +**Note:** predicate group detect is quite simplistic. A leftOperand that is an array +is assumed to be a predicate instead. If you need to use an array in the leftOperand positon use a PredicateExpression +```php +use LaravelFreelancerNL\FluentAQL\Expressions\PredicateExpression; + +// ... + +$qb->FILTER([ + new PredicateExpression([1, 3, 4], 'ANY IN', [ 4, 5, 6 ]), + [false, '!==', true] + ]); +``` +resolves to : +```aql +FILTER [1, 3, 4] ANY IN [ 4, 5, 6 ] AND false !== true +``` + +### Changing the logical operator between groups: +You can specify a logicalOperator for a predicate which will define its relation +to the preceding predicate. + +In the previous example the predicates where combined with an 'AND' logical operator. +By adding an 'OR' operator to the second predicate you change this default. + +**Example: get users whose age is not between 17 and 68.** +```php +$qb->for('u', 'users') + ->filter([ + ['u.age', '<=', 18], + ['u.age', '>=', 67, 'OR'] + ]) + ->return('u'); +``` +resolves to : +```aql +FOR u IN users FILTER u.age <= 18 OR u.age >= 67 RETURN u +``` diff --git a/src/AQL/HasArangoSearchFunctions.php b/src/AQL/HasArangoSearchFunctions.php index 46117ee..ea5662e 100644 --- a/src/AQL/HasArangoSearchFunctions.php +++ b/src/AQL/HasArangoSearchFunctions.php @@ -222,7 +222,7 @@ public function like( * @param null|string|object $analyzer * @return FunctionExpression */ - public function ngramMatch( + public function nGramMatch( mixed $path, mixed $target, mixed $threshold = null, diff --git a/tests/Unit/AQL/ArangoSearchFunctionsTest.php b/tests/Unit/AQL/ArangoSearchFunctionsTest.php index 74e8c32..f2ed4b6 100644 --- a/tests/Unit/AQL/ArangoSearchFunctionsTest.php +++ b/tests/Unit/AQL/ArangoSearchFunctionsTest.php @@ -248,7 +248,7 @@ public function testNgramMatch() { $qb = new QueryBuilder(); $qb->for('doc', 'viewName') - ->search($qb->ngramMatch("doc.text", "quick fox")) + ->search($qb->nGramMatch("doc.text", "quick fox")) ->return('doc.text'); self::assertEquals( @@ -262,7 +262,7 @@ public function testNgramMatchOptionalArgs() { $qb = new QueryBuilder(); $qb->for('doc', 'viewName') - ->search($qb->ngramMatch("doc.text", "quick fox", 0.8, "bigram")) + ->search($qb->nGramMatch("doc.text", "quick fox", 0.8, "bigram")) ->return('doc.text'); self::assertEquals(