예제 #1
0
파일: expr.py 프로젝트: mcaramma/edgedb
def _cast_expr(ql_type: qlast.TypeName, ir_expr: irast.Base, *,
               source_context: parsing.ParserContext,
               ctx: context.ContextLevel) -> irast.Base:
    try:
        orig_type = irutils.infer_type(ir_expr, ctx.schema)
    except errors.EdgeQLError:
        # It is possible that the source expression is unresolved
        # if the expr is an empty set (or a coalesce of empty sets).
        orig_type = None

    if isinstance(orig_type, s_types.Tuple):
        # For tuple-to-tuple casts we generate a new tuple
        # to simplify things on sqlgen side.
        new_type = typegen.ql_typeref_to_type(ql_type, ctx=ctx)
        if not isinstance(new_type, s_types.Tuple):
            raise errors.EdgeQLError(f'cannot cast tuple to {new_type.name}',
                                     context=source_context)

        if len(orig_type.element_types) != len(new_type.element_types):
            raise errors.EdgeQLError(
                f'cannot cast to {new_type.name}: '
                f'number of elements is not the same',
                context=source_context)

        new_names = list(new_type.element_types)

        elements = []
        for i, n in enumerate(orig_type.element_types):
            val = setgen.generated_set(irast.TupleIndirection(expr=ir_expr,
                                                              name=n),
                                       ctx=ctx)
            val.path_id = irutils.tuple_indirection_path_id(
                ir_expr.path_id, n, orig_type.element_types[n])

            val_type = irutils.infer_type(val, ctx.schema)
            new_el_name = new_names[i]
            if val_type != new_type.element_types[new_el_name]:
                # Element cast
                val = _cast_expr(ql_type.subtypes[i],
                                 val,
                                 ctx=ctx,
                                 source_context=source_context)

            elements.append(irast.TupleElement(name=new_el_name, val=val))

        return irast.Tuple(named=new_type.named, elements=elements)

    elif isinstance(ir_expr, irast.EmptySet):
        # For the common case of casting an empty set, we simply
        # generate a new EmptySet node of the requested type.
        scls = typegen.ql_typeref_to_type(ql_type, ctx=ctx)
        return irutils.new_empty_set(ctx.schema,
                                     scls=scls,
                                     alias=ir_expr.path_id.target.name.name)

    else:
        typ = typegen.ql_typeref_to_ir_typeref(ql_type, ctx=ctx)
        return setgen.ensure_set(irast.TypeCast(expr=ir_expr, type=typ),
                                 ctx=ctx)
예제 #2
0
파일: expr.py 프로젝트: mcaramma/edgedb
def compile_Tuple(expr: qlast.Base, *,
                  ctx: context.ContextLevel) -> irast.Base:
    elements = []

    for i, el in enumerate(expr.elements):
        element = irast.TupleElement(name=str(i),
                                     val=dispatch.compile(el, ctx=ctx))
        elements.append(element)

    return setgen.generated_set(irast.Tuple(elements=elements), ctx=ctx)
예제 #3
0
파일: expr.py 프로젝트: dungeon2567/edgedb
def compile_TupleElement(expr: qlast.Base, *,
                         ctx: context.ContextLevel) -> irast.Base:
    name = expr.name.name
    if expr.name.module:
        name = f'{expr.name.module}::{name}'

    val = setgen.ensure_set(dispatch.compile(expr.val, ctx=ctx), ctx=ctx)

    element = irast.TupleElement(
        name=name,
        val=val,
    )

    return element
예제 #4
0
파일: cast.py 프로젝트: dungeon2567/edgedb
def _cast_tuple(ir_set: irast.Base, orig_stype: s_types.Type,
                new_stype: s_types.Type, *, srcctx: parsing.ParserContext,
                ctx: context.ContextLevel) -> irast.Base:

    direct_cast = _find_cast(orig_stype, new_stype, srcctx=srcctx, ctx=ctx)

    if direct_cast is not None:
        # Direct casting to non-tuple involves casting each tuple
        # element and also keeping the cast around the whole tuple.
        # This is to trigger the downstream logic of casting
        # objects (in elements of the tuple).
        elements = []
        for i, n in enumerate(orig_stype.element_types):
            val = setgen.generated_set(irast.TupleIndirection(expr=ir_set,
                                                              name=n),
                                       ctx=ctx)
            val.path_id = irutils.tuple_indirection_path_id(
                ir_set.path_id,
                n,
                orig_stype.element_types[n],
                schema=ctx.env.schema)

            val_type = inference.infer_type(val, ctx.env)
            # Element cast
            val = compile_cast(val, new_stype, ctx=ctx, srcctx=srcctx)

            elements.append(irast.TupleElement(name=n, val=val))

        new_tuple = setgen.ensure_set(astutils.make_tuple(
            elements, named=orig_stype.named, ctx=ctx),
                                      ctx=ctx)

        return _cast_to_ir(new_tuple,
                           direct_cast,
                           orig_stype,
                           new_stype,
                           ctx=ctx)

    if not new_stype.is_tuple():
        raise errors.QueryError(
            f'cannot cast {orig_stype.get_displayname(ctx.env.schema)!r} '
            f'to {new_stype.get_displayname(ctx.env.schema)!r}',
            context=srcctx)

    if len(orig_stype.element_types) != len(new_stype.element_types):
        raise errors.QueryError(
            f'cannot cast {orig_stype.get_displayname(ctx.env.schema)!r} '
            f'to {new_stype.get_displayname(ctx.env.schema)!r}: ',
            f'the number of elements is not the same',
            context=srcctx)

    # For tuple-to-tuple casts we generate a new tuple
    # to simplify things on sqlgen side.
    new_names = list(new_stype.element_types)

    elements = []
    for i, n in enumerate(orig_stype.element_types):
        val = setgen.generated_set(irast.TupleIndirection(expr=ir_set, name=n),
                                   ctx=ctx)
        val.path_id = irutils.tuple_indirection_path_id(
            ir_set.path_id,
            n,
            orig_stype.element_types[n],
            schema=ctx.env.schema)

        val_type = inference.infer_type(val, ctx.env)
        new_el_name = new_names[i]
        new_subtypes = list(new_stype.get_subtypes())
        if val_type != new_stype.element_types[new_el_name]:
            # Element cast
            val = compile_cast(val, new_subtypes[i], ctx=ctx, srcctx=srcctx)

        elements.append(irast.TupleElement(name=new_el_name, val=val))

    return setgen.ensure_set(astutils.make_tuple(named=new_stype.named,
                                                 elements=elements,
                                                 ctx=ctx),
                             ctx=ctx)