Пример #1
0
    async def compile_graphql(
        self,
        dbver: bytes,
        gql: str,
        tokens: Optional[List[Tuple[gql_lexer.TokenKind, int, int, int, int,
                                    str]]],
        substitutions: Optional[Dict[str, Tuple[str, int, int]]],
        operation_name: str = None,
        variables: Optional[Mapping[str, object]] = None,
    ) -> CompiledOperation:

        db = await self._get_database(dbver)

        if tokens is None:
            ast = graphql.parse_text(gql)
        else:
            ast = graphql.parse_tokens(gql, tokens)
        op = graphql.translate_ast(
            db.gqlcore,  # type: ignore[attr-defined]
            ast,
            variables=variables,
            substitutions=substitutions,
            operation_name=operation_name)

        ir = qlcompiler.compile_ast_to_ir(
            op.edgeql_ast,
            schema=db.schema,
            options=qlcompiler.CompilerOptions(
                json_parameters=True,
                allow_top_level_shape_dml=True,
            ),
        )

        if ir.cardinality.is_multi():
            raise errors.ResultCardinalityMismatchError(
                f'compiled GrqphQL query has cardinality {ir.cardinality}, '
                f'expected ONE')

        sql_text, argmap = pg_compiler.compile_ir_to_sql(
            ir,
            pretty=bool(debug.flags.edgeql_compile),
            expected_cardinality_one=True,
            output_format=pg_compiler.OutputFormat.JSON)

        args: List[Optional[str]] = [None] * len(argmap)
        for argname, param in argmap.items():
            args[param.index - 1] = argname

        sql_bytes = sql_text.encode()
        sql_hash = self._hash_sql(sql_bytes)

        return CompiledOperation(
            sql=sql_bytes,
            sql_hash=sql_hash,
            sql_args=args,  # type: ignore[arg-type]  # XXX: optional bug?
            dbver=dbver,
            cacheable=op.cacheable,
            cache_deps_vars=op.cache_deps_vars,
            variables=op.variables_desc,
        )
Пример #2
0
    def compile_expr_field(
        self,
        schema: s_schema.Schema,
        context: sd.CommandContext,
        field: so.Field[Any],
        value: s_expr.Expression,
        track_schema_ref_exprs: bool = False,
    ) -> s_expr.Expression:
        from . import objtypes as s_objtypes

        singletons: List[s_types.Type]
        if field.name == 'expr':
            # type ignore below, for the class is used as mixin
            parent_ctx = context.get_ancestor(
                IndexSourceCommandContext,  # type: ignore
                self)
            assert parent_ctx is not None
            assert isinstance(parent_ctx.op, sd.ObjectCommand)
            subject = parent_ctx.op.get_object(schema, context)

            if isinstance(subject, s_abc.Pointer):
                singletons = []
                path_prefix_anchor = None
            else:
                assert isinstance(subject, s_objtypes.ObjectType)
                singletons = [subject]
                path_prefix_anchor = qlast.Subject().name

            expr = type(value).compiled(
                value,
                schema=schema,
                options=qlcompiler.CompilerOptions(
                    modaliases=context.modaliases,
                    schema_object_context=self.get_schema_metaclass(),
                    anchors={qlast.Subject().name: subject},
                    path_prefix_anchor=path_prefix_anchor,
                    singletons=frozenset(singletons),
                    apply_query_rewrites=not context.stdmode,
                    track_schema_ref_exprs=track_schema_ref_exprs,
                ),
            )

            # Check that the inferred cardinality is no more than 1
            from edb.ir import ast as ir_ast
            assert isinstance(expr.irast, ir_ast.Statement)
            if expr.irast.cardinality.is_multi():
                raise errors.ResultCardinalityMismatchError(
                    f'possibly more than one element returned by '
                    f'the index expression where only singletons '
                    f'are allowed')

            return expr
        else:
            return super().compile_expr_field(schema, context, field, value,
                                              track_schema_ref_exprs)
