[PATCH] add rpc v6: support multiple _by_ fields

尤立宇 afg984 at gmail.com
Fri Jun 1 03:24:16 UTC 2018


Hi, this is a WIP patch following up the one at March:
[PATCH] feat(rpc): return "providers" packages when querying by `name`
or `name-desc`
(I failed to make git-send-email to reply to the thread)

The goal is to allow tools to use the RPC to resolve dependencies reliably,
by introducing a new version of the RPC (v6):
1. Support querying by the provides field
2. Support querying with multiple _by_, for example, by[]=name&by[]=provides

The design pretty much follows the one discussed (in the thread
mentioned above) previously,
I can bring up more context if needed.
Here's a draft document of how it works:
https://github.com/afg984/aurweb/wiki/aurweb-RPC-Interface-(v6-draft)

This is a WIP patch, and I'd like to get some feedback before moving on.

There are a few things worth noting:
1. commit 1ff40987 implemented search by depends, checkdepends,
optdepends. They are currently left out.
2. v5 allowed searching for orphan packages by leaving out the arg=
argument. This is left out as well.
3. as search and info is now a similar concept (and a little different
than those in v5), I've implemented them in a separate function. I'd
like to know if this is the way to go, or I should try to reuse the
existing structure.

2018-06-01 10:50 GMT+08:00 Li-Yu Yu <afg984 at gmail.com>:
> ---
>  web/lib/aurjson.class.php | 125 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 120 insertions(+), 5 deletions(-)
>
> diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php
> index c51e9c2..db11117 100644
> --- a/web/lib/aurjson.class.php
> +++ b/web/lib/aurjson.class.php
> @@ -20,6 +20,14 @@ class AurJSON {
>                 'name', 'name-desc', 'maintainer',
>                 'depends', 'makedepends', 'checkdepends', 'optdepends'
>         );
> +       private static $exposed_fields_v6 = array(
> +               'name', 'description', 'maintainer', 'provides',
> +       );
> +       private static $exposed_fields_map_v6 = array(
> +               'name' => 'Packages.Name',
> +               'description' => 'Packages.Description',
> +               'maintainer' => 'Packages.Maintainer',
> +       );
>         private static $exposed_depfields = array(
>                 'depends', 'makedepends', 'checkdepends', 'optdepends'
>         );
> @@ -80,7 +88,7 @@ class AurJSON {
>                 if (isset($http_data['v'])) {
>                         $this->version = intval($http_data['v']);
>                 }
> -               if ($this->version < 1 || $this->version > 5) {
> +               if ($this->version < 1 || $this->version > 6) {
>                         return $this->json_error('Invalid version specified.');
>                 }
>
> @@ -94,8 +102,21 @@ class AurJSON {
>                 if (isset($http_data['search_by']) && !isset($http_data['by'])) {
>                         $http_data['by'] = $http_data['search_by'];
>                 }
> -               if (isset($http_data['by']) && !in_array($http_data['by'], self::$exposed_fields)) {
> -                       return $this->json_error('Incorrect by field specified.');
> +               if (isset($http_data['by'])) {
> +                       if ($this->version < 6) {
> +                               if (!in_array($http_data['by'], self::$exposed_fields)) {
> +                                       return $this->json_error('Incorrect by field specified.');
> +                               }
> +                       } else {
> +                               if (!is_array($http_data['by'])) {
> +                                       $http_data['by'] = array($http_data['by']);
> +                               }
> +                               foreach ($http_data['by'] as $by) {
> +                                       if (!in_array($by, self::$exposed_fields_v6)) {
> +                                               return $this->json_error("Incorrect by field '$by' specified.");
> +                                       }
> +                               }
> +                       }
>                 }
>
>                 $this->dbh = DB::connect();
> @@ -109,7 +130,11 @@ class AurJSON {
>                 if ($type == 'info' && $this->version >= 5) {
>                         $type = 'multiinfo';
>                 }
> -               $json = call_user_func(array(&$this, $type), $http_data);
> +               if ($this->version < 6) {
> +                       $json = call_user_func(array(&$this, $type), $http_data);
> +               } else {
> +                       $json = $this->info_search_v6($type, $http_data);
> +               }
>
>                 $etag = md5($json);
>                 header("Etag: \"$etag\"");
> @@ -374,6 +399,21 @@ class AurJSON {
>                 }
>                 $result = $this->dbh->query($query);
>
> +               return $this->process_result($type, $result);
> +       }
> +
> +
> +       /*
> +        * Retrieve package information from a dbh->query result
> +        *
> +        * @param $type The request type.
> +        * @param $result A dbh->query result.
> +        *
> +        * @return mixed Returns an array of package matches.
> +        */
> +       private function process_result($type, $result) {
> +               $max_results = config_get_int('options', 'max_rpc_results');
> +
>                 if ($result) {
>                         $resultcount = 0;
>                         $search_data = array();
> @@ -515,6 +555,82 @@ class AurJSON {
>                 return $this->process_query('search', $where_condition);
>         }
>
> +       /*
> +        * Performs a info or search query to the package database.
> +        *
> +        * @param $type The request type.
> +        * @param array $http_data Query parameters.
> +        *
> +        * @return mixed Returns an array of package matches.
> +        */
> +       private function info_search_v6($type, $http_data) {
> +               if (isset($http_data['by'])) {
> +                       $query_by = $http_data['by'];
> +                       if (!is_array($query_by)) {
> +                               $query_by = array($query_by);
> +                       }
> +               } else {
> +                       if ($type == "multiinfo") {
> +                               $query_by = array('name');
> +                       } else { // search
> +                               $query_by = array('name', 'description');
> +                       }
> +               }
> +
> +               if ($type == "multiinfo") {
> +                       $args = $http_data['arg'];
> +                       if (!is_array($args)) {
> +                               $args = array($args);
> +                       }
> +                       foreach ($args as $i => $arg) {
> +                               $args[$i] = $this->dbh->quote($arg);
> +                       }
> +                       $op_rhs = " IN (" . implode(",", $args) . ")";
> +               } else {
> +                       $keyword_string = $http_data['arg'];
> +                       $keyword_string = $this->dbh->quote("%" . addcslashes($keyword_string, '%_') . "%");
> +                       $op_rhs = " LIKE " . $keyword_string;
> +               }
> +
> +               $has_provides_query = false;
> +               $where_condition = "";
> +               foreach ($query_by as $index => $by) {
> +                       if ($index != 0) {
> +                               $where_condition .= " OR ";
> +                       }
> +                       if ($by == "provides") {
> +                               $has_provides_query = true;
> +                               $where_condition .= "(RelationTypes.Name = 'provides' AND ";
> +                               $where_condition .= "PackageRelations.RelName $op_rhs)";
> +                       } else {
> +                               $where_condition .= self::$exposed_fields_map_v6[$by];
> +                               $where_condition .= $op_rhs;
> +                       }
> +               }
> +
> +               $max_results = config_get_int('options', 'max_rpc_results');
> +               $fields = implode(',', self::$fields_v4);
> +               $q = "SELECT {$fields} " .
> +                       "FROM Packages LEFT JOIN PackageBases " .
> +                       "ON PackageBases.ID = Packages.PackageBaseID " .
> +                       "LEFT JOIN Users " .
> +                       "ON PackageBases.MaintainerUID = Users.ID ";
> +               if ($has_provides_query) {
> +                       $q .= "LEFT JOIN PackageRelations ON PackageRelations.PackageID = Packages.ID ";
> +                       $q .= "LEFT JOIN RelationTypes ON RelationTypes.ID = PackageRelations.RelTypeID ";
> +               }
> +               $q .= "WHERE ${where_condition} ";
> +               $q .= "AND PackageBases.PackagerUID IS NOT NULL ";
> +               if ($has_provides_query) {
> +                       $q .= "GROUP BY Packages.ID ";
> +               }
> +               $q .= "LIMIT $max_results";
> +
> +               $result = $this->dbh->query($q);
> +
> +               return $this->process_result($type, $result);
> +       }
> +
>         /*
>          * Returns the info on a specific package.
>          *
> @@ -680,4 +796,3 @@ class AurJSON {
>                 return json_encode($output);
>         }
>  }
> -
> --
> 2.17.1
>


More information about the aur-dev mailing list