Beispiel #1
0
 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'])
Beispiel #2
0
 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)
Beispiel #3
0
 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'])
Beispiel #4
0
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
Beispiel #5
0
    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)
Beispiel #6
0
 def setup_class(cls):
     collection_field = CollectionField(Collection('name', 'path'),
                                        Field('document:'))
     cls.i = SingleCollectionIndex("name", collection_field)
Beispiel #7
0
 def test_pass(self):
     CollectionField(
         Collection('name', 'path'),
         Field('document:'))
     self.assertEqual(1 + 1, 2)
Beispiel #8
0
 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))
Beispiel #9
0
 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))
Beispiel #10
0
 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))
Beispiel #11
0
 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))
Beispiel #12
0
 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')
Beispiel #13
0
 def test_document_field(self):
     spec = Field.parse_spec('document:')
     self.assertEqual(spec[0], 'document')
     self.assertEqual(spec[1], [''])
Beispiel #14
0
 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)
Beispiel #15
0
 def test_name(self):
     field = Field('name:')
     self.assertEqual(field.run(self.d), 'Test document')
Beispiel #16
0
 def test_document(self):
     field = Field('document:')
     self.assertEqual(field.run(self.d), 'asdf')
Beispiel #17
0
 def test_marshal(self):
     field = Field('document:')
     self.assertEqual(field.marshal(), 'document:')
Beispiel #18
0
 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']