Skip to content

Commit bd57f8e

Browse files
committed
Optimized the filtering operators to support AND/OR and NULL operators. Fixed IN operator and simplified the usage
1 parent 72de3cd commit bd57f8e

16 files changed

+285
-132
lines changed

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# The MIT License (MIT)
22

3-
Copyright (c) 2018 Lasse Rafn <lasserafn@gmail.com>
3+
Copyright (c) Lasse Rafn <lasserafn@gmail.com>
44

55
> Permission is hereby granted, free of charge, to any person obtaining a copy
66
> of this software and associated documentation files (the "Software"), to deal

src/Builders/Builder.php

Lines changed: 172 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
namespace LasseRafn\Economic\Builders;
44

5+
use LasseRafn\Economic\FilterOperators\AndOperator;
6+
use LasseRafn\Economic\FilterOperators\EqualsOperator;
7+
use LasseRafn\Economic\FilterOperators\FilterOperatorInterface;
8+
use LasseRafn\Economic\FilterOperators\GreaterThanOperator;
9+
use LasseRafn\Economic\FilterOperators\GreaterThanOrEqualOperator;
10+
use LasseRafn\Economic\FilterOperators\InOperator;
11+
use LasseRafn\Economic\FilterOperators\LessThanOperator;
12+
use LasseRafn\Economic\FilterOperators\LessThanOrEqualOperator;
13+
use LasseRafn\Economic\FilterOperators\LikeOperator;
14+
use LasseRafn\Economic\FilterOperators\NotEqualsOperator;
15+
use LasseRafn\Economic\FilterOperators\NotInOperator;
16+
use LasseRafn\Economic\FilterOperators\NullOperator;
17+
use LasseRafn\Economic\FilterOperators\OperatorNotFound;
18+
use LasseRafn\Economic\FilterOperators\OrOperator;
519
use LasseRafn\Economic\Utils\Model;
620
use LasseRafn\Economic\Utils\Request;
721

@@ -18,11 +32,13 @@ public function __construct(Request $request)
1832
$this->request = $request;
1933
}
2034

21-
/**
22-
* @param $id
23-
*
24-
* @return mixed|Model
25-
*/
35+
/**
36+
* @param $id
37+
*
38+
* @return Model
39+
* @throws \LasseRafn\Economic\Exceptions\EconomicClientException
40+
* @throws \LasseRafn\Economic\Exceptions\EconomicRequestException
41+
*/
2642
public function find($id)
2743
{
2844
return $this->request->handleWithExceptions(function () use ($id) {
@@ -34,6 +50,11 @@ public function find($id)
3450
});
3551
}
3652

53+
/**
54+
* @return Model
55+
* @throws \LasseRafn\Economic\Exceptions\EconomicClientException
56+
* @throws \LasseRafn\Economic\Exceptions\EconomicRequestException
57+
*/
3758
public function first()
3859
{
3960
return $this->request->handleWithExceptions(function () {
@@ -50,29 +71,16 @@ public function first()
5071
});
5172
}
5273

53-
/**
54-
* @param array $filters
55-
*
56-
* @return \Illuminate\Support\Collection|Model[]
57-
*/
74+
/**
75+
* @param array $filters
76+
*
77+
* @return \Illuminate\Support\Collection|Model[]
78+
* @throws \LasseRafn\Economic\Exceptions\EconomicClientException
79+
* @throws \LasseRafn\Economic\Exceptions\EconomicRequestException
80+
*/
5881
public function get($filters = [])
5982
{
60-
$urlFilters = '';
61-
62-
if (count($filters) > 0) {
63-
$urlFilters .= '?filter=';
64-
65-
$i = 1;
66-
foreach ($filters as $filter) {
67-
$urlFilters .= $filter[0].$this->switchComparison($filter[1]).$this->escapeFilter($filter[2]); // todo fix arrays aswell ([1,2,3,...] string)
68-
69-
if (count($filters) > $i) {
70-
$urlFilters .= '$and:'; // todo allow $or: also
71-
}
72-
73-
$i++;
74-
}
75-
}
83+
$urlFilters = $this->generateQueryStringFromFilterArray($filters);
7684

7785
return $this->request->handleWithExceptions(function () use ($urlFilters) {
7886
$response = $this->request->curl->get("/{$this->entity}{$urlFilters}");
@@ -93,33 +101,20 @@ public function get($filters = [])
93101
});
94102
}
95103

