コード例 #1
0
    def validate(self) -> bool:
        missing_fields = []
        if not bool(self.name):
            missing_fields.append('name')
        if not bool(self.entity):
            missing_fields.append('entity')
        if bool(self.cardinality):
            if not bool(self.cardinality.minimum):
                missing_fields.append('cardinality.minimum')
            if not bool(self.cardinality.maximum):
                missing_fields.append('cardinality.maximum')

        if missing_fields:
            logger.error(
                self._TAG, self.ctx,
                Errors.validate_error_string(self.at_corpus_path,
                                             missing_fields))
            return False

        if bool(self.cardinality):
            if not CardinalitySettings._is_minimum_valid(
                    self.cardinality.minimum):
                logger.error(
                    self._TAG, self.ctx,
                    'Invalid minimum cardinality {}.'.format(
                        self.cardinality.minimum))
                return False
            if not CardinalitySettings._is_maximum_valid(
                    self.cardinality.maximum):
                logger.error(
                    self._TAG, self.ctx,
                    'Invalid maximum cardinality {}.'.format(
                        self.cardinality.maximum))
                return False
        return True
コード例 #2
0
ファイル: utils.py プロジェクト: minettes/CDM
def cardinality_settings_from_data(data: CardinalitySettings, attribute: CdmAttribute) -> CardinalitySettings:
    """Converts cardinality data into a CardinalitySettings object"""
    if data is None:
        return None

    cardinality = CardinalitySettings(attribute)
    cardinality.minimum = data.get('minimum')
    cardinality.maximum = data.get('maximum')

    if cardinality.minimum is not None and cardinality.maximum is not None:
        return cardinality
    else:
        return None

    return data
コード例 #3
0
ファイル: projection_directive.py プロジェクト: rt112000/CDM
    def __init__(self,
                 res_opt: 'ResolveOptions',
                 owner: 'CdmObjectDefinition',
                 owner_ref: Optional['CdmObjectReference'] = None):
        # --- internal ---

        # Resolution option used
        self._res_opt = res_opt  # type: ResolveOptions

        # The calling referencing EntityDef, the EntityAttributeDef, or the TypeAttributeDef that contains this projection
        self._owner = owner  # type: CdmObjectDefinition

        # The EntityRef to the owning EntityDef, EntityAttributeDef, or TypeAttributeDef
        self._owner_ref = owner_ref  # type: CdmObjectReference

        if owner and owner.object_type == CdmObjectType.ENTITY_ATTRIBUTE_DEF:
            # If EntityAttributeDef - then the Cardinality from the Owner EntityAttributeDef
            # This is ignored for EntityDef and will default to min:max = 0:1
            self._cardinality = owner.cardinality if owner.cardinality else CardinalitySettings(
                owner)  # type: CardinalitySettings
            # For entity attribute - get if the source is polymorphic
            self._is_source_polymorphic = owner.is_polymorphic_source is not None and owner.is_polymorphic_source == True  # type: bool
        else:
            self._cardinality = None
            self._is_source_polymorphic = False

        # Is referenceOnly
        self._is_reference_only = res_opt.directives.has(
            'referenceOnly'
        ) == True if res_opt.directives else False  # type: bool

        # Is normalized
        self._is_normalized = res_opt.directives.has(
            'normalized'
        ) == True if res_opt.directives else False  # type: bool

        #  Is structured
        self._is_structured = res_opt.directives.has(
            'structured'
        ) == True if res_opt.directives else False  # type: bool

        #  Is virtual
        self._is_virtual = res_opt.directives.has(
            'virtual') == True if res_opt.directives else False  # type: bool

        # Has maximum depth override flag
        self._has_no_maximum_depth = res_opt.directives.has(
            'noMaxDepth'
        ) == True if res_opt.directives else False  # type: bool

        # Is array
        self._is_array = res_opt.directives.has(
            'isArray'
        ) == True if res_opt.directives else False  # type: Optional[bool]

        # if noMaxDepth directive the max depth is 32 else defaults to what was set by the user
        # these depths were arbitrary and were set for the resolution guidance
        # re-using the same for projections as well
        self._maximum_depth = DepthInfo.MAX_DEPTH_LIMIT if self._has_no_maximum_depth else res_opt.max_depth  # type: Optional[int]
