Exemple #1
0
class UpdaterTest(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)

        self.updater = Updater(self.schema)

        self.employee_spec = self.schema.add_spec('employee')
        self.schema.add_field(self.employee_spec, 'name', 'str')
        self.schema.add_field(self.employee_spec, 'age', 'int')

        self.division_spec = self.schema.add_spec('division')
        self.schema.add_field(self.division_spec, 'name', 'str')
        self.schema.add_field(self.division_spec, 'employees', 'collection', 'employee')

        self.schema.add_field(self.schema.root, 'divisions', 'collection', 'division')

    def test_update_simple_field(self):
        self.schema.add_calc(self.division_spec, 'older_employees', 'self.employees[age>30]')

        division_id_1 = self.schema.insert_resource(
            'division', {'name': 'sales'}, 'divisions')
        employee_id_1 = self.schema.insert_resource(
            'employee', {'name': 'bob', 'age': 31}, 'employees', 'division', division_id_1)

        self.updater.update_calc('division', 'older_employees', division_id_1)

        division_data = self.db.resource_division.find_one()
        self.assertEquals({
            '_id': self.schema.decodeid(division_id_1),
            '_grants': [],
            'name': 'sales',
            '_canonical_url': '/divisions/%s' % division_id_1,
            '_parent_canonical_url': '/',
            '_parent_field_name': 'divisions',
            '_parent_id': None,
            '_parent_type': 'root',
            'older_employees': [ObjectId(employee_id_1[2:])],
        }, division_data)

        self.updater.update_fields('employee', employee_id_1, {"age": 20})

        division_data = self.db.resource_division.find_one()
        self.assertEquals({
            '_id': self.schema.decodeid(division_id_1),
            '_grants': [],
            'name': 'sales',
            '_canonical_url': '/divisions/%s' % division_id_1,
            '_parent_canonical_url': '/',
            '_parent_field_name': 'divisions',
            '_parent_id': None,
            '_parent_type': 'root',
            'older_employees': [],
        }, division_data)

    def test_update_containing_collection(self):
        self.schema.add_calc(self.division_spec, 'older_employees', 'self.employees[age>30]')

        division_id_1 = self.schema.insert_resource(
            'division', {'name': 'sales'}, 'divisions')

        self.updater.update_calc('division', 'older_employees', division_id_1)

        division_data = self.db.resource_division.find_one()
        self.assertEquals({
            '_id': self.schema.decodeid(division_id_1),
            '_grants': [],
            '_canonical_url': '/divisions/%s' % division_id_1,
            'name': 'sales',
            '_parent_canonical_url': '/',
            '_parent_field_name': 'divisions',
            '_parent_id': None,
            '_parent_type': 'root',
            'older_employees': [],
        }, division_data)

        employee_id_1 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'Bob',
            'age': 41,
        })

        division_data = self.db.resource_division.find_one()
        self.assertEquals({
            '_id': self.schema.decodeid(division_id_1),
            '_grants': [],
            '_canonical_url': '/divisions/%s' % division_id_1,
            'name': 'sales',
            '_parent_canonical_url': '/',
            '_parent_field_name': 'divisions',
            '_parent_id': None,
            '_parent_type': 'root',
            'older_employees': [ObjectId(employee_id_1[2:])],
        }, division_data)

        employee_data = self.db.resource_employee.find_one()
        self.assertEquals({
            '_id': self.schema.decodeid(employee_id_1),
            '_grants': [],
            '_canonical_url': '/divisions/%s/employees/%s' % (division_id_1, employee_id_1),
            'name': 'Bob',
            'age': 41,
            '_parent_canonical_url': '/divisions/%s' % division_id_1,
            '_parent_field_name': 'employees',
            '_parent_id': ObjectId(division_id_1[2:]),
            '_parent_type': 'division',
        }, employee_data)

    def test_update_link_collection(self):
        self.schema.add_field(self.division_spec, 'managers', 'linkcollection', 'employee')
        self.schema.add_calc(self.division_spec, 'older_managers', 'self.managers[age>30]')
        self.schema.add_calc(self.division_spec, 'older_non_retired_managers', 'self.older_managers[age<65]')
        log.debug("start")

        division_id_1 = self.schema.insert_resource(
            'division', {'name': 'sales'}, 'divisions')
        log.debug("inserted")

        employee_id_1 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'Bob',
            'age': 41
        })
        log.debug("created 1")
        employee_id_2 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'Ned',
            'age': 70
        })
        log.debug("created 2")
        employee_id_3 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'Fred',
            'age': 25
        })
        log.debug("created 3")

        self.updater.create_linkcollection_entry('division', division_id_1, 'managers', employee_id_1)
        log.debug("created entry 1")
        self.updater.create_linkcollection_entry('division', division_id_1, 'managers', employee_id_2)
        log.debug("created entry 2")
        self.updater.create_linkcollection_entry('division', division_id_1, 'managers', employee_id_3)
        log.debug("created entry 3")

        division_data = self.db.resource_division.find_one()
        self.assertEquals("sales", division_data['name'])
        self.assertEquals(3, len(division_data['managers']))
        self.assertTrue({"_id" : self.schema.decodeid(employee_id_1)} in division_data['managers'])
        self.assertTrue({"_id" : self.schema.decodeid(employee_id_2)} in division_data['managers'])
        self.assertTrue({"_id" : self.schema.decodeid(employee_id_3)} in division_data['managers'])
        self.assertEquals(sorted([
            self.schema.decodeid(employee_id_1),
            self.schema.decodeid(employee_id_2),
        ]), sorted(division_data['older_managers']))
        self.assertEquals([
            self.schema.decodeid(employee_id_1)],
            division_data['older_non_retired_managers'])
        self.assertEquals({
            "_id" : self.schema.decodeid(division_id_1),
            '_grants': [],
            '_canonical_url': '/divisions/%s' % division_id_1,
            "_parent_field_name" : "divisions",
            "_parent_id" : None,
            "_parent_type" : "root",
            "_parent_canonical_url" : '/',
            "name" : "sales",
            "managers" : [
                    {
                            "_id" : self.schema.decodeid(employee_id_1)
                    },
                    {
                            "_id" : self.schema.decodeid(employee_id_2)
                    },
                    {
                            "_id" : self.schema.decodeid(employee_id_3)
                    }
            ],
            "older_managers" : [
                    self.schema.decodeid(employee_id_1),
                    self.schema.decodeid(employee_id_2),
            ],
            "older_non_retired_managers" : [
                    self.schema.decodeid(employee_id_1),
            ]
        }, division_data)

    def test_reverse_aggregation_loopback(self):
        self.schema.add_field(self.division_spec, 'managers', 'linkcollection', 'employee')
        self.schema.add_calc(self.employee_spec, 'all_my_subordinates', 'self.link_division_managers.employees')

        division_id_1 = self.schema.insert_resource(
            'division', {'name': 'sales'}, 'divisions')

        employee_id_1 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'bob', 'age': 21})
        employee_id_2 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'ned', 'age': 31})
        employee_id_3 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'fred', 'age': 41})
        employee_id_4 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {
            'name': 'mike', 'age': 51})

        # add manager
        calc_spec = self.schema.calc_trees[('employee', 'all_my_subordinates')]
        self.assertEquals({'division.managers', 'division.employees'}, calc_spec.get_resource_dependencies())
        self.updater.create_linkcollection_entry('division', division_id_1, 'managers', employee_id_1)

        employee_data = self.db.resource_employee.find_one()
        self.assertEquals({
            "_id" : self.schema.decodeid(employee_id_1),
            '_grants': [],
            '_canonical_url': '/divisions/%s/employees/%s' % (division_id_1, employee_id_1),
            "_parent_field_name" : "employees",
            "_parent_id" : self.schema.decodeid(division_id_1),
            "_parent_type" : "division",
            "_parent_canonical_url" : "/divisions/%s" % division_id_1,
            "name" : "bob",
            "age": 21,
            "all_my_subordinates" : [
                self.schema.decodeid(employee_id_1),
                self.schema.decodeid(employee_id_2),
                self.schema.decodeid(employee_id_3),
                self.schema.decodeid(employee_id_4),
            ]}, employee_data)

    def test_resource_deps_for_field(self):
        self.schema.add_calc(self.employee_spec, 'all_ages', 'divisions.employees.age + 10')

        # add manager
        calc_spec = self.schema.calc_trees[('employee', 'all_ages')]
        self.assertEquals({'division.employees', 'root.divisions', 'employee.age'}, calc_spec.get_resource_dependencies())
