Пример #1
0
    def visit_Set(self, node):
        if node.expr is not None:
            result = self.visit(node.expr)
        else:
            links = []

            while node.rptr and (not node.show_as_anchor
                                 or self.context.inline_anchors):
                rptr = node.rptr
                ptrcls = rptr.ptrcls
                pname = ptrcls.shortname

                if isinstance(rptr.target.scls, s_objtypes.ObjectType):
                    target = rptr.target.scls.shortname
                    target = qlast.TypeName(maintype=qlast.ObjectRef(
                        name=target.name, module=target.module))
                else:
                    target = None

                link = qlast.Ptr(
                    ptr=qlast.ObjectRef(name=pname.name, ),
                    direction=rptr.direction,
                    target=target,
                )
                if isinstance(ptrcls.source, s_links.Link):
                    link.type = 'property'
                links.append(link)

                node = node.rptr.source

            result = qlast.Path()

            if node.show_as_anchor and not self.context.inline_anchors:
                if issubclass(node.show_as_anchor, qlast.Expr):
                    step = node.show_as_anchor()
                else:
                    step = qlast.ObjectRef(name=node.show_as_anchor)
            else:
                step = qlast.ObjectRef(name=node.scls.shortname.name,
                                       module=node.scls.shortname.module)

            result.steps.append(step)
            result.steps.extend(reversed(links))

        if node.shape:
            result = qlast.Shape(expr=result, elements=[])

            for el in node.shape:
                rptr = el.rptr
                ptrcls = rptr.ptrcls
                pn = ptrcls.shortname

                pn = qlast.ShapeElement(expr=qlast.Path(steps=[
                    qlast.Ptr(ptr=qlast.ObjectRef(name=pn.name),
                              direction=rptr.direction)
                ]))

                result.elements.append(pn)

        return result
Пример #2
0
 def reduce_ShapePath(self, *kids):
     self.val = qlast.ShapeElement(
         expr=kids[0].val
     )
Пример #3
0
    def visit_Field(self, node):
        if self._is_duplicate_field(node):
            return

        is_top, path, prevt, target, steps = \
            self._prepare_field(node)

        json_mode = False
        is_shadowed = prevt.is_field_shadowed(node.name)

        # determine if there needs to be extra subqueries
        if not prevt.dummy and target.dummy:
            json_mode = True

            # this is a special introspection type
            eql, shape, filterable = target.get_template()

            spec = qlast.ShapeElement(
                expr=qlast.Path(steps=[
                    qlast.Ptr(ptr=qlast.ObjectRef(
                        name=node.alias or node.name))
                ]),
                compexpr=eql,
            )

        elif is_shadowed and not node.alias:
            # shadowed field that doesn't need an alias
            spec = filterable = shape = qlast.ShapeElement(
                expr=qlast.Path(steps=steps), )

        elif not node.selection_set or is_shadowed and node.alias:
            # this is either an unshadowed terminal field or an aliased
            # shadowed field
            prefix = qlast.Path(steps=self.get_path_prefix(-1))
            eql, shape, filterable = prevt.get_field_template(
                node.name, parent=prefix, has_shape=bool(node.selection_set))
            spec = qlast.ShapeElement(
                expr=qlast.Path(steps=[
                    qlast.Ptr(ptr=qlast.ObjectRef(
                        # this is already a sub-query
                        name=node.alias or node.name))
                ]),
                compexpr=eql)

        else:
            # if the parent is NOT a shadowed type, we need an explicit SELECT
            eql, shape, filterable = target.get_template()
            spec = qlast.ShapeElement(
                expr=qlast.Path(steps=[
                    qlast.Ptr(ptr=qlast.ObjectRef(
                        # this is already a sub-query
                        name=node.alias or node.name))
                ]),
                compexpr=eql)

        if node.selection_set is not None:
            if json_mode:
                pass

            else:
                # a single recursion target, so we can process
                # selection set now
                self._context.fields.append({})
                vals = self.visit(node.selection_set)
                self._context.fields.pop()

                if shape:
                    shape.elements = vals
                if filterable:
                    where, orderby, offset, limit = \
                        self._visit_arguments(node.arguments)
                    filterable.where = where
                    filterable.orderby = orderby
                    filterable.offset = offset
                    filterable.limit = limit
                    # just to make sure that limit doesn't change the
                    # serialization from list to a single object, we
                    # need to force multi-cardinality, while being careful
                    # as to not set the cardinality qualifier on a
                    # non-computable shape element.
                    if (limit is not None
                            and (isinstance(filterable, qlast.Statement)
                                 or filterable.compexpr is not None)):
                        spec.cardinality = qlast.Cardinality.MANY

        path.pop()
        return spec
