Exemple #1
0
def cardinality_from_ptrcls(
    schema: s_schema.Schema,
    ptrcls: s_pointers.PointerLike,
    *,
    direction: s_pointers.PointerDirection = (
        s_pointers.PointerDirection.Outbound),
) -> Tuple[Optional[qltypes.Cardinality], Optional[qltypes.Cardinality]]:

    out_card = ptrcls.get_cardinality(schema)
    required = ptrcls.get_required(schema)
    if out_card is None or not out_card.is_known():
        # The cardinality is not yet known.
        out_cardinality = None
        dir_cardinality = None
    else:
        assert isinstance(out_card, qltypes.SchemaCardinality)
        out_cardinality = qltypes.Cardinality.from_schema_value(
            required, out_card)
        # Determine the cardinality of a given endpoint set.
        if direction == s_pointers.PointerDirection.Outbound:
            dir_cardinality = out_cardinality
        else:
            # Backward link cannot be required, but exclusivity
            # controls upper bound on cardinality.
            if ptrcls.is_exclusive(schema):
                dir_cardinality = qltypes.Cardinality.AT_MOST_ONE
            else:
                dir_cardinality = qltypes.Cardinality.MANY

    return out_cardinality, dir_cardinality
Exemple #2
0
 def _update_ref_cardinality(
     ptrcls: s_pointers.PointerLike,
     *,
     ctx: context.ContextLevel,
 ) -> None:
     if ptrcls.singular(ctx.env.schema, ptrref.direction):
         ptrref.dir_cardinality = qltypes.Cardinality.ONE
     else:
         ptrref.dir_cardinality = qltypes.Cardinality.MANY
     out_cardinality = ptrcls.get_cardinality(ctx.env.schema)
     assert out_cardinality is not None
     ptrref.out_cardinality = out_cardinality
Exemple #3
0
def _is_computable_ptr(
    ptrcls: s_pointers.PointerLike,
    *,
    ctx: context.ContextLevel,
) -> bool:
    try:
        qlexpr = ctx.source_map[ptrcls].qlexpr
    except KeyError:
        pass
    else:
        return qlexpr is not None

    return (ptrcls.is_pure_computable(ctx.env.schema) or
            (ctx.env.options.apply_query_rewrites
             and ptrcls not in ctx.disable_shadowing
             and bool(ptrcls.get_schema_reflection_default(ctx.env.schema))))
Exemple #4
0
def _is_computable_ptr(
        ptrcls: s_pointers.PointerLike, *,
        is_mut_assign: bool=False,
        ctx: context.ContextLevel) -> bool:
    try:
        qlexpr = ctx.source_map[ptrcls][0]
    except KeyError:
        pass
    else:
        return qlexpr is not None

    if ptrcls.is_pure_computable(ctx.env.schema):
        return True

    if is_mut_assign and ptrcls.get_default(ctx.env.schema) is not None:
        return True

    return False
Exemple #5
0
def _link_has_shape(ptrcls: s_pointers.PointerLike, *,
                    ctx: context.ContextLevel) -> bool:
    if not isinstance(ptrcls, s_links.Link):
        return False

    ptr_shape = {p for p, _ in ctx.env.view_shapes[ptrcls]}
    for p in ptrcls.get_pointers(ctx.env.schema).objects(ctx.env.schema):
        if p.is_special_pointer(ctx.env.schema) or p not in ptr_shape:
            continue
        else:
            return True

    return False
Exemple #6
0
def _is_computable_ptr(
    ptrcls: s_pointers.PointerLike,
    *,
    ctx: context.ContextLevel,
) -> bool:
    try:
        qlexpr = ctx.source_map[ptrcls].qlexpr
    except KeyError:
        pass
    else:
        return qlexpr is not None

    return ptrcls.is_pure_computable(ctx.env.schema)
Exemple #7
0
def cardinality_from_ptrcls(
    schema: s_schema.Schema,
    ptrcls: s_pointers.PointerLike,
) -> Tuple[Optional[qltypes.Cardinality], Optional[qltypes.Cardinality]]:

    out_card = ptrcls.get_cardinality(schema)
    required = ptrcls.get_required(schema)
    if out_card is None or not out_card.is_known():
        # The cardinality is not yet known.
        out_cardinality = None
        in_cardinality = None
    else:
        assert isinstance(out_card, qltypes.SchemaCardinality)
        out_cardinality = qltypes.Cardinality.from_schema_value(
            required, out_card)
        # Backward link cannot be required, but exclusivity
        # controls upper bound on cardinality.
        if not ptrcls.generic(schema) and ptrcls.is_exclusive(schema):
            in_cardinality = qltypes.Cardinality.AT_MOST_ONE
        else:
            in_cardinality = qltypes.Cardinality.MANY

    return out_cardinality, in_cardinality
