def test_metadata_field(self): spec = Field.parse_spec('metadata:foo') self.assertEqual(spec[0], 'metadata') self.assertEqual(spec[1], ['foo']) spec = Field.parse_spec('metadata:foo.bar') self.assertEqual(spec[0], 'metadata') self.assertEqual(spec[1], ['foo', 'bar'])
def setup_class(cls): from_collection_field = CollectionField(Collection('from', 'path'), Field('document:')) to_collection_field = CollectionField(Collection('to', 'path'), Field('document:')) cls.i = CrossCollectionIndex("name", from_collection_field, to_collection_field)
def test_populates_fields(self): field = Field('document:') self.assertEqual(field.field_type, 'document') self.assertEqual(field.path_parts, None) field = Field('metadata:foo.bar') self.assertEqual(field.field_type, 'metadata') self.assertEqual(field.path_parts, ['foo', 'bar'])
class Filter: """Stores a single filter for comparing a field to a value""" #: OPERATORS contains a list of comparisons and operations for running #: queries OPERATORS = { 'eq': lambda x, y: x == y, 'ne': lambda x, y: x != y, 'gt': lambda x, y: x > y, 'lt': lambda x, y: x < y, 'ge': lambda x, y: x >= y, 'le': lambda x, y: x <= y, 'in': lambda x, y: x in y, 'contains': lambda x, y: y in x, } def __init__(self, filter_obj): """creates a filter object from a dict""" self.field = Field(filter_obj['field']) self.operator = filter_obj['op'] self.value = filter_obj['value'] def run(self, document): """runs the test against the document, comparing the metadata field specified by the filter's field against the provided value using the provided operation """ return self.OPERATORS[self.operator]( self.field.run(document), self.value) @classmethod def is_filter(cls, obj): """duck-types a dict to see if it looks like a filter object""" try: if sorted(obj.keys()) != ['field', 'op', 'value']: return False if obj['op'] not in cls.OPERATORS: return False return True except: return False
def from_object(cls, config_obj): """Parses a configuration object (as generated by loading a yaml configuration file) into an internal object used by the database """ # Ensure there's only one key. if len(config_obj) != 1: raise cls.MalformedConfiguration( 'config may only contain one root-level key') name, config_obj = config_obj.popitem() # Ensure that collections and indices keys exist and are lists. if 'collections' not in config_obj or 'indices' not in config_obj: raise cls.MalformedConfiguration( 'config must contain `collections` and `indices` keys (even ' 'if they are empty lists)') if type(config_obj['collections']) not in [list, tuple]: raise cls.MalformedConfiguration( '`collections` must be a list (even if it is empty)') if type(config_obj['indices']) not in [list, tuple]: raise cls.MalformedConfiguration( '`indices` must be a list (even if it is empty)') # Fetch all collections. collections = {} for collection in config_obj['collections']: cname = collection.get('name', None) cpath = collection.get('path', None) # Ensure name and path are specified if cname is None or cpath is None: raise cls.MalformedConfiguration( 'collection `name` and `path` are required') collections[cname] = Collection(cname, cpath) del config_obj['collections'] # Fetch and parse all indices indices = {} for index in config_obj['indices']: cname = index.get('name', None) cfrom = index.get('from', None) cto = index.get('to', None) # Ensure an index name and a from field are specified. if cname is None or cfrom is None: raise cls.MalformedConfiguration( 'index `name` and `from` fields are required') # Ensure that the referenced collection exists cfrom_collection = collections.get(cfrom[0], None) if cfrom_collection is None: raise cls.MalformedConfiguration( 'indicies must specify a valid collection by name in the ' 'from field') cfrom_field = Field(cfrom[1]) cf_from = CollectionField(cfrom_collection, cfrom_field) # Build a single or cross collection index depending on the # presence of a `to` collection field. if cto is None: indices[cname] = SingleCollectionIndex(cname, cf_from) else: cto_collection = collections.get(cto[0], None) if cto_collection is None: raise cls.MalformedConfiguration( 'indicies must specify a valid collection by name in ' 'the to field') cto_field = Field(cto[1]) cf_to = CollectionField(cto_collection, cto_field) indices[cname] = CrossCollectionIndex(cname, cf_from, cf_to) del config_obj['indices'] # Grab additional configuration values, supplying defaults if needed. options = DEFAULT_OPTIONS.copy() options.update(config_obj) return Configuration(name, collections, indices, options)
def setup_class(cls): collection_field = CollectionField(Collection('name', 'path'), Field('document:')) cls.i = SingleCollectionIndex("name", collection_field)
def test_pass(self): CollectionField( Collection('name', 'path'), Field('document:')) self.assertEqual(1 + 1, 2)
def test_metadata_without_path_invalid(self): with self.assertRaises(Field.MalformedSpec) as context: Field.parse_spec('metadata:') self.assertTrue( 'metadata must contain a path' in str(context.exception))
def test_document_with_path_invalid(self): with self.assertRaises(Field.MalformedSpec) as context: Field.parse_spec('document:bad-wolf') self.assertTrue( 'document must not contain a path' in str(context.exception))
def test_invalid_field_type(self): with self.assertRaises(Field.MalformedSpec) as context: Field.parse_spec('bad-wolf:') self.assertTrue('valid field types are "document" and "metadata"' in str(context.exception))
def test_field_type_required(self): with self.assertRaises(Field.MalformedSpec) as context: Field.parse_spec('document...') print(dir(context.exception)) self.assertTrue( 'spec must take the form of `type:path`' in str(context.exception))
def test_create(self): f = Filter({'field': 'd:', 'op': 'eq', 'value': 'asdf'}) self.assertEqual(f.field, Field('d:')) self.assertEqual(f.operator, 'eq') self.assertEqual(f.value, 'asdf')
def test_document_field(self): spec = Field.parse_spec('document:') self.assertEqual(spec[0], 'document') self.assertEqual(spec[1], [''])
def test_metadata(self): field = Field('metadata:foo.bar') self.assertEqual(field.run(self.d), 42) field = Field('metadata:foo.baz') self.assertEqual(field.run(self.d), None)
def test_name(self): field = Field('name:') self.assertEqual(field.run(self.d), 'Test document')
def test_document(self): field = Field('document:') self.assertEqual(field.run(self.d), 'asdf')
def test_marshal(self): field = Field('document:') self.assertEqual(field.marshal(), 'document:')
def __init__(self, filter_obj): """creates a filter object from a dict""" self.field = Field(filter_obj['field']) self.operator = filter_obj['op'] self.value = filter_obj['value']