Beispiel #1
0
def compile_OperatorCall(expr: irast.OperatorCall, *,
                         ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    if (str(expr.func_shortname) == 'std::IF'
            and expr.args[0].cardinality.is_single()
            and expr.args[2].cardinality.is_single()):
        if_expr, condition, else_expr = (a.expr for a in expr.args)
        return pgast.CaseExpr(args=[
            pgast.CaseWhen(expr=dispatch.compile(condition, ctx=ctx),
                           result=dispatch.compile(if_expr, ctx=ctx))
        ],
                              defresult=dispatch.compile(else_expr, ctx=ctx))
    elif (str(expr.func_shortname) == 'std::??'
          and expr.args[0].cardinality.is_single()
          and expr.args[1].cardinality.is_single()):
        l_expr, r_expr = (a.expr for a in expr.args)
        return pgast.CoalesceExpr(args=[
            dispatch.compile(l_expr, ctx=ctx),
            dispatch.compile(r_expr, ctx=ctx),
        ], )
    elif expr.typemod is ql_ft.TypeModifier.SetOfType:
        raise errors.UnsupportedFeatureError(
            f'set returning operator {expr.func_shortname!r} is not supported '
            f'in simple expressions')

    args = _compile_call_args(expr, ctx=ctx)
    return compile_operator(expr, args, ctx=ctx)
Beispiel #2
0
def aggregate_json_output(stmt: pgast.Query, ir_set: irast.Set, *,
                          env: context.Environment) -> pgast.Query:

    subrvar = pgast.RangeSubselect(
        subquery=stmt, alias=pgast.Alias(aliasname=env.aliases.get('aggw')))

    stmt_res = stmt.target_list[0]

    if stmt_res.name is None:
        stmt_res = stmt.target_list[0] = pgast.ResTarget(
            name=env.aliases.get('v'),
            val=stmt_res.val,
        )

    new_val = pgast.FuncCall(name=_get_json_func('agg', env=env),
                             args=[pgast.ColumnRef(name=[stmt_res.name])])

    new_val = pgast.CoalesceExpr(
        args=[new_val, pgast.StringConstant(val='[]')])

    result = pgast.SelectStmt(target_list=[pgast.ResTarget(val=new_val)],
                              from_clause=[subrvar])

    result.ctes = stmt.ctes
    result.argnames = stmt.argnames
    stmt.ctes = []

    return result
Beispiel #3
0
def array_as_json_object(
    expr: pgast.BaseExpr,
    *,
    styperef: irast.TypeRef,
    env: context.Environment,
) -> pgast.BaseExpr:
    el_type = styperef.subtypes[0]

    if irtyputils.is_tuple(el_type):
        coldeflist = []
        json_args: List[pgast.BaseExpr] = []
        is_named = any(st.element_name for st in el_type.subtypes)

        for i, st in enumerate(el_type.subtypes):
            if is_named:
                colname = st.element_name
                json_args.append(pgast.StringConstant(val=st.element_name))
            else:
                colname = str(i)

            val: pgast.BaseExpr = pgast.ColumnRef(name=[colname])
            if irtyputils.is_collection(st):
                val = coll_as_json_object(val, styperef=st, env=env)

            json_args.append(val)

            if not irtyputils.is_persistent_tuple(el_type):
                # Column definition list is only allowed for functions
                # returning "record", i.e. an anonymous tuple, which
                # would not be the case for schema-persistent tuple types.
                coldeflist.append(
                    pgast.ColumnDef(
                        name=colname,
                        typename=pgast.TypeName(
                            name=pgtypes.pg_type_from_ir_typeref(st)
                        )
                    )
                )

        if is_named:
            json_func = _get_json_func('build_object', env=env)
        else:
            json_func = _get_json_func('build_array', env=env)

        return pgast.SelectStmt(
            target_list=[
                pgast.ResTarget(
                    val=pgast.CoalesceExpr(
                        args=[
                            pgast.FuncCall(
                                name=_get_json_func('agg', env=env),
                                args=[
                                    pgast.FuncCall(
                                        name=json_func,
                                        args=json_args,
                                    )
                                ]
                            ),
                            pgast.StringConstant(val='[]'),
                        ]
                    ),
                    ser_safe=True,
                )
            ],
            from_clause=[
                pgast.RangeFunction(
                    alias=pgast.Alias(
                        aliasname=env.aliases.get('q'),
                    ),
                    is_rowsfrom=True,
                    functions=[
                        pgast.FuncCall(
                            name=('unnest',),
                            args=[expr],
                            coldeflist=coldeflist,
                        )
                    ]
                )
            ]
        )
    else:
        return pgast.FuncCall(
            name=_get_json_func('to', env=env), args=[expr],
            null_safe=True, ser_safe=True)
Beispiel #4
0
def array_as_json_object(expr, *, styperef, env):
    el_type = styperef.subtypes[0]

    if irtyputils.is_tuple(el_type):
        coldeflist = []
        json_args = []
        is_named = any(st.element_name for st in el_type.subtypes)

        for i, st in enumerate(el_type.subtypes):
            if is_named:
                colname = env.aliases.get(st.element_name)
                json_args.append(pgast.StringConstant(val=st.element_name))
            else:
                colname = env.aliases.get(str(i))

            val = pgast.ColumnRef(name=[colname])
            if irtyputils.is_collection(st):
                val = coll_as_json_object(val, styperef=st, env=env)

            json_args.append(val)

            coldeflist.append(
                pgast.ColumnDef(name=colname,
                                typename=pgast.TypeName(
                                    name=pgtypes.pg_type_from_ir_typeref(st))))

        if is_named:
            json_func = _get_json_func('build_object', env=env)
        else:
            json_func = _get_json_func('build_array', env=env)

        return pgast.SelectStmt(target_list=[
            pgast.ResTarget(
                val=pgast.CoalesceExpr(args=[
                    pgast.FuncCall(name=_get_json_func('agg', env=env),
                                   args=[
                                       pgast.FuncCall(
                                           name=json_func,
                                           args=json_args,
                                       )
                                   ]),
                    pgast.StringConstant(val='[]'),
                ]),
                ser_safe=True,
            )
        ],
                                from_clause=[
                                    pgast.RangeFunction(
                                        alias=pgast.Alias(
                                            aliasname=env.aliases.get('q'), ),
                                        is_rowsfrom=True,
                                        functions=[
                                            pgast.FuncCall(
                                                name=('unnest', ),
                                                args=[expr],
                                                coldeflist=coldeflist,
                                            )
                                        ])
                                ])
    else:
        return pgast.FuncCall(name=_get_json_func('to', env=env),
                              args=[expr],
                              null_safe=True,
                              ser_safe=True)
Beispiel #5
0
def array_as_json_object(
    expr: pgast.BaseExpr,
    *,
    styperef: irast.TypeRef,
    env: context.Environment,
) -> pgast.BaseExpr:
    el_type = styperef.subtypes[0]

    is_tuple = irtyputils.is_tuple(el_type)
    # Tuples and bytes might need underlying casts to be done
    if is_tuple or irtyputils.is_bytes(el_type):
        coldeflist = []

        out_alias = env.aliases.get('q')

        val: pgast.BaseExpr
        if is_tuple:
            json_args: List[pgast.BaseExpr] = []
            is_named = any(st.element_name for st in el_type.subtypes)
            for i, st in enumerate(el_type.subtypes):
                if is_named:
                    colname = st.element_name
                    assert colname
                    json_args.append(pgast.StringConstant(val=colname))
                else:
                    colname = str(i)

                val = pgast.ColumnRef(name=[colname])
                val = serialize_expr_to_json(val,
                                             styperef=st,
                                             nested=True,
                                             env=env)

                json_args.append(val)

                if not irtyputils.is_persistent_tuple(el_type):
                    # Column definition list is only allowed for functions
                    # returning "record", i.e. an anonymous tuple, which
                    # would not be the case for schema-persistent tuple types.
                    coldeflist.append(
                        pgast.ColumnDef(
                            name=colname,
                            typename=pgast.TypeName(
                                name=pgtypes.pg_type_from_ir_typeref(st))))

            json_func = 'build_object' if is_named else 'build_array'
            agg_arg = _build_json(json_func, json_args, env=env)

            needs_unnest = bool(el_type.subtypes)
        else:
            assert not el_type.subtypes
            val = pgast.ColumnRef(name=[out_alias])
            agg_arg = serialize_expr_to_json(val,
                                             styperef=el_type,
                                             nested=True,
                                             env=env)
            needs_unnest = True

        return pgast.SelectStmt(
            target_list=[
                pgast.ResTarget(
                    val=pgast.CoalesceExpr(args=[
                        pgast.FuncCall(
                            name=_get_json_func('agg', env=env),
                            args=[agg_arg],
                        ),
                        pgast.StringConstant(val='[]'),
                    ]),
                    ser_safe=True,
                )
            ],
            from_clause=[
                pgast.RangeFunction(alias=pgast.Alias(aliasname=out_alias),
                                    is_rowsfrom=True,
                                    functions=[
                                        pgast.FuncCall(
                                            name=('unnest', ),
                                            args=[expr],
                                            coldeflist=coldeflist,
                                        )
                                    ])
            ] if needs_unnest else [],
        )
    else:
        return pgast.FuncCall(name=_get_json_func('to', env=env),
                              args=[expr],
                              null_safe=True,
                              ser_safe=True)