Пример #4
0
    def visit_Field(self, node):
        if self._is_duplicate_field(node):
            return

        is_top, path, prevt, target, steps = \
            self._prepare_field(node)

        json_mode = False

        # determine if there needs to be extra subqueries
        if not prevt.dummy and target.dummy:
            json_mode = True

            # this is a special introspection type
            eql, shape, filterable = target.get_template()

            spec = qlast.ShapeElement(
                expr=qlast.Path(steps=[
                    qlast.Ptr(ptr=qlast.ObjectRef(
                        name=node.alias or node.name))
                ]),
                compexpr=eql,
            )

        elif prevt.is_field_shadowed(node.name):
            if prevt.has_native_field(node.name) and not node.alias:
                spec = filterable = shape = qlast.ShapeElement(
                    expr=qlast.Path(steps=steps), )
            else:
                prefix = qlast.Path(steps=self.get_path_prefix(-1))
                eql, shape, filterable = prevt.get_field_template(
                    node.name,
                    parent=prefix,
                    has_shape=bool(node.selection_set))
                spec = qlast.ShapeElement(
                    expr=qlast.Path(steps=[
                        qlast.Ptr(ptr=qlast.ObjectRef(
                            # this is already a sub-query
                            name=node.alias or node.name))
                    ]),
                    compexpr=eql)

        else:
            # if the parent is NOT a shadowed type, we need an explicit SELECT
            eql, shape, filterable = target.get_template()
            spec = qlast.ShapeElement(
                expr=qlast.Path(steps=[
                    qlast.Ptr(ptr=qlast.ObjectRef(
                        # this is already a sub-query
                        name=node.alias or node.name))
                ]),
                compexpr=eql)

        if node.selection_set is not None:
            if json_mode:
                pass

            else:
                # a single recursion target, so we can process
                # selection set now
                self._context.fields.append({})
                vals = self.visit(node.selection_set)
                self._context.fields.pop()

                if shape:
                    shape.elements = vals
                if filterable:
                    where, orderby, offset, limit = \
                        self._visit_arguments(node.arguments)
                    filterable.where = where
                    filterable.orderby = orderby
                    filterable.offset = offset
                    filterable.limit = limit

        path.pop()
        return spec
