def _create_new_projection_attribute_state_set(
            proj_ctx: 'ProjectionContext',
            proj_output_set: 'ProjectionAttributeStateSet',
            new_res_attr_FK: 'ResolvedAttribute',
            ref_attr_name: str
    ) -> 'ProjectionAttributeStateSet':
        pas_list = ProjectionResolutionCommonUtil._get_leaf_list(proj_ctx, ref_attr_name)
        source_entity = proj_ctx._projection_directive._original_source_entity_attribute_name

        if not source_entity:
            logger.warning(proj_output_set._ctx, CdmOperationReplaceAsForeignKey.__name__, \
                CdmOperationReplaceAsForeignKey._create_new_projection_attribute_state_set.__name__, None, CdmLogCode.WARN_PROJ_FK_WITHOUT_SOURCE_ENTITY, ref_attr_name)

        if pas_list is not None:
            # update the new foreign key resolved attribute with trait param with reference details
            reqd_trait = new_res_attr_FK.resolved_traits.find(proj_ctx._projection_directive._res_opt, 'is.linkedEntity.identifier')
            if reqd_trait and source_entity:
                trait_param_ent_ref = ProjectionResolutionCommonUtil._create_foreign_key_linked_entity_identifier_trait_parameter(proj_ctx._projection_directive, proj_output_set._ctx.corpus, pas_list)
                reqd_trait.parameter_values.update_parameter_value(proj_ctx._projection_directive._res_opt, 'entityReferences', trait_param_ent_ref)

            # Create new output projection attribute state set for FK and add prevPas as previous state set
            new_proj_attr_state_FK = ProjectionAttributeState(proj_output_set._ctx)
            new_proj_attr_state_FK._current_resolved_attribute = new_res_attr_FK
            new_proj_attr_state_FK._previous_state_list = pas_list

            proj_output_set._add(new_proj_attr_state_FK)
        else:
            # Log error & return proj_output_set without any change
            logger.error(proj_output_set._ctx, CdmOperationReplaceAsForeignKey.__name__, CdmOperationReplaceAsForeignKey._create_new_projection_attribute_state_set.__name__, None, CdmLogCode.ERR_PROJ_REF_ATTR_STATE_FAILURE, ref_attr_name)
        return proj_output_set
    def _append_projection_attribute_state(
            self, proj_ctx: 'ProjectionContext',
            proj_output_set: 'ProjectionAttributeStateSet',
            attr_ctx: 'CdmAttributeContext') -> 'ProjectionAttributeStateSet':
        # Create a new attribute context for the operation
        attr_ctx_op_exclude_attrs_param = AttributeContextParameters()
        attr_ctx_op_exclude_attrs_param._under = attr_ctx
        attr_ctx_op_exclude_attrs_param._type = CdmAttributeContextType.OPERATION_EXCLUDE_ATTRIBUTES
        attr_ctx_op_exclude_attrs_param._name = 'operation/index{}/operationExcludeAttributes'.format(
            self._index)
        attr_ctx_op_exclude_attrs = CdmAttributeContext._create_child_under(
            proj_ctx._projection_directive._res_opt,
            attr_ctx_op_exclude_attrs_param)

        # Get the top-level attribute names of the attributes to exclude
        # We use the top-level names because the exclude list may contain a previous name our current resolved attributes had
        top_level_exclude_attribute_names = ProjectionResolutionCommonUtil._get_top_list(
            proj_ctx, self.exclude_attributes)

        # Iterate through all the projection attribute states generated from the source's resolved attributes
        # Each projection attribute state contains a resolved attribute that it is corresponding to
        for current_PAS in proj_ctx._current_attribute_state_set._values:
            # Check if the current projection attribute state's resolved attribute is in the list of attributes to exclude
            # If this attribute is not in the exclude list, then we are including it in the output
            if current_PAS._current_resolved_attribute.resolved_name not in top_level_exclude_attribute_names:
                # Create a new attribute context for the attribute that we are including
                attr_ctx_added_attr_param = AttributeContextParameters()
                attr_ctx_added_attr_param._under = attr_ctx
                attr_ctx_added_attr_param._type = CdmAttributeContextType.ATTRIBUTE_DEFINITION
                attr_ctx_added_attr_param._name = current_PAS._current_resolved_attribute.resolved_name
                attr_ctx_added_attr = CdmAttributeContext._create_child_under(
                    proj_ctx._projection_directive._res_opt,
                    attr_ctx_added_attr_param)

                # Create a projection attribute state for the included attribute
                # We only create projection attribute states for attributes that are not in the exclude list
                # Add the current projection attribute state as the previous state of the new projection attribute state
                new_PAS = ProjectionAttributeState(proj_output_set._ctx)
                new_PAS._current_resolved_attribute = current_PAS._current_resolved_attribute
                new_PAS._previous_state_list = [current_PAS]

                proj_output_set._add(new_PAS)
            else:
                # The current projection attribute state's resolved attribute is in the exclude list

                # Get the attribute name the way it appears in the exclude list
                # For our attribute context, we want to use the attribute name the attribute has in the exclude list rather than its current name
                exclude_attribute_name = top_level_exclude_attribute_names[
                    current_PAS._current_resolved_attribute.resolved_name]

                # Create a new attribute context for the excluded attribute
                attr_ctx_excluded_attr_param = AttributeContextParameters()
                attr_ctx_excluded_attr_param._under = attr_ctx_op_exclude_attrs
                attr_ctx_excluded_attr_param._type = CdmAttributeContextType.ATTRIBUTE_DEFINITION
                attr_ctx_excluded_attr_param._name = exclude_attribute_name
                attr_ctx_excluded_attr = CdmAttributeContext._create_child_under(
                    proj_ctx._projection_directive._res_opt,
                    attr_ctx_excluded_attr_param)

        return proj_output_set
    def _append_projection_attribute_state(self, proj_ctx: 'ProjectionContext', proj_output_set: 'ProjectionAttributeStateSet', attr_ctx: 'CdmAttributeContext') -> 'ProjectionAttributeStateSet':
        # Create a new attribute context for the operation
        attr_ctx_op_exclude_attrs_param = AttributeContextParameters()
        attr_ctx_op_exclude_attrs_param._under = attr_ctx
        attr_ctx_op_exclude_attrs_param._type = CdmAttributeContextType.OPERATION_EXCLUDE_ATTRIBUTES
        attr_ctx_op_exclude_attrs_param._name = 'operation/index{}/operationExcludeAttributes'.format(self._index)
        attr_ctx_op_exclude_attrs = CdmAttributeContext._create_child_under(proj_ctx._projection_directive._res_opt, attr_ctx_op_exclude_attrs_param)

        # Get the top-level attribute names of the attributes to exclude
        # We use the top-level names because the exclude list may contain a previous name our current resolved attributes had
        top_level_exclude_attribute_names = ProjectionResolutionCommonUtil._get_top_list(proj_ctx, self.exclude_attributes)

        # Initialize a projection attribute context tree builder with the created attribute context for the operation
        attr_ctx_tree_builder = ProjectionAttributeContextTreeBuilder(attr_ctx_op_exclude_attrs)

        # Iterate through all the projection attribute states generated from the source's resolved attributes
        # Each projection attribute state contains a resolved attribute that it is corresponding to
        for current_PAS in proj_ctx._current_attribute_state_set._states:
            # Check if the current projection attribute state's resolved attribute is in the list of attributes to exclude
            # If this attribute is not in the exclude list, then we are including it in the output
            if current_PAS._current_resolved_attribute.resolved_name not in top_level_exclude_attribute_names:
                # Create the attribute context parameters and just store it in the builder for now
                # We will create the attribute contexts at the end
                attr_ctx_tree_builder._create_and_store_attribute_context_parameters(
                    None, current_PAS, current_PAS._current_resolved_attribute,
                    CdmAttributeContextType.ATTRIBUTE_DEFINITION,
                    current_PAS._current_resolved_attribute.att_ctx,  # lineage is the included attribute
                    None)  # don't know who will point here yet

                # Create a projection attribute state for the included attribute by creating a copy of the current state
                # Copy() sets the current state as the previous state for the new one
                # We only create projection attribute states for attributes that are not in the exclude list
                new_PAS = current_PAS._copy()

                proj_output_set._add(new_PAS)
            else:
                # The current projection attribute state's resolved attribute is in the exclude list

                # Get the attribute name the way it appears in the exclude list
                exclude_attribute_name = top_level_exclude_attribute_names[current_PAS._current_resolved_attribute.resolved_name]

                # Create the attribute context parameters and just store it in the builder for now
                # We will create the attribute contexts at the end
                attr_ctx_tree_builder._create_and_store_attribute_context_parameters(
                    exclude_attribute_name, current_PAS, current_PAS._current_resolved_attribute,
                    CdmAttributeContextType.ATTRIBUTE_EXCLUDED,
                    current_PAS._current_resolved_attribute.att_ctx,  # lineage is the included attribute
                    None)  # don't know who will point here yet, excluded, so... this could be the end for you.

        # Create all the attribute contexts and construct the tree
        attr_ctx_tree_builder._construct_attribute_context_tree(proj_ctx)

        return proj_output_set
    def _create_new_projection_attribute_state_set(
            proj_ctx: 'ProjectionContext',
            proj_output_set: 'ProjectionAttributeStateSet',
            new_res_attr_FK: 'ResolvedAttribute',
            ref_attr_name: str) -> 'ProjectionAttributeStateSet':
        pas_list = ProjectionResolutionCommonUtil._get_leaf_list(
            proj_ctx, ref_attr_name)

        if pas_list is not None:
            # update the new foreign key resolved attribute with trait param with reference details
            reqd_trait = new_res_attr_FK.resolved_traits.find(
                proj_ctx._projection_directive._res_opt,
                'is.linkedEntity.identifier')
            if reqd_trait:
                trait_param_ent_ref = ProjectionResolutionCommonUtil._create_foreign_key_linked_entity_identifier_trait_parameter(
                    proj_ctx._projection_directive,
                    proj_output_set._ctx.corpus, pas_list)
                reqd_trait.parameter_values.update_parameter_value(
                    proj_ctx._projection_directive._res_opt,
                    'entityReferences', trait_param_ent_ref)

            # Create new output projection attribute state set for FK and add prevPas as previous state set
            new_proj_attr_state_FK = ProjectionAttributeState(
                proj_output_set._ctx)
            new_proj_attr_state_FK._current_resolved_attribute = new_res_attr_FK
            new_proj_attr_state_FK._previous_state_list = pas_list

            proj_output_set._add(new_proj_attr_state_FK)
        else:
            # Log error & return proj_output_set without any change
            logger.error(
                CdmOperationReplaceAsForeignKey.__name__, proj_output_set._ctx,
                'Unable to locate state for reference attribute \"{}\".'.
                format(ref_attr_name), CdmOperationReplaceAsForeignKey.
                _create_new_projection_attribute_state_set.__name__)

        return proj_output_set