Exemple #2
0
class UpdaterTest(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)
        self.updater = Updater(self.schema)

        self.employee_spec = self.schema.add_spec('employee')
        self.schema.add_field(self.employee_spec, 'name', 'str')
        self.schema.add_field(self.schema.root, 'employees', 'collection',
                              'employee')

        self.api = Api(self.schema)

        self.db.delete_calc.create_index([
            ('update_id', pymongo.ASCENDING),
            ('resource_id', pymongo.ASCENDING),
        ],
                                         unique=True)

    def test_aggregation_merge(self):
        employee_id_1 = self.api.post('employees', {'name': 'ned'})
        employee_id_2 = self.api.post('employees', {'name': 'bob'})

        cursor = self.db.resource_employee.aggregate([
            {
                "$set": {
                    "update_id": 1
                }
            },
            {
                "$project": {
                    "resource_id": "$_id",
                    "update_id": True,
                    "_id": False
                }
            },
            {
                "$merge": {
                    "into": "delete_calc",
                    "on": ["update_id", "resource_id"],
                    "whenNotMatched": "insert"
                }
            },
        ])

        cursor = self.db.resource_employee.aggregate([
            {
                "$set": {
                    "update_id": 2
                }
            },
            {
                "$project": {
                    "resource_id": "$_id",
                    "update_id": True,
                    "_id": False
                }
            },
            {
                "$merge": {
                    "into": "delete_calc",
                    "on": ["update_id", "resource_id"],
                    "whenNotMatched": "insert"
                }
            },
        ])

        employee_id_3 = self.api.post('employees', {'name': 'fred'})

        cursor = self.db.resource_employee.aggregate([
            {
                "$set": {
                    "update_id": 2
                }
            },
            {
                "$project": {
                    "resource_id": "$_id",
                    "update_id": True,
                    "_id": False
                }
            },
            {
                "$merge": {
                    "into": "delete_calc",
                    "on": ["update_id", "resource_id"],
                    "whenNotMatched": "insert"
                }
            },
        ])

        self.assertEqual([], list(cursor))