96-
/**
97-
* @param int $page
98-
* @param int $pageSize
99-
* @param array $filters
100-
*
101-
* @return \Illuminate\Support\Collection|Model[]
102-
*/
104+
/**
105+
* @param int $page
106+
* @param int $pageSize
107+
* @param array $filters
108+
*
109+
* @return \Illuminate\Support\Collection|Model[]
110+
* @throws \LasseRafn\Economic\Exceptions\EconomicClientException
111+
* @throws \LasseRafn\Economic\Exceptions\EconomicRequestException
112+
*/
103113
public function getByPage($page = 0, $pageSize = 500, $filters = [])
104114
{
105115
$items = collect([]);
106116

107-
$urlFilters = '';
108-
109-
if (count($filters) > 0) {
110-
$urlFilters .= '&filter=';
111-
112-
$i = 1;
113-
foreach ($filters as $filter) {
114-
$urlFilters .= $filter[0].$this->switchComparison($filter[1]).$this->escapeFilter($filter[2]); // todo fix arrays aswell ([1,2,3,...] string)
115-
116-
if (count($filters) > $i) {
117-
$urlFilters .= '$and:'; // todo allow $or: also
118-
}
119-
120-
$i++;
121-
}
122-
}
117+
$urlFilters = $this->generateQueryStringFromFilterArray($filters);
123118

124119
return $this->request->handleWithExceptions(function () use ($pageSize, &$page, &$items, $urlFilters) {
125120
$response = $this->request->curl->get("/{$this->entity}?skippages={$page}&pagesize={$pageSize}{$urlFilters}");
@@ -138,34 +133,22 @@ public function getByPage($page = 0, $pageSize = 500, $filters = [])
138133
});
139134
}
140135

