Esempio n. 1
0
    def _create_begin(self, schema, context):
        from edb.edgeql import parser as edgeql_parser
        from edb.edgeql import utils as edgeql_utils

        parent_ctx = context.get(sd.CommandContextToken)
        subject = schema.get(parent_ctx.op.classname)

        expr = self.get_attribute_value('expr')

        if expr.qlast is not None:
            tree = expr.qlast
        else:
            tree = edgeql_parser.parse(expr.text, context.modaliases)

        _, _, qlexpr = edgeql_utils.normalize_tree(
            tree,
            schema,
            modaliases=context.modaliases,
            anchors={qlast.Subject: subject},
            inline_anchors=True,
        )

        self.set_attribute_value('expr', s_expr.Expression(text=qlexpr))

        return sd.CreateObject._create_begin(
            self, schema, context)
    def _parse_subject_indexes(self, subject, subjdecl):
        module_aliases = {None: subject.get_name(self._schema).module}

        for indexdecl in subjdecl.indexes:
            index_name = self._get_ref_name(indexdecl.name)
            index_name = subject.get_name(self._schema) + '.' + index_name
            local_name = s_name.get_specialized_name(
                index_name, subject.get_name(self._schema))

            der_name = s_name.Name(name=local_name,
                                   module=subject.get_name(
                                       self._schema).module)

            _, _, index_expr = qlutils.normalize_tree(
                indexdecl.expression,
                self._schema,
                modaliases=module_aliases,
                anchors={qlast.Subject: subject},
                inline_anchors=True)

            self._schema, index = s_indexes.Index.create_in_schema(
                self._schema,
                name=der_name,
                expr=s_expr.Expression(text=index_expr),
                subject=subject)

            self._schema = subject.add_index(self._schema, index)
Esempio n. 3
0
    def _parse_computable(self, expr, schema, context) -> so.ObjectRef:
        from edb.edgeql import utils as ql_utils
        from . import sources as s_sources

        # "source" attribute is set automatically as a refdict back-attr
        parent_ctx = context.get(s_sources.SourceCommandContext)
        source_name = parent_ctx.op.classname

        source = schema.get(source_name, default=None)
        if source is None:
            raise errors.SchemaDefinitionError(
                f'cannot define link/property computables in CREATE TYPE',
                hint='Perform a CREATE TYPE without the link '
                     'followed by ALTER TYPE defining the computable',
                context=expr.context
            )

        ir, _, target_expr = ql_utils.normalize_tree(
            expr, schema,
            anchors={qlast.Source: source},
            path_prefix_anchor=qlast.Source,
            singletons=[source],
            modaliases=context.modaliases)

        target = utils.reduce_to_typeref(schema, ir.stype)

        self.add(
            sd.AlterObjectProperty(
                property='default',
                new_value=s_expr.Expression(text=target_expr)
            )
        )

        self.add(
            sd.AlterObjectProperty(
                property='computable',
                new_value=True
            )
        )

        self.add(
            sd.AlterObjectProperty(
                property='cardinality',
                new_value=ir.cardinality
            )
        )

        return target
Esempio n. 4
0
    def _normalize_constraint_expr(cls,
                                   schema,
                                   module_aliases,
                                   expr,
                                   subject,
                                   *,
                                   inline_anchors=False):
        from edb.edgeql import parser as edgeql_parser
        from edb.edgeql import utils as edgeql_utils

        if isinstance(expr, str):
            tree = edgeql_parser.parse(expr, module_aliases)
        else:
            tree = expr

        ir, edgeql_tree, _ = edgeql_utils.normalize_tree(
            tree,
            schema,
            modaliases=module_aliases,
            anchors={qlast.Subject: subject},
            inline_anchors=inline_anchors)

        return edgeql_tree.result, ir