Exemple #3
0
class SchemaTest(unittest.TestCase):
    def setUp(self):
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)
        self.maxDiff = None

    def test_load_basic_spec(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                        "age": {
                            "type": "int"
                        }
                    },
                },
            }
        })
        self.schema.load_schema()
        self.assertEquals(1, len(self.schema.specs))
        self.assertEquals(
            "str", self.schema.specs['employee'].fields['name'].field_type)
        self.assertEquals(
            "int", self.schema.specs['employee'].fields['age'].field_type)

    def test_load_basic_link_with_reverse_link(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                    },
                },
                "department": {
                    "fields": {
                        "manager": {
                            "type": "link",
                            "target_spec_name": "employee",
                        },
                    },
                },
            }
        })
        self.schema.load_schema()
        self.assertEquals(2, len(self.schema.specs))
        self.assertEquals(
            "str", self.schema.specs['employee'].fields['name'].field_type)
        self.assertEquals(
            "link",
            self.schema.specs['department'].fields['manager'].field_type)
        self.assertEquals(
            "employee",
            self.schema.specs['department'].fields['manager'].target_spec_name)

        self.assertEquals(
            "reverse_link", self.schema.specs['employee'].
            fields['link_department_manager'].field_type)
        self.assertEquals(
            "department", self.schema.specs['employee'].
            fields['link_department_manager'].target_spec_name)

    def test_load_collection_with_parent_link(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                    },
                },
                "department": {
                    "fields": {
                        "employees": {
                            "type": "collection",
                            "target_spec_name": "employee",
                        },
                    },
                },
            },
        })
        self.schema.load_schema()
        self.assertEquals(2, len(self.schema.specs))
        self.assertEquals(
            "str", self.schema.specs['employee'].fields['name'].field_type)
        self.assertEquals(
            "collection",
            self.schema.specs['department'].fields['employees'].field_type)
        self.assertEquals(
            "employee", self.schema.specs['department'].fields['employees'].
            target_spec_name)

        self.assertEquals(
            "parent_collection", self.schema.specs['employee'].
            fields['parent_department_employees'].field_type)
        self.assertEquals(
            "department", self.schema.specs['employee'].
            fields['parent_department_employees'].target_spec_name)

    def test_load_link_collection_with_reverse_link(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                    },
                },
                "department": {
                    "fields": {
                        "parttimers": {
                            "type": "linkcollection",
                            "target_spec_name": "employee",
                        },
                    },
                },
            }
        })
        self.schema.load_schema()
        self.assertEquals(2, len(self.schema.specs))
        self.assertEquals(
            "str", self.schema.specs['employee'].fields['name'].field_type)
        self.assertEquals(
            "linkcollection",
            self.schema.specs['department'].fields['parttimers'].field_type)
        self.assertEquals(
            "employee", self.schema.specs['department'].fields['parttimers'].
            target_spec_name)

        self.assertEquals(
            "reverse_link_collection", self.schema.specs['employee'].
            fields['link_department_parttimers'].field_type)
        self.assertEquals(
            "department", self.schema.specs['employee'].
            fields['link_department_parttimers'].target_spec_name)

    def test_save_resource_encode_id(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                    },
                },
            }
        })
        self.schema.load_schema()
        employee_id = self.schema.insert_resource('employee', {'name': 'Bob'},
                                                  'employees')
        new_resource = self.db.resource_employee.find_one()
        self.assertEquals(ObjectId(employee_id[2:]),
                          self.schema.decodeid(employee_id))
        self.assertEquals(
            {
                '_id': self.schema.decodeid(employee_id),
                '_grants': [],
                '_canonical_url': '/employees/%s' % employee_id,
                'name': 'Bob',
                '_parent_canonical_url': '/',
                '_parent_field_name': 'employees',
                '_parent_id': None,
                '_parent_type': 'root',
            }, new_resource)
        self.assertEquals('ID%s' % (new_resource['_id'], ), employee_id)

    def test_update_field(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                    },
                },
            }
        })
        self.schema.load_schema()
        employee_id = self.schema.insert_resource('employee', {'name': 'Bob'},
                                                  'employees')
        self.schema.update_resource_fields('employee', employee_id,
                                           {'name': 'Ned'})
        reload_employee = self.db.resource_employee.find_one(
            {'_id': self.schema.decodeid(employee_id)})
        self.assertEquals('Ned', reload_employee['name'])

    def test_roots(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                    },
                },
                "department": {
                    "fields": {
                        "manager": {
                            "type": "link",
                            "target_spec_name": "employee",
                        },
                    },
                },
            },
            "root": {
                "employees": {
                    "type": "collection",
                    "target_spec_name": "employee",
                },
                "departments": {
                    "type": "collection",
                    "target_spec_name": "department",
                }
            },
        })
        self.schema.load_schema()
        self.assertEquals(2, len(self.schema.specs))
        self.assertEquals(2, len(self.schema.root.fields))
        self.assertEquals('collection',
                          self.schema.root.fields['employees'].field_type)
        self.assertEquals(
            'employee', self.schema.root.fields['employees'].target_spec_name)
        self.assertEquals('collection',
                          self.schema.root.fields['departments'].field_type)
        self.assertEquals(
            'department',
            self.schema.root.fields['departments'].target_spec_name)

    def test_canonical_url(self):
        self.db.metaphor_schema.insert_one({
            "specs": {
                "employee": {
                    "fields": {
                        "name": {
                            "type": "str"
                        },
                        "age": {
                            "type": "int"
                        },
                        "division": {
                            "type": "link",
                            "target_spec_name": "division",
                        },
                    },
                },
                "division": {
                    "fields": {
                        "name": {
                            "type": "str",
                        },
                        "yearly_sales": {
                            "type": "int",
                        },
                        "sections": {
                            "type": "collection",
                            "target_spec_name": "section",
                        }
                    },
                },
                "section": {
                    "fields": {
                        "name": {
                            "type": "str",
                        },
                    },
                },
            },
            "root": {
                "employees": {
                    "type": "collection",
                    "target_spec_name": "employee",
                },
                "divisions": {
                    "type": "collection",
                    "target_spec_name": "division",
                }
            },
        })
        self.schema.load_schema()

        division_id_1 = self.schema.insert_resource('division', {
            'name': 'sales',
            'yearly_sales': 100
        }, 'divisions')

        self.assertEquals(
            {
                '_id': self.schema.decodeid(division_id_1),
                '_grants': [],
                '_canonical_url': '/divisions/%s' % division_id_1,
                '_parent_id': None,
                '_parent_type': 'root',
                '_parent_field_name': 'divisions',
                '_parent_canonical_url': '/',
                'name': 'sales',
                'yearly_sales': 100,
            }, self.db['resource_division'].find_one(
                {'_id': self.schema.decodeid(division_id_1)}))

        section_id_1 = self.schema.insert_resource(
            'section', {'name': 'appropriation'},
            parent_type='division',
            parent_id=division_id_1,
            parent_field_name='sections')

        self.assertEquals(
            {
                '_id': self.schema.decodeid(division_id_1),
                '_grants': [],
                '_canonical_url': '/divisions/%s' % division_id_1,
                '_parent_id': None,
                '_parent_type': 'root',
                '_parent_field_name': 'divisions',
                '_parent_canonical_url': '/',
                'name': 'sales',
                'yearly_sales': 100,
            }, self.db['resource_division'].find_one(
                {'_id': self.schema.decodeid(division_id_1)}))

        self.assertEquals(
            {
                '_id':
                self.schema.decodeid(section_id_1),
                '_grants': [],
                '_canonical_url':
                '/divisions/%s/sections/%s' % (division_id_1, section_id_1),
                '_parent_id':
                self.schema.decodeid(division_id_1),
                '_parent_type':
                'division',
                '_parent_field_name':
                'sections',
                '_parent_canonical_url':
                '/divisions/%s' % division_id_1,
                'name':
                'appropriation',
            }, self.db['resource_section'].find_one(
                {'_id': self.schema.decodeid(section_id_1)}))

    def test_calc_infer_type(self):
        spec = self.schema.add_spec('employees')
        self.schema.add_field(spec, 'name', 'str')
        calc_field = self.schema.add_calc(spec, 'current_name', 'self.name')

        self.assertEquals('str', calc_field.infer_type().field_type)
        self.assertTrue(calc_field.is_primitive())
        self.assertFalse(calc_field.is_collection())

    def test_calc_infer_type_collection(self):
        spec = self.schema.add_spec('employees')
        buddy_spec = self.schema.add_spec('buddy')
        self.schema.add_field(spec, 'buddies', 'collection', 'buddy')
        calc_field = self.schema.add_calc(spec, 'all_buddies', 'self.buddies')

        self.assertEquals(buddy_spec, calc_field.infer_type())
        self.assertFalse(calc_field.is_primitive())
        self.assertTrue(calc_field.is_collection())

    def test_delete_linkcollection_entry(self):
        pass

    def test_parse_fields_test(self):
        # add parsing and validation for field types
        pass

    def test_initialize_schema(self):
        self.schema.create_initial_schema()

        schema = self.db.metaphor_schema.find_one()
        self.assertEqual(
            {
                "groups": {
                    "target_spec_name": "group",
                    "type": "collection"
                },
                "users": {
                    "target_spec_name": "user",
                    "type": "collection"
                }
            }, schema['root'])
        self.assertEqual(
            {
                'grant': {
                    'fields': {
                        'type': {
                            'type': 'str'
                        },
                        'url': {
                            'type': 'str'
                        }
                    }
                },
                'group': {
                    'fields': {
                        'grants': {
                            'target_spec_name': 'grant',
                            'type': 'collection'
                        },
                        'name': {
                            'type': 'str'
                        }
                    }
                },
                'user': {
                    'fields': {
                        'admin': {
                            'type': 'bool'
                        },
                        'create_grants': {
                            'calc_str':
                            "self.groups.grants[type='create'].url",
                            'deps': [
                                'grant.type', 'grant.url', 'group.grants',
                                'user.groups'
                            ],
                            'type':
                            'calc'
                        },
                        'delete_grants': {
                            'calc_str':
                            "self.groups.grants[type='delete'].url",
                            'deps': [
                                'grant.type', 'grant.url', 'group.grants',
                                'user.groups'
                            ],
                            'type':
                            'calc'
                        },
                        'groups': {
                            'target_spec_name': 'group',
                            'type': 'linkcollection'
                        },
                        'password': {
                            'type': 'str'
                        },
                        'put_grants': {
                            'calc_str':
                            "self.groups.grants[type='put'].url",
                            'deps': [
                                'grant.type', 'grant.url', 'group.grants',
                                'user.groups'
                            ],
                            'type':
                            'calc'
                        },
                        'read_grants': {
                            'calc_str':
                            "self.groups.grants[type='read'].url",
                            'deps': [
                                'grant.type', 'grant.url', 'group.grants',
                                'user.groups'
                            ],
                            'type':
                            'calc'
                        },
                        'update_grants': {
                            'calc_str':
                            "self.groups.grants[type='update'].url",
                            'deps': [
                                'grant.type', 'grant.url', 'group.grants',
                                'user.groups'
                            ],
                            'type':
                            'calc'
                        },
                        'username': {
                            'type': 'str'
                        }
                    }
                }
            }, schema['specs'])

    def test_load_calcs_by_dependency(self):
        self.schema.create_spec('employee')
        self.schema.create_field('employee', 'name', 'str')

        self.schema.create_spec('branch')
        self.schema.create_field('branch', 'income', 'int')
        self.schema.create_field('branch', 'employees', 'collection',
                                 'employee')

        self.schema.create_spec('section')
        self.schema.create_field('section', 'branch', 'link', 'branch')

        self.schema.load_schema()

        self.schema.create_field(
            'employee', 'average_section_income', 'calc', None,
            'average(self.parent_branch_employees.income)')
        self.schema.create_field('branch', 'section', 'calc', None,
                                 'self.link_section_branch')
        self.schema.create_field('section', 'employees', 'calc', None,
                                 'self.branch.employees')

        expected = {
            "employee": {
                "fields": {
                    "name": {
                        "type": "str"
                    },
                    "average_section_income": {
                        "type": "calc",
                        "calc_str":
                        "average(self.parent_branch_employees.income)",
                        "deps": ["branch.income"],
                    },
                },
            },
            "branch": {
                "fields": {
                    "income": {
                        "type": "int",
                    },
                    "employees": {
                        "type": "collection",
                        "target_spec_name": "employee",
                    },
                    "section": {
                        "type": "calc",
                        "calc_str": "self.link_section_branch",
                        "deps": ["section.branch"],
                    },
                },
            },
            "section": {
                "fields": {
                    "branch": {
                        "type": "link",
                        "target_spec_name": "branch",
                    },
                    "employees": {
                        "type": "calc",
                        "calc_str": "self.branch.employees",
                        "deps": ["branch.employees", "section.branch"],
                    },
                },
            },
        }

        self.assertEqual(expected, self.db.metaphor_schema.find_one()['specs'])

        self.schema.load_schema()
        self.assertEquals(3, len(self.schema.specs))

    def test_load_calcs_by_dependency_almost_circular(self):
        self.schema.create_spec('primary')
        self.schema.create_field('primary', 'name', 'str')
        self.schema.create_field('primary',
                                 'calced_name',
                                 'calc',
                                 calc_str="self.name + 'a'")

        self.schema.create_spec('secondary')
        self.schema.create_field('secondary', 'name', 'str')
        self.schema.create_field('secondary',
                                 'calced_name',
                                 'calc',
                                 calc_str="self.name + 'b'")

        self.schema.create_field('primary', 'secondary', 'link', 'secondary')
        self.schema.create_field('secondary', 'primary', 'link', 'primary')

        self.schema.create_field('primary',
                                 'secondary_name',
                                 'calc',
                                 calc_str="self.secondary.calced_name")
        self.schema.create_field('secondary',
                                 'primary_name',
                                 'calc',
                                 calc_str="self.primary.calced_name")

        self.schema.load_schema()
        self.assertEquals(2, len(self.schema.specs))
