示例#1
0
def process_view(
        *,
        stype: s_nodes.Node,
        path_id: irast.PathId,
        elements: typing.List[qlast.ShapeElement],
        view_rptr: typing.Optional[context.ViewRPtr]=None,
        view_name: typing.Optional[sn.SchemaName]=None,
        is_insert: bool=False,
        is_update: bool=False,
        ctx: context.CompilerContext) -> s_nodes.Node:

    cache_key = tuple(elements)
    view_scls = ctx.shape_type_cache.get(cache_key)
    if view_scls is not None:
        return view_scls

    with ctx.newscope(fenced=True, temporary=True) as scopectx:
        scopectx.path_scope.attach_path(path_id)
        if ctx.expr_exposed or is_insert or is_update:
            view_path_id_ns = irast.WeakNamespace(ctx.aliases.get('ns'))
            scopectx.path_id_namespace |= {view_path_id_ns}
            scopectx.path_scope.namespaces.add(view_path_id_ns)
        else:
            view_path_id_ns = None

        view_scls = _process_view(
            stype=stype, path_id=path_id, elements=elements,
            view_rptr=view_rptr, view_name=view_name,
            is_insert=is_insert, is_update=is_update,
            path_id_namespace=view_path_id_ns, ctx=scopectx
        )

    ctx.shape_type_cache[cache_key] = view_scls

    return view_scls
示例#2
0
文件: setgen.py 项目: mcaramma/edgedb
    def newctx():
        with ctx.new() as subctx:
            subctx.class_view_overrides = {}
            subctx.partial_path_prefix = None

            subctx.modaliases = qlctx.modaliases.copy()
            subctx.aliased_views = qlctx.aliased_views.new_child()
            if source_scls.is_view():
                subctx.aliased_views[source.scls.name] = None
            subctx.source_map = qlctx.source_map.copy()
            subctx.view_nodes = qlctx.view_nodes.copy()
            subctx.view_sets = qlctx.view_sets.copy()
            subctx.view_map = qlctx.view_map.new_child()

            source_scope = pathctx.get_set_scope(rptr.source, ctx=ctx)
            if source_scope and source_scope.namespaces:
                subctx.path_id_namespace += tuple(source_scope.namespaces)

            subctx.pending_stmt_own_path_id_namespace = \
                irast.WeakNamespace(ctx.aliases.get('ns'))

            subns = subctx.pending_stmt_full_path_id_namespace = \
                {subctx.pending_stmt_own_path_id_namespace}

            self_view = ctx.view_sets.get(source.scls)
            if self_view:
                if self_view.path_id.namespace:
                    subns.update(self_view.path_id.namespace)
                inner_path_id = self_view.path_id.merge_namespace(
                    subctx.path_id_namespace + tuple(subns))
            else:
                if source.path_id.namespace:
                    subns.update(source.path_id.namespace)

                if inner_source_path_id is not None:
                    # The path id recorded in the source map may
                    # contain namespaces referring to a temporary
                    # scope subtree used by `process_view()`.
                    # Since we recompile the computable expression
                    # using the current path id namespace, the
                    # original source path id needs to be fixed.
                    inner_path_id = inner_source_path_id \
                        .strip_namespace(qlctx.path_id_namespace) \
                        .merge_namespace(subctx.path_id_namespace)
                else:
                    inner_path_id = pathctx.get_path_id(source.scls,
                                                        ctx=subctx)

                inner_path_id = inner_path_id.merge_namespace(subns)

            remapped_source = new_set_from_set(rptr.source, ctx=subctx)
            remapped_source.path_id = \
                remapped_source.path_id.merge_namespace(subns)
            remapped_source.rptr = rptr.source.rptr
            subctx.view_map[inner_path_id] = remapped_source
            yield subctx
示例#3
0
def declare_view(expr: qlast.Base,
                 alias: str,
                 *,
                 fully_detached: bool = False,
                 temporary_scope: bool = True,
                 ctx: context.ContextLevel) -> irast.Set:

    with ctx.newscope(temporary=temporary_scope, fenced=True) as subctx:
        if not fully_detached:
            cached_view_set = ctx.expr_view_cache.get((expr, alias))
            # Detach the view namespace and record the prefix
            # in the parent statement's fence node.
            add_ns = (irast.WeakNamespace(ctx.aliases.get('ns')), )
            subctx.path_id_namespace = subctx.path_id_namespace + add_ns
            ctx.path_scope.namespaces.add(subctx.path_id_namespace[-1])
        else:
            cached_view_set = None

        if ctx.stmt is not None:
            subctx.stmt = ctx.stmt.parent_stmt

        if cached_view_set is not None:
            subctx.view_scls = cached_view_set.scls
            view_name = cached_view_set.scls.name
        else:
            if isinstance(alias, s_name.SchemaName):
                basename = alias
            else:
                basename = s_name.SchemaName(module='__view__', name=alias)

            view_name = s_name.SchemaName(
                module=ctx.derived_target_module or '_',
                name=s_obj.NamedObject.get_specialized_name(
                    basename, ctx.aliases.get('w')))

        subctx.toplevel_result_view_name = view_name

        view_set = dispatch.compile(astutils.ensure_qlstmt(expr), ctx=subctx)
        # The view path id _itself_ should not be in the nested namespace.
        view_set.path_id = view_set.path_id.replace_namespace(
            ctx.path_id_namespace)
        ctx.aliased_views[alias] = view_set.scls
        ctx.path_scope_map[view_set] = subctx.path_scope
        ctx.expr_view_cache[expr, alias] = view_set

    return view_set