コード例 #4
0
    async def test_zero_minimum_cardinality(self):
        """
        Test case scenario for Bug #23 from the projections internal bug bash
        Reference Link: https://commondatamodel.visualstudio.com/CDM/_workitems/edit/23
        """
        test_name = "test_zero_minimum_cardinality"

        corpus = TestHelper.get_local_corpus(self.tests_subpath, test_name)

        def callback(level, message):
            self.fail(message)

        corpus.set_event_callback(callback, CdmStatusLevel.WARNING)

        # Create Local Root Folder
        local_root = corpus.storage.fetch_root_folder('local')

        # Create Manifest
        manifest = corpus.make_object(CdmObjectType.MANIFEST_DEF, 'default')
        local_root.documents.append(manifest, 'default.manifest.cdm.json')

        entity_name = 'TestEntity'

        # Create Entity
        entity = corpus.make_object(CdmObjectType.ENTITY_DEF, entity_name)
        entity.extends_entity = corpus.make_ref(CdmObjectType.ENTITY_REF,
                                                'CdmEntity', True)

        # Create Entity Document
        document = corpus.make_object(CdmObjectType.DOCUMENT_DEF,
                                      '{}.cdm.json'.format(entity_name), False)
        document.definitions.append(entity)
        local_root.documents.append(document, document.name)
        manifest.entities.append(entity)

        attribute_name = 'testAttribute'
        attribute_data_type = 'string'
        attribute_purpose = 'hasA'

        # Create Type Attribute
        attribute = corpus.make_object(CdmObjectType.TYPE_ATTRIBUTE_DEF,
                                       attribute_name, False)
        foo = attribute.is_nullable
        attribute.data_type = corpus.make_ref(CdmObjectType.DATA_TYPE_REF,
                                              attribute_data_type, True)
        attribute.purpose = corpus.make_ref(CdmObjectType.PURPOSE_REF,
                                            attribute_purpose, True)
        attribute.display_name = attribute_name

        if entity:
            entity.attributes.append(attribute)

        attribute.cardinality = CardinalitySettings(attribute)
        attribute.cardinality.minimum = '0'
        attribute.cardinality.maximum = '*'

        self.assertTrue(attribute.is_nullable)
コード例 #5
0
    def validate(self) -> bool:
        missing_fields = []
        if not bool(self.name):
            missing_fields.append('name')
        if not bool(self.entity):
            missing_fields.append('entity')
        if bool(self.cardinality):
            if not bool(self.cardinality.minimum):
                missing_fields.append('cardinality.minimum')
            if not bool(self.cardinality.maximum):
                missing_fields.append('cardinality.maximum')

        if missing_fields:
            logger.error(
                self.ctx, self._TAG, 'validate', self.at_corpus_path,
                CdmLogCode.ERR_VALDN_INTEGRITY_CHECK_FAILURE,
                self.at_corpus_path,
                ', '.join(map(lambda s: '\'' + s + '\'', missing_fields)))
            return False

        if bool(self.cardinality):
            if not CardinalitySettings._is_minimum_valid(
                    self.cardinality.minimum):
                logger.error(self.ctx, self._TAG, 'validate',
                             self.at_corpus_path,
                             CdmLogCode.ERR_VALDN_INVALID_MIN_CARDINALITY,
                             self.cardinality.minimum)
                return False
            if not CardinalitySettings._is_maximum_valid(
                    self.cardinality.maximum):
                logger.error(self.ctx, self._TAG, 'validate',
                             self.at_corpus_path,
                             CdmLogCode.ERR_VALDN_INVALID_MAX_CARDINALITY,
                             self.cardinality.maximum)
                return False
        return True