Exemple #8
0
def ensure_ptrref_cardinality(
        ptrcls: s_pointers.PointerLike,
        ptrref: irast.BasePointerRef, *,
        ctx: context.ContextLevel) -> None:

    if ptrcls.get_cardinality(ctx.env.schema) is None:
        # The cardinality of the pointer is not yet, known,
        # schedule an update of the PointerRef when it
        # becomes available
        def _update_ref_cardinality(ptrcls, *, ctx):
            if ptrcls.singular(ctx.env.schema, ptrref.direction):
                ptrref.dir_cardinality = qltypes.Cardinality.ONE
            else:
                ptrref.dir_cardinality = qltypes.Cardinality.MANY
            ptrref.out_cardinality = ptrcls.get_cardinality(ctx.env.schema)

        once_pointer_cardinality_is_inferred(
            ptrcls, _update_ref_cardinality, ctx=ctx)
Exemple #9
0
def ensure_ptrref_cardinality(
        ptrcls: s_pointers.PointerLike,
        ptrref: irast.BasePointerRef, *,
        ctx: context.ContextLevel) -> None:

    if ptrcls.get_cardinality(ctx.env.schema) is None:
        # The cardinality of the pointer is not yet, known,
        # schedule an update of the PointerRef when it
        # becomes available
        def _update_ref_cardinality(
            ptrcls: s_pointers.PointerLike,
            *,
            ctx: context.ContextLevel,
        ) -> None:

            out_card, dir_card = typeutils.cardinality_from_ptrcls(
                ctx.env.schema, ptrcls, direction=ptrref.direction)
            assert dir_card is not None
            assert out_card is not None
            ptrref.dir_cardinality = dir_card
            ptrref.out_cardinality = out_card

        once_pointer_cardinality_is_inferred(
            ptrcls, _update_ref_cardinality, ctx=ctx)