Exemple #4
0
class UpdaterTest(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)

        self.updater = Updater(self.schema)

        self.employee_spec = self.schema.add_spec('employee')
        self.schema.add_field(self.employee_spec, 'name', 'str')
        self.schema.add_field(self.employee_spec, 'age', 'int')

        self.division_spec = self.schema.add_spec('division')
        self.schema.add_field(self.division_spec, 'name', 'str')
        self.schema.add_field(self.division_spec, 'employees',
                              'linkcollection', 'employee')
        self.schema.add_calc(self.division_spec, 'older_employees',
                             'self.employees[age>30]')

        self.schema.add_field(self.schema.root, 'divisions', 'collection',
                              'division')
        self.schema.add_field(self.schema.root, 'employees', 'collection',
                              'employee')

    def test_update_only_linked_resources(self):
        employee_id_1 = self.schema.insert_resource('employee', {
            'name': 'ned',
            'age': 10
        }, 'employees')
        employee_id_2 = self.schema.insert_resource('employee', {
            'name': 'bob',
            'age': 10
        }, 'employees')

        division_id_1 = self.schema.insert_resource('division',
                                                    {'name': 'sales'},
                                                    'divisions')
        division_id_2 = self.schema.insert_resource('division',
                                                    {'name': 'marketting'},
                                                    'divisions')

        self.schema.create_linkcollection_entry('division', division_id_1,
                                                'employees', employee_id_1)
        self.schema.create_linkcollection_entry('division', division_id_2,
                                                'employees', employee_id_1)
        self.schema.create_linkcollection_entry('division', division_id_2,
                                                'employees', employee_id_2)

        self.assertEqual([
            self.schema.decodeid(division_id_1),
            self.schema.decodeid(division_id_2)
        ],
                         self.updater.get_affected_ids_for_resource(
                             'division', 'older_employees', self.employee_spec,
                             employee_id_1))
        self.assertEqual([self.schema.decodeid(division_id_2)],
                         self.updater.get_affected_ids_for_resource(
                             'division', 'older_employees', self.employee_spec,
                             employee_id_2))