コード例 #6
0
    def test_minimum(self):
        """Unit test for CardinalitySetting.IsMinimumValid"""
        test_name = 'TestMinimum'

        corpus = ProjectionTestUtils.get_local_corpus(self.tests_subpath, test_name)

        def callback(level, message):
            if 'CardinalitySettings | Invalid minimum cardinality -1.' not in message:
                self.fail('Some unexpected failure - {}!'.format(message))
        corpus.set_event_callback(callback, CdmStatusLevel.WARNING)

        # Create Dummy Type Attribute
        attribute = corpus.make_object(CdmObjectType.TYPE_ATTRIBUTE_DEF, "dummyAttribute", False)
        attribute.cardinality = CardinalitySettings(attribute)
        attribute.cardinality.minimum = '-1'
コード例 #7
0
    def from_data(
            ctx: CdmCorpusContext,
            data: TypeAttribute,
            entity_name: Optional[str] = None) -> CdmTypeAttributeDefinition:
        type_attribute = ctx.corpus.make_object(
            CdmObjectType.TYPE_ATTRIBUTE_DEF, data.get('name'))
        type_attribute.purpose = PurposeReferencePersistence.from_data(
            ctx, data.get('purpose'))
        type_attribute.data_type = DataTypeReferencePersistence.from_data(
            ctx, data.get('dataType'))

        if data.get('cardinality'):
            min_cardinality = None
            if data.get('cardinality').get('minimum'):
                min_cardinality = data.get('cardinality').get('minimum')

            max_cardinality = None
            if data.get('cardinality').get('maximum'):
                max_cardinality = data.get('cardinality').get('maximum')

            if not min_cardinality or not max_cardinality:
                logger.error(
                    _TAG, ctx,
                    'Both minimum and maximum are required for the Cardinality property.'
                )

            if not CardinalitySettings._is_minimum_valid(min_cardinality):
                logger.error(
                    _TAG, ctx,
                    'Invalid minimum cardinality {}.'.format(min_cardinality))

            if not CardinalitySettings._is_maximum_valid(max_cardinality):
                logger.error(
                    _TAG, ctx,
                    'Invalid maximum cardinality {}.'.format(max_cardinality))

            if min_cardinality and max_cardinality and CardinalitySettings._is_minimum_valid(
                    min_cardinality) and CardinalitySettings._is_maximum_valid(
                        max_cardinality):
                type_attribute.cardinality = CardinalitySettings(
                    type_attribute)
                type_attribute.cardinality.minimum = min_cardinality
                type_attribute.cardinality.maximum = max_cardinality

        type_attribute.attribute_context = AttributeContextReferencePersistence.from_data(
            ctx, data.get('attributeContext'))
        type_attribute.resolution_guidance = AttributeResolutionGuidancePersistence.from_data(
            ctx, data.get('resolutionGuidance'))

        applied_traits = utils.create_trait_reference_array(
            ctx, data.get('appliedTraits'))
        type_attribute.applied_traits.extend(applied_traits)

        if data.get('isPrimaryKey') and entity_name:
            t2p_map = TraitToPropertyMap(type_attribute)
            t2p_map._update_property_value(
                'isPrimaryKey',
                entity_name + '/(resolvedAttributes)/' + type_attribute.name)

        type_attribute.explanation = data.explanation
        type_attribute.is_read_only = utils._property_from_data_to_bool(
            data.isReadOnly)
        type_attribute.is_nullable = utils._property_from_data_to_bool(
            data.isNullable)
        type_attribute.source_name = utils._property_from_data_to_string(
            data.sourceName)
        type_attribute.source_ordering = utils._property_from_data_to_int(
            data.sourceOrdering)
        type_attribute.display_name = utils._property_from_data_to_string(
            data.displayName)
        type_attribute.description = utils._property_from_data_to_string(
            data.description)
        type_attribute.value_constrained_to_list = utils._property_from_data_to_bool(
            data.valueConstrainedToList)
        type_attribute.maximum_length = utils._property_from_data_to_int(
            data.maximumLength)
        type_attribute.maximum_value = utils._property_from_data_to_string(
            data.maximumValue)
        type_attribute.minimum_value = utils._property_from_data_to_string(
            data.minimumValue)
        type_attribute.default_value = data.defaultValue
        type_attribute.projection = ProjectionPersistence.from_data(
            ctx, data.projection)

        if data.get('dataFormat') is not None:
            try:
                type_attribute.data_format = TypeAttributePersistence._data_type_from_data(
                    data.dataFormat)
            except ValueError:
                logger.warning(
                    TypeAttributePersistence.__name__, ctx,
                    'Couldn\'t find an enum value for {}.'.format(
                        data.dataFormat),
                    TypeAttributePersistence.from_data.__name__)

        return type_attribute