Exemple #10
0
def ptrref_from_ptrcls(  # NoQA: F811
    *,
    schema: s_schema.Schema,
    ptrcls: s_pointers.PointerLike,
    direction: s_pointers.PointerDirection = (
        s_pointers.PointerDirection.Outbound),
    cache: Optional[Dict[PtrRefCacheKey, irast.BasePointerRef]] = None,
    typeref_cache: Optional[Dict[TypeRefCacheKey, irast.TypeRef]] = None,
) -> irast.BasePointerRef:
    """Return an IR pointer descriptor for a given schema pointer.

    An IR PointerRef is an object that fully describes a schema pointer for
    the purposes of query compilation.

    Args:
        schema:
            A schema instance, in which the type *t* is defined.
        ptrcls:
            A :class:`schema.pointers.Pointer` instance for which to
            return the PointerRef.
        direction:
            The direction of the pointer in the path expression.

    Returns:
        An instance of a subclass of :class:`ir.ast.BasePointerRef`
        corresponding to the given schema pointer.
    """

    if cache is not None:
        cached = cache.get((ptrcls, direction))
        if cached is not None:
            return cached

    kwargs: Dict[str, Any] = {}

    ircls: Type[irast.BasePointerRef]

    source_ref: Optional[irast.TypeRef]
    target_ref: Optional[irast.TypeRef]
    out_source: Optional[irast.TypeRef]

    if isinstance(ptrcls, irast.TupleIndirectionLink):
        ircls = irast.TupleIndirectionPointerRef
    elif isinstance(ptrcls, irast.TypeIntersectionLink):
        ircls = irast.TypeIntersectionPointerRef
        kwargs['optional'] = ptrcls.is_optional()
        kwargs['is_empty'] = ptrcls.is_empty()
        kwargs['is_subtype'] = ptrcls.is_subtype()
        kwargs['rptr_specialization'] = ptrcls.get_rptr_specialization()
    elif isinstance(ptrcls, s_pointers.Pointer):
        ircls = irast.PointerRef
        kwargs['id'] = ptrcls.id
    else:
        raise AssertionError(f'unexpected pointer class: {ptrcls}')

    target = ptrcls.get_far_endpoint(schema, direction)
    if target is not None and not isinstance(target, irast.TypeRef):
        assert isinstance(target, s_types.Type)
        target_ref = type_to_typeref(schema, target, cache=typeref_cache)
    else:
        target_ref = target

    source = ptrcls.get_near_endpoint(schema, direction)

    source_ptr: Optional[irast.BasePointerRef]
    if (isinstance(ptrcls, s_props.Property)
            and isinstance(source, s_links.Link)):
        source_ptr = ptrref_from_ptrcls(
            ptrcls=source,
            direction=direction,
            schema=schema,
            cache=cache,
            typeref_cache=typeref_cache,
        )
        source_ref = None
    else:
        if source is not None and not isinstance(source, irast.TypeRef):
            assert isinstance(source, s_types.Type)
            source_ref = type_to_typeref(schema,
                                         source,
                                         cache=typeref_cache)
        else:
            source_ref = source
        source_ptr = None

    if direction is s_pointers.PointerDirection.Inbound:
        out_source = target_ref
        out_target = source_ref
    else:
        out_source = source_ref
        out_target = target_ref

    out_cardinality, dir_cardinality = cardinality_from_ptrcls(
        schema, ptrcls, direction=direction)

    schema, material_ptrcls = ptrcls.material_type(schema)
    material_ptr: Optional[irast.BasePointerRef]
    if material_ptrcls is not None and material_ptrcls != ptrcls:
        material_ptr = ptrref_from_ptrcls(
            ptrcls=material_ptrcls,
            direction=direction,
            schema=schema,
            cache=cache,
            typeref_cache=typeref_cache,
        )
    else:
        material_ptr = None

    union_components: Set[irast.BasePointerRef] = set()
    union_of = ptrcls.get_union_of(schema)
    union_is_concrete = False
    if union_of:
        union_ptrs = set()

        for component in union_of.objects(schema):
            assert isinstance(component, s_pointers.Pointer)
            schema, material_comp = component.material_type(schema)
            union_ptrs.add(material_comp)

        non_overlapping, union_is_concrete = s_utils.get_non_overlapping_union(
            schema,
            union_ptrs,
        )

        union_components = {
            ptrref_from_ptrcls(
                ptrcls=p,
                direction=direction,
                schema=schema,
                cache=cache,
                typeref_cache=typeref_cache,
            ) for p in non_overlapping
        }

    intersection_components: Set[irast.BasePointerRef] = set()
    intersection_of = ptrcls.get_intersection_of(schema)
    if intersection_of:
        intersection_ptrs = set()

        for component in intersection_of.objects(schema):
            assert isinstance(component, s_pointers.Pointer)
            schema, material_comp = component.material_type(schema)
            intersection_ptrs.add(material_comp)

        intersection_components = {
            ptrref_from_ptrcls(
                ptrcls=p,
                direction=direction,
                schema=schema,
                cache=cache,
                typeref_cache=typeref_cache,
            ) for p in intersection_ptrs
        }

    std_parent_name = None
    for ancestor in ptrcls.get_ancestors(schema).objects(schema):
        ancestor_name = ancestor.get_name(schema)
        if ancestor_name.module == 'std' and ancestor.generic(schema):
            std_parent_name = ancestor_name
            break

    is_derived = ptrcls.get_is_derived(schema)
    base_ptr: Optional[irast.BasePointerRef]
    if is_derived:
        base_ptrcls = ptrcls.get_bases(schema).first(schema)
        top_ptr_name = type(base_ptrcls).get_default_base_name()
        if base_ptrcls.get_name(schema) != top_ptr_name:
            base_ptr = ptrref_from_ptrcls(
                ptrcls=base_ptrcls,
                direction=direction,
                schema=schema,
                cache=cache,
                typeref_cache=typeref_cache,
            )
        else:
            base_ptr = None
    else:
        base_ptr = None

    if (
        material_ptr is None
        and isinstance(ptrcls, s_pointers.Pointer)
    ):
        descendants = frozenset(
            ptrref_from_ptrcls(
                ptrcls=child,
                direction=direction,
                schema=schema,
                cache=cache,
                typeref_cache=typeref_cache,
            )
            for child in ptrcls.children(schema)
            if not child.get_is_derived(schema)
        )
    else:
        descendants = frozenset()

    kwargs.update(dict(
        out_source=out_source,
        out_target=out_target,
        name=ptrcls.get_name(schema),
        shortname=ptrcls.get_shortname(schema),
        path_id_name=ptrcls.get_path_id_name(schema),
        std_parent_name=std_parent_name,
        direction=direction,
        source_ptr=source_ptr,
        base_ptr=base_ptr,
        material_ptr=material_ptr,
        descendants=descendants,
        is_derived=ptrcls.get_is_derived(schema),
        is_computable=ptrcls.get_computable(schema),
        union_components=union_components,
        intersection_components=intersection_components,
        union_is_concrete=union_is_concrete,
        has_properties=ptrcls.has_user_defined_properties(schema),
        dir_cardinality=dir_cardinality,
        out_cardinality=out_cardinality,
    ))

    ptrref = ircls(**kwargs)

    if cache is not None:
        cache[ptrcls, direction] = ptrref

    return ptrref
