Example #1
0
def compile_TypeCast(expr: irast.TypeCast, *,
                     ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    pg_expr = dispatch.compile(expr.expr, ctx=ctx)

    if expr.sql_cast:
        # Use explicit SQL cast.

        pg_type = pg_types.pg_type_from_ir_typeref(expr.to_type)
        return pgast.TypeCast(arg=pg_expr,
                              type_name=pgast.TypeName(name=pg_type))

    elif expr.sql_function or expr.sql_expr:
        # Cast implemented as a function.

        if expr.sql_expr:
            func_name = common.get_cast_backend_name(expr.cast_name,
                                                     expr.cast_module_id,
                                                     aspect='function')
        else:
            func_name = tuple(expr.sql_function.split('.'))

        return pgast.FuncCall(
            name=func_name,
            args=[pg_expr],
        )

    else:
        raise RuntimeError('cast not supported')
Example #2
0
def compile_TypeCast(
        expr: irast.TypeCast, *,
        ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    pg_expr = dispatch.compile(expr.expr, ctx=ctx)

    if expr.sql_cast:
        # Use explicit SQL cast.

        pg_type = pg_types.pg_type_from_ir_typeref(expr.to_type)
        res: pgast.BaseExpr = pgast.TypeCast(
            arg=pg_expr,
            type_name=pgast.TypeName(
                name=pg_type
            )
        )

    elif expr.sql_function or expr.sql_expr:
        # Cast implemented as a function.

        if expr.sql_expr:
            func_name = common.get_cast_backend_name(
                expr.cast_name, expr.cast_module_id, aspect='function')
        else:
            func_name = tuple(expr.sql_function.split('.'))

        res = pgast.FuncCall(
            name=func_name,
            args=[pg_expr],
        )

    else:
        raise RuntimeError('cast not supported')

    if expr.cardinality_mod is qlast.CardinalityModifier.Required:
        res = pgast.FuncCall(
            name=('edgedb', '_raise_exception_on_null'),
            args=[
                res,
                pgast.StringConstant(
                    val='invalid_parameter_value',
                ),
                pgast.StringConstant(
                    val='invalid null value in cast',
                ),
                pgast.StringConstant(val=''),
            ]
        )

    return res
Example #3
0
def serialize_expr_to_json(expr: pgast.BaseExpr,
                           *,
                           styperef: irast.TypeRef,
                           nested: bool = False,
                           env: context.Environment) -> pgast.BaseExpr:

    val: pgast.BaseExpr

    if isinstance(expr, pgast.TupleVar):
        val = tuple_var_as_json_object(expr, styperef=styperef, env=env)

    elif isinstance(expr, (pgast.RowExpr, pgast.ImplicitRowExpr)):
        val = _build_json(
            'build_array',
            args=expr.args,
            null_safe=True,
            ser_safe=True,
            env=env,
        )

    elif irtyputils.is_collection(styperef) and not expr.ser_safe:
        val = coll_as_json_object(expr, styperef=styperef, env=env)

    # TODO: We'll probably want to generalize this to other custom JSON
    # casts once they exist.
    elif (irtyputils.is_bytes(styperef) and not expr.ser_safe):
        cast_name = s_casts.get_cast_fullname_from_names(
            'std', 'std::bytes', 'std::json')
        val = pgast.FuncCall(name=common.get_cast_backend_name(
            cast_name, aspect='function'),
                             args=[expr],
                             null_safe=True,
                             ser_safe=True)

    elif not nested:
        val = pgast.FuncCall(name=_get_json_func('to', env=env),
                             args=[expr],
                             null_safe=True,
                             ser_safe=True)

    else:
        val = expr

    return val
Example #4
0
def _compile_config_value(
    op: irast.ConfigSet,
    *,
    ctx: context.CompilerContextLevel,
) -> pgast.BaseExpr:
    val: pgast.BaseExpr

    if op.backend_setting:
        assert op.backend_expr is not None
        expr = op.backend_expr
    else:
        expr = op.expr

    with ctx.new() as subctx:
        if op.backend_setting or op.scope == qltypes.ConfigScope.GLOBAL:
            output_format = context.OutputFormat.NATIVE
        else:
            output_format = context.OutputFormat.JSONB

        with context.output_format(ctx, output_format):
            if isinstance(expr, irast.EmptySet):
                # Special handling for empty sets, because we want a
                # singleton representation of the value and not an empty rel
                # in this context.
                if op.cardinality is qltypes.SchemaCardinality.One:
                    val = pgast.NullConstant()
                elif subctx.env.output_format is context.OutputFormat.JSONB:
                    val = pgast.TypeCast(
                        arg=pgast.StringConstant(val='[]'),
                        type_name=pgast.TypeName(name=('jsonb', ), ),
                    )
                else:
                    val = pgast.TypeCast(
                        arg=pgast.ArrayExpr(elements=[]),
                        type_name=pgast.TypeName(name=('text[]', ), ),
                    )
            else:
                val = dispatch.compile(expr, ctx=subctx)
                assert isinstance(val, pgast.SelectStmt), "expected SelectStmt"

                pathctx.get_path_serialized_output(val,
                                                   expr.path_id,
                                                   env=ctx.env)

                if op.cardinality is qltypes.SchemaCardinality.Many:
                    val = output.aggregate_json_output(val, expr, env=ctx.env)

    # For globals, we need to output the binary encoding so that we
    # can just hand it back to the server. We abuse `record_send` to
    # act as a generic `_send` function
    if op.scope is qltypes.ConfigScope.GLOBAL:
        val = pgast.FuncCall(
            name=('substring', ),
            args=[
                pgast.FuncCall(
                    name=('record_send', ),
                    args=[pgast.RowExpr(args=[val])],
                ),
                # The first twelve bytes are header, the rest is the
                # encoding of the actual element
                pgast.NumericConstant(val="13"),
            ],
        )
        cast_name = s_casts.get_cast_fullname_from_names(
            'std', 'std::bytes', 'std::json')
        val = pgast.FuncCall(
            name=common.get_cast_backend_name(cast_name, aspect='function'),
            args=[val],
        )

    if op.backend_setting and op.scope is qltypes.ConfigScope.INSTANCE:
        assert isinstance(val, pgast.SelectStmt) and len(val.target_list) == 1
        val = val.target_list[0].val
        if isinstance(val, pgast.TypeCast):
            val = val.arg
        if not isinstance(val, pgast.BaseConstant):
            raise AssertionError('value is not a constant in ConfigSet')

    return val