コード例 #8
0
    def from_data(ctx: CdmCorpusContext,
                  data: EntityAttribute) -> CdmEntityAttributeDefinition:
        entity_attribute = ctx.corpus.make_object(
            CdmObjectType.ENTITY_ATTRIBUTE_DEF, data.name)

        entity_attribute.description = data.description
        entity_attribute.display_name = data.displayName
        entity_attribute.explanation = data.explanation

        if data.get('cardinality'):
            min_cardinality = None
            if data.get('cardinality').get('minimum'):
                min_cardinality = data.get('cardinality').get('minimum')

            max_cardinality = None
            if data.get('cardinality').get('maximum'):
                max_cardinality = data.get('cardinality').get('maximum')

            if not min_cardinality or not max_cardinality:
                logger.error(ctx, _TAG,
                             EntityAttributePersistence.from_data.__name__,
                             None,
                             CdmLogCode.ERR_PERSIST_CARDINALITY_PROP_MISSING)

            if not CardinalitySettings._is_minimum_valid(min_cardinality):
                logger.error(ctx, _TAG,
                             EntityAttributePersistence.from_data.__name__,
                             None,
                             CdmLogCode.ERR_PERSIST_INVALID_MIN_CARDINALITY,
                             min_cardinality)

            if not CardinalitySettings._is_maximum_valid(max_cardinality):
                logger.error(ctx, _TAG,
                             EntityAttributePersistence.from_data.__name__,
                             None,
                             CdmLogCode.ERR_PERSIST_INVALID_MAX_CARDINALITY,
                             max_cardinality)

            if min_cardinality and max_cardinality and CardinalitySettings._is_minimum_valid(
                    min_cardinality) and CardinalitySettings._is_maximum_valid(
                        max_cardinality):
                entity_attribute.cardinality = CardinalitySettings(
                    entity_attribute)
                entity_attribute.cardinality.minimum = min_cardinality
                entity_attribute.cardinality.maximum = max_cardinality

        entity_attribute.is_polymorphic_source = data.get(
            'isPolymorphicSource')

        is_projection = data.get('entity') and not isinstance(
            data.get('entity'), str) and data.get('entity').get('source')

        if is_projection:
            projection = ProjectionPersistence.from_data(
                ctx, data.get('entity'))
            projection.owner = entity_attribute

            inline_entity_ref = ctx.corpus.make_object(
                CdmObjectType.ENTITY_REF, None)
            inline_entity_ref.explicit_reference = projection
            entity_attribute.entity = inline_entity_ref
        else:
            entity_attribute.entity = EntityReferencePersistence.from_data(
                ctx, data.get('entity'))

        entity_attribute.purpose = PurposeReferencePersistence.from_data(
            ctx, data.get('purpose'))
        utils.add_list_to_cdm_collection(
            entity_attribute.applied_traits,
            utils.create_trait_reference_array(ctx, data.get('appliedTraits')))

        # Ignore resolution guidance if the entity is a projection
        if data.get('resolutionGuidance') and is_projection:
            logger.error(ctx, _TAG, 'from_data', None,
                         CdmLogCode.ERR_PERSIST_ENTITY_ATTR_UNSUPPORTED,
                         entity_attribute.name)
        else:
            entity_attribute.resolution_guidance = AttributeResolutionGuidancePersistence.from_data(
                ctx, data.get('resolutionGuidance'))

        return entity_attribute
