Esempio n. 1
0
    def __init__(self,
                 entity: Optional['CdmEntityDefinition'] = None,
                 rasb: Optional['ResolvedAttributeSetBuilder'] = None) -> None:
        self.entity = entity  # type: Optional[CdmEntityDefinition]

        # --- internal ---
        self._rasb = rasb if rasb else ResolvedAttributeSetBuilder(
        )  # type: ResolvedAttributeSetBuilder
Esempio n. 2
0
    def _fetch_resolved_attributes(
        self,
        res_opt: 'ResolveOptions',
        acp_in_context: Optional['AttributeContextParameters'] = None
    ) -> 'ResolvedAttributeSet':
        from cdm.resolvedmodel import ResolvedAttributeSet
        from cdm.utilities import SymbolSet

        from .cdm_attribute_context import CdmAttributeContext
        from .cdm_corpus_def import CdmCorpusDefinition
        from .cdm_entity_attribute_def import CdmEntityAttributeDefinition
        from .cdm_entity_def import CdmEntityDefinition
        from cdm.resolvedmodel.resolved_attribute_set_builder import ResolvedAttributeSetBuilder

        was_previously_resolving = self.ctx.corpus._is_currently_resolving
        self.ctx.corpus._is_currently_resolving = True
        if not res_opt:
            res_opt = ResolveOptions(
                self, self.ctx.corpus.default_resolution_directives)

        in_circular_reference = False
        was_in_circular_reference = res_opt._in_circular_reference
        if isinstance(self, CdmEntityDefinition):
            in_circular_reference = self in res_opt._currently_resolving_entities
            res_opt._currently_resolving_entities.add(self)
            res_opt._in_circular_reference = in_circular_reference

            # uncomment this line as a test to turn off allowing cycles
            #if in_circular_reference:
            #    return ResolvedAttributeSet()

        kind = 'rasb'
        ctx = self.ctx
        rasb_result = None
        rasb_cache = self._fetch_object_from_cache(
            res_opt, acp_in_context)  # type: ResolvedAttributeSetBuilder
        under_ctx = None

        current_depth = res_opt._depth_info.current_depth

        # store the previous symbol set, we will need to add it with
        # children found from the constructResolvedTraits call
        curr_sym_ref_set = res_opt._symbol_ref_set or SymbolSet()
        res_opt._symbol_ref_set = SymbolSet()

        # if using the cache passes the maxDepth, we cannot use it
        if rasb_cache \
                and res_opt._depth_info.max_depth \
                and res_opt._depth_info.current_depth + rasb_cache._resolved_attribute_set._depth_traveled > res_opt._depth_info.max_depth:
            rasb_cache = None

        if not rasb_cache:
            # a new context node is needed for these attributes,
            # this tree will go into the cache, so we hang it off a placeholder parent
            # when it is used from the cache (or now), then this placeholder parent is ignored and the things under it are
            # put into the 'receiving' tree
            under_ctx = CdmAttributeContext._get_under_context_for_cache_context(
                res_opt, self.ctx, acp_in_context)

            rasb_cache = self._construct_resolved_attributes(
                res_opt, under_ctx)  # type: ResolvedAttributeSetBuilder

            if rasb_cache:
                # register set of possible docs
                o_def = self.fetch_object_definition(res_opt)
                if o_def is not None:
                    ctx.corpus._register_definition_reference_symbols(
                        o_def, kind, res_opt._symbol_ref_set)

                    # get the new cache tag now that we have the list of docs
                    cache_tag = ctx.corpus._create_definition_cache_tag(
                        res_opt, self, kind, 'ctx' if acp_in_context else None)
                    # save this as the cached version
                    if cache_tag:
                        ctx._cache[cache_tag] = rasb_cache
                # get the 'under_ctx' of the attribute set from the acp that is wired into the target tree
                under_ctx = cast(ResolvedAttributeSetBuilder, rasb_cache)\
                    ._resolved_attribute_set.attribute_context\
                    ._get_under_context_from_cache_context(res_opt, acp_in_context) \
                    if cast(ResolvedAttributeSetBuilder, rasb_cache)._resolved_attribute_set.attribute_context else None
        else:
            # get the 'under_ctx' of the attribute set from the cache. The one stored there was build with a different
            # acp and is wired into the fake placeholder. so now build a new under_ctx wired into the output tree but with
            # copies of all cached children
            under_ctx = cast(ResolvedAttributeSetBuilder, rasb_cache) \
                ._resolved_attribute_set.attribute_context \
                ._get_under_context_from_cache_context(res_opt, acp_in_context) \
                if cast(ResolvedAttributeSetBuilder, rasb_cache)._resolved_attribute_set.attribute_context else None
            # under_ctx._validate_lineage(res_opt)  # debugging

        if rasb_cache:
            # either just built something or got from cache
            # either way, same deal: copy resolved attributes and copy the context tree associated with it
            # 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree
            # 2. deep copy the tree.
            #
            # 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree
            rasb_result = ResolvedAttributeSetBuilder()
            rasb_result._resolved_attribute_set = cast(
                ResolvedAttributeSetBuilder,
                rasb_cache)._resolved_attribute_set.copy()

            # 2. deep copy the tree and map the context references.
            if under_ctx:  # null context? means there is no tree, probably 0 attributes came out
                if under_ctx.associate_tree_copy_with_attributes(
                        res_opt, rasb_result._resolved_attribute_set) is False:
                    return None

        if isinstance(self, CdmEntityAttributeDefinition):
            # if we hit the maxDepth, we are now going back up
            res_opt._depth_info.current_depth = current_depth
            # now at the top of the chain where max depth does not influence the cache
            if res_opt._depth_info.current_depth == 0:
                res_opt._depth_info.max_depth_exceeded = False

        if not in_circular_reference and self.object_type == CdmObjectType.ENTITY_DEF:
            # should be removed from the root level only
            # if it is in a circular reference keep it there
            res_opt._currently_resolving_entities.remove(self)

        res_opt._in_circular_reference = was_in_circular_reference

        # merge child reference symbols set with current
        curr_sym_ref_set._merge(res_opt._symbol_ref_set)
        res_opt._symbol_ref_set = curr_sym_ref_set

        self.ctx.corpus._is_currently_resolving = was_previously_resolving
        return rasb_result._resolved_attribute_set if rasb_result else rasb_result