Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
def _inheritance_cast_to_ir(ir_set: irast.Set, orig_stype: s_types.Type,
                            new_stype: s_types.Type, *,
                            ctx: context.ContextLevel) -> irast.Set:

    orig_typeref = irutils.type_to_typeref(ctx.env.schema, orig_stype)
    new_typeref = irutils.type_to_typeref(ctx.env.schema, new_stype)
    cast_ir = irast.TypeCast(
        expr=ir_set,
        from_type=orig_typeref,
        to_type=new_typeref,
        cast_name=None,
        sql_function=None,
        sql_cast=True,
        sql_expr=False,
    )

    return setgen.ensure_set(cast_ir, ctx=ctx)
Ejemplo n.º 3
0
def _cast_to_ir(ir_set: irast.Set, cast: s_casts.Cast,
                orig_stype: s_types.Type, new_stype: s_types.Type, *,
                ctx: context.ContextLevel) -> irast.Set:

    orig_typeref = irutils.type_to_typeref(ctx.env.schema, orig_stype)
    new_typeref = irutils.type_to_typeref(ctx.env.schema, new_stype)
    cast_ir = irast.TypeCast(
        expr=ir_set,
        from_type=orig_typeref,
        to_type=new_typeref,
        cast_name=cast.get_name(ctx.env.schema),
        sql_function=cast.get_from_function(ctx.env.schema),
        sql_cast=cast.get_from_cast(ctx.env.schema),
        sql_expr=bool(cast.get_code(ctx.env.schema)),
    )

    return setgen.ensure_set(cast_ir, ctx=ctx)
Ejemplo n.º 4
0
def _cast_array_literal(ir_set: irast.Set, orig_stype: s_types.Type,
                        new_stype: s_types.Type, *,
                        srcctx: parsing.ParserContext,
                        ctx: context.ContextLevel) -> irast.Base:

    orig_typeref = irutils.type_to_typeref(ctx.env.schema, orig_stype)
    new_typeref = irutils.type_to_typeref(ctx.env.schema, new_stype)

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

    if direct_cast is None:
        if not new_stype.is_array():
            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) from None
        el_type = new_stype.get_subtypes()[0]
    else:
        el_type = new_stype

    casted_els = []
    for el in ir_set.expr.elements:
        el = compile_cast(el, el_type, ctx=ctx, srcctx=srcctx)
        casted_els.append(el)

    new_array = setgen.generated_set(irast.Array(elements=casted_els,
                                                 stype=orig_stype),
                                     ctx=ctx)

    if direct_cast is not None:
        return _cast_to_ir(new_array,
                           direct_cast,
                           orig_stype,
                           new_stype,
                           ctx=ctx)

    else:
        cast_ir = irast.TypeCast(
            expr=new_array,
            from_type=orig_typeref,
            to_type=new_typeref,
            sql_cast=True,
        )

    return setgen.ensure_set(cast_ir, ctx=ctx)
Ejemplo n.º 5
0
def new_expression_set(ir_expr,
                       path_id=None,
                       alias=None,
                       typehint: typing.Optional[irast.TypeRef] = None,
                       *,
                       ctx: context.ContextLevel) -> irast.Set:
    if isinstance(ir_expr, irast.EmptySet) and typehint is not None:
        ir_expr = irast.TypeCast(expr=ir_expr, type=typehint)

    result_type = irutils.infer_type(ir_expr, ctx.schema)

    if path_id is None:
        path_id = getattr(ir_expr, 'path_id', None)

        if not path_id:
            if alias is None:
                raise ValueError('either path_id or alias are required')
            path_id = get_expression_path_id(result_type, alias, ctx=ctx)

    return new_set(path_id=path_id, scls=result_type, expr=ir_expr, ctx=ctx)