Пример #3
0
    async def compile_graphql(
            self,
            dbver: int,
            gql: str,
            operation_name: str=None,
            variables: Optional[Mapping[str, object]]=None):

        db = await self._get_database(dbver)

        op = graphql.translate(
            db.gqlcore,
            gql,
            variables=variables,
            operation_name=operation_name)

        ir = ql_compiler.compile_ast_to_ir(
            op.edgeql_ast,
            schema=db.schema,
            json_parameters=True)

        if ir.cardinality is not qltypes.Cardinality.ONE:
            raise errors.ResultCardinalityMismatchError(
                f'compiled GrqphQL query has cardinality {ir.cardinality}, '
                f'expected ONE')

        sql_text, argmap = pg_compiler.compile_ir_to_sql(
            ir,
            pretty=debug.flags.edgeql_compile,
            expected_cardinality_one=True,
            output_format=pg_compiler.OutputFormat.JSON)

        args = [None] * len(argmap)
        for argname, argpos in argmap.items():
            args[argpos - 1] = argname

        sql_bytes = sql_text.encode()
        sql_hash = self._hash_sql(sql_bytes)

        return CompiledOperation(
            sql=sql_bytes,
            sql_hash=sql_hash,
            sql_args=args,
            dbver=dbver,
            cacheable=op.cacheable,
            cache_deps_vars=op.cache_deps_vars,
            variables=op.variables_desc,
        )
Пример #4
0
def compile_graphql(
    std_schema: s_schema.FlatSchema,
    user_schema: s_schema.FlatSchema,
    global_schema: s_schema.FlatSchema,
    database_config: Mapping[str, Any],
    system_config: Mapping[str, Any],
    gql: str,
    tokens: Optional[List[Tuple[gql_lexer.TokenKind, int, int, int, int,
                                str]]],
    substitutions: Optional[Dict[str, Tuple[str, int, int]]],
    operation_name: str = None,
    variables: Optional[Mapping[str, object]] = None,
) -> CompiledOperation:
    if tokens is None:
        ast = graphql.parse_text(gql)
    else:
        ast = graphql.parse_tokens(gql, tokens)

    gqlcore = _get_gqlcore(std_schema, user_schema, global_schema)

    op = graphql.translate_ast(gqlcore,
                               ast,
                               variables=variables,
                               substitutions=substitutions,
                               operation_name=operation_name)

    ir = qlcompiler.compile_ast_to_ir(
        op.edgeql_ast,
        schema=s_schema.ChainedSchema(
            std_schema,
            user_schema,
            global_schema,
        ),
        options=qlcompiler.CompilerOptions(
            json_parameters=True,
            allow_top_level_shape_dml=True,
        ),
    )

    if ir.cardinality.is_multi():
        raise errors.ResultCardinalityMismatchError(
            f'compiled GrqphQL query has cardinality {ir.cardinality}, '
            f'expected ONE')

    sql_text, argmap = pg_compiler.compile_ir_to_sql(
        ir,
        pretty=bool(debug.flags.edgeql_compile),
        expected_cardinality_one=True,
        output_format=pg_compiler.OutputFormat.JSON)

    args: List[Optional[str]] = [None] * len(argmap)
    for argname, param in argmap.items():
        args[param.index - 1] = argname

    sql_bytes = sql_text.encode()
    sql_hash = hashlib.sha1(sql_bytes).hexdigest().encode('latin1')

    return CompiledOperation(
        sql=sql_bytes,
        sql_hash=sql_hash,
        sql_args=args,  # type: ignore[arg-type]  # XXX: optional bug?
        cacheable=op.cacheable,
        cache_deps_vars=op.cache_deps_vars,
        variables=op.variables_desc,
    )