Ejemplo n.º 5
0
    def _append_projection_attribute_state(self, proj_ctx: 'ProjectionContext', proj_attr_state_set: 'ProjectionAttributeStateSet', attr_ctx: 'CdmAttributeContext') -> 'ProjectionAttributeStateSet':
        # Create a new attribute context for the operation
        attr_ctx_op_include_attrs_param = AttributeContextParameters()  # type: AttributeContextParameters
        attr_ctx_op_include_attrs_param._under = attr_ctx
        attr_ctx_op_include_attrs_param._type = CdmAttributeContextType.OPERATION_INCLUDE_ATTRIBUTES
        attr_ctx_op_include_attrs_param._name = 'operation/indexIndex{}/operationIncludeAttributes'.format(self._index)

        attr_ctx_op_include_attrs = CdmAttributeContext._create_child_under(proj_ctx._projection_directive._res_opt, attr_ctx_op_include_attrs_param)  # type: CdmAttributeContext

        # Get the top-level attribute names for each of the included attributes
        # Since the include operation allows providing either current state resolved attribute names
        #   or the previous state resolved attribute names, we search for the name in the PAS tree
        #   and fetch the top level resolved attribute names.
        top_level_include_attribute_names = ProjectionResolutionCommonUtil._get_top_list(proj_ctx, self.include_attributes)  # type: Dict[str, str]

        # Initialize a projection attribute context tree builder with the created attribute context for the operation
        attr_ctx_tree_builder = ProjectionAttributeContextTreeBuilder(attr_ctx_op_include_attrs)

        # Iterate through all the PAS in the PASSet generated from the projection source's resolved attributes
        for current_PAS in proj_ctx._current_attribute_state_set._states:
            # Check if the current PASs RA is in the list of attributes to include.
            if current_PAS._current_resolved_attribute.resolved_name in top_level_include_attribute_names:
                # Get the attribute name the way it appears in the include list
                include_attribute_name = top_level_include_attribute_names[current_PAS._current_resolved_attribute.resolved_name]  # type: str

                # Create the attribute context parameters and just store it in the builder for now
                # We will create the attribute contexts at the end
                attr_ctx_tree_builder._create_and_store_attribute_context_parameters(include_attribute_name, current_PAS, current_PAS._current_resolved_attribute, CdmAttributeContextType.ATTRIBUTE_DEFINITION)

                # Create a projection attribute state for the included attribute by creating a copy of the current state
                # Copy() sets the current state as the previous state for the new one
                # We only create projection attribute states for attributes in the include list
                new_PAS = current_PAS._copy()

                proj_attr_state_set._add(new_PAS)
            else:
                # Create the attribute context parameters and just store it in the builder for now
                # We will create the attribute contexts at the end
                attr_ctx_tree_builder._create_and_store_attribute_context_parameters(None, current_PAS, current_PAS._current_resolved_attribute, CdmAttributeContextType.ATTRIBUTE_DEFINITION)

        # Create all the attribute contexts and construct the tree
        attr_ctx_tree_builder._construct_attribute_context_tree(proj_ctx)

        return proj_attr_state_set