示例#4
0
def computable_ptr_set(rptr: irast.Pointer,
                       *,
                       unnest_fence: bool = False,
                       ctx: context.ContextLevel) -> irast.Set:
    """Return ir.Set for a pointer defined as a computable."""
    ptrcls = rptr.ptrcls

    # Must use an entirely separate context, as the computable
    # expression is totally independent from the surrounding query.
    subctx = stmtctx.init_context(schema=ctx.schema)
    self_ = rptr.source
    source_scls = self_.scls
    # 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 rptr.ptrcls.derived_from.
    if source_scls.is_view():
        self_ = copy.copy(self_)
        self_.scls = source_scls.peel_view()
        self_.shape = []

        if self_.rptr is not None:
            derived_from = self_.rptr.ptrcls.derived_from
            if (derived_from is not None and not derived_from.generic()
                    and derived_from.derived_from is not None
                    and ptrcls.is_link_property()):
                self_.rptr.ptrcls = derived_from

    subctx.anchors[qlast.Source] = self_

    subctx.aliases = ctx.aliases
    subctx.stmt = ctx.stmt
    subctx.view_scls = ptrcls.target
    subctx.view_rptr = context.ViewRPtr(source_scls, ptrcls=ptrcls, rptr=rptr)
    subctx.toplevel_stmt = ctx.toplevel_stmt
    subctx.path_scope = ctx.path_scope
    subctx.pending_cardinality = ctx.pending_cardinality
    subctx.completion_work = ctx.completion_work
    subctx.pointer_derivation_map = ctx.pointer_derivation_map
    subctx.class_shapes = ctx.class_shapes
    subctx.all_sets = ctx.all_sets
    subctx.path_scope_map = ctx.path_scope_map
    subctx.scope_id_ctr = ctx.scope_id_ctr
    subctx.expr_exposed = ctx.expr_exposed

    if ptrcls.is_link_property():
        source_path_id = rptr.source.path_id.ptr_path()
    else:
        source_path_id = rptr.target.path_id.src_path()

    path_id = source_path_id.extend(ptrcls,
                                    s_pointers.PointerDirection.Outbound,
                                    ptrcls.target)

    subctx.path_scope.contain_path(path_id)

    try:
        qlexpr, qlctx = ctx.source_map[ptrcls]
    except KeyError:
        if not ptrcls.default:
            raise ValueError(
                f'{ptrcls.shortname!r} is not a computable pointer')

        if isinstance(ptrcls.default, s_expr.ExpressionText):
            qlexpr = astutils.ensure_qlstmt(qlparser.parse(ptrcls.default))
        else:
            qlexpr = qlast.Constant(value=ptrcls.default)

        qlctx = None
    else:
        subctx.modaliases = qlctx.modaliases.copy()
        subctx.aliased_views = qlctx.aliased_views.new_child()
        if source_scls.is_view():
            subctx.aliased_views[self_.scls.name] = None
        subctx.source_map = qlctx.source_map.copy()
        subctx.view_nodes = qlctx.view_nodes.copy()
        subctx.view_sets = qlctx.view_sets.copy()
        subctx.view_map = qlctx.view_map.new_child()
        subctx.singletons = qlctx.singletons.copy()
        subctx.path_id_namespce = qlctx.path_id_namespace

    if qlctx is None:
        # This is a schema-level computable expression, put all
        # class refs into a separate namespace.
        subctx.path_id_namespace = (subctx.aliases.get('ns'), )
    else:
        subctx.pending_stmt_own_path_id_namespace = \
            irast.WeakNamespace(ctx.aliases.get('ns'))

        subns = subctx.pending_stmt_full_path_id_namespace = \
            {subctx.pending_stmt_own_path_id_namespace}

        self_view = ctx.view_sets.get(self_.scls)
        if self_view:
            if self_view.path_id.namespace:
                subns.update(self_view.path_id.namespace)
            inner_path_id = self_view.path_id.merge_namespace(
                subctx.path_id_namespace + tuple(subns))
        else:
            if self_.path_id.namespace:
                subns.update(self_.path_id.namespace)
            inner_path_id = pathctx.get_path_id(
                self_.scls, ctx=subctx).merge_namespace(subns)

        remapped_source = new_set_from_set(rptr.source, ctx=subctx)
        remapped_source.path_id = \
            remapped_source.path_id.merge_namespace(subns)
        subctx.view_map[inner_path_id] = remapped_source

    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)

    if ptrcls in ctx.pending_cardinality:
        comp_ir_set_copy = copy.copy(comp_ir_set)

        stmtctx.get_pointer_cardinality_later(ptrcls=ptrcls,
                                              irexpr=comp_ir_set_copy,
                                              ctx=ctx)

        def _check_cardinality(ctx):
            if ptrcls.singular():
                stmtctx.enforce_singleton_now(comp_ir_set_copy, ctx=ctx)

        stmtctx.at_stmt_fini(_check_cardinality, ctx=ctx)

    comp_ir_set.scls = ptrcls.target
    comp_ir_set.path_id = path_id
    comp_ir_set.rptr = rptr

    rptr.target = comp_ir_set

    return comp_ir_set