Пример #5
0
    def _compile_ql_query(self, ctx: CompileContext,
                          ql: qlast.Base) -> dbstate.BaseQuery:

        current_tx = ctx.state.current_tx()
        session_config = current_tx.get_session_config()

        native_out_format = (ctx.output_format is
                             pg_compiler.OutputFormat.NATIVE)

        single_stmt_mode = ctx.stmt_mode is enums.CompileStatementMode.SINGLE

        implicit_fields = (native_out_format and single_stmt_mode)

        disable_constant_folding = config.lookup(config.get_settings(),
                                                 '__internal_no_const_folding',
                                                 session_config,
                                                 allow_unrecognized=True)

        # the capability to execute transaction or session control
        # commands indicates that session mode is available
        session_mode = ctx.state.capability & (enums.Capability.TRANSACTION
                                               | enums.Capability.SESSION)
        ir = ql_compiler.compile_ast_to_ir(
            ql,
            schema=current_tx.get_schema(),
            modaliases=current_tx.get_modaliases(),
            implicit_tid_in_shapes=implicit_fields,
            implicit_id_in_shapes=implicit_fields,
            disable_constant_folding=disable_constant_folding,
            json_parameters=ctx.json_parameters,
            session_mode=session_mode)

        if ir.cardinality is qltypes.Cardinality.ONE:
            result_cardinality = enums.ResultCardinality.ONE
        else:
            result_cardinality = enums.ResultCardinality.MANY
            if ctx.expected_cardinality_one:
                raise errors.ResultCardinalityMismatchError(
                    f'the query has cardinality {result_cardinality} '
                    f'which does not match the expected cardinality ONE')

        sql_text, argmap = pg_compiler.compile_ir_to_sql(
            ir,
            pretty=debug.flags.edgeql_compile,
            expected_cardinality_one=ctx.expected_cardinality_one,
            output_format=ctx.output_format)

        sql_bytes = sql_text.encode(defines.EDGEDB_ENCODING)

        if single_stmt_mode:
            if native_out_format:
                out_type_data, out_type_id = sertypes.TypeSerializer.describe(
                    ir.schema, ir.stype, ir.view_shapes,
                    ir.view_shapes_metadata)
            else:
                out_type_data, out_type_id = \
                    sertypes.TypeSerializer.describe_json()

            in_array_backend_tids: typing.Optional[typing.Mapping[int,
                                                                  int]] = None

            if ir.params:
                array_params = []
                subtypes = [None] * len(ir.params)
                first_param_name = next(iter(ir.params))
                if first_param_name.isdecimal():
                    named = False
                    for param_name, param_type in ir.params.items():
                        idx = int(param_name)
                        subtypes[idx] = (param_name, param_type)
                        if param_type.is_array():
                            el_type = param_type.get_element_type(ir.schema)
                            array_params.append(
                                (idx, el_type.get_backend_id(ir.schema)))
                else:
                    named = True
                    for param_name, param_type in ir.params.items():
                        idx = argmap[param_name] - 1
                        subtypes[idx] = (param_name, param_type)
                        if param_type.is_array():
                            el_type = param_type.get_element_type(ir.schema)
                            array_params.append(
                                (idx, el_type.get_backend_id(ir.schema)))

                params_type = s_types.Tuple.create(
                    ir.schema,
                    element_types=collections.OrderedDict(subtypes),
                    named=named)
                if array_params:
                    in_array_backend_tids = {p[0]: p[1] for p in array_params}
            else:
                params_type = s_types.Tuple.create(ir.schema,
                                                   element_types={},
                                                   named=False)

            in_type_data, in_type_id = sertypes.TypeSerializer.describe(
                ir.schema, params_type, {}, {})

            in_type_args = None
            if ctx.json_parameters:
                in_type_args = [None] * len(argmap)
                for argname, argpos in argmap.items():
                    in_type_args[argpos - 1] = argname

            sql_hash = self._hash_sql(sql_bytes,
                                      mode=str(ctx.output_format).encode(),
                                      intype=in_type_id.bytes,
                                      outtype=out_type_id.bytes)

            return dbstate.Query(
                sql=(sql_bytes, ),
                sql_hash=sql_hash,
                cardinality=result_cardinality,
                in_type_id=in_type_id.bytes,
                in_type_data=in_type_data,
                in_type_args=in_type_args,
                in_array_backend_tids=in_array_backend_tids,
                out_type_id=out_type_id.bytes,
                out_type_data=out_type_data,
            )

        else:
            if ir.params:
                raise errors.QueryError(
                    'EdgeQL script queries cannot accept parameters')

            return dbstate.SimpleQuery(sql=(sql_bytes, ))