Ejemplo n.º 6
0
    def _append_projection_attribute_state(self, proj_ctx: 'ProjectionContext', proj_output_set: 'ProjectionAttributeStateSet', \
                                           attr_ctx: 'CdmAttributeContext') -> 'ProjectionAttributeStateSet':
        # Create a new attribute context for the operation
        attr_ctx_op_rename_attrs_param = AttributeContextParameters()
        attr_ctx_op_rename_attrs_param._under = attr_ctx
        attr_ctx_op_rename_attrs_param._type = CdmAttributeContextType.OPERATION_RENAME_ATTRIBUTES
        attr_ctx_op_rename_attrs_param._name = 'operation/index{}/operationRenameAttributes'.format(
            self._index)
        attr_ctx_op_rename_attrs = CdmAttributeContext._create_child_under(
            proj_ctx._projection_directive._res_opt,
            attr_ctx_op_rename_attrs_param)  # type: CdmAttributeContext

        # Get the list of attributes that will be renamed
        rename_attributes = None  # type: List[str]
        if self.apply_to is not None:
            rename_attributes = self.apply_to
        else:
            rename_attributes = []
            for current_PAS in proj_ctx._current_attribute_state_set._states:
                rename_attributes.append(
                    current_PAS._current_resolved_attribute._resolved_name)

        # Get the top-level attribute names of the attributes to rename
        # We use the top-level names because the rename list may contain a previous name our current resolved attributes had
        top_level_rename_attribute_names = ProjectionResolutionCommonUtil._get_top_list(
            proj_ctx, rename_attributes)  # type: Dict[str, str]

        source_attribute_name = proj_ctx._projection_directive._original_source_entity_attribute_name  # type: str

        # Initialize a projection attribute context tree builder with the created attribute context for the operation
        attr_ctx_tree_builder = ProjectionAttributeContextTreeBuilder(
            attr_ctx_op_rename_attrs)

        # Iterate through all the projection attribute states generated from the source's resolved attributes
        # Each projection attribute state contains a resolved attribute that it is corresponding to
        for current_PAS in proj_ctx._current_attribute_state_set._states:
            # Check if the current projection attribute state's resolved attribute is in the list of attributes to rename
            # If this attribute is not in the rename list, then we are including it in the output without changes
            if current_PAS._current_resolved_attribute.resolved_name in top_level_rename_attribute_names:
                if isinstance(current_PAS._current_resolved_attribute.target,
                              CdmAttribute):
                    # The current attribute should be renamed

                    new_attribute_name = self._get_new_attribute_name(
                        current_PAS, source_attribute_name)  # type: str

                    # Create new resolved attribute with the new name, set the new attribute as target
                    res_attr_new = self._create_new_resolved_attribute(
                        proj_ctx, None,
                        current_PAS._current_resolved_attribute.target,
                        new_attribute_name)  # type: ResolvedAttribute

                    # Get the attribute name the way it appears in the applyTo list
                    apply_to_name = top_level_rename_attribute_names[
                        current_PAS._current_resolved_attribute.resolved_name]

                    # Create the attribute context parameters and just store it in the builder for now
                    # We will create the attribute contexts at the end
                    attr_ctx_tree_builder._create_and_store_attribute_context_parameters(
                        apply_to_name,
                        current_PAS,
                        res_attr_new,
                        CdmAttributeContextType.ATTRIBUTE_DEFINITION,
                        current_PAS._current_resolved_attribute.
                        att_ctx,  # lineage is the original attribute
                        None)  # don't know who will point here yet

                    # Create a projection attribute state for the renamed attribute by creating a copy of the current state
                    # Copy() sets the current state as the previous state for the new one
                    # We only create projection attribute states for attributes that are in the rename list
                    new_PAS = current_PAS._copy()

                    # Update the resolved attribute to be the new renamed attribute we created
                    new_PAS._current_resolved_attribute = res_attr_new

                    proj_output_set._add(new_PAS)
                else:
                    logger.warning(
                        self._TAG, self.ctx,
                        'RenameAttributes is not supported on an attribute group yet.'
                    )
                    # Add the attribute without changes
                    proj_output_set._add(current_PAS)
            else:
                # Pass through
                proj_output_set._add(current_PAS)

        # Create all the attribute contexts and construct the tree
        attr_ctx_tree_builder._construct_attribute_context_tree(proj_ctx)

        return proj_output_set