class MoveResourceTest(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)

        self.updater = Updater(self.schema)

        self.employee_spec = self.schema.add_spec('employee')
        self.schema.add_field(self.employee_spec, 'name', 'str')
        self.schema.add_field(self.employee_spec, 'age', 'int')

        self.schema.add_field(self.schema.root, 'current_employees', 'collection', 'employee')
        self.schema.add_field(self.schema.root, 'former_employees', 'collection', 'employee')

        self.calcs_spec = self.schema.add_spec('calcs')

    def test_move_from_root(self):
        self.schema.add_calc(self.calcs_spec, 'sum_employee_age', 'sum(current_employees.age)')
        self.schema.add_field(self.schema.root, 'calcs', 'collection', 'calcs')

        # add root resources
        employee_id_1 = self.schema.insert_resource('employee', {'name': 'Bob', 'age': 10}, 'current_employees')
        employee_id_2 = self.schema.insert_resource('employee', {'name': 'Ned', 'age': 14}, 'current_employees')

        calcs_id_1 = self.schema.insert_resource('calcs', {}, 'calcs')

        # create move update
        self.move_resource = MoveResourceUpdate(
            self.updater,
            self.schema,
            None,
            'root',
            'root',
            'former_employees',
            'current_employees')

        from_path_agg, from_path_spec, from_path_is_coll = self.move_resource.from_path_agg()

        self.assertEqual([
            {'$match': {
                '$and': [
                    {'_parent_field_name': 'current_employees'},
                    {'_parent_canonical_url': '/'}
                ]
            }},
        ], from_path_agg)
        self.assertEqual(self.schema.specs['employee'], from_path_spec)
        self.assertTrue(from_path_is_coll)

        affected_ids_agg_before = self.move_resource.affected_aggs()
        self.assertEqual([
            ('calcs', 'sum_employee_age', [
            {'$lookup': {'as': '_field_sum_employee_age',
               'from': 'resource_calcs',
               'pipeline': []}},
            {'$group': {'_id': '$_field_sum_employee_age'}},
            {'$unwind': '$_id'},
            {'$replaceRoot': {'newRoot': '$_id'}}])
        ], affected_ids_agg_before)

        # check affected agg to path
        affected_ids_agg_after = self.move_resource.affected_aggs_to_path()
        self.assertEqual([
        ], affected_ids_agg_after)

        # check affected ids
        self.assertEqual(set([
            ('calcs', 'sum_employee_age', self.schema.decodeid(calcs_id_1)),
        ]), self.move_resource.affected_ids())

        # check affected ids for to path
        self.assertEqual(set([
        ]), self.move_resource.affected_ids_to_path())

    def test_move_from_root_after_aggs(self):
        self.schema.add_calc(self.calcs_spec, 'sum_employee_age', 'sum(former_employees.age)')
        self.schema.add_field(self.schema.root, 'calcs', 'collection', 'calcs')

        # add root resources
        employee_id_1 = self.schema.insert_resource('employee', {'name': 'Bob', 'age': 10}, 'current_employees')
        employee_id_2 = self.schema.insert_resource('employee', {'name': 'Ned', 'age': 14}, 'current_employees')

        calcs_id_1 = self.schema.insert_resource('calcs', {}, 'calcs')

        # create move update
        self.move_resource = MoveResourceUpdate(
            self.updater,
            self.schema,
            None,
            'root',
            'former_employees',
            'former_employees',
            'current_employees')

        from_path_agg, from_path_spec, from_path_is_coll = self.move_resource.from_path_agg()

        self.assertEqual([
            {'$match': {
                '$and': [
                    {'_parent_field_name': 'current_employees'},
                    {'_parent_canonical_url': '/'}
                ]
            }},
        ], from_path_agg)
        self.assertEqual(self.schema.specs['employee'], from_path_spec)
        self.assertTrue(from_path_is_coll)

        affected_ids_agg_before = self.move_resource.affected_aggs()
        self.assertEqual([
        ], affected_ids_agg_before)

        # check affected agg to path
        affected_ids_agg_after = self.move_resource.affected_aggs_to_path()
        self.assertEqual([
            ('calcs', 'sum_employee_age',
            [{'$lookup': {'as': '_field_sum_employee_age',
                            'from': 'resource_calcs',
                            'pipeline': []}},
            {'$group': {'_id': '$_field_sum_employee_age'}},
            {'$unwind': '$_id'},
            {'$replaceRoot': {'newRoot': '$_id'}}])], affected_ids_agg_after)

        # check affected ids
        self.assertEqual(set([
        ]), self.move_resource.affected_ids())

        # need to perform the move before the after ids will show up
        self.move_resource.perform_move()

        # check affected ids for to path
        self.assertEqual(set([
            ('calcs', 'sum_employee_age', self.schema.decodeid(calcs_id_1)),
        ]), self.move_resource.affected_ids_to_path())

        # check canonical_url
        employee = self.db['resource_employee'].find_one({'_id': self.schema.decodeid(employee_id_1 )})
        self.assertEqual('/', employee['_parent_canonical_url'])
        self.assertEqual('former_employees', employee['_parent_field_name'])

    def test_move_from_root_more_resources(self):
        self.schema.add_calc(self.calcs_spec, 'sum_employee_age', 'sum(current_employees.age)')
        self.schema.add_field(self.schema.root, 'calcs', 'collection', 'calcs')

        # add root resources
        employee_id_1 = self.schema.insert_resource('employee', {'name': 'Bob', 'age': 10}, 'current_employees')
        employee_id_2 = self.schema.insert_resource('employee', {'name': 'Ned', 'age': 14}, 'current_employees')

        calcs_id_1 = self.schema.insert_resource('calcs', {}, 'calcs')
        calcs_id_2 = self.schema.insert_resource('calcs', {}, 'calcs')

        # create move update
        self.move_resource = MoveResourceUpdate(
            self.updater,
            self.schema,
            None,
            'root',
            'root',
            'former_employees',
            'current_employees')

        # check affected ids
        self.assertEqual(set([
            ('calcs', 'sum_employee_age', self.schema.decodeid(calcs_id_1)),
            ('calcs', 'sum_employee_age', self.schema.decodeid(calcs_id_2)),
        ]), self.move_resource.affected_ids())

    def test_move_from_child_collection(self):
        self.division_spec = self.schema.add_spec('division')
        self.schema.add_field(self.division_spec, 'name', 'str')

        self.schema.add_field(self.schema.root, 'divisions', 'collection', 'division')
        self.schema.add_field(self.schema.root, 'calcs', 'collection', 'calcs')

        self.schema.add_field(self.division_spec, 'employees', 'collection', 'employee')

        self.schema.add_field(self.calcs_spec, 'division', 'link', 'division')
        self.schema.add_calc(self.calcs_spec, 'sum_division_employee_age', 'sum(self.division.employees.age)')

        # add root resources
        division_id_1 = self.schema.insert_resource('division', {'name': 'Sales'}, 'divisions')
        division_id_2 = self.schema.insert_resource('division', {'name': 'Marketting'}, 'divisions')

        employee_id_1 = self.schema.insert_resource('employee', {'name': 'Bob', 'age': 10}, 'employees', 'division', division_id_1)
        employee_id_2 = self.schema.insert_resource('employee', {'name': 'Ned', 'age': 14}, 'employees', 'division', division_id_1)
        employee_id_3 = self.schema.insert_resource('employee', {'name': 'Fred', 'age': 16}, 'employees', 'division', division_id_2)

        calcs_id_1 = self.schema.insert_resource('calcs', {"division": division_id_1}, 'calcs')
        calcs_id_2 = self.schema.insert_resource('calcs', {"division": division_id_2}, 'calcs')

        # create move update
        self.move_resource = MoveResourceUpdate(
            self.updater,
            self.schema,
            division_id_2,
            'division',
            'employees',
            'divisions/%s/employees' % division_id_2,
            'divisions/%s/employees' % division_id_1)

        # check from agg
        from_path_agg, from_path_spec, from_path_is_coll = self.move_resource.from_path_agg()
        self.assertEqual([
            {'$match': {'$and': [{'_parent_field_name': 'divisions'},
                                 {'_parent_canonical_url': '/'}]}},
            {'$match': {'_id': self.schema.decodeid(division_id_1)}},
            {'$lookup': {'as': '_field_employees',
                        'foreignField': '_parent_id',
                        'from': 'resource_employee',
                        'localField': '_id'}},
            {'$group': {'_id': '$_field_employees'}},
            {'$unwind': '$_id'},
            {'$replaceRoot': {'newRoot': '$_id'}}], from_path_agg)
        self.assertEqual(self.schema.specs['employee'], from_path_spec)
        self.assertTrue(from_path_is_coll)

        # check affected ids agg
        affected_ids_agg_before = self.move_resource.affected_aggs()
        self.assertEqual([
            ('calcs', 'sum_division_employee_age', [
            # lookup to division
            {'$lookup': {'as': '_field_employees',
                        'foreignField': '_id',
                        'from': 'resource_division',
                        'localField': '_parent_id'}},
            {'$group': {'_id': '$_field_employees'}},
            {'$unwind': '$_id'},
            {'$replaceRoot': {'newRoot': '$_id'}},
            # lookup to calcs
            {'$lookup': {'as': '_field_division',
                        'foreignField': 'division',
                        'from': 'resource_calcs',
                        'localField': '_id'}},
            {'$group': {'_id': '$_field_division'}},
            {'$unwind': '$_id'},
            {'$replaceRoot': {'newRoot': '$_id'}}])], affected_ids_agg_before)

        # check affected ids
        self.assertEqual(set([
            ('calcs', 'sum_division_employee_age', self.schema.decodeid(calcs_id_1)),
        ]), self.move_resource.affected_ids())
