diff --git a/sgschema/schema.py b/sgschema/schema.py index 3591f8b..4010aa5 100644 --- a/sgschema/schema.py +++ b/sgschema/schema.py @@ -192,6 +192,7 @@ def resolve_entity(self, entity_spec, implicit_aliases=True, strict=False): if not op.isalnum(): raise ValueError('unknown entity operation for %r' % entity_spec) + # Actual entity names have preference over implicit aliases. if entity_spec in self.entities: return [entity_spec] @@ -217,6 +218,12 @@ def _resolve_field(self, entity_spec, field_spec, auto_prefix=True, implicit_ali except KeyError: raise ValueError('%r is not an entity type' % entity_spec) + # These two are special, and should always be returned as-is. + # We only need to do "type" in this way, since "id" usually exists + # as a numeric field, but it feels right. + if field_spec in ('id', 'type'): + return [field_spec] + op = field_spec[0] if op == '!': return [field_spec[1:]] @@ -230,6 +237,8 @@ def _resolve_field(self, entity_spec, field_spec, auto_prefix=True, implicit_ali if not op.isalnum(): raise ValueError('unknown field operation for %s %r' % (entity_spec, field_spec)) + # Actual field names have preference over automatic prefixes or + # implicit aliases. if field_spec in entity.fields: return [field_spec] diff --git a/tests/test_resolve.py b/tests/test_resolve.py index a3ccc32..6d1f13c 100644 --- a/tests/test_resolve.py +++ b/tests/test_resolve.py @@ -11,13 +11,15 @@ def setUp(self): 'Entity': { 'aliases': ['A', 'with:Namespace'], 'tags': ['X'], - } + }, + 'Another': {} }, 'entity_aliases': { 'B': 'Entity', }, 'entity_tags': { 'Y': ['Entity'], + 'Multiple': ['Entity', 'Another'], } }) @@ -43,6 +45,14 @@ def test_missing(self): self.assertEqual(self.s.resolve_entity('Missing'), ['Missing']) self.assertRaises(ValueError, self.s.resolve_entity, 'Missing', strict=True) + def test_one(self): + self.assertEqual(self.s.resolve_one_entity('Entity'), 'Entity') + self.assertEqual(self.s.resolve_one_entity('!Entity'), 'Entity') + self.assertEqual(self.s.resolve_one_entity('$A'), 'Entity') + self.assertEqual(self.s.resolve_one_entity('#X'), 'Entity') + self.assertRaises(ValueError, self.s.resolve_one_entity, '#Missing') + self.assertRaises(ValueError, self.s.resolve_one_entity, '#Multiple') + class TestResolveFields(TestCase): @@ -58,6 +68,7 @@ def setUp(self): 'tags': ['x'], }, + 'sg_version': {}, 'sg_type': {}, 'name': {}, 'sg_name': {}, @@ -89,8 +100,12 @@ def test_implicit(self): self.assertEqual(self.s.resolve_field('Entity', 'b'), ['attr']) def test_prefix(self): + self.assertEqual(self.s.resolve_field('Entity', 'sg_version'), ['sg_version']) + self.assertEqual(self.s.resolve_field('Entity', 'version'), ['sg_version']) # Auto-prefix. + self.assertEqual(self.s.resolve_field('Entity', '!version'), ['version']) # Doesn't exist. + self.assertEqual(self.s.resolve_field('Entity', 'sg_type'), ['sg_type']) - self.assertEqual(self.s.resolve_field('Entity', 'type'), ['sg_type']) + self.assertEqual(self.s.resolve_field('Entity', 'type'), ['type']) # This overlaps the implicit "type"! self.assertEqual(self.s.resolve_field('Entity', '!type'), ['type']) self.assertEqual(self.s.resolve_field('Entity', 'sg_name'), ['sg_name'])