Ejemplo n.º 7
0
    def _construct_projection_context(
            self,
            proj_directive: 'ProjectionDirective',
            attr_ctx: 'CdmAttributeContext',
            ras: Optional['ResolvedAttributeSet'] = None
    ) -> 'ProjectionContext':
        """
        A function to construct projection context and populate the resolved attribute set that ExtractResolvedAttributes method can then extract
        This function is the entry point for projection resolution.
        This function is expected to do the following 3 things:
        - Create an condition expression tree & default if appropriate
        - Create and initialize Projection Context
        - Process operations
        """
        if not attr_ctx:
            return None

        proj_context = None

        # Add projection to context tree
        acp_proj = AttributeContextParameters()
        acp_proj._under = attr_ctx
        acp_proj._type = CdmAttributeContextType.PROJECTION
        acp_proj._name = self.fetch_object_definition_name()
        acp_proj._regarding = proj_directive._owner_ref
        acp_proj._include_traits = False

        ac_proj = CdmAttributeContext._create_child_under(
            proj_directive._res_opt, acp_proj)

        acp_source = AttributeContextParameters()
        acp_source._under = ac_proj
        acp_source._type = CdmAttributeContextType.SOURCE
        acp_source._name = 'source'
        acp_source._regarding = None
        acp_source._include_traits = False

        ac_source = CdmAttributeContext._create_child_under(
            proj_directive._res_opt, acp_source)

        # Initialize the projection context
        ctx = proj_directive._owner.ctx if proj_directive._owner else None

        if self.source:
            source = self.source.fetch_object_definition(
                proj_directive._res_opt)
            if source.object_type == CdmObjectType.PROJECTION_DEF:
                # A Projection

                proj_context = source._construct_projection_context(
                    proj_directive, ac_source, ras)
            else:
                # An Entity Reference

                acp_source_projection = AttributeContextParameters()
                acp_source_projection._under = ac_source
                acp_source_projection._type = CdmAttributeContextType.ENTITY
                acp_source_projection._name = self.source.named_reference if self.source.named_reference else self.source.explicit_reference.get_name(
                )
                acp_source_projection._regarding = self.source
                acp_source_projection._include_traits = False

                ras = self.source._fetch_resolved_attributes(
                    proj_directive._res_opt,
                    acp_source_projection)  # type: ResolvedAttributeSet
                # clean up the context tree, it was left in a bad state on purpose in this call
                ras.attribute_context._finalize_attribute_context(
                    proj_directive._res_opt, ac_source.at_corpus_path,
                    self.in_document, self.in_document, None, False)

                # if polymorphic keep original source as previous state
                poly_source_set = None
                if proj_directive._is_source_polymorphic:
                    poly_source_set = ProjectionResolutionCommonUtil._get_polymorphic_source_set(
                        proj_directive, ctx, self.source, ras)

                # Now initialize projection attribute state
                pas_set = ProjectionResolutionCommonUtil._initialize_projection_attribute_state_set(
                    proj_directive, ctx, ras,
                    proj_directive._is_source_polymorphic, poly_source_set)

                proj_context = ProjectionContext(proj_directive,
                                                 ras.attribute_context)
                proj_context._current_attribute_state_set = pas_set
        else:
            # A type attribute

            # Initialize projection attribute state
            pas_set = ProjectionResolutionCommonUtil._initialize_projection_attribute_state_set(
                proj_directive,
                ctx,
                ras,
                is_source_polymorphic=False,
                polymorphic_set=None)

            proj_context = ProjectionContext(proj_directive,
                                             ras.attribute_context)
            proj_context._current_attribute_state_set = pas_set

        is_condition_valid = False
        input_values = InputValues(proj_directive)
        is_condition_valid = ExpressionTree._evaluate_condition(
            self.condition, input_values)

        if is_condition_valid and self.operations and len(self.operations) > 0:
            # Just in case operations were added programmatically, reindex operations
            for i in range(len(self.operations)):
                self.operations[i]._index = i + 1

            # Operation

            acp_gen_attr_set = AttributeContextParameters()
            acp_gen_attr_set._under = attr_ctx
            acp_gen_attr_set._type = CdmAttributeContextType.GENERATED_SET
            acp_gen_attr_set._name = '_generatedAttributeSet'

            ac_gen_attr_set = CdmAttributeContext._create_child_under(
                proj_directive._res_opt, acp_gen_attr_set)

            # Start with an empty list for each projection
            pas_operations = ProjectionAttributeStateSet(
                proj_context._current_attribute_state_set._ctx)

            # The attribute set that the operation will execute on
            operation_working_attribute_set = None  # type: ProjectionAttributeStateSet

            # The attribute set containing the attributes from the source
            source_attribute_set = proj_context._current_attribute_state_set  # type: ProjectionAttributeStateSet

            # Specifies if the operation is the first on the list to run
            first_operation_to_run = True
            for operation in self.operations:
                operation_condition = ExpressionTree._evaluate_condition(
                    operation.condition, input_values)

                if not operation_condition:
                    # Skip this operation if the condition does not evaluate to true
                    continue

                # If run_sequentially is not true then all the operations will receive the source input
                # Unless the operation overwrites this behavior using the source_input property
                source_input = operation.source_input if operation.source_input is not None else not self.run_sequentially

                # If this is the first operation to run it will get the source attribute set since the operations attribute set starts empty
                if source_input or first_operation_to_run:
                    proj_context._current_attribute_state_set = source_attribute_set
                    operation_working_attribute_set = pas_operations
                else:
                    # Needs to create a copy since this set can be modified by the operation
                    proj_context._current_attribute_state_set = pas_operations._copy(
                    )
                    operation_working_attribute_set = ProjectionAttributeStateSet(
                        proj_context._current_attribute_state_set._ctx)

                # Evaluate projections and apply to empty state
                new_pas_operations = operation._append_projection_attribute_state(
                    proj_context, operation_working_attribute_set,
                    ac_gen_attr_set)

                # If the operations fails or it is not implemented the projection cannot be evaluated so keep previous valid state.
                if new_pas_operations is not None:
                    first_operation_to_run = False
                    pas_operations = new_pas_operations

            # If no operation ran successfully pas_operations will be empty
            if not first_operation_to_run:
                # Finally update the current state to the projection context
                proj_context._current_attribute_state_set = pas_operations

        return proj_context
