-
-
Notifications
You must be signed in to change notification settings - Fork 260
Expand file tree
/
Copy pathRequestOptions.php
More file actions
470 lines (408 loc) 路 10 KB
/
Copy pathRequestOptions.php
File metadata and controls
470 lines (408 loc) 路 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
<?php
namespace SMW;
/**
* Container object for various options that can be used when retrieving
* data from the store. These options are mostly relevant for simple,
* direct requests -- inline queries may require more complex options due
* to their more complex structure.
* Options that should not be used or where default values should be used
* can be left as initialised.
*
* @license GPL-2.0-or-later
* @since 1.0
*
* @author Markus Kr枚tzsch
*/
class RequestOptions {
/**
* Used to identify a constraint conition set forth by the QueryResult
* process which doesn't modify the `limit`.
*/
const CONDITION_CONSTRAINT_RESULT = 'condition.constraint.result';
/**
* Used to identify a constraint conidtion set forth by any other query
* process.
*/
const CONDITION_CONSTRAINT = 'conditon.constraint';
/**
* Defines a prefetch fingerprint
*/
const PREFETCH_FINGERPRINT = 'prefetch.fingerprint';
/**
* Defines an individual search field
*/
const SEARCH_FIELD = 'search_field';
/**
* Opt-in flag asking a cursor-aware lookup to populate cursor metadata
* (`firstCursor`, `lastCursor`, `cursorHasMore`) on this RequestOptions
* instance even when `cursorAfter` / `cursorBefore` are not set (i.e.
* the first page of a cursor-paginated UI). Callers that do not consume
* cursor metadata should leave this unset.
*
* @since 7.0.0
*/
const CURSOR_MODE = 'cursor.mode';
/**
* The maximum number of results that should be returned.
*
* @var int
*/
public $limit = -1;
/**
* For certain queries (prefetch using WHERE IN) using the limit will cause
* the whole set to be restricted on a bulk instead of only applied to a subset
* therefore allow the exclude the limit and apply an restriction during the
* post-processing.
*
* @var bool
*/
public $exclude_limit = false;
/**
* A numerical offset. The first $offset results are skipped.
* Note that this does not imply a defined order of results
* (see RequestOptions->$sort below).
*
* @var int
*/
public $offset = 0;
/**
* A numerical size to indicate a "look ahead" beyond the defined
* limit.
*
* @var int
*/
public $lookahead = 0;
/**
* Should the result be ordered? The employed order is defined
* by the type of result that are requested: wiki pages and strings
* are ordered alphabetically, whereas other data is ordered
* numerically. Usually, the order should be fairly "natural".
*
* @var string|false
*/
public $sort = false;
/**
* If RequestOptions->$sort is true, this parameter defines whether
* the results are ordered in ascending or descending order.
*
* @var bool
*/
public $ascending = true;
/**
* Specifies a lower or upper bound for the values returned by the query.
* Whether it is lower or upper is specified by the parameter "ascending"
* (true->lower, false->upper).
*
* @var bool|int|string|null
*/
public $boundary = null;
/**
* Specifies whether or not the requested boundary should be returned
* as a result.
*
* @var bool
*/
public $include_boundary = true;
/**
* An array of string conditions that are applied if the result has a
* string label that can be subject to those patterns.
*
* @var StringCondition[]
*/
private array $stringConditions = [];
/**
* Contains extra conditions which a consumer is being allowed to interpret
* freely to modify a search condition.
*
* @var array
*/
private $extraConditions = [];
/**
* @var array
*/
private $options = [];
/**
* @var string|null
*/
private $caller;
public ?bool $conditionConstraint = null;
public ?bool $isChain = null;
public ?bool $isFirstChain = null;
public ?bool $natural = null;
private ?int $cursorAfter = null;
private ?int $cursorBefore = null;
private ?int $firstCursor = null;
private ?int $lastCursor = null;
private bool $cursorHasMore = false;
public function setCursorAfter( int $id ): void {
$this->cursorAfter = $id;
}
public function getCursorAfter(): ?int {
return $this->cursorAfter;
}
public function setCursorBefore( int $id ): void {
$this->cursorBefore = $id;
}
public function getCursorBefore(): ?int {
return $this->cursorBefore;
}
public function setFirstCursor( int $id ): void {
$this->firstCursor = $id;
}
public function getFirstCursor(): ?int {
return $this->firstCursor;
}
public function setLastCursor( int $id ): void {
$this->lastCursor = $id;
}
public function getLastCursor(): ?int {
return $this->lastCursor;
}
public function hasCursor(): bool {
return $this->cursorAfter !== null || $this->cursorBefore !== null;
}
public function setCursorHasMore( bool $hasMore ): void {
$this->cursorHasMore = $hasMore;
}
public function getCursorHasMore(): bool {
return $this->cursorHasMore;
}
/**
* @since 3.1
*
* @param string $caller
*/
public function setCaller( $caller ): void {
$this->caller = $caller;
}
/**
* @since 3.1
*
* @return string
*/
public function getCaller() {
return $this->caller;
}
/**
* @since 1.0
*
* @param string $string to match
* @param int $condition one of STRCOND_PRE, STRCOND_POST, STRCOND_MID
* @param bool $isOr
* @param bool $isNot
*/
public function addStringCondition( $string, $condition, $isOr = false, $isNot = false ): void {
$this->stringConditions[] = new StringCondition( $string, $condition, $isOr, $isNot );
}
/**
* Return the specified array of SMWStringCondition objects.
*
* @since 1.0
*
* @return array
*/
public function getStringConditions(): array {
return $this->stringConditions;
}
/**
* @since 2.5
*
* @param mixed $extraCondition
*
* @return void
*/
public function addExtraCondition( $extraCondition ): void {
$this->extraConditions[] = $extraCondition;
}
/**
* @since 2.5
*
* @return array
*/
public function getExtraConditions(): array {
return $this->extraConditions;
}
/**
* @since 3.1
*
* @return void
*/
public function emptyExtraConditions(): void {
$this->extraConditions = [];
}
/**
* @since 3.0
*
* @param string $key
* @param bool|int|string $value
*
* @return void
*/
public function setOption( $key, $value ): void {
$this->options[$key] = $value;
}
/**
* @since 3.1
*
* @param string $key
*
* @return void
*/
public function deleteOption( $key ): void {
unset( $this->options[$key] );
}
/**
* @since 3.0
*
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function getOption( $key, $default = null ) {
if ( isset( $this->options[$key] ) ) {
return $this->options[$key];
}
return $default;
}
/**
* @since 2.5
*
* @param int $limit
*
* @return void
*/
public function setLimit( $limit ): void {
$this->limit = (int)$limit;
}
/**
* @since 2.5
*
* @return int
*/
public function getLimit(): int {
return (int)$this->limit;
}
/**
* @since 2.5
*
* @param int $offset
*
* @return void
*/
public function setOffset( $offset ): void {
$this->offset = (int)$offset;
}
/**
* @since 2.5
*
* @return int
*/
public function getOffset(): int {
return (int)$this->offset;
}
/**
* @since 3.2
*
* @param int $lookahead
*
* @return void
*/
public function setLookahead( int $lookahead ): void {
$this->lookahead = $lookahead;
}
/**
* @since 3.2
*
* @return int
*/
public function getLookahead(): int {
return $this->lookahead;
}
/**
* @since 2.4
*
* @return string
*/
public function getHash(): string|false {
$stringConditions = '';
foreach ( $this->stringConditions as $stringCondition ) {
$stringConditions .= $stringCondition->getHash();
}
return json_encode( [
$this->limit,
$this->offset,
$this->lookahead,
$this->sort,
$this->ascending,
$this->boundary,
$this->include_boundary,
$this->exclude_limit,
$stringConditions,
$this->extraConditions,
$this->options,
$this->cursorAfter,
$this->cursorBefore,
] );
}
/**
* Option-bag keys that only steer query execution or prime a lower-level
* cache; they never change which values, or in what order, are selected and
* are therefore excluded from getValueHash(). Every option NOT listed here
* is treated as value-affecting and included, so a newly added
* value-affecting option participates in the value identity by default.
*/
private const NON_VALUE_OPTIONS = [
self::PREFETCH_FINGERPRINT,
'ORDER BY',
'GROUP BY',
'DISTINCT',
'NO_GROUPBY',
'NO_DISTINCT',
'hash.index',
];
/**
* Value identity of this request: two RequestOptions with the same value
* hash select the same set of values in the same order.
*
* Unlike getHash(), which is a whole-object identity relied on by
* lower-level lookup caches that must key on execution hints (for example
* PREFETCH_FINGERPRINT), this deliberately excludes those hints so it is
* safe as a value cache key, such as the one built by PrefetchCache. The
* typed value fields are listed explicitly; the option bag is included in
* full minus NON_VALUE_OPTIONS, so a new value-affecting option is covered
* by default.
*
* lookahead and exclude_limit are omitted on purpose: both are normalized
* to a fixed value by the prefetch machinery, so they are constants in the
* path that consumes this hash and are not part of the caller's value
* identity. RequestOptionsTest guards that every declared property stays
* classified.
*
* @since 7.2.0
*/
public function getValueHash(): string {
$stringConditions = '';
foreach ( $this->stringConditions as $stringCondition ) {
$stringConditions .= $stringCondition->getHash();
}
$options = array_diff_key( $this->options, array_flip( self::NON_VALUE_OPTIONS ) );
// The insertion order of options must not change the identity.
ksort( $options );
return md5( json_encode( [
$this->limit,
$this->offset,
$this->sort,
$this->ascending,
$this->boundary,
$this->include_boundary,
$this->conditionConstraint,
$this->natural,
$this->cursorAfter,
$this->cursorBefore,
$stringConditions,
$this->extraConditions,
$options,
] ) );
}
}