Exemple #6
0
class UpdaterTest(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)

        self.updater = Updater(self.schema)

        self.schema.create_initial_schema()


        self.company_spec = self.schema.add_spec('company')
        self.employee_spec = self.schema.add_spec('employee')
        self.division_spec = self.schema.add_spec('division')

        self.schema.add_field(self.company_spec, 'divisions', 'collection', 'division')

        self.schema.add_field(self.employee_spec, 'name', 'str')

        self.schema.add_field(self.division_spec, 'employees', 'collection', 'employee')

        self.schema.add_field(self.schema.root, 'companies', 'collection', 'company')


    def test_delete_group(self):
        self.admin_group_id = self.updater.create_resource('group', 'root', 'groups', None, {'name': 'admin'}, self.schema.read_root_grants('groups'))

        self.grant_id = self.updater.create_resource('grant', 'group', 'grants', self.admin_group_id, {'type': 'read', 'url': '/companies'})

        self.user_id = self.updater.create_resource('user', 'root', 'users', None, {'username': '******', 'password': '******', 'admin': True}, self.schema.read_root_grants('users'))

        self.updater.create_linkcollection_entry('user', self.user_id, 'groups', self.admin_group_id)


        user_db = self.db['resource_user'].find_one()
        self.assertEqual(1, len(user_db['read_grants']))

        self.updater.delete_linkcollection_entry('user', self.schema.decodeid(self.user_id), 'groups', self.admin_group_id)

        user_db = self.db['resource_user'].find_one()
        self.assertEqual(0, len(user_db['read_grants']))

    def test_root_grants(self):
        group_id = self.updater.create_resource('group', 'root', 'groups', None, {'name': 'readall'}, self.schema.read_root_grants('groups'))
        grant_id = self.updater.create_resource('grant', 'group', 'grants', group_id, {'type': 'read', 'url': '/'})

        company_id = self.updater.create_resource('company', 'root', 'companies', None, {}, self.schema.read_root_grants('companies'))

        company_data = self.db['resource_company'].find_one({})
        self.assertEqual([self.schema.decodeid(grant_id)], company_data['_grants'])

    def test_nested_grants(self):
        group_id = self.updater.create_resource('group', 'root', 'groups', None, {'name': 'readall'}, self.schema.read_root_grants('groups'))
        grant_id = self.updater.create_resource('grant', 'group', 'grants', group_id, {'type': 'read', 'url': '/'})

        company_id = self.updater.create_resource('company', 'root', 'companies', None, {}, self.schema.read_root_grants('companies'))

        company_path = "companies/%s" % company_id
        division_id_1 = self.updater.create_resource('division', 'company', 'divisions', company_id, {}, self.schema.read_root_grants(company_path))
        division_id_2 = self.updater.create_resource('division', 'company', 'divisions', company_id, {}, self.schema.read_root_grants(company_path))

        division_1_path = "companies/%s/divisions/%s" % (company_id, division_id_1)
        employee_id_1 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {}, self.schema.read_root_grants(division_1_path))
        employee_id_2 = self.updater.create_resource('employee', 'division', 'employees', division_id_1, {}, self.schema.read_root_grants(division_1_path))

        division_2_path = "companies/%s/divisions/%s" % (company_id, division_id_2)
        employee_id_3 = self.updater.create_resource('employee', 'division', 'employees', division_id_2, {}, self.schema.read_root_grants(division_2_path))
        employee_id_4 = self.updater.create_resource('employee', 'division', 'employees', division_id_2, {}, self.schema.read_root_grants(division_2_path))

        # check grants
        company_data = self.db['resource_company'].find_one({})
        self.assertEqual([self.schema.decodeid(grant_id)], company_data['_grants'])

        division_1_data = self.db['resource_division'].find_one({"_id": self.schema.decodeid(division_id_1)})
        self.assertEqual([self.schema.decodeid(grant_id)], division_1_data['_grants'])

        division_2_data = self.db['resource_division'].find_one({"_id": self.schema.decodeid(division_id_2)})
        self.assertEqual([self.schema.decodeid(grant_id)], division_2_data['_grants'])

        employee_1_data = self.db['resource_employee'].find_one({"_id": self.schema.decodeid(employee_id_1)})
        self.assertEqual([self.schema.decodeid(grant_id)], employee_1_data['_grants'])

        employee_2_data = self.db['resource_employee'].find_one({"_id": self.schema.decodeid(employee_id_2)})
        self.assertEqual([self.schema.decodeid(grant_id)], employee_2_data['_grants'])

        employee_3_data = self.db['resource_employee'].find_one({"_id": self.schema.decodeid(employee_id_3)})
        self.assertEqual([self.schema.decodeid(grant_id)], employee_3_data['_grants'])

        employee_4_data = self.db['resource_employee'].find_one({"_id": self.schema.decodeid(employee_id_4)})
        self.assertEqual([self.schema.decodeid(grant_id)], employee_4_data['_grants'])

    def test_deleting_grant_removes_grant_id(self):
        group_id = self.updater.create_resource('group', 'root', 'groups', None, {'name': 'readall'}, self.schema.read_root_grants('groups'))
        grant_id = self.updater.create_resource('grant', 'group', 'grants', group_id, {'type': 'read', 'url': '/'})

        company_id = self.updater.create_resource('company', 'root', 'companies', None, {}, self.schema.read_root_grants('companies'))

        self.updater.delete_resource('grant', grant_id, 'group', 'grants')

        company_data = self.db['resource_company'].find_one({})
        self.assertEqual([], company_data['_grants'])
