示例#1
0
文件: typegen.py 项目: virajs/edgedb
def type_to_ql_typeref(t: s_obj.Object) -> qlast.TypeName:
    if not isinstance(t, s_types.Collection):
        result = qlast.TypeName(
            maintype=qlast.ObjectRef(module=t.name.module, name=t.name.name))
    else:
        result = qlast.TypeName(
            maintype=qlast.ObjectRef(name=t.schema_name),
            subtypes=[type_to_ql_typeref(st) for st in t.get_subtypes()])

    return result
示例#2
0
文件: utils.py 项目: virajs/edgedb
def typeref_to_ast(t: so.Object) -> ql_ast.TypeName:
    if not isinstance(t, s_types.Collection):
        if isinstance(t, so.ObjectRef):
            name = t.classname
        else:
            name = t.name

        result = ql_ast.TypeName(
            maintype=ql_ast.ObjectRef(module=name.module, name=name.name))
    else:
        result = ql_ast.TypeName(
            maintype=ql_ast.ObjectRef(name=t.schema_name),
            subtypes=[typeref_to_ast(st) for st in t.get_subtypes()])

    return result
示例#3
0
    def visit_TypeCast(self, node):
        if node.type.subtypes:
            typ = qlast.TypeName(
                maintype=qlast.ObjectRef(name=node.type.maintype),
                subtypes=[
                    qlast.ObjectRef(module=stn.module, name=stn.name)
                    for stn in node.type.subtypes
                ])
        else:
            mtn = node.type.maintype
            mt = qlast.ObjectRef(module=mtn.module, name=mtn.name)
            typ = qlast.TypeName(maintype=mt)

        result = qlast.TypeCast(expr=self.visit(node.expr), type=typ)

        return result
示例#4
0
    def _apply_field_ast(self, context, node, op):
        if op.property == 'type':
            tp = op.new_value
            if isinstance(tp, s_types.Collection):
                maintype = tp.schema_name
                stt = tp.get_subtypes()

                for st in stt:
                    eltype = qlast.ObjectRef(module=st.module, name=st.name)
                tnn = qlast.TypeName(maintype=maintype, subtypes=[eltype])
            else:
                tnn = qlast.TypeName(maintype=tp)

            node.type = tnn

        else:
            super()._apply_field_ast(context, node, op)
示例#5
0
    def reduce_ARRAY_LANGBRACKET_NonArrayTypeName_OptDimensions_RANGBRACKET(
            self, *kids):
        subtype = kids[2].val
        dimensions = kids[3].val

        self.val = qlast.TypeName(
            maintype=qlast.ObjectRef(name='array'),
            subtypes=[subtype],
            dimensions=dimensions,
        )
示例#6
0
    def reduce_NodeName(self, *kids):
        maintype = kids[0].val

        # maintype cannot be 'map' or 'array'
        if maintype.module is None:
            if maintype.name in ('array', 'map'):
                raise EdgeQLSyntaxError(f"Unexpected {maintype.name!r}",
                                        context=kids[0].context)

        self.val = qlast.TypeName(maintype=maintype)
示例#7
0
    def reduce_ATTRIBUTE_ParenRawString_DeclarationSpecsBlob(self, *kids):
        eql = kids[1].parse_as_attribute_decl()
        attributes = []
        for spec in kids[2].val:
            if isinstance(spec, esast.Attribute):
                attributes.append(spec)
            else:
                raise SchemaSyntaxError('illegal definition',
                                        context=spec.context)

        self.val = esast.AttributeDeclaration(
            name=eql.name.name,
            extends=[qlast.TypeName(maintype=base) for base in eql.bases],
            type=eql.type,
            attributes=attributes)
示例#8
0
    def reduce_Expr_LBRACKET_IS_NodeName_RBRACKET(self, *kids):
        # The path filter rule is here to resolve ambiguity with
        # indexes and slices, so Expr needs to be enforced as a path.
        #
        # NOTE: We specifically disallow "Foo.(bar[IS Baz])"" because
        # it is incorrect logical grouping. The example where the
        # incorrect grouping is more obvious is: "Foo.<(bar[IS Baz])"
        path = kids[0].val

        if (isinstance(path, qlast.Path)
                and isinstance(path.steps[-1], qlast.Ptr)):
            # filtering a longer path
            path.steps[-1].target = kids[3].val
            self.val = path

        else:
            # any other expression is a path with a filter
            self.val = qlast.TypeFilter(
                expr=path, type=qlast.TypeName(maintype=kids[3].val))