Exemple #11
0
def ptrref_from_ptrcls(*,
                       source_ref: irast.TypeRef,
                       target_ref: irast.TypeRef,
                       ptrcls: s_pointers.PointerLike,
                       direction: s_pointers.PointerDirection,
                       parent_ptr: Optional[irast.PointerRef] = None,
                       include_descendants: bool = True,
                       schema) -> irast.BasePointerRef:

    kwargs = {}

    if ptrcls.is_tuple_indirection():
        ircls = irast.TupleIndirectionPointerRef
    elif ptrcls.is_type_indirection():
        ircls = irast.TypeIndirectionPointerRef
        kwargs['optional'] = ptrcls.is_optional()
        kwargs['ancestral'] = ptrcls.is_ancestral()
    else:
        ircls = irast.PointerRef
        kwargs['id'] = ptrcls.id
        name = ptrcls.get_name(schema)
        kwargs['module_id'] = schema.get_global(s_mod.Module, name.module).id

    if direction is s_pointers.PointerDirection.Inbound:
        out_source = target_ref
        out_target = source_ref
    else:
        out_source = source_ref
        out_target = target_ref

    out_cardinality = ptrcls.get_cardinality(schema)
    if out_cardinality is None:
        # The cardinality is not yet known.
        dir_cardinality = None
    elif ptrcls.singular(schema, direction):
        dir_cardinality = qltypes.Cardinality.ONE
    else:
        dir_cardinality = qltypes.Cardinality.MANY

    material_ptrcls = ptrcls.material_type(schema)
    if material_ptrcls is not None and material_ptrcls is not ptrcls:
        material_ptr = ptrref_from_ptrcls(source_ref=source_ref,
                                          target_ref=target_ref,
                                          ptrcls=material_ptrcls,
                                          direction=direction,
                                          parent_ptr=parent_ptr,
                                          schema=schema)
    else:
        material_ptr = None

    union_components = set()
    union_of = ptrcls.get_union_of(schema)
    if union_of:
        for component in union_of.objects(schema):
            material_comp = component.material_type(schema)
            union_components.add(
                ptrref_from_ptrcls(
                    source_ref=source_ref,
                    target_ref=target_ref,
                    ptrcls=material_comp,
                    direction=direction,
                    parent_ptr=parent_ptr,
                    schema=schema,
                ))
    elif (material_ptr is None and not ptrcls.generic(schema)
          and not ptrcls.get_is_local(schema)):
        for base in ptrcls.as_locally_defined(schema):
            union_components.add(
                ptrref_from_ptrcls(
                    source_ref=source_ref,
                    target_ref=target_ref,
                    ptrcls=base,
                    direction=direction,
                    parent_ptr=parent_ptr,
                    schema=schema,
                    include_descendants=False,
                ))

    descendants = set()

    if not union_components:
        source = ptrcls.get_source(schema)
        if isinstance(source, s_abc.ObjectType) and include_descendants:
            ptrs = {material_ptrcls}
            ptrname = ptrcls.get_shortname(schema).name
            for descendant in source.descendants(schema):
                ptr = descendant.getptr(schema, ptrname)
                if ptr is not None:
                    desc_material_ptr = ptr.material_type(schema)
                    if (desc_material_ptr not in ptrs
                            and desc_material_ptr.get_is_local(schema)):
                        ptrs.add(desc_material_ptr)
                        descendants.add(
                            ptrref_from_ptrcls(
                                source_ref=source_ref,
                                target_ref=target_ref,
                                ptrcls=desc_material_ptr,
                                direction=direction,
                                parent_ptr=parent_ptr,
                                schema=schema,
                            ))

    std_parent_name = None
    for ancestor in ptrcls.get_ancestors(schema).objects(schema):
        ancestor_name = ancestor.get_name(schema)
        if ancestor_name.module == 'std' and ancestor.generic(schema):
            std_parent_name = ancestor_name
            break

    kwargs.update(
        dict(
            dir_source=source_ref,
            dir_target=target_ref,
            out_source=out_source,
            out_target=out_target,
            name=ptrcls.get_name(schema),
            shortname=ptrcls.get_shortname(schema),
            std_parent_name=std_parent_name,
            direction=direction,
            parent_ptr=parent_ptr,
            material_ptr=material_ptr,
            is_derived=ptrcls.get_is_derived(schema),
            descendants=descendants,
            union_components=union_components,
            has_properties=ptrcls.has_user_defined_properties(schema),
            required=ptrcls.get_required(schema),
            dir_cardinality=dir_cardinality,
            out_cardinality=out_cardinality,
        ))

    return ircls(**kwargs)
