Пример #1
0
def tuple_indirection_set(
        path_tip: irast.Set, *,
        source: s_sources.Source,
        ptr_name: typing.Tuple[str, str],
        source_context: parsing.ParserContext,
        ctx: context.ContextLevel) -> irast.Set:

    if ptr_name[0] is not None:
        el_name = '::'.join(ptr_name)
    else:
        el_name = ptr_name[1]

    if el_name in source.element_types:
        path_id = irutils.tuple_indirection_path_id(
            path_tip.path_id, el_name,
            source.element_types[el_name])
        expr = irast.TupleIndirection(
            expr=path_tip, name=el_name, path_id=path_id,
            context=source_context)
    else:
        raise errors.EdgeQLReferenceError(
            f'{el_name} is not a member of a tuple',
            context=source_context)

    return generated_set(expr, ctx=ctx)
Пример #2
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)
Пример #3
0
def tuple_indirection_set(path_tip: irast.Set, *, source: s_sources.Source,
                          ptr_name: str, source_context: parsing.ParserContext,
                          ctx: context.ContextLevel) -> irast.Set:

    el_name = ptr_name
    el_norm_name = source.normalize_index(ctx.env.schema, el_name)
    el_type = source.get_subtype(ctx.env.schema, el_name)

    path_id = irutils.tuple_indirection_path_id(path_tip.path_id,
                                                el_norm_name,
                                                el_type,
                                                schema=ctx.env.schema)
    expr = irast.TupleIndirection(expr=path_tip,
                                  name=el_norm_name,
                                  path_id=path_id,
                                  context=source_context)

    return generated_set(expr, ctx=ctx)
Пример #4
0
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)