Esempio n. 5
0
    def _assert_normalize_expr(self,
                               text,
                               expected,
                               expected_const_type=None,
                               *,
                               anchors=None,
                               inline_anchors=False):
        edgeql_tree = eql_parser.parse(text)
        schema = self.__class__.schema
        ir, _, normalized = eql_utils.normalize_tree(
            edgeql_tree,
            schema,
            anchors=anchors,
            inline_anchors=inline_anchors)

        self.assertEqual(
            textwrap.dedent(normalized).strip(),
            textwrap.dedent(expected).strip())

        if expected_const_type is not None:
            self.assertEqual(
                schema.get_by_id(ir.expr.typeref.id).get_displayname(schema),
                expected_const_type)
    def _normalize_objtype_expressions(self, objtype, typedecl):
        """Interpret and validate EdgeQL expressions in type declaration."""
        for ptrdecl in itertools.chain(typedecl.links, typedecl.properties):
            link_name = ptrdecl.name
            spec_link = objtype.getptr(self._schema, link_name)

            if ptrdecl.expr is not None:
                # Computable
                self._normalize_ptr_default(ptrdecl.expr, objtype, spec_link,
                                            ptrdecl)

            for attr in ptrdecl.fields:
                name = attr.name.name
                if name == 'default':
                    if isinstance(attr.value, edgeql.ast.SelectQuery):
                        self._normalize_ptr_default(attr.value, objtype,
                                                    spec_link, ptrdecl)
                    else:
                        expr = attr.value
                        _, _, default = qlutils.normalize_tree(
                            expr, self._schema)
                        self._schema = spec_link.set_field_value(
                            self._schema, 'default',
                            s_expr.Expression(text=default))
    def _normalize_ptr_default(self, expr, source, ptr, ptrdecl):
        module_aliases = {None: source.get_name(self._schema).module}

        ir, _, expr_text = qlutils.normalize_tree(
            expr,
            self._schema,
            modaliases=module_aliases,
            anchors={qlast.Source: source},
            path_prefix_anchor=qlast.Source,
            singletons=[source])

        expr_type = ir.stype

        self._schema = ptr.set_field_value(self._schema, 'default',
                                           s_expr.Expression(text=expr_text))

        if ptr.is_pure_computable(self._schema):
            # Pure computable without explicit target.
            # Fixup pointer target and target property.
            self._schema = ptr.set_field_value(self._schema, 'target',
                                               expr_type)

            if isinstance(ptr, s_links.Link):
                if not isinstance(expr_type, s_objtypes.ObjectType):
                    raise errors.InvalidLinkTargetError(
                        f'invalid link target, expected object type, got '
                        f'{expr_type.__class__.__name__}',
                        context=ptrdecl.expr.context)
            else:
                if not isinstance(expr_type,
                                  (s_scalars.ScalarType, s_types.Collection)):
                    raise errors.InvalidPropertyTargetError(
                        f'invalid property type: expected primitive type, '
                        f'got {expr_type.__class__.__name__}',
                        context=ptrdecl.expr.context)

            if isinstance(ptr, s_links.Link):
                tgt_prop = ptr.getptr(self._schema, 'target')
                self._schema = tgt_prop.set_field_value(
                    self._schema, 'target', expr_type)

            self._schema = ptr.set_field_value(self._schema, 'cardinality',
                                               ir.cardinality)

            if ptrdecl.cardinality is not ptr.get_cardinality(self._schema):
                if ptrdecl.cardinality is qltypes.Cardinality.ONE:
                    raise errors.SchemaError(
                        f'computable expression possibly returns more than '
                        f'one value, but the '
                        f'{ptr.get_schema_class_displayname()} '
                        f'is declared as "single"',
                        context=expr.context)

        if (not isinstance(expr_type, s_abc.Type)
                or (ptr.get_target(self._schema) is not None
                    and not expr_type.issubclass(
                        self._schema, ptr.get_target(self._schema)))):
            raise errors.SchemaError(
                'default value query must yield a single result of '
                'type {!r}'.format(
                    ptr.get_target(self._schema).get_name(self._schema)),
                context=expr.context)