def computable_ptr_set(rptr: irast.Pointer, *, unnest_fence: bool = False, same_computable_scope: bool = False, ctx: context.ContextLevel) -> irast.Set: """Return ir.Set for a pointer defined as a computable.""" ptrcls = irtyputils.ptrcls_from_ptrref(rptr.ptrref, schema=ctx.env.schema) source_set = rptr.source source_scls = get_set_type(source_set, ctx=ctx) # process_view() may generate computable pointer expressions # in the form "self.linkname". To prevent infinite recursion, # self must resolve to the parent type of the view NOT the view # type itself. Similarly, when resolving computable link properties # make sure that we use ptrcls.derived_from. if source_scls.is_view(ctx.env.schema): source_set_stype = source_scls.peel_view(ctx.env.schema) source_set = new_set_from_set(source_set, stype=source_set_stype, preserve_scope_ns=True, ctx=ctx) source_set.shape = [] if source_set.rptr is not None: schema = ctx.env.schema source_rptrref = source_set.rptr.ptrref source_rptrcls = irtyputils.ptrcls_from_ptrref(source_rptrref, schema=schema) derived_from = source_rptrcls.get_derived_from(schema) if (derived_from is not None and not derived_from.generic(schema) and derived_from.get_derived_from(schema) is not None and ptrcls.is_link_property(schema)): source_set.rptr.ptrref = irtyputils.ptrref_from_ptrcls( source_ref=source_rptrref.dir_source, target_ref=source_rptrref.dir_target, direction=source_rptrref.direction, parent_ptr=source_rptrref.parent_ptr, ptrcls=derived_from, schema=schema, ) stmtctx.ensure_ptrref_cardinality(derived_from, source_set.rptr.ptrref, ctx=ctx) try: qlexpr, qlctx, inner_source_path_id, path_id_ns = \ ctx.source_map[ptrcls] except KeyError: ptrcls_default = ptrcls.get_default(ctx.env.schema) if not ptrcls_default: ptrcls_sn = ptrcls.get_shortname(ctx.env.schema) raise ValueError(f'{ptrcls_sn!r} is not a computable pointer') qlexpr = astutils.ensure_qlstmt(qlparser.parse(ptrcls_default.text)) qlctx = None inner_source_path_id = None path_id_ns = None if qlctx is None: # Schema-level computable, completely detached context newctx = ctx.detached else: newctx = _get_computable_ctx(rptr=rptr, source=source_set, source_scls=source_scls, inner_source_path_id=inner_source_path_id, path_id_ns=path_id_ns, same_scope=same_computable_scope, qlctx=qlctx, ctx=ctx) if ptrcls.is_link_property(ctx.env.schema): source_path_id = rptr.source.path_id.ptr_path() else: source_path_id = rptr.target.path_id.src_path() result_stype = ptrcls.get_target(ctx.env.schema) result_path_id = pathctx.extend_path_id( source_path_id, ptrcls=ptrcls, direction=s_pointers.PointerDirection.Outbound, target=result_stype, ns=ctx.path_id_namespace, ctx=ctx) with newctx() as subctx: subctx.view_scls = result_stype subctx.view_rptr = context.ViewRPtr(source_scls, ptrcls=ptrcls, rptr=rptr) subctx.anchors[qlast.Source] = source_set subctx.empty_result_type_hint = ptrcls.get_target(ctx.env.schema) subctx.partial_path_prefix = source_set if isinstance(qlexpr, qlast.Statement) and unnest_fence: subctx.stmt_metadata[qlexpr] = context.StatementMetadata( is_unnest_fence=True) comp_ir_set = dispatch.compile(qlexpr, ctx=subctx) comp_ir_set_copy = new_set_from_set(comp_ir_set, ctx=ctx) pending_cardinality = ctx.pending_cardinality.get(ptrcls) if pending_cardinality is not None and not pending_cardinality.from_parent: stmtctx.get_pointer_cardinality_later( ptrcls=ptrcls, irexpr=comp_ir_set_copy, specified_card=pending_cardinality.specified_cardinality, source_ctx=pending_cardinality.source_ctx, ctx=ctx) def _check_cardinality(ctx): if ptrcls.singular(ctx.env.schema): stmtctx.enforce_singleton_now(comp_ir_set_copy, ctx=ctx) stmtctx.at_stmt_fini(_check_cardinality, ctx=ctx) comp_ir_set = new_set_from_set(comp_ir_set, path_id=result_path_id, rptr=rptr, ctx=ctx) rptr.target = comp_ir_set return comp_ir_set
def computable_ptr_set( rptr: irast.Pointer, *, unnest_fence: bool = False, same_computable_scope: bool = False, srcctx: Optional[parsing.ParserContext] = None, ctx: context.ContextLevel, ) -> irast.Set: """Return ir.Set for a pointer defined as a computable.""" ptrcls = typegen.ptrcls_from_ptrref(rptr.ptrref, ctx=ctx) source_set = rptr.source source_scls = get_set_type(source_set, ctx=ctx) # process_view() may generate computable pointer expressions # in the form "self.linkname". To prevent infinite recursion, # self must resolve to the parent type of the view NOT the view # type itself. Similarly, when resolving computable link properties # make sure that we use the parent of derived ptrcls. if source_scls.is_view(ctx.env.schema): source_set_stype = source_scls.peel_view(ctx.env.schema) source_set = new_set_from_set(source_set, stype=source_set_stype, preserve_scope_ns=True, ctx=ctx) source_set.shape = [] if source_set.rptr is not None: source_rptrref = source_set.rptr.ptrref if source_rptrref.base_ptr is not None: source_rptrref = source_rptrref.base_ptr source_set.rptr = irast.Pointer( source=source_set.rptr.source, target=source_set, ptrref=source_rptrref, direction=source_set.rptr.direction, ) qlctx: Optional[context.ContextLevel] inner_source_path_id: Optional[irast.PathId] try: comp_info = ctx.source_map[ptrcls] qlexpr = comp_info.qlexpr assert isinstance(comp_info.context, context.ContextLevel) qlctx = comp_info.context inner_source_path_id = comp_info.path_id path_id_ns = comp_info.path_id_ns except KeyError: comp_expr = ptrcls.get_expr(ctx.env.schema) schema_qlexpr: Optional[qlast.Expr] = None if comp_expr is None and ctx.env.options.apply_query_rewrites: schema_deflt = ptrcls.get_schema_reflection_default(ctx.env.schema) if schema_deflt is not None: assert isinstance(ptrcls, s_pointers.Pointer) ptrcls_n = ptrcls.get_shortname(ctx.env.schema).name schema_qlexpr = qlast.BinOp( left=qlast.Path(steps=[ qlast.Source(), qlast.Ptr( ptr=qlast.ObjectRef(name=ptrcls_n), direction=s_pointers.PointerDirection.Outbound, type=('property' if ptrcls.is_link_property( ctx.env.schema) else None)) ], ), right=qlparser.parse_fragment(schema_deflt), op='??', ) if schema_qlexpr is None: if comp_expr is None: ptrcls_sn = ptrcls.get_shortname(ctx.env.schema) raise errors.InternalServerError( f'{ptrcls_sn!r} is not a computable pointer') comp_qlexpr = qlparser.parse(comp_expr.text) assert isinstance(comp_qlexpr, qlast.Expr), 'expected qlast.Expr' schema_qlexpr = comp_qlexpr # NOTE: Validation of the expression type is not the concern # of this function. For any non-object pointer target type, # the default expression must be assignment-cast into that # type. target_scls = ptrcls.get_target(ctx.env.schema) assert target_scls is not None if not target_scls.is_object_type(): schema_qlexpr = qlast.TypeCast( type=typegen.type_to_ql_typeref(target_scls, ctx=ctx), expr=schema_qlexpr, ) qlexpr = astutils.ensure_qlstmt(schema_qlexpr) qlctx = None inner_source_path_id = None path_id_ns = None newctx: Callable[[], ContextManager[context.ContextLevel]] if qlctx is None: # Schema-level computable, completely detached context newctx = ctx.detached else: newctx = _get_computable_ctx(rptr=rptr, source=source_set, source_scls=source_scls, inner_source_path_id=inner_source_path_id, path_id_ns=path_id_ns, same_scope=same_computable_scope, qlctx=qlctx, ctx=ctx) if ptrcls.is_link_property(ctx.env.schema): source_path_id = rptr.source.path_id.ptr_path() else: src_path = rptr.target.path_id.src_path() assert src_path is not None source_path_id = src_path result_path_id = pathctx.extend_path_id( source_path_id, ptrcls=ptrcls, ns=ctx.path_id_namespace, ctx=ctx, ) result_stype = ptrcls.get_target(ctx.env.schema) base_object = ctx.env.schema.get('std::BaseObject', type=s_types.Type) with newctx() as subctx: subctx.disable_shadowing.add(ptrcls) if result_stype != base_object: subctx.view_scls = result_stype subctx.view_rptr = context.ViewRPtr(source_scls, ptrcls=ptrcls, rptr=rptr) # type: ignore subctx.anchors[qlast.Source().name] = source_set subctx.empty_result_type_hint = ptrcls.get_target(ctx.env.schema) subctx.partial_path_prefix = source_set # On a mutation, make the expr_exposed. This corresponds with # a similar check on is_mutation in _normalize_view_ptr_expr. if (source_scls.get_expr_type(ctx.env.schema) != s_types.ExprType.Select): subctx.expr_exposed = True if isinstance(qlexpr, qlast.Statement): subctx.stmt_metadata[qlexpr] = context.StatementMetadata( is_unnest_fence=unnest_fence, iterator_target=True, ) comp_ir_set = ensure_set(dispatch.compile(qlexpr, ctx=subctx), ctx=subctx) comp_ir_set = new_set_from_set(comp_ir_set, path_id=result_path_id, rptr=rptr, context=srcctx, ctx=ctx) rptr.target = comp_ir_set return comp_ir_set
def computable_ptr_set( rptr: irast.Pointer, *, unnest_fence: bool=False, hoist_iterators: bool=False, same_computable_scope: bool=False, from_default_expr: bool=False, ctx: context.ContextLevel) -> irast.Set: """Return ir.Set for a pointer defined as a computable.""" ptrcls = typegen.ptrcls_from_ptrref(rptr.ptrref, ctx=ctx) source_set = rptr.source source_scls = get_set_type(source_set, ctx=ctx) # process_view() may generate computable pointer expressions # in the form "self.linkname". To prevent infinite recursion, # self must resolve to the parent type of the view NOT the view # type itself. Similarly, when resolving computable link properties # make sure that we use the parent of derived ptrcls. if source_scls.is_view(ctx.env.schema): source_set_stype = source_scls.peel_view(ctx.env.schema) source_set = new_set_from_set( source_set, stype=source_set_stype, preserve_scope_ns=True, ctx=ctx) source_set.shape = [] if source_set.rptr is not None: source_set.rptr = irast.Pointer( source=source_set.rptr.source, target=source_set, ptrref=source_set.rptr.ptrref.base_ptr, direction=source_set.rptr.direction, ) qlctx: Optional[context.ContextLevel] inner_source_path_id: Optional[irast.PathId] try: qlexpr, qlctx, inner_source_path_id, path_id_ns = \ ctx.source_map[ptrcls] except KeyError: if from_default_expr: comp_expr = ptrcls.get_default(ctx.env.schema) else: comp_expr = ptrcls.get_expr(ctx.env.schema) if comp_expr is None: ptrcls_sn = ptrcls.get_shortname(ctx.env.schema) raise ValueError( f'{ptrcls_sn!r} is not a computable pointer') qlexpr = qlparser.parse(comp_expr.text) # NOTE: Validation of the expression type is not the concern # of this function. For any non-object pointer target type, # the default expression must be assignment-cast into that # type. target_scls = ptrcls.get_target(ctx.env.schema) assert target_scls is not None if not target_scls.is_object_type(): qlexpr = qlast.TypeCast( type=astutils.type_to_ql_typeref( target_scls, schema=ctx.env.schema), expr=qlexpr, ) qlexpr = astutils.ensure_qlstmt(qlexpr) qlctx = None inner_source_path_id = None path_id_ns = None newctx: Callable[[], ContextManager[context.ContextLevel]] if qlctx is None: # Schema-level computable, completely detached context newctx = ctx.detached else: newctx = _get_computable_ctx( rptr=rptr, source=source_set, source_scls=source_scls, inner_source_path_id=inner_source_path_id, path_id_ns=path_id_ns, same_scope=same_computable_scope, qlctx=qlctx, ctx=ctx) if ptrcls.is_link_property(ctx.env.schema): source_path_id = rptr.source.path_id.ptr_path() else: src_path = rptr.target.path_id.src_path() assert src_path is not None source_path_id = src_path result_path_id = pathctx.extend_path_id( source_path_id, ptrcls=ptrcls, ns=ctx.path_id_namespace, ctx=ctx) result_stype = ptrcls.get_target(ctx.env.schema) with newctx() as subctx: subctx.view_scls = result_stype assert isinstance(source_scls, s_sources.Source) subctx.view_rptr = context.ViewRPtr( source_scls, ptrcls=ptrcls, rptr=rptr) subctx.anchors[qlast.Source] = source_set subctx.empty_result_type_hint = ptrcls.get_target(ctx.env.schema) subctx.partial_path_prefix = source_set if isinstance(qlexpr, qlast.Statement): subctx.stmt_metadata[qlexpr] = context.StatementMetadata( is_unnest_fence=unnest_fence, iterator_target=True, ) comp_ir_set = ensure_set( dispatch.compile(qlexpr, ctx=subctx), ctx=subctx) comp_ir_set_copy = new_set_from_set(comp_ir_set, ctx=ctx) pending_cardinality = ctx.pending_cardinality.get(ptrcls) if pending_cardinality is not None: stmtctx.get_pointer_cardinality_later( ptrcls=ptrcls, irexpr=comp_ir_set_copy, specified_card=pending_cardinality.specified_cardinality, source_ctx=pending_cardinality.source_ctx, ctx=ctx) stmtctx.enforce_pointer_cardinality(ptrcls, comp_ir_set_copy, ctx=ctx) comp_ir_set = new_set_from_set( comp_ir_set, path_id=result_path_id, rptr=rptr, ctx=ctx) rptr.target = comp_ir_set return comp_ir_set