Пример #5
0
def _process_view(*,
                  scls: 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:
    view_scls = schemactx.derive_view(scls,
                                      is_insert=is_insert,
                                      is_update=is_update,
                                      derived_name=view_name,
                                      ctx=ctx)
    is_mutation = is_insert or is_update
    is_defining_shape = ctx.expr_exposed or is_mutation

    pointers = []

    for shape_el in elements:
        with ctx.newscope(fenced=True) as scopectx:
            pointers.append(
                _normalize_view_ptr_expr(shape_el,
                                         view_scls,
                                         path_id=path_id,
                                         is_insert=is_insert,
                                         is_update=is_update,
                                         view_rptr=view_rptr,
                                         ctx=scopectx))

    if is_insert:
        explicit_ptrs = {ptrcls.shortname for ptrcls in pointers}

        for pn, ptrcls in scls.pointers.items():
            if (not ptrcls.default or pn in explicit_ptrs
                    or ptrcls.is_pure_computable()):
                continue

            default_ql = qlast.ShapeElement(expr=qlast.Path(steps=[
                qlast.Ptr(ptr=qlast.ObjectRef(name=ptrcls.shortname.name,
                                              module=ptrcls.shortname.module))
            ]))

            with ctx.newscope(fenced=True) as scopectx:
                scopectx.singletons = ctx.singletons.copy()
                scopectx.singletons.add(path_id)
                pointers.append(
                    _normalize_view_ptr_expr(default_ql,
                                             view_scls,
                                             path_id=path_id,
                                             is_insert=is_insert,
                                             is_update=is_update,
                                             view_rptr=view_rptr,
                                             ctx=scopectx))

    # Check if the view shape includes _only_ the link properties.
    # If so, we do not need to derive a new target view.
    lprops_only = True
    for ptrcls in pointers:
        if not ptrcls.is_link_property():
            lprops_only = False
            break

    if lprops_only:
        view_scls = scls

    for ptrcls in pointers:
        if ptrcls.is_link_property():
            source = view_rptr.derived_ptrcls
        else:
            source = view_scls

        if ptrcls.source is source and isinstance(source, s_sources.Source):
            # source may be an ScalarType in shapes that reference __type__,
            # hence the isinstance check.
            source.add_pointer(ptrcls, replace=True)

        if is_defining_shape:
            if source is None:
                # The nested shape is merely selecting the pointer,
                # so the link class has not been derived.  But for
                # the purposes of shape tracking, we must derive it
                # still.
                source = derive_ptrcls(view_rptr,
                                       target_scls=view_scls,
                                       ctx=ctx)

            ctx.class_shapes[source].append(ptrcls)

    if view_rptr is not None and view_rptr.derived_ptrcls is not None:
        view_scls.rptr = view_rptr.derived_ptrcls

    return view_scls
Пример #6
0
def _process_view(
        *,
        stype: s_nodes.Node,
        path_id: irast.PathId,
        path_id_namespace: typing.Optional[irast.WeakNamespace]=None,
        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:
    view_scls = schemactx.derive_view(
        stype, is_insert=is_insert, is_update=is_update,
        derived_name=view_name, ctx=ctx)
    is_mutation = is_insert or is_update
    is_defining_shape = ctx.expr_exposed or is_mutation

    pointers = []

    for shape_el in elements:
        with ctx.newscope(fenced=True) as scopectx:
            pointers.append(_normalize_view_ptr_expr(
                shape_el, view_scls, path_id=path_id,
                path_id_namespace=path_id_namespace,
                is_insert=is_insert, is_update=is_update,
                view_rptr=view_rptr, ctx=scopectx))

    if is_insert:
        explicit_ptrs = {ptrcls.get_shortname(ctx.env.schema).name
                         for ptrcls in pointers}

        scls_pointers = stype.get_pointers(ctx.env.schema)
        for pn, ptrcls in scls_pointers.items(ctx.env.schema):
            if (not ptrcls.get_default(ctx.env.schema) or
                    pn in explicit_ptrs or
                    ptrcls.is_pure_computable(ctx.env.schema)):
                continue

            ptrcls_sn = ptrcls.get_shortname(ctx.env.schema)
            default_ql = qlast.ShapeElement(expr=qlast.Path(steps=[
                qlast.Ptr(ptr=qlast.ObjectRef(name=ptrcls_sn.name,
                                              module=ptrcls_sn.module))
            ]))

            with ctx.newscope(fenced=True) as scopectx:
                pointers.append(_normalize_view_ptr_expr(
                    default_ql, view_scls, path_id=path_id,
                    path_id_namespace=path_id_namespace,
                    is_insert=is_insert, is_update=is_update,
                    view_rptr=view_rptr, ctx=scopectx))

    # Check if the view shape includes _only_ the link properties.
    # If so, we do not need to derive a new target view.
    lprops_only = True
    for ptrcls in pointers:
        if not ptrcls.is_link_property(ctx.env.schema):
            lprops_only = False
            break

    if lprops_only:
        view_scls = stype

    for ptrcls in pointers:
        if ptrcls.is_link_property(ctx.env.schema):
            source = view_rptr.derived_ptrcls
        else:
            source = view_scls

        if (ptrcls.get_source(ctx.env.schema) is source and
                isinstance(source, s_sources.Source)):
            # source may be an ScalarType in shapes that reference __type__,
            # hence the isinstance check.
            ctx.env.schema = source.add_pointer(
                ctx.env.schema, ptrcls, replace=True)

        if is_defining_shape:
            if source is None:
                # The nested shape is merely selecting the pointer,
                # so the link class has not been derived.  But for
                # the purposes of shape tracking, we must derive it
                # still.  The derived pointer must be treated the same
                # as the original, as this is not a new computable,
                # and both `Foo.ptr` and `Foo { ptr }` are the same path,
                # hence the `transparent` modifier.
                source = derive_ptrcls(
                    view_rptr, target_scls=view_scls,
                    transparent=True, ctx=ctx)

            ctx.class_shapes[source].append(ptrcls)

    if (view_rptr is not None and view_rptr.derived_ptrcls is not None and
            view_scls is not stype):
        ctx.env.schema = view_scls.set_field_value(
            ctx.env.schema, 'rptr', view_rptr.derived_ptrcls)

    return view_scls