Exemple #12
0
def ptrref_from_ptrcls(*,
                       source_ref: irast.TypeRef,
                       target_ref: irast.TypeRef,
                       ptrcls: s_pointers.PointerLike,
                       direction: s_pointers.PointerDirection,
                       parent_ptr: typing.Optional[irast.PointerRef] = None,
                       schema) -> irast.BasePointerRef:

    kwargs = {}

    if ptrcls.is_tuple_indirection():
        ircls = irast.TupleIndirectionPointerRef
    elif ptrcls.is_type_indirection():
        ircls = irast.TypeIndirectionPointerRef
        kwargs['optional'] = ptrcls.is_optional()
        kwargs['ancestral'] = ptrcls.is_ancestral()
    else:
        ircls = irast.PointerRef
        kwargs['id'] = ptrcls.id
        name = ptrcls.get_name(schema)
        kwargs['module_id'] = schema.get_global(s_mod.Module, name.module).id

    if direction is s_pointers.PointerDirection.Inbound:
        out_source = target_ref
        out_target = source_ref
    else:
        out_source = source_ref
        out_target = target_ref

    out_cardinality = ptrcls.get_cardinality(schema)
    if out_cardinality is None:
        # The cardinality is not yet known.
        dir_cardinality = None
    elif ptrcls.singular(schema, direction):
        dir_cardinality = qltypes.Cardinality.ONE
    else:
        dir_cardinality = qltypes.Cardinality.MANY

    material_ptrcls = ptrcls.material_type(schema)
    if material_ptrcls is not None and material_ptrcls is not ptrcls:
        material_ptr = ptrref_from_ptrcls(source_ref=source_ref,
                                          target_ref=target_ref,
                                          ptrcls=material_ptrcls,
                                          direction=direction,
                                          parent_ptr=parent_ptr,
                                          schema=schema)
    else:
        material_ptr = None

    if ptrcls.get_derived_from(schema) is not None:
        derived_ptrcls = ptrcls.get_nearest_non_derived_parent(schema)
        derived_from_ptr = ptrref_from_ptrcls(source_ref=source_ref,
                                              target_ref=target_ref,
                                              ptrcls=derived_ptrcls,
                                              direction=direction,
                                              parent_ptr=parent_ptr,
                                              schema=schema)
    else:
        derived_from_ptr = None

    descendants = set()

    source = ptrcls.get_source(schema)
    if isinstance(source, s_objtypes.ObjectType):
        ptrs = {material_ptrcls}
        ptrname = ptrcls.get_shortname(schema).name
        for descendant in source.descendants(schema):
            ptr = descendant.getptr(schema, ptrname)
            if ptr is not None:
                desc_material_ptr = ptr.material_type(schema)
                if desc_material_ptr not in ptrs:
                    ptrs.add(desc_material_ptr)
                    descendants.add(
                        ptrref_from_ptrcls(
                            source_ref=source_ref,
                            target_ref=target_ref,
                            ptrcls=desc_material_ptr,
                            direction=direction,
                            parent_ptr=parent_ptr,
                            schema=schema,
                        ))

    kwargs.update(
        dict(
            dir_source=source_ref,
            dir_target=target_ref,
            out_source=out_source,
            out_target=out_target,
            name=ptrcls.get_name(schema),
            shortname=ptrcls.get_shortname(schema),
            direction=direction,
            parent_ptr=parent_ptr,
            material_ptr=material_ptr,
            derived_from_ptr=derived_from_ptr,
            descendants=descendants,
            has_properties=ptrcls.has_user_defined_properties(schema),
            required=ptrcls.get_required(schema),
            dir_cardinality=dir_cardinality,
            out_cardinality=out_cardinality,
        ))

    return ircls(**kwargs)