1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @file QueryCommand.php |
5
|
|
|
* @brief This file contains the QueryCommand class. |
6
|
|
|
* @details |
7
|
|
|
* @author Filippo F. Fadda |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
|
11
|
|
|
namespace EoC\CLI\Command; |
12
|
|
|
|
13
|
|
|
|
14
|
|
|
use Symfony\Component\Console\Input\InputArgument; |
15
|
|
|
use Symfony\Component\Console\Input\InputOption; |
16
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
17
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
18
|
|
|
|
19
|
|
|
use EoC\Opt\ViewQueryOpts; |
20
|
|
|
|
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @brief Query a view and outputs the result. |
24
|
|
|
* @nosubgrouping |
25
|
|
|
* @todo Fix a bug when read map and reduce from file. |
26
|
|
|
*/ |
27
|
|
|
class QueryCommand extends AbstractCommand { |
28
|
|
|
|
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @brief Configures the command. |
32
|
|
|
*/ |
33
|
|
|
protected function configure() { |
34
|
|
|
$this->setName("query"); |
35
|
|
|
$this->setDescription("Queries a view and outputs the result"); |
36
|
|
|
|
37
|
|
|
$this->addArgument("design-doc/view-name", |
38
|
|
|
InputArgument::REQUIRED, |
39
|
|
|
<<<'DESC' |
40
|
|
|
The design document name followed by the view you want query |
41
|
|
|
In case of a temporary view, use: _temp_view --map=map.txt --reduce=reduce.txt. |
42
|
|
|
The files map.txt and reduce.txt must contains the map and reduce functions implementation. |
43
|
|
|
DESC |
44
|
|
|
); |
45
|
|
|
|
46
|
|
|
$this->addArgument("keys", |
47
|
|
|
InputArgument::IS_ARRAY | InputArgument::OPTIONAL, |
48
|
|
|
<<<'DESC' |
49
|
|
|
Used to retrieve just the view rows matching that set of keys |
50
|
|
|
Rows are returned in the order of the specified keys. |
51
|
|
|
Combining this feature with --include-docs results in the so-called multi-document-fetch feature. |
52
|
|
|
Keys must be separated by a space. |
53
|
|
|
The value is treated as string unless you specify a type for it. |
54
|
|
|
Supported types are string, integer, float and boolean. |
55
|
|
|
The argument type can be specified using the syntax %b/false. The slash is followed by the value. |
56
|
|
|
%s - the argument is treated as a string. |
57
|
|
|
%b - the argument is treated as a boolean. |
58
|
|
|
%i - the argument is treated as an integer. |
59
|
|
|
%f - the argument is treated as a float. |
60
|
|
|
DESC |
61
|
|
|
); |
62
|
|
|
|
63
|
|
|
// General options. |
64
|
|
|
$this->addOption("key", |
65
|
|
|
NULL, |
66
|
|
|
InputOption::VALUE_REQUIRED, |
67
|
|
|
<<<'DESC' |
68
|
|
|
Returns only documents that match the specified key |
69
|
|
|
The value is treated as string unless you specify a type for it. |
70
|
|
|
Supported types are string, integer, float and boolean. |
71
|
|
|
The argument type can be specified using the syntax %b/false. The slash is followed by the value. |
72
|
|
|
%s - the argument is treated as a string. |
73
|
|
|
%b - the argument is treated as a boolean. |
74
|
|
|
%i - the argument is treated as an integer. |
75
|
|
|
%f - the argument is treated as a float. |
76
|
|
|
DESC |
77
|
|
|
); |
78
|
|
|
|
79
|
|
|
$this->addOption("startkey", |
80
|
|
|
NULL, |
81
|
|
|
InputOption::VALUE_REQUIRED, |
82
|
|
|
<<<'DESC' |
83
|
|
|
Defines the first key to be included in the range |
84
|
|
|
In case the key is a string, it must be quoted with double quotes and escaped, like --startkey=mykey. |
85
|
|
|
To provide a complex key, instead, you must use --startkey=[book,{}]. |
86
|
|
|
The {} symbol is a wildcard used in JavaScript to create an empty object. |
87
|
|
|
Don't put a space between the values of your complex key, because the console will consider them like new arguments. |
88
|
|
|
If your key contains a space, remember to backspace it like follows: --startkey=[my\ book,{}]. |
89
|
|
|
The value is treated as string unless you specify a type for it. |
90
|
|
|
Supported types are string, integer, float and boolean. |
91
|
|
|
The argument type can be specified using the syntax %b/false. The slash is followed by the value. |
92
|
|
|
%s - the argument is treated as a string. |
93
|
|
|
%b - the argument is treated as a boolean. |
94
|
|
|
%i - the argument is treated as an integer. |
95
|
|
|
%f - the argument is treated as a float. |
96
|
|
|
DESC |
97
|
|
|
); |
98
|
|
|
|
99
|
|
|
$this->addOption("endkey", |
100
|
|
|
NULL, |
101
|
|
|
InputOption::VALUE_REQUIRED, |
102
|
|
|
<<<'DESC' |
103
|
|
|
Defines the last key to be included in the range |
104
|
|
|
The value is treated as string unless you specify a type for it. |
105
|
|
|
Supported types are string, interger, float and boolean. |
106
|
|
|
The argument type can be specified using the syntax %b/false. The slash is followed by the value. |
107
|
|
|
%s - the argument is treated as a string. |
108
|
|
|
%b - the argument is treated as a boolean. |
109
|
|
|
%i - the argument is treated as an integer. |
110
|
|
|
%f - the argument is treated as a float. |
111
|
|
|
DESC |
112
|
|
|
); |
113
|
|
|
|
114
|
|
|
$this->addOption("startkey-docid", |
115
|
|
|
NULL, |
116
|
|
|
InputOption::VALUE_REQUIRED, |
117
|
|
|
"Sets the ID of the document with which to start the range"); |
118
|
|
|
|
119
|
|
|
$this->addOption("endkey-docid", |
120
|
|
|
NULL, |
121
|
|
|
InputOption::VALUE_REQUIRED, |
122
|
|
|
"Sets the ID of the document with which to end the range"); |
123
|
|
|
|
124
|
|
|
$this->addOption("limit", |
125
|
|
|
NULL, |
126
|
|
|
InputOption::VALUE_REQUIRED, |
127
|
|
|
"Limit the number of results"); |
128
|
|
|
|
129
|
|
|
$this->addOption("group-results", |
130
|
|
|
NULL, |
131
|
|
|
InputOption::VALUE_NONE, |
132
|
|
|
"Results should be grouped"); |
133
|
|
|
|
134
|
|
|
$this->addOption("group-level", |
135
|
|
|
NULL, |
136
|
|
|
InputOption::VALUE_REQUIRED, |
137
|
|
|
"Level at which documents should be grouped"); |
138
|
|
|
|
139
|
|
|
$this->addOption("do-not-reduce", |
140
|
|
|
NULL, |
141
|
|
|
InputOption::VALUE_NONE, |
142
|
|
|
"Even if a reduce function is defined for the view, doesn't call it"); |
143
|
|
|
|
144
|
|
|
$this->addOption("include-docs", |
145
|
|
|
NULL, |
146
|
|
|
InputOption::VALUE_NONE, |
147
|
|
|
"Includes documents in the output"); |
148
|
|
|
|
149
|
|
|
$this->addOption("exclude-results", |
150
|
|
|
NULL, |
151
|
|
|
InputOption::VALUE_NONE, |
152
|
|
|
"Don't get any data, but all meta-data for this View; the number of documents in this View for example"); |
153
|
|
|
|
154
|
|
|
$this->addOption("exclude-endkey", |
155
|
|
|
NULL, |
156
|
|
|
InputOption::VALUE_NONE, |
157
|
|
|
"Tells CouchDB to not include end key in the result"); |
158
|
|
|
|
159
|
|
|
$this->addOption("reverse-order", |
160
|
|
|
NULL, |
161
|
|
|
InputOption::VALUE_NONE, |
162
|
|
|
"Reverses order of results"); |
163
|
|
|
|
164
|
|
|
$this->addOption("skip", |
165
|
|
|
NULL, |
166
|
|
|
InputOption::VALUE_REQUIRED, |
167
|
|
|
"Skips the defined number of documents"); |
168
|
|
|
|
169
|
|
|
$this->addOption("include-conflicts", |
170
|
|
|
NULL, |
171
|
|
|
InputOption::VALUE_NONE, |
172
|
|
|
"Includes conflict documents"); |
173
|
|
|
|
174
|
|
|
$this->addOption("include-missing-keys", |
175
|
|
|
NULL, |
176
|
|
|
InputOption::VALUE_NONE, |
177
|
|
|
"Includes all the rows, even if a match for a key is not found"); |
178
|
|
|
|
179
|
|
|
|
180
|
|
|
// Temporary view options. |
181
|
|
|
$this->addOption("map", |
182
|
|
|
NULL, |
183
|
|
|
InputOption::VALUE_REQUIRED, |
184
|
|
|
"Load map function from this file; to be used with _temp_view only, ignored otherwise"); |
185
|
|
|
|
186
|
|
|
$this->addOption("reduce", |
187
|
|
|
NULL, |
188
|
|
|
InputOption::VALUE_REQUIRED, |
189
|
|
|
"Load reduce function from this file; to be used with _temp_view only, ignored otherwise"); |
190
|
|
|
|
191
|
|
|
$this->addOption("language", |
192
|
|
|
NULL, |
193
|
|
|
InputOption::VALUE_REQUIRED, |
194
|
|
|
"The language used to implement the map and reduce functions; if no specified, PHP assumed"); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @brief Executes the command. |
200
|
|
|
*/ |
201
|
|
|
protected function execute(InputInterface $input, OutputInterface $output) { |
202
|
|
|
$couch = $this->getConnection(); |
203
|
|
|
|
204
|
|
|
$view = $input->getArgument('design-doc/view-name'); |
205
|
|
|
|
206
|
|
|
if ($input->getArgument('keys')) { |
207
|
|
|
$args = $input->getArgument('keys'); |
208
|
|
|
|
209
|
|
|
$keys = []; |
210
|
|
|
foreach ($args as $key) |
211
|
|
|
$keys[] = $this->castArg($key, FALSE); |
|
|
|
|
212
|
|
|
} |
213
|
|
|
else |
214
|
|
|
$keys = NULL; |
215
|
|
|
|
216
|
|
|
// Sets the options. |
217
|
|
|
$opts = new ViewQueryOpts(); |
218
|
|
|
|
219
|
|
|
// Key. |
220
|
|
|
if ($key = $input->getOption('key')) |
221
|
|
|
$opts->setKey($this->castArg($key)); |
222
|
|
|
|
223
|
|
|
// Start key. |
224
|
|
|
if ($startkey = $input->getOption('startkey')) |
225
|
|
|
$opts->setStartKey($this->castArg($startkey)); |
226
|
|
|
|
227
|
|
|
// End key. |
228
|
|
|
if ($endkey = $input->getOption('endkey')) |
229
|
|
|
$opts->setEndKey($this->castArg($endkey)); |
230
|
|
|
|
231
|
|
|
// Start doc id. |
232
|
|
|
if ($docId = $input->getOption('startkey-docid')) |
233
|
|
|
$opts->setStartDocId($docId); |
234
|
|
|
|
235
|
|
|
// End doc id. |
236
|
|
|
if ($docId = $input->getOption('endkey-docid')) |
237
|
|
|
$opts->setEndDocId($docId); |
238
|
|
|
|
239
|
|
|
// Limit. |
240
|
|
|
$limit = (int)$input->getOption('limit'); |
241
|
|
|
if ($limit > 0) |
242
|
|
|
$opts->setLimit($limit); |
243
|
|
|
|
244
|
|
|
// Group results. |
245
|
|
|
if ($input->getOption('group-results')) |
246
|
|
|
$opts->groupResults(); |
247
|
|
|
|
248
|
|
|
// Sets group level. |
249
|
|
|
$level = (int)$input->getOption('group-level'); |
250
|
|
|
if ($level > 0) |
251
|
|
|
$opts->setGroupLevel($level); |
252
|
|
|
|
253
|
|
|
// Do not reduce. |
254
|
|
|
if ($input->getOption('do-not-reduce')) |
255
|
|
|
$opts->doNotReduce(); |
256
|
|
|
|
257
|
|
|
// Includes docs. |
258
|
|
|
if ($input->getOption('include-docs')) |
259
|
|
|
$opts->includeDocs(); |
260
|
|
|
|
261
|
|
|
// Excludes results. |
262
|
|
|
if ($input->getOption('exclude-results')) |
263
|
|
|
$opts->excludeResults(); |
264
|
|
|
|
265
|
|
|
// Excludes endkey. |
266
|
|
|
if ($input->getOption('exclude-endkey')) |
267
|
|
|
$opts->excludeEndKey(); |
268
|
|
|
|
269
|
|
|
// Reverses order of results. |
270
|
|
|
if ($input->getOption('reverse-order')) |
271
|
|
|
$opts->reverseOrderOfResults(); |
272
|
|
|
|
273
|
|
|
// Skips the defined number of documents. |
274
|
|
|
$skip = (int)$input->getOption('skip'); |
275
|
|
|
if ($skip > 0) |
276
|
|
|
$opts->skipDocs($skip); |
277
|
|
|
|
278
|
|
|
// Includes conflicts. |
279
|
|
|
if ($input->getOption('include-conflicts')) |
280
|
|
|
$opts->includeConflicts(); |
281
|
|
|
|
282
|
|
|
// Includes missing keys. |
283
|
|
|
if ($input->getOption('include-missing-keys')) |
284
|
|
|
$opts->includeMissingKeys(); |
285
|
|
|
|
286
|
|
|
if ($view == "_temp_view") { |
287
|
|
|
|
288
|
|
|
// Map and reduce functions. |
289
|
|
|
if ($fileName = $input->getOption('map')) { |
290
|
|
|
$map = file_get_contents($fileName); |
291
|
|
|
|
292
|
|
|
if ($fileName = $input->getOption('reduce')) |
293
|
|
|
$reduce = file_get_contents($fileName); |
294
|
|
|
else |
295
|
|
|
$reduce = ""; |
296
|
|
|
|
297
|
|
|
$language = $input->getOption('language'); |
298
|
|
|
if (empty($language)) |
299
|
|
|
$language = "php"; |
300
|
|
|
} |
301
|
|
|
else |
302
|
|
|
throw new \InvalidArgumentException("You didn't provided the map function."); |
303
|
|
|
|
304
|
|
|
print_r($couch->queryTempView($this->getDatabase(), $map, $reduce, $keys, $opts, $language)); |
305
|
|
|
} |
306
|
|
|
elseif ($view == "_all_docs") { |
307
|
|
|
print_r($couch->queryAllDocs($this->getDatabase(), $keys, $opts)); |
308
|
|
|
} |
309
|
|
|
else { |
310
|
|
|
$names = explode('/', $view, 2); |
311
|
|
|
|
312
|
|
|
if (count($names) == 2) |
313
|
|
|
print_r($couch->queryView($this->getDatabase(), $names[0], $names[1], $keys, $opts)); |
314
|
|
|
else |
315
|
|
|
throw new \InvalidArgumentException("You have to specify design-doc/view-name."); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
} |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.