示例#9
0
    def _classbases_from_ast(cls, astnode, context, schema):
        classname = cls._classname_from_ast(astnode, context, schema)

        modaliases = context.modaliases

        bases = so.ObjectList(
            utils.ast_to_typeref(
                qlast.TypeName(maintype=b),
                modaliases=modaliases, schema=schema)
            for b in getattr(astnode, 'bases', None) or []
        )

        mcls = cls.get_schema_metaclass()
        if not bases and classname not in mcls.get_root_classes():
            default_base = mcls.get_default_base_name()

            if default_base is not None and classname != default_base:
                bases = so.ObjectList([
                    so.ObjectRef(classname=default_base)
                ])

        return bases
示例#10
0
    def _cmd_tree_from_ast(cls, astnode, context, schema):
        cmd = super()._cmd_tree_from_ast(astnode, context, schema)

        if isinstance(astnode, cls.referenced_astnode):
            objcls = cls.get_schema_metaclass()

            try:
                base = utils.ast_to_typeref(
                    qlast.TypeName(maintype=astnode.name),
                    modaliases=context.modaliases,
                    schema=schema)
            except s_err.ItemNotFoundError:
                # Certain concrete items, like pointers create
                # abstract parents implicitly.
                nname = objcls.get_shortname(cmd.classname)
                base = so.ObjectRef(
                    classname=sn.Name(module=nname.module, name=nname.name))

            cmd.add(
                sd.AlterObjectProperty(property='bases',
                                       new_value=so.ObjectList([base])))

            referrer_ctx = cls.get_referrer_context(context)
            referrer_class = referrer_ctx.op.get_schema_metaclass()
            referrer_name = referrer_ctx.op.classname
            refdict = referrer_class.get_refdict_for_class(objcls)

            cmd.add(
                sd.AlterObjectProperty(
                    property=refdict.backref_attr,
                    new_value=so.ObjectRef(classname=referrer_name)))

            if getattr(astnode, 'is_abstract', None):
                cmd.add(
                    sd.AlterObjectProperty(property='is_abstract',
                                           new_value=True))

        return cmd
示例#11
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)
示例#12
0
    def _classname_from_ast(cls, astnode, context, schema):
        name = super()._classname_from_ast(astnode, context, schema)

        parent_ctx = cls.get_referrer_context(context)
        if parent_ctx is not None:
            referrer_name = parent_ctx.op.classname

            try:
                base_ref = utils.ast_to_typeref(
                    qlast.TypeName(maintype=astnode.name),
                    modaliases=context.modaliases,
                    schema=schema)
            except s_err.ItemNotFoundError:
                base_name = sn.Name(name)
            else:
                base_name = base_ref.classname

            pcls = cls.get_schema_metaclass()
            pnn = pcls.get_specialized_name(base_name, referrer_name)

            name = sn.Name(name=pnn, module=referrer_name.module)

        return name
示例#13
0
 def reduce_TUPLE_LANGBRACKET_NamedTupleTypeList_RANGBRACKET(self, *kids):
     self.val = qlast.TypeName(
         maintype=qlast.ObjectRef(name='tuple'),
         subtypes=kids[2].val,
     )
示例#14
0
 def reduce_MAP_LANGBRACKET_TypeName_COMMA_TypeName_RANGBRACKET(
         self, *kids):
     self.val = qlast.TypeName(
         maintype=qlast.ObjectRef(name='map'),
         subtypes=[kids[2].val, kids[4].val],
     )
