def test_popProperties(self): expected = ['prop1', 'prop2'] rs = resultspec.ResultSpec( properties=[resultspec.Property(b'property', 'eq', expected)]) self.assertEqual(len(rs.properties), 1) self.assertEqual(rs.popProperties(), expected) self.assertEqual(len(rs.properties), 0)
def test_properties_injection(self): resultSpec = resultspec.OptimisedResultSpec( properties=[resultspec.Property(b'property', 'eq', 'reason')]) build = yield self.callGet(('builders', 77, 'builds', 3), resultSpec=resultSpec) self.validateData(build) self.assertIn('reason', build['properties'])
def testGetProperties(self): prop = resultspec.Property(b'property', 'eq', '*') buildrequest = yield self.callGet(('buildrequests', 44), resultSpec=resultspec.ResultSpec(properties=[prop])) self.assertEqual(buildrequest['buildrequestid'], 44) self.assertEqual(buildrequest['properties'], {u'prop1': (u'one', u'fake1'), u'prop2': (u'two', u'fake2')})
def test_properties_injection(self): resultSpec = resultspec.OptimisedResultSpec( properties=[resultspec.Property(b'property', 'eq', 'reason')]) builds = yield self.callGet(('builds', ), resultSpec=resultSpec) for build in builds: self.validateData(build) self.assertTrue(any(('reason' in b['properties']) for b in builds))
def testGetProperties(self): self.master.db.insertTestData([ fakedb.BuildsetProperty(buildsetid=8822, property_name='prop1', property_value='["one", "fake1"]'), fakedb.BuildsetProperty(buildsetid=8822, property_name='prop2', property_value='["two", "fake2"]'), ]) prop = resultspec.Property(b'property', 'eq', '*') buildrequests = yield self.callGet(('builders', 78, 'buildrequests'), resultSpec=resultspec.ResultSpec(properties=[prop])) self.assertEqual(len(buildrequests), 1) self.assertEqual(buildrequests[0]['buildrequestid'], 46) self.assertEqual(buildrequests[0]['properties'], {u'prop1': (u'one', u'fake1'), u'prop2': (u'two', u'fake2')})
def decodeResultSpec(self, request, endpoint): reqArgs = request.args def checkFields(fields, negOk=False): for k in fields: if k[0] == '-' and negOk: k = k[1:] if k not in entityType.fieldNames: raise BadRequest("no such field %r" % (k, )) entityType = endpoint.rtype.entityType limit = offset = order = fields = None filters, properties = [], [] for arg in reqArgs: if arg == 'order': order = reqArgs[arg] checkFields(order, True) continue elif arg == 'field': fields = reqArgs[arg] checkFields(fields, False) continue elif arg == 'limit': try: limit = int(reqArgs[arg][0]) except Exception: raise BadRequest('invalid limit') continue elif arg == 'offset': try: offset = int(reqArgs[arg][0]) except Exception: raise BadRequest('invalid offset') continue elif arg == 'property': try: props = [v.decode('utf-8') for v in reqArgs[arg]] except Exception: raise BadRequest('invalid property value for %s' % arg) properties.append(resultspec.Property(arg, 'eq', props)) continue elif arg in entityType.fieldNames: field = entityType.fields[arg] try: values = [field.valueFromString(v) for v in reqArgs[arg]] except Exception: raise BadRequest('invalid filter value for %s' % arg) filters.append(resultspec.Filter(arg, 'eq', values)) continue elif '__' in arg: field, op = arg.rsplit('__', 1) args = reqArgs[arg] operators = (resultspec.Filter.singular_operators if len(args) == 1 else resultspec.Filter.plural_operators) if op in operators and field in entityType.fieldNames: fieldType = entityType.fields[field] try: values = [ fieldType.valueFromString(v) for v in reqArgs[arg] ] except Exception: raise BadRequest('invalid filter value for %s' % arg) filters.append(resultspec.Filter(field, op, values)) continue raise BadRequest("unrecognized query parameter '%s'" % (arg, )) # if ordering or filtering is on a field that's not in fields, bail out if fields: fieldsSet = set(fields) if order and set(order) - fieldsSet: raise BadRequest("cannot order on un-selected fields") for filter in filters: if filter.field not in fieldsSet: raise BadRequest("cannot filter on un-selected fields") # build the result spec rspec = resultspec.ResultSpec(fields=fields, limit=limit, offset=offset, order=order, filters=filters, properties=properties) # for singular endpoints, only allow fields if not endpoint.isCollection: if rspec.filters: raise BadRequest("this is not a collection") return rspec
def resultspec_from_jsonapi(self, req_args, entityType, is_collection): def checkFields(fields, negOk=False): for field in fields: k = bytes2unicode(field) if k[0] == '-' and negOk: k = k[1:] if k not in entityType.fieldNames: raise exceptions.InvalidQueryParameter( "no such field '{}'".format(k)) limit = offset = order = fields = None filters, properties = [], [] limit = offset = order = fields = None filters, properties = [], [] for arg in req_args: argStr = bytes2unicode(arg) if argStr == 'order': order = tuple([bytes2unicode(o) for o in req_args[arg]]) checkFields(order, True) elif argStr == 'field': fields = req_args[arg] checkFields(fields, False) elif argStr == 'limit': try: limit = int(req_args[arg][0]) except Exception as e: raise exceptions.InvalidQueryParameter( 'invalid limit') from e elif argStr == 'offset': try: offset = int(req_args[arg][0]) except Exception as e: raise exceptions.InvalidQueryParameter( 'invalid offset') from e elif argStr == 'property': try: props = [] for v in req_args[arg]: if not isinstance(v, (bytes, str)): raise TypeError("Invalid type {} for {}".format( type(v), v)) props.append(bytes2unicode(v)) except Exception as e: raise exceptions.InvalidQueryParameter( 'invalid property value for {}'.format(arg)) from e properties.append(resultspec.Property(arg, 'eq', props)) elif argStr in entityType.fieldNames: field = entityType.fields[argStr] try: values = [field.valueFromString(v) for v in req_args[arg]] except Exception as e: raise exceptions.InvalidQueryParameter( 'invalid filter value for {}'.format(argStr)) from e filters.append(resultspec.Filter(argStr, 'eq', values)) elif '__' in argStr: field, op = argStr.rsplit('__', 1) args = req_args[arg] operators = (resultspec.Filter.singular_operators if len(args) == 1 else resultspec.Filter.plural_operators) if op in operators and field in entityType.fieldNames: fieldType = entityType.fields[field] try: values = [ fieldType.valueFromString(v) for v in req_args[arg] ] except Exception as e: raise exceptions.InvalidQueryParameter( 'invalid filter value for {}'.format( argStr)) from e filters.append(resultspec.Filter(field, op, values)) else: raise exceptions.InvalidQueryParameter( "unrecognized query parameter '{}'".format(argStr)) # if ordering or filtering is on a field that's not in fields, bail out if fields: fields = [bytes2unicode(f) for f in fields] fieldsSet = set(fields) if order and {o.lstrip('-') for o in order} - fieldsSet: raise exceptions.InvalidQueryParameter( "cannot order on un-selected fields") for filter in filters: if filter.field not in fieldsSet: raise exceptions.InvalidQueryParameter( "cannot filter on un-selected fields") # build the result spec rspec = resultspec.ResultSpec(fields=fields, limit=limit, offset=offset, order=order, filters=filters, properties=properties) # for singular endpoints, only allow fields if not is_collection: if rspec.filters: raise exceptions.InvalidQueryParameter( "this is not a collection") return rspec