コード例 #9
0
    def from_data(
            ctx: CdmCorpusContext,
            data: TypeAttribute,
            entity_name: Optional[str] = None) -> CdmTypeAttributeDefinition:
        type_attribute = ctx.corpus.make_object(
            CdmObjectType.TYPE_ATTRIBUTE_DEF, data.get('name'))
        type_attribute.purpose = PurposeReferencePersistence.from_data(
            ctx, data.get('purpose'))
        type_attribute.data_type = DataTypeReferencePersistence.from_data(
            ctx, data.get('dataType'))

        if data.get('cardinality'):
            min_cardinality = None
            if data.get('cardinality').get('minimum'):
                min_cardinality = data.get('cardinality').get('minimum')

            max_cardinality = None
            if data.get('cardinality').get('maximum'):
                max_cardinality = data.get('cardinality').get('maximum')

            if not min_cardinality or not max_cardinality:
                logger.error(ctx, _TAG, 'from_data', None,
                             CdmLogCode.ERR_PERSIST_CARDINALITY_PROP_MISSING)

            if not CardinalitySettings._is_minimum_valid(min_cardinality):
                logger.error(ctx, _TAG, 'from_data', None,
                             CdmLogCode.ERR_VALDN_INVALID_MIN_CARDINALITY,
                             min_cardinality)

            if not CardinalitySettings._is_maximum_valid(max_cardinality):
                logger.error(ctx, _TAG, 'from_data', None,
                             CdmLogCode.ERR_VALDN_INVALID_MAX_CARDINALITY,
                             max_cardinality)

            if min_cardinality and max_cardinality and CardinalitySettings._is_minimum_valid(
                    min_cardinality) and CardinalitySettings._is_maximum_valid(
                        max_cardinality):
                type_attribute.cardinality = CardinalitySettings(
                    type_attribute)
                type_attribute.cardinality.minimum = min_cardinality
                type_attribute.cardinality.maximum = max_cardinality

        type_attribute.attribute_context = AttributeContextReferencePersistence.from_data(
            ctx, data.get('attributeContext'))
        utils.add_list_to_cdm_collection(
            type_attribute.applied_traits,
            utils.create_trait_reference_array(ctx, data.get('appliedTraits')))
        type_attribute.resolution_guidance = AttributeResolutionGuidancePersistence.from_data(
            ctx, data.get('resolutionGuidance'))

        if data.get('isPrimaryKey') and entity_name:
            t2p_map = TraitToPropertyMap(type_attribute)
            t2p_map._update_property_value(
                'isPrimaryKey',
                entity_name + '/(resolvedAttributes)/' + type_attribute.name)

        type_attribute.explanation = data.explanation
        type_attribute.is_read_only = utils._property_from_data_to_bool(
            data.isReadOnly)
        type_attribute.is_nullable = utils._property_from_data_to_bool(
            data.isNullable)
        type_attribute.source_name = utils._property_from_data_to_string(
            data.sourceName)
        type_attribute.source_ordering = utils._property_from_data_to_int(
            data.sourceOrdering)
        type_attribute.display_name = utils._property_from_data_to_string(
            data.displayName)
        type_attribute.description = utils._property_from_data_to_string(
            data.description)
        type_attribute.value_constrained_to_list = utils._property_from_data_to_bool(
            data.valueConstrainedToList)
        type_attribute.maximum_length = utils._property_from_data_to_int(
            data.maximumLength)
        type_attribute.maximum_value = utils._property_from_data_to_string(
            data.maximumValue)
        type_attribute.minimum_value = utils._property_from_data_to_string(
            data.minimumValue)
        type_attribute.default_value = data.defaultValue
        type_attribute.projection = ProjectionPersistence.from_data(
            ctx, data.projection)

        if data.get('dataFormat') is not None:
            try:
                type_attribute.data_format = TypeAttributePersistence._data_type_from_data(
                    data.dataFormat)
            except ValueError:
                logger.warning(ctx, _TAG,
                               TypeAttributePersistence.from_data.__name__,
                               None, CdmLogCode.WARN_PERSIST_ENUM_NOT_FOUND,
                               data.dataFormat)

        return type_attribute
