* API: revisions & pageset cleanup
authorYuri Astrakhan <yurik@users.mediawiki.org>
Sat, 30 Sep 2006 08:06:27 +0000 (08:06 +0000)
committerYuri Astrakhan <yurik@users.mediawiki.org>
Sat, 30 Sep 2006 08:06:27 +0000 (08:06 +0000)
includes/api/ApiBase.php
includes/api/ApiPageSet.php
includes/api/ApiQuery.php
includes/api/ApiQueryRevisions.php

index 1f87592..c3ce8e5 100644 (file)
@@ -92,16 +92,9 @@ abstract class ApiBase {
                        $msg = $lnPrfx . implode($lnPrfx, $msg) . "\n";\r
 \r
                        // Parameters\r
-                       $params = $this->getAllowedParams();\r
-                       if ($params !== false) {\r
-                               $paramsDescription = $this->getParamDescription();\r
-                               $msg .= "Parameters:\n";\r
-                               foreach (array_keys($params) as $paramName) {\r
-                                       $desc = isset ($paramsDescription[$paramName]) ? $paramsDescription[$paramName] : '';\r
-                                       if (is_array($desc))\r
-                                               $desc = implode("\n" . str_repeat(' ', 19), $desc);\r
-                                       $msg .= sprintf("  %-14s - %s\n", $paramName, $desc);\r
-                               }\r
+                       $paramsMsg = $this->makeHelpMsgParameters();\r
+                       if ($paramsMsg !== false) {\r
+                               $msg .= "Parameters:\n$paramsMsg";\r
                        }\r
 \r
                        // Examples\r
@@ -119,6 +112,25 @@ abstract class ApiBase {
                return $msg;\r
        }\r
 \r
+       public function makeHelpMsgParameters() {\r
+               $params = $this->getAllowedParams();\r
+               if ($params !== false) {\r
+                       \r
+                       $paramsDescription = $this->getParamDescription();\r
+                       $msg = '';\r
+                       foreach (array_keys($params) as $paramName) {\r
+                               $desc = isset ($paramsDescription[$paramName]) ? $paramsDescription[$paramName] : '';\r
+                               if (is_array($desc))\r
+                                       $desc = implode("\n" . str_repeat(' ', 19), $desc);\r
+                               $msg .= sprintf("  %-14s - %s\n", $paramName, $desc);\r
+                       }\r
+                       return $msg;\r
+               \r
+               }\r
+               else\r
+                       return false; \r
+       }\r
+\r
        /**\r
         * Returns the description string for this module\r
         */\r
@@ -153,89 +165,88 @@ abstract class ApiBase {
        * This method can be used to generate local variables using extract().\r
        */\r
        public function extractRequestParams() {\r
-               global $wgRequest;\r
-\r
                $params = $this->getAllowedParams();\r
                $results = array ();\r
 \r
-               foreach ($params as $param => $enumParams) {\r
-\r
-                       if (!is_array($enumParams)) {\r
-                               $default = $enumParams;\r
-                               $multi = false;\r
-                               $type = gettype($enumParams);\r
-                       } else {\r
-                               $default = isset ($enumParams[GN_ENUM_DFLT]) ? $enumParams[GN_ENUM_DFLT] : null;\r
-                               $multi = isset ($enumParams[GN_ENUM_ISMULTI]) ? $enumParams[GN_ENUM_ISMULTI] : false;\r
-                               $type = isset ($enumParams[GN_ENUM_TYPE]) ? $enumParams[GN_ENUM_TYPE] : null;\r
-\r
-                               // When type is not given, and no choices, the type is the same as $default\r
-                               if (!isset ($type)) {\r
-                                       if (isset ($default))\r
-                                               $type = gettype($default);\r
-                                       else\r
-                                               $type = 'NULL'; // allow everything\r
-                               }\r
-                       }\r
+               foreach ($params as $paramName => $paramSettings)\r
+                       $results[$paramName] = $this->getParameter($paramName, $paramSettings);\r
 \r
-                       if ($type == 'boolean') {\r
-                               if (!isset ($default))\r
-                                       $default = false;\r
+               return $results;\r
+       }\r
 \r
-                               if ($default !== false) {\r
-                                       // Having a default value of anything other than 'false' is pointless\r
-                                       $this->dieDebug("Boolean param $param's default is set to '$default'");\r
-                               }\r
+       public function getParameter($paramName, $paramSettings){\r
+               global $wgRequest;\r
+\r
+               if (!is_array($paramSettings)) {\r
+                       $default = $paramSettings;\r
+                       $multi = false;\r
+                       $type = gettype($paramSettings);\r
+               } else {\r
+                       $default = isset ($paramSettings[GN_ENUM_DFLT]) ? $paramSettings[GN_ENUM_DFLT] : null;\r
+                       $multi = isset ($paramSettings[GN_ENUM_ISMULTI]) ? $paramSettings[GN_ENUM_ISMULTI] : false;\r
+                       $type = isset ($paramSettings[GN_ENUM_TYPE]) ? $paramSettings[GN_ENUM_TYPE] : null;\r
+\r
+                       // When type is not given, and no choices, the type is the same as $default\r
+                       if (!isset ($type)) {\r
+                               if (isset ($default))\r
+                                       $type = gettype($default);\r
+                               else\r
+                                       $type = 'NULL'; // allow everything\r
                        }\r
+               }\r
 \r
-                       $value = $wgRequest->getVal($param, $default);\r
-\r
-                       if (isset ($value) && ($multi || is_array($type)))\r
-                               $value = $this->parseMultiValue($param, $value, $multi, is_array($type) ? $type : null);\r
-\r
-                       // More validation only when choices were not given\r
-                       // choices were validated in parseMultiValue()\r
-                       if (!is_array($type) && isset ($value)) {\r
-\r
-                               switch ($type) {\r
-                                       case 'NULL' : // nothing to do\r
-                                               break;\r
-                                       case 'string' : // nothing to do\r
-                                               break;\r
-                                       case 'integer' : // Force everything using intval()\r
-                                               $value = is_array($value) ? array_map('intval', $value) : intval($value);\r
-                                               break;\r
-                                       case 'limit' :\r
-                                               if (!isset ($enumParams[GN_ENUM_MAX1]) || !isset ($enumParams[GN_ENUM_MAX2]))\r
-                                                       $this->dieDebug("MAX1 or MAX2 are not defined for the limit $param");\r
-                                               if ($multi)\r
-                                                       $this->dieDebug("Multi-values not supported for $param");\r
-                                               $min = isset ($enumParams[GN_ENUM_MIN]) ? $enumParams[GN_ENUM_MIN] : 0;\r
-                                               $value = intval($value);\r
-                                               $this->validateLimit($param, $value, $min, $enumParams[GN_ENUM_MAX1], $enumParams[GN_ENUM_MAX2]);\r
-                                               break;\r
-                                       case 'boolean' :\r
-                                               if ($multi)\r
-                                                       $this->dieDebug("Multi-values not supported for $param");\r
-                                               $value = isset ($value);\r
-                                               break;\r
-                                       case 'timestamp' :\r
-                                               if ($multi)\r
-                                                       $this->dieDebug("Multi-values not supported for $param");\r
-                                               $value = $this->prepareTimestamp($value); // Adds quotes around timestamp                                                       \r
-                                               break;\r
-                                       default :\r
-                                               $this->dieDebug("Param $param's type is unknown - $type");\r
-\r
-                               }\r
+               if ($type == 'boolean') {\r
+                       if (isset ($default) && $default !== false) {\r
+                               // Having a default value of anything other than 'false' is pointless\r
+                               $this->dieDebug("Boolean param $paramName's default is set to '$default'");\r
                        }\r
 \r
-                       $results[$param] = $value;\r
+            $value = $wgRequest->getCheck($paramName);\r
+               } else\r
+               $value = $wgRequest->getVal($paramName, $default);\r
+\r
+               if (isset ($value) && ($multi || is_array($type)))\r
+                       $value = $this->parseMultiValue($paramName, $value, $multi, is_array($type) ? $type : null);\r
+\r
+               // More validation only when choices were not given\r
+               // choices were validated in parseMultiValue()\r
+               if (!is_array($type) && isset ($value)) {\r
+\r
+                       switch ($type) {\r
+                               case 'NULL' : // nothing to do\r
+                                       break;\r
+                               case 'string' : // nothing to do\r
+                                       break;\r
+                               case 'integer' : // Force everything using intval()\r
+                                       $value = is_array($value) ? array_map('intval', $value) : intval($value);\r
+                                       break;\r
+                               case 'limit' :\r
+                                       if (!isset ($paramSettings[GN_ENUM_MAX1]) || !isset ($paramSettings[GN_ENUM_MAX2]))\r
+                                               $this->dieDebug("MAX1 or MAX2 are not defined for the limit $paramName");\r
+                                       if ($multi)\r
+                                               $this->dieDebug("Multi-values not supported for $paramName");\r
+                                       $min = isset ($paramSettings[GN_ENUM_MIN]) ? $paramSettings[GN_ENUM_MIN] : 0;\r
+                                       $value = intval($value);\r
+                                       $this->validateLimit($paramName, $value, $min, $paramSettings[GN_ENUM_MAX1], $paramSettings[GN_ENUM_MAX2]);\r
+                                       break;\r
+                               case 'boolean' :\r
+                                       if ($multi)\r
+                                               $this->dieDebug("Multi-values not supported for $paramName");\r
+                                       break;\r
+                               case 'timestamp' :\r
+                                       if ($multi)\r
+                                               $this->dieDebug("Multi-values not supported for $paramName");\r
+                                       $value = $this->prepareTimestamp($value); // Adds quotes around timestamp                                                       \r
+                                       break;\r
+                               default :\r
+                                       $this->dieDebug("Param $paramName's type is unknown - $type");\r
+\r
+                       }\r
                }\r
 \r
-               return $results;\r
+               return $value;  \r
        }\r
-\r
+       \r
        /**\r
        * Return an array of values that were given in a "a|b|c" notation,\r
        * after it optionally validates them against the list allowed values.\r
index 7854e94..eaa97ae 100644 (file)
@@ -32,12 +32,10 @@ if (!defined('MEDIAWIKI')) {
 class ApiPageSet extends ApiQueryBase {
 
        private $mAllPages; // [ns][dbkey] => page_id or 0 when missing
-       private $mResolveRedirs;
        private $mGoodTitles, $mMissingTitles, $mRedirectTitles, $mNormalizedTitles;
 
-       public function __construct($query, $resolveRedirs) {
+       public function __construct($query) {
                parent :: __construct($query, __CLASS__);
-               $this->mResolveRedirs = $resolveRedirs;
 
                $this->mAllPages = array ();
                $this->mGoodTitles = array ();
@@ -82,9 +80,23 @@ class ApiPageSet extends ApiQueryBase {
        /**
         * Returns the number of unique pages (not revisions) in the set.
         */
-       public function getPageCount() {
+       public function getGoodTitleCount() {
                return count($this->getGoodTitles());
        }
+       
+       /**
+        * Get the list of revision IDs (requested with revids= parameter)
+        */
+       public function getRevisionIDs() {
+               $this->dieUsage(__FUNCTION__ . " is not implemented", 'notimplemented');
+       }
+       
+       /**
+        * Returns the number of revisions (requested with revids= parameter)
+        */
+       public function getRevisionCount() {
+               return 0; // TODO: implement
+       }
 
        /**
         * This method populates internal variables with page information
@@ -100,19 +112,19 @@ class ApiPageSet extends ApiQueryBase {
         * #5 Substitute the original LinkBatch object with the new list
         * #6 Repeat from step #1     
         */
-       public function populateTitles($titles) {
-               $this->profileIn();
+       private function populateTitles($titles, $redirects) {
+               
                $pageFlds = array (
                        'page_id',
                        'page_namespace',
                        'page_title'
                );
-               if ($this->mResolveRedirs) {
+               if ($redirects) {
                        $pageFlds[] = 'page_is_redirect';
                }
 
                // Get validated and normalized title objects
-               $linkBatch = $this->processTitlesStrings($titles);
+               $linkBatch = $this->processTitlesStrArray($titles);
 
                $db = $this->getDB();
 
@@ -138,7 +150,7 @@ class ApiPageSet extends ApiQueryBase {
                                $title = Title :: makeTitle($row->page_namespace, $row->page_title);
                                $this->mAllPages[$row->page_namespace][$row->page_title] = $row->page_id;
 
-                               if ($this->mResolveRedirs && $row->page_is_redirect == '1') {
+                               if ($redirects && $row->page_is_redirect == '1') {
                                        $redirectIds[$row->page_id] = $title;
                                } else {
                                        $this->mGoodTitles[$row->page_id] = $title;
@@ -156,7 +168,7 @@ class ApiPageSet extends ApiQueryBase {
                                }
                        }
 
-                       if (!$this->mResolveRedirs || empty ($redirectIds))
+                       if (!$redirects || empty ($redirectIds))
                                break;
 
                        //
@@ -199,7 +211,6 @@ class ApiPageSet extends ApiQueryBase {
                        }
                        $db->freeResult($res);
                }
-               $this->profileOut();
        }
 
        /**
@@ -209,7 +220,7 @@ class ApiPageSet extends ApiQueryBase {
         * 
         * @return LinkBatch of title objects.
         */
-       private function processTitlesStrings($titles) {
+       private function processTitlesStrArray($titles) {
 
                $linkBatch = new LinkBatch();
 
@@ -237,12 +248,69 @@ class ApiPageSet extends ApiQueryBase {
                return $linkBatch;
        }
 
-       public function populatePageIDs($pageids) {
+       private function populatePageIDs($pageids) {
                $this->dieUsage(__FUNCTION__ . " is not implemented", 'notimplemented');
        }
 
        public function execute() {
-               $this->dieDebug("execute() is not supported on this object");
+               $titles = $pageids = $revids = $redirects = null;
+               extract($this->extractRequestParams());
+               
+               // Only one of the titles/pageids/revids is allowed at the same time
+               $dataSource = null;
+               if (isset ($titles))
+                       $dataSource = 'titles';
+               if (isset ($pageids)) {
+                       if (isset ($dataSource))
+                               $this->dieUsage("Cannot use 'pageids' at the same time as '$dataSource'", 'multisource');
+                       $dataSource = 'pageids';
+               }
+               if (isset ($revids)) {
+                       if (isset ($dataSource))
+                               $this->dieUsage("Cannot use 'revids' at the same time as '$dataSource'", 'multisource');
+                       $dataSource = 'revids';
+               }
+
+               switch ($dataSource) {
+                       case 'titles' :
+                               $this->populateTitles($titles, $redirects);
+                               break;
+                       case 'pageids' :
+                               $this->populatePageIDs($pageids, $redirects);
+                               break;
+                       case 'revids' :
+                               $this->populateRevIDs($revids);
+                               break;
+                       default :
+                               // Do nothing - some queries do not need any of the data sources.
+                               break;
+               }
+       }
+
+       protected function getAllowedParams() {
+               return array (
+                       'titles' => array (
+                               GN_ENUM_ISMULTI => true
+                       ),
+                       'pageids' => array (
+                               GN_ENUM_TYPE => 'integer',
+                               GN_ENUM_ISMULTI => true
+                       ),
+                       'revids' => array (
+                               GN_ENUM_TYPE => 'integer',
+                               GN_ENUM_ISMULTI => true
+                       ),
+                       'redirects' => false
+               );
+       }
+       
+       protected function getParamDescription() {
+               return array (
+                       'titles' => 'A list of titles to work on',
+                       'pageids' => 'A list of page IDs to work on',
+                       'revids' => 'A list of revision IDs to work on',
+                       'redirects' => 'Automatically resolve redirects'
+               );
        }
 }
 ?>
\ No newline at end of file
index 5bddbac..d882a53 100644 (file)
@@ -96,30 +96,22 @@ class ApiQuery extends ApiBase {
         * #5 Execute all requested modules\r
         */\r
        public function execute() {\r
-               $meta = $prop = $list = $generator = $titles = $pageids = null;\r
-               $redirects = null;\r
+               $meta = $prop = $list = $generator = null;\r
                extract($this->extractRequestParams());\r
 \r
                //\r
                // Create and initialize PageSet\r
                //\r
-               $dataSource = null;\r
-               if (isset ($titles) && isset($pageids))\r
-                       $this->dieUsage("At present you may not use titles= and pageids= at the same time", 'multisource');\r
-\r
-               $this->mData = new ApiPageSet($this, $redirects);\r
-\r
-               if (isset($titles))\r
-                       $this->mData->populateTitles($titles);\r
-\r
-               if (isset($pageids))\r
-                       $this->mData->populatePageIDs($pageids);\r
+               $this->mData = new ApiPageSet($this);\r
+               $this->mData->profileIn();\r
+               $this->mData->execute();\r
+               $this->mData->profileOut();\r
 \r
                //\r
                // If generator is provided, get a new dataset to work on\r
                //\r
                if (isset ($generator))\r
-                       $this->executeGenerator($generator, $redirects);\r
+                       $this->executeGenerator($generator);\r
 \r
                // Instantiate required modules\r
                // During instantiation, modules may optimize data requests through the $this->mData object \r
@@ -145,14 +137,12 @@ class ApiQuery extends ApiBase {
                }\r
 \r
                // Show redirect information\r
-               if ($redirects) {\r
-                       foreach ($this->mData->getRedirectTitles() as $titleStrFrom => $titleStrTo) {\r
-                               $this->getResult()->addMessage('query', 'redirects', array (\r
-                                       'from' => $titleStrFrom,\r
-                                       'to' => $titleStrTo,\r
-                                       '*' => ''\r
-                               ), 'r');\r
-                       }\r
+               foreach ($this->mData->getRedirectTitles() as $titleStrFrom => $titleStrTo) {\r
+                       $this->getResult()->addMessage('query', 'redirects', array (\r
+                               'from' => $titleStrFrom,\r
+                               'to' => $titleStrTo,\r
+                               '*' => ''\r
+                       ), 'r');\r
                }\r
 \r
                // Execute all requested modules.\r
@@ -163,7 +153,7 @@ class ApiQuery extends ApiBase {
                }\r
        }\r
 \r
-       protected function executeGenerator($generator, $redirects) {\r
+       protected function executeGenerator($generator) {\r
 \r
                // Find class that implements requested generator\r
                if (isset ($this->mQueryListModules[$generator]))\r
@@ -195,18 +185,10 @@ class ApiQuery extends ApiBase {
                        'list' => array (\r
                                GN_ENUM_ISMULTI => true,\r
                                GN_ENUM_TYPE => $this->mListModuleNames\r
-                       ),\r
+                       )\r
                        //                      'generator' => array (\r
                        //                              GN_ENUM_TYPE => $this->mAllowedGenerators\r
                        //                      ),\r
-                       'titles' => array (\r
-                               GN_ENUM_ISMULTI => true\r
-                       ),\r
-                       //                      'pageids' => array (\r
-                       //                              GN_ENUM_TYPE => 'integer',\r
-                       //                              GN_ENUM_ISMULTI => true\r
-                       //                      ),\r
-                       'redirects' => false\r
                );\r
        }\r
 \r
@@ -250,15 +232,21 @@ class ApiQuery extends ApiBase {
                return $msg;\r
        }\r
 \r
+       /**\r
+        * Override to add extra parameters from PageSet\r
+        */     \r
+       public function makeHelpMsgParameters() {\r
+               $module = new ApiPageSet($this);\r
+               return $module->makeHelpMsgParameters() . parent :: makeHelpMsgParameters();\r
+       }\r
+       \r
+\r
        protected function getParamDescription() {\r
                return array (\r
                        'meta' => 'Which meta data to get about the site',\r
                        'prop' => 'Which properties to get for the titles/revisions/pageids',\r
                        'list' => 'Which lists to get',\r
                        'generator' => 'Use the output of a list as the input for other prop/list/meta items',\r
-                       'titles' => 'A list of titles to work on',\r
-                       'pageids' => 'A list of page IDs to work on',\r
-                       'redirects' => 'Automatically resolve redirects'\r
                );\r
        }\r
 \r
index 4be5d7a..83771b9 100644 (file)
@@ -36,40 +36,33 @@ class ApiQueryRevisions extends ApiQueryBase {
        }
 
        public function execute() {
-               $rvrevids = $rvlimit = $rvstartid = $rvendid = $rvstart = $rvend = $rvdir = $rvprop = null;
+               $rvlimit = $rvstartid = $rvendid = $rvstart = $rvend = $rvdir = $rvprop = null;
                extract($this->extractRequestParams());
 
-               //
-               // Parameter validation
-               //
-
                // true when ordered by timestamp from older to newer, false otherwise
                $dirNewer = ($rvdir === 'newer');
 
-               // If any of those parameters are used, we can only work with a single page
+               // If any of those parameters are used, work in "enumeration" mode.
+               // Enum mode can only be used when exactly one page is provided.
                // Enumerating revisions on multiple pages make it extremelly 
                // difficult to manage continuations and require additional sql indexes  
                $enumRevMode = ($rvlimit !== 0 || $rvstartid !== 0 || $rvendid !== 0 || $dirNewer || isset ($rvstart) || isset ($rvend));
 
-               if ($rvstartid !== 0 || $rvendid !== 0)
-                       $this->dieUsage('rvstartid/rvendid not implemented', 'notimplemented');
-
                $data = $this->getData();
-               $pageCount = $data->getPageCount();
+               $pageCount = $data->getGoodTitleCount();
+               $revCount = $data->getRevisionCount();
 
-               if (!empty ($rvrevids)) {
-                       if ($pageCount > 0)
-                               $this->dieUsage('The rvrevids= parameter may not be used with titles, pageids, and generator options.', 'rv_rvrevids');
+               if ($revCount > 0 && $pageCount > 0)
+                       $this->dieUsage('The rvrevids= parameter may not be used with titles, pageids, and generator options.', 'rv_rvrevids');
 
-                       if ($enumRevMode)
-                               $this->dieUsage('The rvrevids= parameter may not be used with the list options (rvlimit, rvstartid, rvendid, dirNewer, rvstart, rvend).', 'rv_rvrevids');
-               } else {
-                       if ($pageCount < 1)
-                               $this->dieUsage('No pages were given. Please use titles, pageids or a generator to provide page(s) to work on.', 'rv_no_pages');
+               if ($revCount > 0 && $enumRevMode)
+                       $this->dieUsage('The rvrevids= parameter may not be used with the list options (rvlimit, rvstartid, rvendid, dirNewer, rvstart, rvend).', 'rv_rvrevids');
 
-                       if ($enumRevMode && $pageCount > 1)
-                               $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the rvlimit, rvstartid, rvendid, dirNewer, rvstart, and rvend parameters may only be used on a single page.', 'rv_multpages');
-               }
+               if ($revCount === 0 && $pageCount === 0)
+                       $this->dieUsage('No pages were given. Please use titles, pageids or a generator to provide page(s) to work on.', 'rv_no_pages');
+
+               if ($revCount === 0 && $pageCount > 1 && $enumRevMode)
+                       $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the rvlimit, rvstartid, rvendid, dirNewer, rvstart, and rvend parameters may only be used on a single page.', 'rv_multpages');
 
                $tables = array (
                        'revision'
@@ -111,7 +104,7 @@ class ApiQueryRevisions extends ApiQueryBase {
                                                $fields[] = 'old_id';
                                                $fields[] = 'old_text';
                                                $fields[] = 'old_flags';
-                        $showContent = true;
+                                               $showContent = true;
                                                break;
                                        default :
                                                $this->dieDebug("unknown rvprop $prop");
@@ -124,37 +117,60 @@ class ApiQueryRevisions extends ApiQueryBase {
 
                if ($enumRevMode) {
 
+                       // This is mostly to prevent parameter errors (and optimize sql?)
+                       if ($rvstartid !== 0 && isset ($rvstart))
+                               $this->dieUsage('rvstart and rvstartid cannot be used together', 'rv_badparams');
+
+                       if ($rvendid !== 0 && isset ($rvend))
+                               $this->dieUsage('rvend and rvend cannot be used together', 'rv_badparams');
+
+                       $options['ORDER BY'] = 'rev_timestamp' . ($dirNewer ? '' : ' DESC');
+                       $before = ($dirNewer ? '<=' : '>=');
+                       $after = ($dirNewer ? '>=' : '<=');
+
+                       if ($rvstartid !== 0)
+                               $conds[] = 'rev_id' . $after . intval($rvstartid);
+                       if ($rvendid !== 0)
+                               $conds[] = 'rev_id' . $before . intval($rvendid);
                        if (isset ($rvstart))
-                               $conds[] = 'rev_timestamp >= ' . $this->prepareTimestamp($rvstart);
+                               $conds[] = 'rev_timestamp' . $after . $this->prepareTimestamp($rvstart);
                        if (isset ($rvend))
-                               $conds[] = 'rev_timestamp <= ' . $this->prepareTimestamp($rvend);
+                               $conds[] = 'rev_timestamp' . $before . $this->prepareTimestamp($rvend);
 
                        // must manually initialize unset rvlimit
                        if (!isset ($rvlimit))
                                $rvlimit = 10;
 
-                       $options['ORDER BY'] = 'rev_timestamp' . ($dirNewer ? '' : ' DESC');
-
                        $this->validateLimit('rvlimit', $rvlimit, 1, $userMax, $botMax);
 
-                       // There is only one ID
-                       $conds['rev_page'] = array_keys($data->getGoodTitles());
-
-               } else {
-                       // When working in multi-page non-enumeration mode,
-                       // limit to the latest revision only
-                       $tables[] = 'page';
-                       $conds[] = 'page_id=rev_page';
-                       $conds[] = 'page_latest=rev_id';
-                       $this->validateLimit('page_count', $pageCount, 1, $userMax, $botMax);
-
-                       // Get all page IDs
-                       $conds['page_id'] = array_keys($data->getGoodTitles());
-            
-            $rvlimit = $pageCount; // assumption testing -- we should never get more then $pageCount rows.
-               }
+                       // There is only one ID, use it
+                       $conds['rev_page'] = array_pop(array_keys($data->getGoodTitles()));
+
+               } else
+                       if ($pageCount > 0) {
+                               // When working in multi-page non-enumeration mode,
+                               // limit to the latest revision only
+                               $tables[] = 'page';
+                               $conds[] = 'page_id=rev_page';
+                               $conds[] = 'page_latest=rev_id';
+                               $this->validateLimit('page_count', $pageCount, 1, $userMax, $botMax);
+
+                               // Get all page IDs
+                               $conds['page_id'] = array_keys($data->getGoodTitles());
+
+                               $rvlimit = $pageCount; // assumption testing -- we should never get more then $pageCount rows.
+                       } else
+                               if ($revCount > 0) {
+                                       $this->validateLimit('rev_count', $revCount, 1, $userMax, $botMax);
+
+                                       // Get all revision IDs
+                                       $conds['rev_id'] = array_keys($data->getRevisionIDs());
 
-        $options['LIMIT'] = $rvlimit +1;
+                                       $rvlimit = $revCount; // assumption testing -- we should never get more then $revCount rows.
+                               } else
+                                       $this->dieDebug('param validation?');
+
+               $options['LIMIT'] = $rvlimit +1;
 
                $db = $this->getDB();
                $this->profileDBIn();
@@ -167,9 +183,9 @@ class ApiQueryRevisions extends ApiQueryBase {
 
                        if (++ $count > $rvlimit) {
                                // We've reached the one extra which shows that there are additional pages to be had. Stop here...
-                if (!$enumRevMode)
-                    $this->dieDebug('Got more rows then expected'); // bug report
-                
+                               if (!$enumRevMode)
+                                       $this->dieDebug('Got more rows then expected'); // bug report
+
                                $startStr = 'rvstartid=' . $row->rev_id;
                                $msg = array (
                                        'continue' => $startStr
@@ -179,9 +195,8 @@ class ApiQueryRevisions extends ApiQueryBase {
                        }
 
                        $vals = array (
-                               'revid' => intval($row->rev_id),
-                               'oldid' => intval($row->rev_text_id
-                       ));
+                               'revid' => intval($row->rev_id
+                       ), 'oldid' => intval($row->rev_text_id));
 
                        if ($row->rev_minor_edit) {
                                $vals['minor'] = '';
@@ -255,7 +270,13 @@ class ApiQueryRevisions extends ApiQueryBase {
        }
 
        protected function getDescription() {
-               return 'module a';
+               return array (
+                       'Get revision information.',
+                       'This module may be used in several ways:',
+                       ' 1) Get data about a set of pages (last revision), by setting titles or pageids parameter.',
+                       ' 2) Get revisions for one given page, by using titles/pageids with rvstart*/rvend*/rvlimit params.',
+                       ' 3) Get data about a set of revisions by setting their IDs with revids parameter.'
+               );
        }
 
        protected function getExamples() {