Ejemplo n.º 8
0
    def _construct_projection_context(self, proj_directive: 'ProjectionDirective', attr_ctx: 'CdmAttributeContext', ras: Optional['ResolvedAttributeSet'] = None) -> 'ProjectionContext':
        """
        A function to construct projection context and populate the resolved attribute set that ExtractResolvedAttributes method can then extract
        This function is the entry point for projection resolution.
        This function is expected to do the following 3 things:
        - Create an condition expression tree & default if appropriate
        - Create and initialize Projection Context
        - Process operations
        """
        proj_context = None

        condition =  self.condition if self.condition  else "(true)"

        # create an expression tree based on the condition
        tree = ExpressionTree()
        self._condition_expression_tree_root = tree._construct_expression_tree(condition)

        if attr_ctx:
            # Add projection to context tree
            acp_proj = AttributeContextParameters()
            acp_proj._under = attr_ctx
            acp_proj._type = CdmAttributeContextType.PROJECTION
            acp_proj._name = self.fetch_object_definition_name()
            acp_proj._regarding = proj_directive._owner_ref
            acp_proj._include_traits = False

            ac_proj = CdmAttributeContext._create_child_under(proj_directive._res_opt, acp_proj)

            acp_source = AttributeContextParameters()
            acp_source._under = ac_proj
            acp_source._type = CdmAttributeContextType.SOURCE
            acp_source._name = 'source'
            acp_source._regarding = None
            acp_source._include_traits = False

            ac_source = CdmAttributeContext._create_child_under(proj_directive._res_opt, acp_source)

            # Initialize the projection context
            ctx = proj_directive._owner.ctx if proj_directive._owner else None

            if self.source:
                source = self.source.fetch_object_definition(proj_directive._res_opt)
                if source.object_type == CdmObjectType.PROJECTION_DEF:
                    # A Projection

                    proj_context = self.source.explicit_reference._construct_projection_context(proj_directive, ac_source, ras)
                else:
                    # An Entity Reference

                    acp_source_projection = AttributeContextParameters()
                    acp_source_projection._under = ac_source
                    acp_source_projection._type = CdmAttributeContextType.ENTITY
                    acp_source_projection._name = self.source.named_reference if self.source.named_reference else self.source.explicit_reference.get_name()
                    acp_source_projection._regarding = self.source
                    acp_source_projection._include_traits = False

                    ras = self.source._fetch_resolved_attributes(proj_directive._res_opt, acp_source_projection)

                    # If polymorphic keep original source as previous state
                    poly_source_set = None
                    if proj_directive._is_source_polymorphic:
                        poly_source_set = ProjectionResolutionCommonUtil._get_polymorphic_source_set(proj_directive, ctx, self.source, acp_source_projection)

                    # Now initialize projection attribute state
                    pas_set = ProjectionResolutionCommonUtil._initialize_projection_attribute_state_set(
                        proj_directive,
                        ctx,
                        ras,
                        proj_directive._is_source_polymorphic,
                        poly_source_set
                    )

                    proj_context = ProjectionContext(proj_directive, ras.attribute_context)
                    proj_context._current_attribute_state_set = pas_set
            else:
                # A type attribute

                # Initialize projection attribute state
                pas_set = ProjectionResolutionCommonUtil._initialize_projection_attribute_state_set(
                    proj_directive,
                    ctx,
                    ras,
                    is_source_polymorphic=False,
                    polymorphic_set=None
                )

                proj_context = ProjectionContext(proj_directive, ras.attribute_context)
                proj_context._current_attribute_state_set = pas_set

            is_condition_valid = False
            if self._condition_expression_tree_root:
                input = InputValues()
                input.no_max_depth = proj_directive._has_no_maximum_depth
                input.is_array = proj_directive._is_array
                input.reference_only = proj_directive._is_reference_only
                input.normalized = proj_directive._is_normalized
                input.structured = proj_directive._is_structured
                input.is_virtual = proj_directive._is_virtual

                current_depth = proj_directive._current_depth
                current_depth += 1
                input.next_depth = current_depth
                proj_directive._current_depth = current_depth

                input.max_depth = proj_directive._maximum_depth
                input.min_cardinality = proj_directive._cardinality._minimum_number if proj_directive._cardinality else None
                input.max_cardinality = proj_directive._cardinality._maximum_number if proj_directive._cardinality else None

                is_condition_valid = ExpressionTree._evaluate_expression_tree(self._condition_expression_tree_root, input)

            if is_condition_valid and self.operations and len(self.operations) > 0:
                # Just in case operations were added programmatically, reindex operations
                for i in range(len(self.operations)):
                    self.operations[i]._index = i + 1

                # Operation

                acp_gen_attr_set = AttributeContextParameters()
                acp_gen_attr_set._under = attr_ctx
                acp_gen_attr_set._type = CdmAttributeContextType.GENERATED_SET
                acp_gen_attr_set._name = '_generatedAttributeSet'

                ac_gen_attr_set = CdmAttributeContext._create_child_under(proj_directive._res_opt, acp_gen_attr_set)

                # Start with an empty list for each projection
                pas_operations = ProjectionAttributeStateSet(proj_context._current_attribute_state_set._ctx)
                for operation in self.operations:
                    # Evaluate projections and apply to empty state
                    new_pas_operations = operation._append_projection_attribute_state(proj_context, pas_operations, ac_gen_attr_set)

                    # If the operations fails or it is not implemented the projection cannot be evaluated so keep previous valid state.
                    if new_pas_operations is not None:
                        pas_operations = new_pas_operations

                # Finally update the current state to the projection context
                proj_context._current_attribute_state_set = pas_operations

        return proj_context