class UpdaterBackgroundTest(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)

        self.api = Api(self.schema)

        self.employee_spec = self.schema.add_spec('employee')
        self.schema.add_field(self.employee_spec, 'name', 'str')
        self.schema.add_field(self.employee_spec, 'age', 'int')

        self.division_spec = self.schema.add_spec('division')
        self.schema.add_field(self.division_spec, 'name', 'str')
        self.schema.add_field(self.division_spec, 'employees', 'collection',
                              'employee')
        self.schema.add_field(self.division_spec, 'managers', 'linkcollection',
                              'employee')
        self.schema.add_calc(self.division_spec, 'older_managers',
                             'self.managers[age>30]')

        self.company_spec = self.schema.add_spec('company')
        self.schema.add_field(self.company_spec, 'name', 'str')
        self.schema.add_field(self.company_spec, 'division', 'link',
                              'division')
        self.schema.add_calc(self.company_spec, 'max_age',
                             'max(self.division.older_managers.age)')

        self.schema.add_field(self.schema.root, 'companies', 'collection',
                              'company')
        self.schema.add_field(self.schema.root, 'divisions', 'collection',
                              'division')

    def test_update(self):
        company_1_id = self.api.post('/companies', {'name': 'Bobs Burgers'})
        division_1_id = self.api.post('/divisions', {'name': 'Kitchen'})

        employee_1_id = self.api.post(
            '/divisions/%s/employees' % division_1_id, {
                'name': 'Bob',
                'age': 38
            })
        employee_2_id = self.api.post(
            '/divisions/%s/employees' % division_1_id, {
                'name': 'Linda',
                'age': 36
            })

        self.api.post('/divisions/%s/managers' % division_1_id,
                      {'id': employee_1_id})
        self.api.post('/divisions/%s/managers' % division_1_id,
                      {'id': employee_2_id})

        self.assertEquals(
            None,
            self.api.get('/companies/%s' % company_1_id)['max_age'])

        self.api.patch('/companies/%s' % company_1_id,
                       {'division': division_1_id})

        self.assertEquals(
            38,
            self.api.get('/companies/%s' % company_1_id)['max_age'])
