#1222 Support the stream_version_lte filter in the API
Merged 5 years ago by mprahl. Opened 5 years ago by mprahl.

file modified
+2
@@ -532,6 +532,8 @@ 

    parameter can be given multiple times, in which case or-ing will be used.

  - ``state_reason``

  - ``stream``

+ - ``stream_version_lte`` - less than or equal to the stream version. This is limited to

+   the major version. This value only applies to base modules.

  - ``submitted_after`` - Zulu ISO 8601 format e.g. ``submitted_after=2016-08-22T09:40:07Z``

  - ``submitted_before`` - Zulu ISO 8601 format e.g. ``submitted_before=2016-08-23T09:40:07Z``

  - ``version``

@@ -366,6 +366,25 @@ 

              .filter(ModuleBuild.context.like(context + '%')).all()

  

      @staticmethod

+     def _add_stream_version_lte_filter(session, query, stream_version):

+         """

+         Adds a less than or equal to filter for stream versions based on x.y.z versioning.

+ 

+         In essence, the filter does `XX0000 <= stream_version <= XXYYZZ`

+ 

+         :param session: a SQLAlchemy session

+         :param query: a SQLAlchemy query to add the filtering to

+         :param int stream_version: the stream version to filter on

+         :return: the query with the added stream version filter

+         """

+         # Compute the minimal stream_version. For example, for `stream_version` 281234,

+         # the minimal `stream_version` is 280000.

+         min_stream_version = (stream_version // 10000) * 10000

+         return query\

+             .filter(ModuleBuild.stream_version <= stream_version)\

+             .filter(ModuleBuild.stream_version >= min_stream_version)

+ 

+     @staticmethod

      def get_last_builds_in_stream_version_lte(session, name, stream_version):

          """

          Returns the latest builds in "ready" state for given name:stream limited by
@@ -378,16 +397,13 @@ 

          :param str name: Name of the module to search builds for.

          :param int stream_version: Maximum stream_version to search builds for.

          """

-         # Compute the minimal stream_version - for example for `stream_version` 281234,

-         # the minimal `stream_version` is 280000.

-         min_stream_version = (stream_version // 10000) * 10000

- 

          query = session.query(ModuleBuild)\

              .filter(ModuleBuild.name == name)\

              .filter(ModuleBuild.state == BUILD_STATES["ready"])\

-             .filter(ModuleBuild.stream_version <= stream_version)\

-             .filter(ModuleBuild.stream_version >= min_stream_version)\

              .order_by(ModuleBuild.version.desc())

+ 

+         query = ModuleBuild._add_stream_version_lte_filter(session, query, stream_version)

+ 

          builds = query.all()

  

          # In case there are multiple versions of single name:stream build, we want to return

@@ -32,7 +32,7 @@ 

  from sqlalchemy.orm import aliased

  import sqlalchemy

  

- from module_build_service import models, api_version, conf

+ from module_build_service import models, api_version, conf, db

  from module_build_service.errors import ValidationError, NotFound

  from .general import scm_url_schemes

  
@@ -206,11 +206,13 @@ 

      :return: flask_sqlalchemy.Pagination

      """

      search_query = dict()

-     special_columns = ['time_submitted', 'time_modified', 'time_completed', 'state']

-     for key in request.args.keys():

+     special_columns = set((

+         'time_submitted', 'time_modified', 'time_completed', 'state', 'stream_version_lte',))

+     columns = models.ModuleBuild.__table__.columns.keys()

+     for key in set(request.args.keys()) - special_columns:

          # Only filter on valid database columns but skip columns that are treated specially or

          # ignored

-         if key not in special_columns and key in models.ModuleBuild.__table__.columns.keys():

+         if key in columns:

              search_query[key] = flask_request.args[key]

  

      # Multiple states can be supplied => or-ing will take place
@@ -281,6 +283,21 @@ 

                  elif context == 'before':

                      query = query.filter(column <= item_datetime)

  

+     stream_version_lte = flask_request.args.get('stream_version_lte')

+     if stream_version_lte is not None:

+         invalid_error = ('An invalid value of stream_version_lte was provided. It must be an '

+                          'integer greater than or equal to 10000.')

+         try:

+             stream_version_lte = int(stream_version_lte)

+         except (TypeError, ValueError):

+             raise ValidationError(invalid_error)

+ 

+         if stream_version_lte < 10000:

+             raise ValidationError(invalid_error)

+ 

+         query = models.ModuleBuild._add_stream_version_lte_filter(

+             db.session, query, stream_version_lte)

+ 

      br_joined = False

      module_br_alias = None

      for item in ('base_module_br', 'name', 'stream', 'version', 'context', 'stream_version',

@@ -652,6 +652,28 @@ 

                                     'provided for the \"modified_after\" parameter')

          assert data['status'] == 400

  

+     @pytest.mark.parametrize('stream_version_lte', ('280000', '290000', '293000', 'invalid',))

+     def test_query_builds_filter_stream_version_lte(self, stream_version_lte):

+         init_data(data_size=1, multiple_stream_versions=True)

+         url = ('/module-build-service/1/module-builds/?name=platform&verbose=true'

+                '&stream_version_lte={}'.format(stream_version_lte))

+         rv = self.client.get(url)

+         data = json.loads(rv.data)

+         total = data.get('meta', {}).get('total')

+         if stream_version_lte == 'invalid':

+             assert data == {

+                 'error': 'Bad Request',

+                 'message': ('An invalid value of stream_version_lte was provided. It must be an '

+                             'integer greater than or equal to 10000.'),

+                 'status': 400

+             }

+         elif stream_version_lte == '280000':

+             assert total == 2

+         elif stream_version_lte == '290000':

+             assert total == 1

+         elif stream_version_lte == '293000':

+             assert total == 3

+ 

      def test_query_builds_order_by(self):

          build = db.session.query(module_build_service.models.ModuleBuild).filter_by(id=2).one()

          build.name = 'candy'

It seems that MBSResolver.get_module_modulemds expects that the API supports filtering by stream_version_lte. This adds that support.

pretty please pagure-ci rebuild

5 years ago

rebased onto 9b08b53853adee53514627aea3fb843fef8a6f85

5 years ago

rebased onto 90de00918ee60fa26edef0705166d14b8fe08774

5 years ago

int(round) for py2 compatibility

Nice suggestion. I'll use that.

rebased onto ac60adfce874f308b4363cd8233190c5e763166b

5 years ago

Nice suggestion. I'll use that.

Actually, this doesn't do what we want:

>>> round(289234, -4)
290000.0

>>> (289234 // 10000) * 10000
280000

rebased onto 2ef1721f71134dd8974d9677376741b1f6b6f03c

5 years ago

@jkaluza could you review this please?

rebased onto d0aea40

5 years ago

Pull-Request has been merged by mprahl

5 years ago