Ejemplo n.º 9
0
    def _append_projection_attribute_state(
            self, proj_ctx: 'ProjectionContext',
            proj_attr_state_set: 'ProjectionAttributeStateSet',
            attr_ctx: 'CdmAttributeContext') -> 'ProjectionAttributeStateSet':
        # Create a new attribute context for the operation
        attr_ctx_op_include_attrs_param = AttributeContextParameters(
        )  # type: AttributeContextParameters
        attr_ctx_op_include_attrs_param._under = attr_ctx
        attr_ctx_op_include_attrs_param._type = CdmAttributeContextType.OPERATION_INCLUDE_ATTRIBUTES
        attr_ctx_op_include_attrs_param._name = 'operation/index{}/operationIncludeAttributes'.format(
            self._index)

        attr_ctx_op_include_attrs = CdmAttributeContext._create_child_under(
            proj_ctx._projection_directive._res_opt,
            attr_ctx_op_include_attrs_param)  # type: CdmAttributeContext

        # Get the top-level attribute names for each of the included attributes
        # Since the include operation allows providing either current state resolved attribute names
        #   or the previous state resolved attribute names, we search for the name in the PAS tree
        #   and fetch the top level resolved attribute names.
        top_level_include_attribute_names = ProjectionResolutionCommonUtil._get_top_list(
            proj_ctx, self.include_attributes)  # type: Dict[str, str]

        # Initialize a projection attribute context tree builder with the created attribute context for the operation
        attr_ctx_tree_builder = ProjectionAttributeContextTreeBuilder(
            attr_ctx_op_include_attrs)

        # Index that holds the current attribute name as the key and the attribute as value
        top_level_include_attribute = {
        }  # type: Dict[str, ProjectionAttributeState]

        # List of attributes that were not included on the final attribute list
        removed_attributes = []  # List[ProjectionAttributeState]

        # Iterate through all the PAS in the PASSet generated from the projection source's resolved attributes
        for current_PAS in proj_ctx._current_attribute_state_set._states:
            # Check if the current PASs RA is in the list of attributes to include.
            if current_PAS._current_resolved_attribute.resolved_name in top_level_include_attribute_names:
                top_level_include_attribute[
                    current_PAS._current_resolved_attribute.
                    resolved_name] = current_PAS
            else:
                removed_attributes.append(current_PAS)

        # Loop through the list of attributes in the same order that was specified by the user
        for key, value in top_level_include_attribute_names.items():
            current_PAS = top_level_include_attribute[key]

            # Get the attribute name the way it appears in the include list
            include_attribute_name = value  # type: str

            # Create the attribute context parameters and just store it in the builder for now
            # We will create the attribute contexts at the end
            attr_ctx_tree_builder._create_and_store_attribute_context_parameters(
                include_attribute_name,
                current_PAS,
                current_PAS._current_resolved_attribute,
                CdmAttributeContextType.ATTRIBUTE_DEFINITION,
                current_PAS._current_resolved_attribute.
                att_ctx,  # lineage is the included attribute
                None)  # don't know who will point here yet

            # Create a projection attribute state for the included attribute by creating a copy of the current state
            # Copy() sets the current state as the previous state for the new one
            # We only create projection attribute states for attributes in the include list
            new_PAS = current_PAS._copy()

            proj_attr_state_set._add(new_PAS)

        # Generate attribute context nodes for the attributes that were not included
        for current_PAS in removed_attributes:
            # Create the attribute context parameters and just store it in the builder for now
            # We will create the attribute contexts at the end
            attr_ctx_tree_builder._create_and_store_attribute_context_parameters(
                None,
                current_PAS,
                current_PAS._current_resolved_attribute,
                CdmAttributeContextType.ATTRIBUTE_EXCLUDED,
                current_PAS._current_resolved_attribute.
                att_ctx,  # lineage is the excluded attribute
                None
            )  # don't know who will point here, probably nobody, I mean, we got excluded

        # Create all the attribute contexts and construct the tree
        attr_ctx_tree_builder._construct_attribute_context_tree(proj_ctx)

        return proj_attr_state_set
