示例#1
0
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
示例#2
0
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
示例#3
0
文件: expr.py 项目: yew1eb/edgedb
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
示例#5
0
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)
示例#6
0
文件: expr.py 项目: willingc/edgedb
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)