Exemple #8
0
class AggregatorTest(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        client = MongoClient()
        client.drop_database('metaphor2_test_db')
        self.db = client.metaphor2_test_db
        self.schema = Schema(self.db)

        self.updater = Updater(self.schema)

        self.employee_spec = self.schema.add_spec('employee')
        self.schema.add_field(self.employee_spec, 'name', 'str')
        self.schema.add_field(self.employee_spec, 'age', 'int')

        self.section_spec = self.schema.add_spec('section')
        self.schema.add_field(self.section_spec, 'name', 'str')
        self.schema.add_field(self.section_spec, 'members', 'linkcollection',
                              'employee')

        self.division_spec = self.schema.add_spec('division')
        self.schema.add_field(self.division_spec, 'name', 'str')
        self.schema.add_field(self.division_spec, 'employees', 'collection',
                              'employee')
        self.schema.add_field(self.division_spec, 'sections', 'collection',
                              'section')

        self.schema.add_field(self.schema.root, 'divisions', 'collection',
                              'division')

        self.aggregator = ReverseAggregator(self.schema)

    def test_simple(self):
        tree = parse('self.employees.age', self.schema.specs['division'])

        employee_id = ObjectId()
        aggregations = self.aggregator.get_for_resource(
            tree, 'employee', employee_id, 'division', 'all_employees_age')

        self.assertEqual([[{
            '$match': {
                '_id': employee_id
            }
        }, {
            '$lookup': {
                'as': '_field_employees',
                'foreignField': '_id',
                'from': 'resource_division',
                'localField': '_parent_id'
            }
        }, {
            '$group': {
                '_id': '$_field_employees'
            }
        }, {
            '$unwind': '$_id'
        }, {
            '$replaceRoot': {
                'newRoot': '$_id'
            }
        }]], aggregations)

    def test_middle_of_calc(self):
        tree = parse('divisions.sections.members.age',
                     self.schema.specs['division'])

        section_id = ObjectId()
        aggregations = self.aggregator.get_for_resource(
            tree, 'section', section_id, 'division', 'all_ages')

        self.assertEqual([[{
            '$match': {
                '_id': section_id
            }
        }, {
            '$lookup': {
                'as': '_field_sections',
                'foreignField': '_id',
                'from': 'resource_division',
                'localField': '_parent_id'
            }
        }, {
            '$group': {
                '_id': '$_field_sections'
            }
        }, {
            '$unwind': '$_id'
        }, {
            '$replaceRoot': {
                'newRoot': '$_id'
            }
        }],
                          [{
                              '$lookup': {
                                  'as': '_field_all_ages',
                                  'from': 'resource_division',
                                  'pipeline': []
                              }
                          }, {
                              '$group': {
                                  '_id': '$_field_all_ages'
                              }
                          }, {
                              '$unwind': '$_id'
                          }, {
                              '$replaceRoot': {
                                  'newRoot': '$_id'
                              }
                          }]], aggregations)

    def test_double(self):
        tree = parse(
            'self.employees.parent_division_employees.sections.members.age',
            self.schema.specs['division'])

        employee_id = ObjectId()
        aggregations = self.aggregator.get_for_resource(
            tree, 'employee', employee_id)

        self.assertEqual([
            [
                {
                    '$match': {
                        '_id': employee_id
                    }
                },
                {
                    '$lookup': {
                        'as': '_field_members',
                        'foreignField': 'members._id',
                        'from': 'resource_section',
                        'localField': '_id'
                    }
                },
                {
                    '$group': {
                        '_id': '$_field_members'
                    }
                },
                {
                    '$unwind': '$_id'
                },
                {
                    '$replaceRoot': {
                        'newRoot': '$_id'
                    }
                },
                {
                    '$lookup': {
                        'as': '_field_sections',
                        'foreignField': '_id',
                        'from': 'resource_division',
                        'localField': '_parent_id'
                    }
                },
                {
                    '$group': {
                        '_id': '$_field_sections'
                    }
                },
                {
                    '$unwind': '$_id'
                },
                {
                    '$replaceRoot': {
                        'newRoot': '$_id'
                    }
                },
                {
                    '$lookup': {
                        'as': '_field_parent_division_employees',
                        'foreignField': '_parent_id',
                        'from': 'resource_employee',
                        'localField': '_id'
                    }
                },
                {
                    '$group': {
                        '_id': '$_field_parent_division_employees'
                    }
                },
                {
                    '$unwind': '$_id'
                },
                {
                    '$replaceRoot': {
                        'newRoot': '$_id'
                    }
                },
                {
                    '$lookup': {
                        'as': '_field_employees',
                        'foreignField': '_id',
                        'from': 'resource_division',
                        'localField': '_parent_id'
                    }
                },
                {
                    '$group': {
                        '_id': '$_field_employees'
                    }
                },
                {
                    '$unwind': '$_id'
                },
                {
                    '$replaceRoot': {
                        'newRoot': '$_id'
                    }
                },
            ],
            [
                {
                    '$match': {
                        '_id': employee_id
                    }
                },
                {
                    '$lookup': {
                        'as': '_field_employees',
                        'foreignField': '_id',
                        'from': 'resource_division',
                        'localField': '_parent_id'
                    }
                },
                {
                    '$group': {
                        '_id': '$_field_employees'
                    }
                },
                {
                    '$unwind': '$_id'
                },
                {
                    '$replaceRoot': {
                        'newRoot': '$_id'
                    }
                },
            ],
        ], aggregations)

    def test_calc(self):
        tree = parse(
            'max(self.employees.age) + min(divisions.employees.age) + 10',
            self.schema.specs['division'])

        employee_id = ObjectId()
        aggregations = self.aggregator.get_for_resource(
            tree, 'employee', employee_id, 'section', 'age_calc')

        self.assertEqual(
            [
                [
                    {
                        '$match': {
                            '_id': employee_id
                        }
                    },
                    {
                        '$lookup': {
                            'as': '_field_employees',
                            'foreignField': '_id',
                            'from': 'resource_division',
                            'localField': '_parent_id'
                        }
                    },
                    {
                        '$group': {
                            '_id': '$_field_employees'
                        }
                    },
                    {
                        '$unwind': '$_id'
                    },
                    {
                        '$replaceRoot': {
                            'newRoot': '$_id'
                        }
                    },
                ],
                # TODO: if two of the aggregations are the same, remove the second one:
                [
                    {
                        '$match': {
                            '_id': employee_id
                        }
                    },
                    {
                        '$lookup': {
                            'as': '_field_employees',
                            'foreignField': '_id',
                            'from': 'resource_division',
                            'localField': '_parent_id'
                        }
                    },
                    {
                        '$group': {
                            '_id': '$_field_employees'
                        }
                    },
                    {
                        '$unwind': '$_id'
                    },
                    {
                        '$replaceRoot': {
                            'newRoot': '$_id'
                        }
                    },
                ],
                [
                    {
                        '$lookup': {
                            'as': '_field_age_calc',
                            'from': 'resource_section',
                            'pipeline': []
                        }
                    },
                    {
                        '$group': {
                            '_id': '$_field_age_calc'
                        }
                    },
                    {
                        '$unwind': '$_id'
                    },
                    {
                        '$replaceRoot': {
                            'newRoot': '$_id'
                        }
                    },
                ]
            ],
            aggregations)

    def test_double_aggregate(self):
        division_id_1 = self.schema.insert_resource('division',
                                                    {'name': 'Sales'},
                                                    'divisions')

        section_id_1 = self.schema.insert_resource('section',
                                                   {'name': 'Sales'},
                                                   'sections', 'division',
                                                   division_id_1)

        employee_id_1 = self.schema.insert_resource('employee', {
            'name': 'ned',
            'age': 10
        }, 'employees', 'division', division_id_1)
        employee_id_2 = self.schema.insert_resource('employee', {
            'name': 'bob',
            'age': 10
        }, 'employees', 'division', division_id_1)

        self.schema.create_linkcollection_entry('section', section_id_1,
                                                'members', employee_id_1)

        tree = parse(
            'self.employees.parent_division_employees.sections.members.age',
            self.schema.specs['division'])

        aggregations = self.aggregator.get_for_resource(
            tree, 'employee', self.schema.decodeid(employee_id_1))

        result = self.schema.db['resource_employee'].aggregate(aggregations[0])
        self.assertEqual(
            {
                '_canonical_url': '/divisions/%s' % division_id_1,
                '_grants': [],
                '_id': self.schema.decodeid(division_id_1),
                '_parent_canonical_url': '/',
                '_parent_field_name': 'divisions',
                '_parent_id': None,
                '_parent_type': 'root',
                'name': 'Sales'
            }, next(result))

    def test_ternary_aggregate(self):
        division_id_1 = self.schema.insert_resource('division',
                                                    {'name': 'Sales'},
                                                    'divisions')

        section_id_1 = self.schema.insert_resource('section',
                                                   {'name': 'Sales'},
                                                   'sections', 'division',
                                                   division_id_1)

        employee_id_1 = self.schema.insert_resource('employee', {
            'name': 'ned',
            'age': 10
        }, 'employees', 'division', division_id_1)
        employee_id_2 = self.schema.insert_resource('employee', {
            'name': 'bob',
            'age': 10
        }, 'employees', 'division', division_id_1)

        self.schema.create_linkcollection_entry('section', section_id_1,
                                                'members', employee_id_1)

        tree = parse(
            'max(self.employees.age) > 20 -> max(self.employees.age) : min(divisions.sections.members.age)',
            self.schema.specs['division'])

        aggregations = self.aggregator.get_for_resource(
            tree, 'employee', self.schema.decodeid(employee_id_1))

        result = self.schema.db['resource_employee'].aggregate(aggregations[0])
        self.assertEqual(
            {
                '_canonical_url': '/divisions/%s' % division_id_1,
                '_grants': [],
                '_id': self.schema.decodeid(division_id_1),
                '_parent_canonical_url': '/',
                '_parent_field_name': 'divisions',
                '_parent_id': None,
                '_parent_type': 'root',
                'name': 'Sales'
            }, next(result))

    def test_simple_root(self):
        # uncertain what case this is testing exactly - section has no link to division
        division_id_1 = self.schema.insert_resource('division',
                                                    {'name': 'Sales'},
                                                    'divisions')

        tree = parse('max(divisions.name)', self.schema.root)

        aggregations = self.aggregator.get_for_resource(
            tree, 'division', self.schema.decodeid(division_id_1), 'division',
            'max_divisions_name')

        self.assertEqual([[{
            '$lookup': {
                'as': '_field_max_divisions_name',
                'from': 'resource_division',
                'pipeline': []
            }
        }, {
            '$group': {
                '_id': '$_field_max_divisions_name'
            }
        }, {
            '$unwind': '$_id'
        }, {
            '$replaceRoot': {
                'newRoot': '$_id'
            }
        }]], aggregations)