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
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
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))))
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
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
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)
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
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)
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)
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
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)
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)