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, )
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)
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, )
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, )
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, ))