示例#15
0
def _normalize_view_ptr_expr(
        shape_el: qlast.ShapeElement,
        view_scls: s_nodes.Node,
        *,
        path_id: irast.PathId,
        is_insert: bool = False,
        is_update: bool = False,
        view_rptr: typing.Optional[context.ViewRPtr] = None,
        ctx: context.CompilerContext) -> s_pointers.Pointer:
    steps = shape_el.expr.steps
    is_linkprop = False
    is_mutation = is_insert or is_update
    # Pointers may be qualified by the explicit source
    # class, which is equivalent to Expr[IS Type].
    is_polymorphic = len(steps) == 2
    scls = view_scls.peel_view()
    ptrsource = scls
    qlexpr = None

    if is_polymorphic:
        source = qlast.TypeFilter(expr=qlast.Path(steps=[qlast.Source()]),
                                  type=qlast.TypeName(maintype=steps[0]))
        lexpr = steps[1]
        ptrsource = schemactx.get_schema_type(steps[0], ctx=ctx)
    elif len(steps) == 1:
        lexpr = steps[0]
        is_linkprop = lexpr.type == 'property'
        if is_linkprop:
            if view_rptr is None:
                raise errors.EdgeQLError(
                    'invalid reference to link property '
                    'in top level shape',
                    context=lexpr.context)
            ptrsource = scls = view_rptr.ptrcls
        source = qlast.Source()
    else:
        raise RuntimeError(
            f'unexpected path length in view shape: {len(steps)}')

    ptrname = (lexpr.ptr.module, lexpr.ptr.name)
    ptrcls_is_derived = False

    compexpr = shape_el.compexpr
    if compexpr is None and is_insert and shape_el.elements:
        # Nested insert short form:
        #     INSERT Foo { bar: Spam { name := 'name' }}
        # Expand to:
        #     INSERT Foo { bar := (INSERT Spam { name := 'name' }) }
        if lexpr.target is not None:
            ptr_target = schemactx.get_schema_type(lexpr.target, ctx=ctx)
        else:
            ptr_target = None

        base_ptrcls = ptrcls = setgen.resolve_ptr(
            ptrsource,
            ptrname,
            s_pointers.PointerDirection.Outbound,
            target=ptr_target,
            ctx=ctx)

        compexpr = qlast.InsertQuery(subject=qlast.Path(steps=[
            qlast.ObjectRef(name=ptrcls.target.name.name,
                            module=ptrcls.target.name.module)
        ]),
                                     shape=shape_el.elements)

    if compexpr is None:
        if lexpr.target is not None:
            ptr_target = schemactx.get_schema_type(lexpr.target, ctx=ctx)
        else:
            ptr_target = None

        base_ptrcls = ptrcls = setgen.resolve_ptr(
            ptrsource,
            ptrname,
            s_pointers.PointerDirection.Outbound,
            target=ptr_target,
            ctx=ctx)

        base_ptr_is_computable = ptrcls in ctx.source_map

        if ptr_target is not None and ptr_target != base_ptrcls.target:
            # This happens when a union type target is narrowed by an
            # [IS Type] construct.  Since the derived pointer will have
            # the correct target, we don't need to do anything, but
            # remove the [IS] qualifier to prevent recursion.
            lexpr.target = None
        else:
            ptr_target = ptrcls.target

        ptr_cardinality = ptrcls.cardinality

        if shape_el.elements:
            sub_view_rptr = context.ViewRPtr(view_scls,
                                             ptrcls,
                                             is_insert=is_insert,
                                             is_update=is_update)

            sub_path_id = path_id.extend(ptrcls, target=ptrcls.target)
            ctx.path_scope.attach_path(sub_path_id)

            if is_update:
                for subel in shape_el.elements or []:
                    is_prop = (isinstance(subel.expr.steps[0], qlast.Ptr)
                               and subel.expr.steps[0].type == 'property')
                    if not is_prop:
                        raise errors.EdgeQLError(
                            'only references to link properties are allowed '
                            'in nested UPDATE shapes',
                            context=subel.context)

                ptr_target = _process_view(scls=ptr_target,
                                           path_id=sub_path_id,
                                           view_rptr=sub_view_rptr,
                                           elements=shape_el.elements,
                                           is_update=True,
                                           ctx=ctx)
            else:
                ptr_target = _process_view(scls=ptr_target,
                                           path_id=sub_path_id,
                                           view_rptr=sub_view_rptr,
                                           elements=shape_el.elements,
                                           ctx=ctx)

            ptrcls = sub_view_rptr.derived_ptrcls
            if ptrcls is None:
                ptrcls_is_derived = False
                ptrcls = sub_view_rptr.ptrcls
            else:
                ptrcls_is_derived = True

        if (shape_el.where or shape_el.orderby or shape_el.offset
                or shape_el.limit or base_ptr_is_computable or is_polymorphic):

            if qlexpr is None:
                qlexpr = qlast.Path(steps=[source, lexpr])

            qlexpr = astutils.ensure_qlstmt(qlexpr)
            qlexpr.where = shape_el.where
            qlexpr.orderby = shape_el.orderby
            qlexpr.offset = shape_el.offset
            qlexpr.limit = shape_el.limit
    else:
        try:
            base_ptrcls = ptrcls = setgen.resolve_ptr(
                ptrsource,
                ptrname,
                s_pointers.PointerDirection.Outbound,
                ctx=ctx)
        except errors.EdgeQLReferenceError:
            if is_mutation:
                raise

            ptr_module = (ptrname[0] or ctx.derived_target_module
                          or scls.name.module)

            if is_linkprop:
                ptr_metacls = s_props.Property
            else:
                ptr_metacls = s_links.Link

            ptr_name = sn.SchemaName(module=ptr_module, name=ptrname[1])
            base_ptrcls = ptrcls = ptr_metacls(name=ptr_name)

        qlexpr = astutils.ensure_qlstmt(compexpr)

        with ctx.newscope(fenced=True) as shape_expr_ctx:
            # Put current pointer class in context, so
            # that references to link properties in sub-SELECT
            # can be resolved.  This is necessary for proper
            # evaluation of link properties on computable links,
            # most importantly, in INSERT/UPDATE context.
            shape_expr_ctx.view_rptr = context.ViewRPtr(view_scls,
                                                        ptrcls,
                                                        is_insert=is_insert,
                                                        is_update=is_update)

            shape_expr_ctx.path_scope.unnest_fence = True

            if is_mutation:
                shape_expr_ctx.expr_exposed = True

            irexpr = dispatch.compile(qlexpr, ctx=shape_expr_ctx)

            irexpr.context = compexpr.context
            derived_ptrcls = shape_expr_ctx.view_rptr.derived_ptrcls
            if derived_ptrcls is not None:
                ptrcls_is_derived = True
                ptrcls = derived_ptrcls

        inferred_cardinality = pathctx.infer_cardinality(irexpr, ctx=ctx)
        if inferred_cardinality == irast.Cardinality.MANY:
            ptr_cardinality = s_pointers.PointerCardinality.ManyToMany
        else:
            ptr_cardinality = s_pointers.PointerCardinality.ManyToOne

        ptr_target = irutils.infer_type(irexpr, ctx.schema)
        if ptr_target is None:
            msg = 'cannot determine expression result type'
            raise errors.EdgeQLError(msg, context=shape_el.context)

        if is_mutation and not ptr_target.assignment_castable_to(
                base_ptrcls.target, schema=ctx.schema):
            # Validate that the insert/update expression is
            # of the correct class.
            lname = f'({ptrsource.name}).{ptrcls.shortname.name}'
            expected = [repr(str(base_ptrcls.target.name))]
            raise edgedb_error.InvalidPointerTargetError(
                f'invalid target for link {str(lname)!r}: '
                f'{str(ptr_target.name)!r} (expecting '
                f'{" or ".join(expected)})')

        if is_mutation and base_ptrcls.singular():
            pathctx.enforce_singleton(irexpr, ctx=ctx)

    if qlexpr is not None or ptr_target is not ptrcls.target:
        if not ptrcls_is_derived:
            if ptrcls.is_link_property():
                rptrcls = view_rptr.derived_ptrcls
                if rptrcls is None:
                    rptrcls = 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 = rptrcls

                src_scls = rptrcls
            else:
                src_scls = view_scls

            ptrcls = schemactx.derive_view(ptrcls,
                                           src_scls,
                                           ptr_target,
                                           is_insert=is_insert,
                                           is_update=is_update,
                                           derived_name_quals=[view_scls.name],
                                           ctx=ctx)

        if qlexpr is not None:
            ctx.source_map[ptrcls] = (qlexpr, ctx)
            ptrcls.computable = True

    if not is_mutation:
        ptrcls.cardinality = ptr_cardinality

    if ptrcls.shortname == 'std::__type__' and qlexpr is not None:
        msg = 'cannot assign to __type__'
        raise errors.EdgeQLError(msg, context=shape_el.context)

    return ptrcls
示例#16
0
 def reduce_ATTRIBUTE_ParenRawString_NL(self, *kids):
     eql = kids[1].parse_as_attribute_decl()
     self.val = esast.AttributeDeclaration(
         name=eql.name.name,
         extends=[qlast.TypeName(maintype=base) for base in eql.bases],
         type=eql.type)