def get_param_anchors_for_callable( params: s_func.ParameterLikeList, schema: s_schema.Schema, *, inlined_defaults: bool, ) -> Tuple[Dict[str, irast.Parameter], List[qlast.AliasedExpr], ]: anchors = {} aliases = [] if inlined_defaults: anchors['__defaults_mask__'] = irast.Parameter( name='__defaults_mask__', typeref=irtyputils.type_to_typeref( # note: no cache schema, cast(s_scalars.ScalarType, schema.get('std::bytes')), ), ) pg_params = s_func.PgParams.from_params(schema, params) for pi, p in enumerate(pg_params.params): p_shortname = p.get_shortname(schema) anchors[p_shortname] = irast.Parameter( name=p_shortname, typeref=irtyputils.type_to_typeref(schema, p.get_type(schema))) if p.get_default(schema) is None: continue if not inlined_defaults: continue aliases.append( qlast.AliasedExpr( alias=p_shortname, expr=qlast. IfElse(condition=qlast.BinOp(left=qlast.FunctionCall( func=('std', 'bytes_get_bit'), args=[ qlast.Path( steps=[qlast.ObjectRef(name='__defaults_mask__')]), qlast.IntegerConstant(value=str(pi)), ]), right=qlast.IntegerConstant( value='0'), op='='), if_expr=qlast.Path( steps=[qlast.ObjectRef(name=p_shortname)]), else_expr=qlast._Optional( expr=p.get_ql_default(schema))))) return anchors, aliases
def get_param_anchors_for_callable(params, schema): anchors = {} aliases = [] anchors['__defaults_mask__'] = irast.Parameter( name='__defaults_mask__', typeref=irtyputils.type_to_typeref(schema, schema.get('std::bytes'))) pg_params = s_func.PgParams.from_params(schema, params) for pi, p in enumerate(pg_params.params): p_shortname = p.get_shortname(schema) anchors[p_shortname] = irast.Parameter( name=p_shortname, typeref=irtyputils.type_to_typeref(schema, p.get_type(schema))) if p.get_default(schema) is None: continue aliases.append( qlast.AliasedExpr( alias=p_shortname, expr=qlast. IfElse(condition=qlast.BinOp(left=qlast.FunctionCall( func=('std', 'bytes_get_bit'), args=[ qlast.Path( steps=[qlast.ObjectRef(name='__defaults_mask__')]), qlast.IntegerConstant(value=str(pi)), ]), right=qlast.IntegerConstant( value='0'), op='='), if_expr=qlast.Path( steps=[qlast.ObjectRef(name=p_shortname)]), else_expr=qlast._Optional( expr=p.get_ql_default(schema))))) return anchors, aliases
def compile_TypeCast(expr: qlast.TypeCast, *, ctx: context.ContextLevel) -> irast.Set: target_typeref = typegen.ql_typeexpr_to_ir_typeref(expr.type, ctx=ctx) ir_expr: irast.Base if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements and irtyputils.is_array(target_typeref)): ir_expr = irast.Array() elif isinstance(expr.expr, qlast.Parameter): pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) if ((pt.is_tuple(ctx.env.schema) or pt.is_anytuple(ctx.env.schema)) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass tuples as query parameters', context=expr.expr.context, ) if (isinstance(pt, s_types.Collection) and pt.contains_array_of_tuples(ctx.env.schema) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass collections with tuple elements' ' as query parameters', context=expr.expr.context, ) param_name = expr.expr.name if expr.cardinality_mod: if expr.cardinality_mod == qlast.CardinalityModifier.Optional: required = False elif expr.cardinality_mod == qlast.CardinalityModifier.Required: required = True else: raise NotImplementedError( f"cardinality modifier {expr.cardinality_mod}") else: required = True if ctx.env.options.json_parameters: if param_name.isdecimal(): raise errors.QueryError( 'queries compiled to accept JSON parameters do not ' 'accept positional parameters', context=expr.expr.context) typeref = typegen.type_to_typeref( ctx.env.get_track_schema_type('std::json'), env=ctx.env, ) param = casts.compile_cast( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), pt, srcctx=expr.expr.context, ctx=ctx, ) else: typeref = typegen.type_to_typeref(pt, env=ctx.env) param = setgen.ensure_set( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), ctx=ctx, ) if param_name not in ctx.env.query_parameters: if ctx.env.query_parameters: first_key: str = next(iter(ctx.env.query_parameters)) if first_key.isdecimal(): if not param_name.isdecimal(): raise errors.QueryError( f'cannot combine positional and named parameters ' f'in the same query', context=expr.expr.context) else: if param_name.isdecimal(): raise errors.QueryError(f'expected a named argument', context=expr.expr.context) ctx.env.query_parameters[param_name] = irast.Param( name=param_name, required=required, schema_type=pt, ir_type=typeref, ) else: param_first_type = ctx.env.query_parameters[param_name].schema_type if not param_first_type.explicitly_castable_to(pt, ctx.env.schema): raise errors.QueryError( f'cannot cast ' f'{param_first_type.get_displayname(ctx.env.schema)} to ' f'{pt.get_displayname(ctx.env.schema)}', context=expr.expr.context) return param else: with ctx.new() as subctx: # We use "exposed" mode in case this is a type of a cast # that wants view shapes, e.g. a std::json cast. We do # this wholesale to support tuple and array casts without # having to analyze the target type (which is cumbersome # in QL AST). subctx.expr_exposed = True ir_expr = dispatch.compile(expr.expr, ctx=subctx) new_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) return casts.compile_cast(ir_expr, new_stype, cardinality_mod=expr.cardinality_mod, ctx=ctx, srcctx=expr.expr.context)
def compile_func_to_ir(func, schema, *, anchors=None, security_context=None, modaliases=None, implicit_id_in_shapes=False, implicit_tid_in_shapes=False): """Compile an EdgeQL function into EdgeDB IR.""" if debug.flags.edgeql_compile: debug.header('EdgeQL Function') debug.print(func.get_code(schema)) trees = ql_parser.parse_block(func.get_code(schema) + ';') if len(trees) != 1: raise errors.InvalidFunctionDefinitionError( 'functions can only contain one statement') tree = trees[0] if modaliases: ql_parser.append_module_aliases(tree, modaliases) if anchors is None: anchors = {} anchors['__defaults_mask__'] = irast.Parameter( name='__defaults_mask__', typeref=irtyputils.type_to_typeref(schema, schema.get('std::bytes'))) func_params = func.get_params(schema) pg_params = s_func.PgParams.from_params(schema, func_params) for pi, p in enumerate(pg_params.params): p_shortname = p.get_shortname(schema) anchors[p_shortname] = irast.Parameter( name=p_shortname, typeref=irtyputils.type_to_typeref(schema, p.get_type(schema))) if p.get_default(schema) is None: continue tree.aliases.append( qlast.AliasedExpr( alias=p_shortname, expr=qlast.IfElse( condition=qlast.BinOp( left=qlast.FunctionCall( func=('std', 'bytes_get_bit'), args=[ qlast.FuncArg( arg=qlast.Path(steps=[ qlast.ObjectRef( name='__defaults_mask__') ])), qlast.FuncArg( arg=qlast.IntegerConstant(value=str(pi))) ]), right=qlast.IntegerConstant(value='0'), op='='), if_expr=qlast.Path( steps=[qlast.ObjectRef(name=p_shortname)]), else_expr=qlast._Optional(expr=p.get_ql_default(schema))))) ir = compile_ast_to_ir( tree, schema, anchors=anchors, func=func, security_context=security_context, modaliases=modaliases, implicit_id_in_shapes=implicit_id_in_shapes, implicit_tid_in_shapes=implicit_tid_in_shapes) return ir
def compile_TypeCast(expr: qlast.TypeCast, *, ctx: context.ContextLevel) -> irast.Set: target_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) target_typeref = typegen.type_to_typeref(target_stype, env=ctx.env) ir_expr: Union[irast.Set, irast.Expr] if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements and irtyputils.is_array(target_typeref)): ir_expr = irast.Array(elements=[], typeref=target_typeref) elif isinstance(expr.expr, qlast.Parameter): pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) if ((pt.is_tuple(ctx.env.schema) or pt.is_anytuple(ctx.env.schema)) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass tuples as query parameters', context=expr.expr.context, ) if (isinstance(pt, s_types.Collection) and pt.contains_array_of_tuples(ctx.env.schema) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass collections with tuple elements' ' as query parameters', context=expr.expr.context, ) param_name = expr.expr.name if expr.cardinality_mod: if expr.cardinality_mod == qlast.CardinalityModifier.Optional: required = False elif expr.cardinality_mod == qlast.CardinalityModifier.Required: required = True else: raise NotImplementedError( f"cardinality modifier {expr.cardinality_mod}") else: required = True if ctx.env.options.json_parameters: if param_name.isdecimal(): raise errors.QueryError( 'queries compiled to accept JSON parameters do not ' 'accept positional parameters', context=expr.expr.context) typeref = typegen.type_to_typeref( ctx.env.get_track_schema_type(sn.QualName('std', 'json')), env=ctx.env, ) param = casts.compile_cast( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), pt, srcctx=expr.expr.context, ctx=ctx, ) else: typeref = typegen.type_to_typeref(pt, env=ctx.env) param = setgen.ensure_set( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), ctx=ctx, ) if param_name not in ctx.env.query_parameters: if ctx.env.query_parameters: first_key: str = next(iter(ctx.env.query_parameters)) if first_key.isdecimal(): if not param_name.isdecimal(): raise errors.QueryError( f'cannot combine positional and named parameters ' f'in the same query', context=expr.expr.context) else: if param_name.isdecimal(): raise errors.QueryError(f'expected a named argument', context=expr.expr.context) ctx.env.query_parameters[param_name] = irast.Param( name=param_name, required=required, schema_type=pt, ir_type=typeref, ) else: param_first_type = ctx.env.query_parameters[param_name].schema_type if not param_first_type.castable_to(pt, ctx.env.schema): raise errors.QueryError( f'cannot cast ' f'{param_first_type.get_displayname(ctx.env.schema)} to ' f'{pt.get_displayname(ctx.env.schema)}', context=expr.expr.context) return param else: with ctx.new() as subctx: if target_stype.contains_json(subctx.env.schema): # JSON wants type shapes and acts as an output sink. subctx.expr_exposed = True subctx.inhibit_implicit_limit = True subctx.implicit_id_in_shapes = False subctx.implicit_tid_in_shapes = False subctx.implicit_tname_in_shapes = False ir_expr = dispatch.compile(expr.expr, ctx=subctx) return casts.compile_cast(ir_expr, target_stype, cardinality_mod=expr.cardinality_mod, ctx=ctx, srcctx=expr.expr.context)
def compile_TypeCast(expr: qlast.TypeCast, *, ctx: context.ContextLevel) -> irast.Set: target_typeref = typegen.ql_typeexpr_to_ir_typeref(expr.type, ctx=ctx) ir_expr: irast.Base if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements and irtyputils.is_array(target_typeref)): ir_expr = irast.Array() elif isinstance(expr.expr, qlast.Parameter): pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) param_name = expr.expr.name if param_name not in ctx.env.query_parameters: if ctx.env.query_parameters: first_key: str = next(iter(ctx.env.query_parameters)) if first_key.isdecimal(): if not param_name.isdecimal(): raise errors.QueryError( f'cannot combine positional and named parameters ' f'in the same query', context=expr.expr.context) else: if param_name.isdecimal(): raise errors.QueryError(f'expected a named argument', context=expr.expr.context) ctx.env.query_parameters[param_name] = pt else: param_first_type = ctx.env.query_parameters[param_name] if not param_first_type.explicitly_castable_to(pt, ctx.env.schema): raise errors.QueryError( f'cannot cast ' f'{param_first_type.get_displayname(ctx.env.schema)} to ' f'{pt.get_displayname(ctx.env.schema)}', context=expr.expr.context) if ctx.env.json_parameters: if param_name.isdecimal(): raise errors.QueryError( 'queries compiled to accept JSON parameters do not ' 'accept positional parameters', context=expr.expr.context) json_typeref = irtyputils.type_to_typeref( ctx.env.schema, ctx.env.get_track_schema_type('std::json')) param = cast.compile_cast( irast.Parameter( typeref=json_typeref, name=param_name, context=expr.expr.context, ), pt, srcctx=expr.expr.context, ctx=ctx, ) else: param = setgen.ensure_set( irast.Parameter( typeref=irtyputils.type_to_typeref(ctx.env.schema, pt), name=param_name, context=expr.expr.context, ), ctx=ctx, ) return param else: with ctx.new() as subctx: # We use "exposed" mode in case this is a type of a cast # that wants view shapes, e.g. a std::json cast. We do # this wholesale to support tuple and array casts without # having to analyze the target type (which is cumbersome # in QL AST). subctx.expr_exposed = True ir_expr = dispatch.compile(expr.expr, ctx=subctx) new_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) return cast.compile_cast(ir_expr, new_stype, ctx=ctx, srcctx=expr.expr.context)