PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.15.3
Independent Analytics – WordPress Analytics Plugin v2.15.3
2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / illuminate / database / Concerns / BuildsQueries.php
independent-analytics / vendor / illuminate / database / Concerns Last commit date
BuildsQueries.php 3 weeks ago CompilesJsonPaths.php 3 weeks ago ExplainsQueries.php 2 years ago ManagesTransactions.php 3 weeks ago ParsesSearchPath.php 3 weeks ago
BuildsQueries.php
401 lines
1 <?php
2
3 namespace IAWPSCOPED\Illuminate\Database\Concerns;
4
5 use IAWPSCOPED\Illuminate\Container\Container;
6 use IAWPSCOPED\Illuminate\Database\Eloquent\Builder;
7 use IAWPSCOPED\Illuminate\Database\MultipleRecordsFoundException;
8 use IAWPSCOPED\Illuminate\Database\Query\Expression;
9 use IAWPSCOPED\Illuminate\Database\RecordsNotFoundException;
10 use IAWPSCOPED\Illuminate\Pagination\Cursor;
11 use IAWPSCOPED\Illuminate\Pagination\CursorPaginator;
12 use IAWPSCOPED\Illuminate\Pagination\LengthAwarePaginator;
13 use IAWPSCOPED\Illuminate\Pagination\Paginator;
14 use IAWPSCOPED\Illuminate\Support\Collection;
15 use IAWPSCOPED\Illuminate\Support\LazyCollection;
16 use IAWPSCOPED\Illuminate\Support\Str;
17 use IAWPSCOPED\Illuminate\Support\Traits\Conditionable;
18 use InvalidArgumentException;
19 use RuntimeException;
20 /** @internal */
21 trait BuildsQueries
22 {
23 use Conditionable;
24 /**
25 * Chunk the results of the query.
26 *
27 * @param int $count
28 * @param callable $callback
29 * @return bool
30 */
31 public function chunk($count, callable $callback)
32 {
33 $this->enforceOrderBy();
34 $page = 1;
35 do {
36 // We'll execute the query for the given page and get the results. If there are
37 // no results we can just break and return from here. When there are results
38 // we will call the callback with the current chunk of these results here.
39 $results = $this->forPage($page, $count)->get();
40 $countResults = $results->count();
41 if ($countResults == 0) {
42 break;
43 }
44 // On each chunk result set, we will pass them to the callback and then let the
45 // developer take care of everything within the callback, which allows us to
46 // keep the memory low for spinning through large result sets for working.
47 if ($callback($results, $page) === \false) {
48 return \false;
49 }
50 unset($results);
51 $page++;
52 } while ($countResults == $count);
53 return \true;
54 }
55 /**
56 * Run a map over each item while chunking.
57 *
58 * @param callable $callback
59 * @param int $count
60 * @return \Illuminate\Support\Collection
61 */
62 public function chunkMap(callable $callback, $count = 1000)
63 {
64 $collection = Collection::make();
65 $this->chunk($count, function ($items) use($collection, $callback) {
66 $items->each(function ($item) use($collection, $callback) {
67 $collection->push($callback($item));
68 });
69 });
70 return $collection;
71 }
72 /**
73 * Execute a callback over each item while chunking.
74 *
75 * @param callable $callback
76 * @param int $count
77 * @return bool
78 *
79 * @throws \RuntimeException
80 */
81 public function each(callable $callback, $count = 1000)
82 {
83 return $this->chunk($count, function ($results) use($callback) {
84 foreach ($results as $key => $value) {
85 if ($callback($value, $key) === \false) {
86 return \false;
87 }
88 }
89 });
90 }
91 /**
92 * Chunk the results of a query by comparing IDs.
93 *
94 * @param int $count
95 * @param callable $callback
96 * @param string|null $column
97 * @param string|null $alias
98 * @return bool
99 */
100 public function chunkById($count, callable $callback, $column = null, $alias = null)
101 {
102 $column ??= $this->defaultKeyName();
103 $alias ??= $column;
104 $lastId = null;
105 $page = 1;
106 do {
107 $clone = clone $this;
108 // We'll execute the query for the given page and get the results. If there are
109 // no results we can just break and return from here. When there are results
110 // we will call the callback with the current chunk of these results here.
111 $results = $clone->forPageAfterId($count, $lastId, $column)->get();
112 $countResults = $results->count();
113 if ($countResults == 0) {
114 break;
115 }
116 // On each chunk result set, we will pass them to the callback and then let the
117 // developer take care of everything within the callback, which allows us to
118 // keep the memory low for spinning through large result sets for working.
119 if ($callback($results, $page) === \false) {
120 return \false;
121 }
122 $lastId = \IAWPSCOPED\data_get($results->last(), $alias);
123 if ($lastId === null) {
124 throw new RuntimeException("The chunkById operation was aborted because the [{$alias}] column is not present in the query result.");
125 }
126 unset($results);
127 $page++;
128 } while ($countResults == $count);
129 return \true;
130 }
131 /**
132 * Execute a callback over each item while chunking by ID.
133 *
134 * @param callable $callback
135 * @param int $count
136 * @param string|null $column
137 * @param string|null $alias
138 * @return bool
139 */
140 public function eachById(callable $callback, $count = 1000, $column = null, $alias = null)
141 {
142 return $this->chunkById($count, function ($results, $page) use($callback, $count) {
143 foreach ($results as $key => $value) {
144 if ($callback($value, ($page - 1) * $count + $key) === \false) {
145 return \false;
146 }
147 }
148 }, $column, $alias);
149 }
150 /**
151 * Query lazily, by chunks of the given size.
152 *
153 * @param int $chunkSize
154 * @return \Illuminate\Support\LazyCollection
155 *
156 * @throws \InvalidArgumentException
157 */
158 public function lazy($chunkSize = 1000)
159 {
160 if ($chunkSize < 1) {
161 throw new InvalidArgumentException('The chunk size should be at least 1');
162 }
163 $this->enforceOrderBy();
164 return LazyCollection::make(function () use($chunkSize) {
165 $page = 1;
166 while (\true) {
167 $results = $this->forPage($page++, $chunkSize)->get();
168 foreach ($results as $result) {
169 (yield $result);
170 }
171 if ($results->count() < $chunkSize) {
172 return;
173 }
174 }
175 });
176 }
177 /**
178 * Query lazily, by chunking the results of a query by comparing IDs.
179 *
180 * @param int $chunkSize
181 * @param string|null $column
182 * @param string|null $alias
183 * @return \Illuminate\Support\LazyCollection
184 *
185 * @throws \InvalidArgumentException
186 */
187 public function lazyById($chunkSize = 1000, $column = null, $alias = null)
188 {
189 return $this->orderedLazyById($chunkSize, $column, $alias);
190 }
191 /**
192 * Query lazily, by chunking the results of a query by comparing IDs in descending order.
193 *
194 * @param int $chunkSize
195 * @param string|null $column
196 * @param string|null $alias
197 * @return \Illuminate\Support\LazyCollection
198 *
199 * @throws \InvalidArgumentException
200 */
201 public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null)
202 {
203 return $this->orderedLazyById($chunkSize, $column, $alias, \true);
204 }
205 /**
206 * Query lazily, by chunking the results of a query by comparing IDs in a given order.
207 *
208 * @param int $chunkSize
209 * @param string|null $column
210 * @param string|null $alias
211 * @param bool $descending
212 * @return \Illuminate\Support\LazyCollection
213 *
214 * @throws \InvalidArgumentException
215 */
216 protected function orderedLazyById($chunkSize = 1000, $column = null, $alias = null, $descending = \false)
217 {
218 if ($chunkSize < 1) {
219 throw new InvalidArgumentException('The chunk size should be at least 1');
220 }
221 $column ??= $this->defaultKeyName();
222 $alias ??= $column;
223 return LazyCollection::make(function () use($chunkSize, $column, $alias, $descending) {
224 $lastId = null;
225 while (\true) {
226 $clone = clone $this;
227 if ($descending) {
228 $results = $clone->forPageBeforeId($chunkSize, $lastId, $column)->get();
229 } else {
230 $results = $clone->forPageAfterId($chunkSize, $lastId, $column)->get();
231 }
232 foreach ($results as $result) {
233 (yield $result);
234 }
235 if ($results->count() < $chunkSize) {
236 return;
237 }
238 $lastId = $results->last()->{$alias};
239 }
240 });
241 }
242 /**
243 * Execute the query and get the first result.
244 *
245 * @param array|string $columns
246 * @return \Illuminate\Database\Eloquent\Model|object|static|null
247 */
248 public function first($columns = ['*'])
249 {
250 return $this->take(1)->get($columns)->first();
251 }
252 /**
253 * Execute the query and get the first result if it's the sole matching record.
254 *
255 * @param array|string $columns
256 * @return \Illuminate\Database\Eloquent\Model|object|static|null
257 *
258 * @throws \Illuminate\Database\RecordsNotFoundException
259 * @throws \Illuminate\Database\MultipleRecordsFoundException
260 */
261 public function sole($columns = ['*'])
262 {
263 $result = $this->take(2)->get($columns);
264 $count = $result->count();
265 if ($count === 0) {
266 throw new RecordsNotFoundException();
267 }
268 if ($count > 1) {
269 throw new MultipleRecordsFoundException($count);
270 }
271 return $result->first();
272 }
273 /**
274 * Paginate the given query using a cursor paginator.
275 *
276 * @param int $perPage
277 * @param array|string $columns
278 * @param string $cursorName
279 * @param \Illuminate\Pagination\Cursor|string|null $cursor
280 * @return \Illuminate\Contracts\Pagination\CursorPaginator
281 */
282 protected function paginateUsingCursor($perPage, $columns = ['*'], $cursorName = 'cursor', $cursor = null)
283 {
284 if (!$cursor instanceof Cursor) {
285 $cursor = \is_string($cursor) ? Cursor::fromEncoded($cursor) : CursorPaginator::resolveCurrentCursor($cursorName, $cursor);
286 }
287 $orders = $this->ensureOrderForCursorPagination(!\is_null($cursor) && $cursor->pointsToPreviousItems());
288 if (!\is_null($cursor)) {
289 $addCursorConditions = function (self $builder, $previousColumn, $i) use(&$addCursorConditions, $cursor, $orders) {
290 $unionBuilders = isset($builder->unions) ? \IAWPSCOPED\collect($builder->unions)->pluck('query') : \IAWPSCOPED\collect();
291 if (!\is_null($previousColumn)) {
292 $originalColumn = $this->getOriginalColumnNameForCursorPagination($this, $previousColumn);
293 $builder->where(Str::contains($originalColumn, ['(', ')']) ? new Expression($originalColumn) : $originalColumn, '=', $cursor->parameter($previousColumn));
294 $unionBuilders->each(function ($unionBuilder) use($previousColumn, $cursor) {
295 $unionBuilder->where($this->getOriginalColumnNameForCursorPagination($this, $previousColumn), '=', $cursor->parameter($previousColumn));
296 $this->addBinding($unionBuilder->getRawBindings()['where'], 'union');
297 });
298 }
299 $builder->where(function (self $builder) use($addCursorConditions, $cursor, $orders, $i, $unionBuilders) {
300 ['column' => $column, 'direction' => $direction] = $orders[$i];
301 $originalColumn = $this->getOriginalColumnNameForCursorPagination($this, $column);
302 $builder->where(Str::contains($originalColumn, ['(', ')']) ? new Expression($originalColumn) : $originalColumn, $direction === 'asc' ? '>' : '<', $cursor->parameter($column));
303 if ($i < $orders->count() - 1) {
304 $builder->orWhere(function (self $builder) use($addCursorConditions, $column, $i) {
305 $addCursorConditions($builder, $column, $i + 1);
306 });
307 }
308 $unionBuilders->each(function ($unionBuilder) use($column, $direction, $cursor, $i, $orders, $addCursorConditions) {
309 $unionBuilder->where(function ($unionBuilder) use($column, $direction, $cursor, $i, $orders, $addCursorConditions) {
310 $unionBuilder->where($this->getOriginalColumnNameForCursorPagination($this, $column), $direction === 'asc' ? '>' : '<', $cursor->parameter($column));
311 if ($i < $orders->count() - 1) {
312 $unionBuilder->orWhere(function (self $builder) use($addCursorConditions, $column, $i) {
313 $addCursorConditions($builder, $column, $i + 1);
314 });
315 }
316 $this->addBinding($unionBuilder->getRawBindings()['where'], 'union');
317 });
318 });
319 });
320 };
321 $addCursorConditions($this, null, 0);
322 }
323 $this->limit($perPage + 1);
324 return $this->cursorPaginator($this->get($columns), $perPage, $cursor, ['path' => Paginator::resolveCurrentPath(), 'cursorName' => $cursorName, 'parameters' => $orders->pluck('column')->toArray()]);
325 }
326 /**
327 * Get the original column name of the given column, without any aliasing.
328 *
329 * @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $builder
330 * @param string $parameter
331 * @return string
332 */
333 protected function getOriginalColumnNameForCursorPagination($builder, string $parameter)
334 {
335 $columns = $builder instanceof Builder ? $builder->getQuery()->columns : $builder->columns;
336 if (!\is_null($columns)) {
337 foreach ($columns as $column) {
338 if (($position = \strripos($column, ' as ')) !== \false) {
339 $original = \substr($column, 0, $position);
340 $alias = \substr($column, $position + 4);
341 if ($parameter === $alias || $builder->getGrammar()->wrap($parameter) === $alias) {
342 return $original;
343 }
344 }
345 }
346 }
347 return $parameter;
348 }
349 /**
350 * Create a new length-aware paginator instance.
351 *
352 * @param \Illuminate\Support\Collection $items
353 * @param int $total
354 * @param int $perPage
355 * @param int $currentPage
356 * @param array $options
357 * @return \Illuminate\Pagination\LengthAwarePaginator
358 */
359 protected function paginator($items, $total, $perPage, $currentPage, $options)
360 {
361 return Container::getInstance()->makeWith(LengthAwarePaginator::class, \compact('items', 'total', 'perPage', 'currentPage', 'options'));
362 }
363 /**
364 * Create a new simple paginator instance.
365 *
366 * @param \Illuminate\Support\Collection $items
367 * @param int $perPage
368 * @param int $currentPage
369 * @param array $options
370 * @return \Illuminate\Pagination\Paginator
371 */
372 protected function simplePaginator($items, $perPage, $currentPage, $options)
373 {
374 return Container::getInstance()->makeWith(Paginator::class, \compact('items', 'perPage', 'currentPage', 'options'));
375 }
376 /**
377 * Create a new cursor paginator instance.
378 *
379 * @param \Illuminate\Support\Collection $items
380 * @param int $perPage
381 * @param \Illuminate\Pagination\Cursor $cursor
382 * @param array $options
383 * @return \Illuminate\Pagination\CursorPaginator
384 */
385 protected function cursorPaginator($items, $perPage, $cursor, $options)
386 {
387 return Container::getInstance()->makeWith(CursorPaginator::class, \compact('items', 'perPage', 'cursor', 'options'));
388 }
389 /**
390 * Pass the query to a given callback.
391 *
392 * @param callable $callback
393 * @return $this
394 */
395 public function tap($callback)
396 {
397 $callback($this);
398 return $this;
399 }
400 }
401