Ejemplo n.º 10
0
    def _append_projection_attribute_state(self, proj_ctx: 'ProjectionContext', proj_output_set: 'ProjectionAttributeStateSet',
                                           attr_ctx: 'CdmAttributeContext') -> 'ProjectionAttributeStateSet':
        # Create a new attribute context for the operation
        attr_ctx_op_alter_traits_param = AttributeContextParameters()
        attr_ctx_op_alter_traits_param._under = attr_ctx
        attr_ctx_op_alter_traits_param._type = CdmAttributeContextType.OPERATION_ALTER_TRAITS
        attr_ctx_op_alter_traits_param._name = 'operation/index{}/{}'.format(self._index, self.get_name())
        attr_ctx_op_alter_traits = CdmAttributeContext._create_child_under(proj_ctx._projection_directive._res_opt, attr_ctx_op_alter_traits_param)

        # Get the top-level attribute names of the selected attributes to apply
        # We use the top-level names because the applyTo list may contain a previous name our current resolved attributes had
        top_level_selected_attribute_names = ProjectionResolutionCommonUtil._get_top_list(
            proj_ctx, self.apply_to) if self.apply_to is not None else None  # type: Dict[str, str]

        # Iterate through all the PAS in the PASSet generated from the projection source's resolved attributes
        for current_PAS in proj_ctx._current_attribute_state_set._states:
            # Check if the current projection attribute state's resolved attribute is in the list of selected attributes
            # If this attribute is not in the list, then we are including it in the output without changes
            if top_level_selected_attribute_names is None or current_PAS._current_resolved_attribute.resolved_name in top_level_selected_attribute_names:

                # Create a new attribute context for the new artifact attribute we will create
                attr_ctx_new_attr_param = AttributeContextParameters()
                attr_ctx_new_attr_param._under = attr_ctx_op_alter_traits
                attr_ctx_new_attr_param._type = CdmAttributeContextType.ATTRIBUTE_DEFINITION
                attr_ctx_new_attr_param._name = current_PAS._current_resolved_attribute.resolved_name
                attr_ctx_new_attr = CdmAttributeContext._create_child_under(proj_ctx._projection_directive._res_opt, attr_ctx_new_attr_param)

                new_res_attr = None

                if isinstance(current_PAS._current_resolved_attribute.target, ResolvedAttributeSet):
                    # Attribute group
                    # Create a copy of resolved attribute set
                    res_attr_new_copy = current_PAS._current_resolved_attribute.target.copy()
                    new_res_attr = ResolvedAttribute(proj_ctx._projection_directive._res_opt, res_attr_new_copy,
                                                     current_PAS._current_resolved_attribute.resolved_name, attr_ctx_new_attr)

                    # the resolved attribute group obtained from previous projection operation may have a different set of traits comparing to the resolved attribute target.
                    #  We would want to take the set of traits from the resolved attribute.
                    new_res_attr.resolved_traits = current_PAS._current_resolved_attribute.resolved_traits.deep_copy()

                elif isinstance(current_PAS._current_resolved_attribute.target, CdmAttribute):
                    # Entity Attribute or Type Attribute
                    new_res_attr = self._create_new_resolved_attribute(
                        proj_ctx, attr_ctx_new_attr, current_PAS._current_resolved_attribute, current_PAS._current_resolved_attribute.resolved_name)

                else:
                    logger.error(self.ctx, self._TAG, CdmOperationAlterTraits._append_projection_attribute_state.__name__,
                                 self.at_corpus_path, CdmLogCode.ERR_PROJ_UNSUPPORTED_SOURCE, str(current_PAS._current_resolved_attribute.object_type), self.get_name())
                    proj_output_set._add(current_PAS)
                    break

                new_res_attr.resolved_traits = new_res_attr.resolved_traits.merge_set(self._resolved_new_traits(proj_ctx, current_PAS))
                self._remove_traits_in_new_attribute(proj_ctx._projection_directive._res_opt, new_res_attr)

                # Create a projection attribute state for the new attribute with new applied traits by creating a copy of the current state
                # Copy() sets the current state as the previous state for the new one
                new_PAS = current_PAS._copy()

                # Update the resolved attribute to be the new attribute we created
                new_PAS._current_resolved_attribute = new_res_attr

                proj_output_set._add(new_PAS)

            else:
                # Pass through
                proj_output_set._add(current_PAS)

        return proj_output_set