141-
/**
142-
* @param array $filters
143-
*
144-
* @return \Illuminate\Support\Collection|Model[]
145-
*/
136+
/**
137+
* @param array $filters
138+
* @param int $pageSize
139+
*
140+
* @return \Illuminate\Support\Collection|Model[]
141+
* @throws \LasseRafn\Economic\Exceptions\EconomicClientException
142+
* @throws \LasseRafn\Economic\Exceptions\EconomicRequestException
143+
*/
146144
public function all($filters = [], $pageSize = 500)
147145
{
148146
$page = 0;
149147
$pagesize = $pageSize;
150148
$hasMore = true;
151149
$items = collect([]);
152150

153-
$urlFilters = '';
154-
155-
if (count($filters) > 0) {
156-
$urlFilters .= '&filter=';
157-
158-
$i = 1;
159-
foreach ($filters as $filter) {
160-
$urlFilters .= $filter[0].$this->switchComparison($filter[1]).$this->escapeFilter($filter[2]); // todo fix arrays aswell ([1,2,3,...] string)
161-
162-
if (count($filters) > $i) {
163-
$urlFilters .= '$and:'; // todo allow $or: also
164-
}
165-
166-
$i++;
167-
}
168-
}
151+
$urlFilters = $this->generateQueryStringFromFilterArray($filters);
169152

170153
return $this->request->handleWithExceptions(function () use (&$hasMore, $pagesize, &$page, &$items, $urlFilters) {
171154
while ($hasMore) {
@@ -194,6 +177,13 @@ public function all($filters = [], $pageSize = 500)
194177
});
195178
}
196179

180+
/**
181+
* @param $data
182+
*
183+
* @return Model
184+
* @throws \LasseRafn\Economic\Exceptions\EconomicClientException
185+
* @throws \LasseRafn\Economic\Exceptions\EconomicRequestException
186+
*/
197187
public function create($data)
198188
{
199189
return $this->request->handleWithExceptions(function () use ($data) {
@@ -207,70 +197,121 @@ public function create($data)
207197
});
208198
}
209199

210-
private function escapeFilter($variable)
200+
/**
201+
* @param string $operator
202+
*
203+
* @return FilterOperatorInterface
204+
*
205+
* @throws OperatorNotFound
206+
*/
207+
protected function getOperator($operator)
208+
{
209+
switch (\mb_strtolower($operator)) {
210+
case '=':
211+
case '==':
212+
case '===':
213+
return new EqualsOperator;
214+
case '!=':
215+
case '!==':
216+
return new NotEqualsOperator;
217+
case '>':
218+
return new GreaterThanOperator;
219+
case '>=':
220+
return new GreaterThanOrEqualOperator;
221+
case '<':
222+
return new LessThanOperator;
223+
case '<=':
224+
return new LessThanOrEqualOperator;
225+
case 'like':
226+
return new LikeOperator;
227+
case 'in':
228+
return new InOperator;
229+
case '!in':
230+
case 'not in':
231+
return new NotInOperator;
232+
case 'or':
233+
case 'or else':
234+
return new OrOperator;
235+
case 'and':
236+
return new AndOperator;
237+
case 'null':
238+
return new NullOperator;
239+
default:
240+
throw new OperatorNotFound($operator);
241+
}
242+
}
243+
244+
protected function generateQueryStringFromFilterArray($filters)
211245
{
212-
$escapedStrings = [
213-
'$',
214-
'(',
215-
')',
216-
'*',
217-
'[',
218-
']',
219-
',',
220-
];
221-
222-
$urlencodedStrings = [
223-
'+',
224-
' ',
225-
];
226-
227-
foreach ($escapedStrings as $escapedString) {
228-
$variable = str_replace($escapedString, '$'.$escapedString, $variable);
229-
}
230-
231-
foreach ($urlencodedStrings as $urlencodedString) {
232-
$variable = str_replace($urlencodedString, urlencode($urlencodedString), $variable);
233-
}
234-
235-
return $variable;
246+
if (\count($filters) === 0) {
247+
return '';
248+
}
249+
250+
$string = '&filter=';
251+
252+
$i = 1;
253+
foreach ($filters as $filter) {
254+
// To support passing in 'and' / 'or' as an individual filter rather than ['', 'and', '']
255+
if (!\is_array($filter) && \count($filter) === 1) {
256+
$filterOperator = $this->getOperator($filter[0] ?? $filter);
257+
258+
if (($filterOperator instanceof OrOperator || $filterOperator instanceof AndOperator)) {
259+
$string.= $filterOperator->queryString;
260+
$i++;
261+
continue;
262+
}
263+
}
264+
265+
$filterOperator = $this->getOperator($filter[1]);
266+
$string .= $filter[0] . $filterOperator->queryString . $this->transformFilterValue($filter[2], $filterOperator);
267+
268+
if (!($filterOperator instanceof OrOperator || $filterOperator instanceof AndOperator) && \count($filters) > $i) {
269+
$string .= (new AndOperator)->queryString;
270+
}
271+
272+
$i++;
273+
}
274+
275+
return $string;
236276
}
237277

238-
private function switchComparison($comparison)
278+
protected function transformFilterValue($value, FilterOperatorInterface $filterOperator)
239279
{
240-
switch ($comparison) {
241-
case '=':
242-
case '==':
243-
$newComparison = '$eq:';
244-
break;
245-
case '!=':
246-
$newComparison = '$ne:';
247-
break;
248-
case '>':
249-
$newComparison = '$gt:';
250-
break;
251-
case '>=':
252-
$newComparison = '$gte:';
253-
break;
254-
case '<':
255-
$newComparison = '$lt:';
256-
break;
257-
case '<=':
258-
$newComparison = '$lte:';
259-
break;
260-
case 'like':
261-
$newComparison = '$like:';
262-
break;
263-
case 'in':
264-
$newComparison = '$in:';
265-
break;
266-
case '!in':
267-
$newComparison = '$nin:';
268-
break;
269-
default:
270-
$newComparison = "${$comparison}:";
271-
break;
272-
}
273-
274-
return $newComparison;
280+
if($value === null) {
281+
return (new NullOperator)->queryString;
282+
}
283+
284+
if ($filterOperator instanceof NullOperator || $filterOperator instanceof OrOperator || $filterOperator instanceof AndOperator ) {
285+
return '';
286+
}
287+
288+
if ($filterOperator instanceof InOperator && \is_array($value)) {
289+
return '[' . implode(',', $value) . ']';
290+
}
291+
292+
$escapedStrings = [
293+
'$',
294+
'(',
295+
')',
296+
'*',
297+
'[',
298+
']',
299+
',',
300+
];
301+
302+
$urlencodedStrings = [
303+
'+',
304+
' ',
305+
];
306+
307+
foreach ($escapedStrings as $escapedString) {
308+
$value = str_replace($escapedString, '$'.$escapedString, $value);
309+
}
310+
311+
foreach ($urlencodedStrings as $urlencodedString) {
312+
$value = str_replace($urlencodedString, urlencode($urlencodedString), $value);
313+
}
314+
315+
return $value;
275316
}
276317
}

src/FilterOperators/AndOperator.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace LasseRafn\Economic\FilterOperators;
4+
5+
class AndOperator implements FilterOperatorInterface
6+
{
7+
public $queryString = '$and:';
8+
}

0 commit comments

Comments
 (0)