コード例 #10
0
    def from_data(ctx: CdmCorpusContext,
                  data: EntityAttribute) -> CdmEntityAttributeDefinition:
        entity_attribute = ctx.corpus.make_object(
            CdmObjectType.ENTITY_ATTRIBUTE_DEF, data.name)

        entity_attribute.description = data.description
        entity_attribute.display_name = data.displayName
        entity_attribute.explanation = data.explanation

        if data.get('cardinality'):
            min_cardinality = None
            if data.get('cardinality').get('minimum'):
                min_cardinality = data.get('cardinality').get('minimum')

            max_cardinality = None
            if data.get('cardinality').get('maximum'):
                max_cardinality = data.get('cardinality').get('maximum')

            if not min_cardinality or not max_cardinality:
                logger.error(
                    _TAG, ctx,
                    'Both minimum and maximum are required for the Cardinality property.'
                )

            if not CardinalitySettings._is_minimum_valid(min_cardinality):
                logger.error(
                    _TAG, ctx,
                    'Invalid minimum cardinality {}.'.format(min_cardinality))

            if not CardinalitySettings._is_maximum_valid(max_cardinality):
                logger.error(
                    _TAG, ctx,
                    'Invalid maximum cardinality {}.'.format(max_cardinality))

            if min_cardinality and max_cardinality and CardinalitySettings._is_minimum_valid(
                    min_cardinality) and CardinalitySettings._is_maximum_valid(
                        max_cardinality):
                entity_attribute.cardinality = CardinalitySettings(
                    entity_attribute)
                entity_attribute.cardinality.minimum = min_cardinality
                entity_attribute.cardinality.maximum = max_cardinality

        entity_attribute.is_polymorphic_source = data.get(
            'isPolymorphicSource')

        is_projection = data.get('entity') and not isinstance(
            data.get('entity'), str) and data.get('entity').get('source')

        if is_projection:
            projection = ProjectionPersistence.from_data(
                ctx, data.get('entity'))
            projection.owner = entity_attribute

            inline_entity_ref = ctx.corpus.make_object(
                CdmObjectType.ENTITY_REF, None)
            inline_entity_ref.explicit_reference = projection
            entity_attribute.entity = inline_entity_ref
        else:
            entity_attribute.entity = EntityReferencePersistence.from_data(
                ctx, data.get('entity'))

        entity_attribute.purpose = PurposeReferencePersistence.from_data(
            ctx, data.get('purpose'))

        applied_traits = utils.create_trait_reference_array(
            ctx, data.get('appliedTraits'))
        entity_attribute.applied_traits.extend(applied_traits)

        # Ignore resolution guidance if the entity is a projection
        if data.get('resolutionGuidance') and is_projection:
            logger.error(
                _TAG, ctx,
                'The EntityAttribute {} is projection based. Resolution guidance is not supported with a projection.'
                .format(entity_attribute.name))
        else:
            entity_attribute.resolution_guidance = AttributeResolutionGuidancePersistence.from_data(
                ctx, data.get('resolutionGuidance'))

        return entity_attribute