Пример #1
0
    def _float_to_path(self, token, context):
        from edgedb.lang.schema import pointers as s_pointers

        # make sure that the float is of the type 0.1
        parts = token.val.split('.')
        if not (len(parts) == 2 and parts[0].isdigit() and parts[1].isdigit()):
            raise EdgeQLSyntaxError(f"Unexpected {token.val!r}",
                                    context=token.context)

        # context for the AST is established manually here
        return [
            qlast.Ptr(
                ptr=qlast.ObjectRef(
                    name=parts[0],
                    context=token.context,
                ),
                direction=s_pointers.PointerDirection.Outbound,
                context=context,
            ),
            qlast.Ptr(
                ptr=qlast.ObjectRef(
                    name=parts[1],
                    context=token.context,
                ),
                direction=s_pointers.PointerDirection.Outbound,
                context=token.context,
            )
        ]
Пример #2
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.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
Пример #3
0
    def reduce_PathStepName(self, *kids):
        from edgedb.lang.schema import pointers as s_pointers

        self.val = qlast.Path(steps=[
            qlast.Ptr(ptr=kids[0].val,
                      direction=s_pointers.PointerDirection.Outbound)
        ])
Пример #4
0
    def get_path_prefix(self, end_trim=None):
        # flatten the path
        path = [step for psteps in self._context.path for step in psteps]

        # find the first shadowed root
        for i, step in enumerate(path):
            base = step.type
            if base.shadow:
                break

        # trim the rest of the path
        path = path[i + 1:end_trim]
        prefix = [qlast.ObjectRef(module=base.module, name=base.short_name)]
        prefix.extend(
            qlast.Ptr(ptr=qlast.ObjectRef(name=step.name)) for step in path)
        return prefix
Пример #5
0
    def _prepare_field(self, node):
        path = self._context.path[-1]
        include_base = self._context.include_base[-1]

        is_top = self._is_top_level_field(node)

        spath = self._context.path[-1]
        prevt, target = self._get_parent_and_current_type()

        # insert normal or specialized link
        steps = []
        if include_base:
            base = spath[0].type
            steps.append(
                qlast.ObjectRef(module=base.module, name=base.short_name))
        steps.append(qlast.Ptr(ptr=qlast.ObjectRef(name=node.name)))

        return is_top, path, prevt, target, steps
Пример #6
0
    def visit_Argument(self, node, *, get_path_prefix):
        op = ast.ops.EQ
        name_parts = node.name

        _, target = self._get_parent_and_current_type()

        name = get_path_prefix()
        name.append(qlast.Ptr(ptr=qlast.ObjectRef(name=name_parts)))
        name = qlast.Path(steps=name)

        value = self.visit(node.value)

        # potentially need to cast the 'name' side into a <str>, so as
        # to be compatible with the 'value'
        typename = target.get_field_type(name_parts).short_name
        if (typename != 'str' and gt.EDB_TO_GQL_SCALARS_MAP[typename]
                in {GraphQLString, GraphQLID}):
            name = qlast.TypeCast(
                expr=name,
                type=qlast.TypeName(maintype=qlast.ObjectRef(name='str')),
            )

        return qlast.BinOp(left=name, op=op, right=value)
Пример #7
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:
                    filterable.where = self._visit_path_where(node.arguments)

        path.pop()
        return spec
Пример #8
0
    def reduce_AT_ShortNodeName(self, *kids):
        from edgedb.lang.schema import pointers as s_pointers

        self.val = qlast.Ptr(ptr=kids[1].val,
                             direction=s_pointers.PointerDirection.Outbound,
                             type='property')
Пример #9
0
    def reduce_DOTBW_PathStepName(self, *kids):
        from edgedb.lang.schema import pointers as s_pointers

        self.val = qlast.Ptr(ptr=kids[1].val,
                             direction=s_pointers.PointerDirection.Inbound)
Пример #10
0
    def reduce_DOT_ICONST(self, *kids):
        # this is a valid link-like syntax for accessing unnamed tuples
        from edgedb.lang.schema import pointers as s_pointers

        self.val = qlast.Ptr(ptr=qlast.ObjectRef(name=kids[1].val),
                             direction=s_pointers.PointerDirection.Outbound)
Пример #11
0
 def reduce_AT_ShortNodeName(self, *kids):
     self.val = qlast.Path(
         steps=[qlast.Ptr(ptr=kids[1].val, type='property')])
Пример #12
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:
            scopectx.singletons = ctx.singletons.copy()
            scopectx.singletons.add(path_id)
            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 = schemactx.derive_view(view_rptr.ptrcls,
                                               view_rptr.source,
                                               view_scls,
                                               is_insert=view_rptr.is_insert,
                                               is_update=view_rptr.is_update,
                                               ctx=ctx)
                view_rptr.derived_ptrcls = source

            ctx.class_shapes[source].append(ptrcls)

    return view_scls