All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flink.table.api.Expressions Maven / Gradle / Ivy

Go to download

There is a newer version: 2.0-preview1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.flink.table.api;

import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.table.connector.source.abilities.SupportsSourceWatermark;
import org.apache.flink.table.expressions.ApiExpressionUtils;
import org.apache.flink.table.expressions.Expression;
import org.apache.flink.table.expressions.ResolvedExpression;
import org.apache.flink.table.expressions.SqlCallExpression;
import org.apache.flink.table.expressions.TimePointUnit;
import org.apache.flink.table.functions.BuiltInFunctionDefinition;
import org.apache.flink.table.functions.BuiltInFunctionDefinitions;
import org.apache.flink.table.functions.FunctionDefinition;
import org.apache.flink.table.functions.UserDefinedFunction;
import org.apache.flink.table.functions.UserDefinedFunctionHelper;
import org.apache.flink.table.types.DataType;
import org.apache.flink.table.types.utils.TypeConversions;
import org.apache.flink.table.types.utils.ValueDataTypeConverter;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.apache.flink.table.expressions.ApiExpressionUtils.objectToExpression;
import static org.apache.flink.table.expressions.ApiExpressionUtils.unresolvedCall;
import static org.apache.flink.table.expressions.ApiExpressionUtils.unresolvedRef;
import static org.apache.flink.table.expressions.ApiExpressionUtils.valueLiteral;
import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_ARRAY;
import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_ARRAYAGG_ABSENT_ON_NULL;
import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_ARRAYAGG_NULL_ON_NULL;
import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_OBJECT;
import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_OBJECTAGG_ABSENT_ON_NULL;
import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_OBJECTAGG_NULL_ON_NULL;
import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_STRING;

/**
 * Entry point of the Table API Expression DSL such as: {@code $("myField").plus(10).abs()}
 *
 * 

This class contains static methods for referencing table columns, creating literals, and * building more complex {@link Expression} chains. {@link ApiExpression ApiExpressions} are pure * API entities that are further translated into {@link ResolvedExpression ResolvedExpressions} * under the hood. * *

For fluent definition of expressions and easier readability, we recommend adding a star import * to the methods of this class: * *

 * import static org.apache.flink.table.api.Expressions.*;
 * 
* *

Check the documentation for more programming language specific APIs, for example, by using * Scala implicits. */ @PublicEvolving public final class Expressions { /** * Creates an unresolved reference to a table's column. * *

Example: * *

{@code
     * tab.select($("key"), $("value"))
     * }
* * @see #col(String) */ // CHECKSTYLE.OFF: MethodName public static ApiExpression $(String name) { return new ApiExpression(unresolvedRef(name)); } // CHECKSTYLE.ON: MethodName /** * Creates an unresolved reference to a table's column. * *

Because {@link #$(String)} is not supported by every JVM language due to the dollar sign, * this method provides a synonym with the same behavior. * *

Example: * *

{@code
     * tab.select(col("key"), col("value"))
     * }
*/ public static ApiExpression col(String name) { return $(name); } /** * Creates a SQL literal. * *

The data type is derived from the object's class and its value. * *

For example: * *

    *
  • {@code lit(12)} leads to {@code INT} *
  • {@code lit("abc")} leads to {@code CHAR(3)} *
  • {@code lit(new BigDecimal("123.45"))} leads to {@code DECIMAL(5, 2)} *
* *

See {@link ValueDataTypeConverter} for a list of supported literal values. */ public static ApiExpression lit(Object v) { return new ApiExpression(valueLiteral(v)); } /** * Creates a SQL literal of a given {@link DataType}. * *

The method {@link #lit(Object)} is preferred as it extracts the {@link DataType} * automatically. Use this method only when necessary. The class of {@code v} must be supported * according to the {@link * org.apache.flink.table.types.logical.LogicalType#supportsInputConversion(Class)}. */ public static ApiExpression lit(Object v, DataType dataType) { return new ApiExpression(valueLiteral(v, dataType)); } /** * Indicates a range from 'start' to 'end', which can be used in columns selection. * *

Example: * *

{@code
     * Table table = ...
     * table.select(withColumns(range(b, c)))
     * }
* * @see #withColumns(Object, Object...) * @see #withoutColumns(Object, Object...) */ public static ApiExpression range(String start, String end) { return apiCall( BuiltInFunctionDefinitions.RANGE_TO, unresolvedRef(start), unresolvedRef(end)); } /** * Indicates an index based range, which can be used in columns selection. * *

Example: * *

{@code
     * Table table = ...
     * table.select(withColumns(range(3, 4)))
     * }
* * @see #withColumns(Object, Object...) * @see #withoutColumns(Object, Object...) */ public static ApiExpression range(int start, int end) { return apiCall(BuiltInFunctionDefinitions.RANGE_TO, valueLiteral(start), valueLiteral(end)); } /** Boolean AND in three-valued logic. */ public static ApiExpression and(Object predicate0, Object predicate1, Object... predicates) { return apiCallAtLeastTwoArgument( BuiltInFunctionDefinitions.AND, predicate0, predicate1, predicates); } /** Boolean OR in three-valued logic. */ public static ApiExpression or(Object predicate0, Object predicate1, Object... predicates) { return apiCallAtLeastTwoArgument( BuiltInFunctionDefinitions.OR, predicate0, predicate1, predicates); } /** * Inverts a given boolean expression. * *

This method supports a three-valued logic by preserving {@code NULL}. This means if the * input expression is {@code NULL}, the result will also be {@code NULL}. * *

The resulting type is nullable if and only if the input type is nullable. * *

Examples: * *

{@code
     * not(lit(true)) // false
     * not(lit(false)) // true
     * not(lit(null, DataTypes.BOOLEAN())) // null
     * }
*/ public static ApiExpression not(Object expression) { return apiCall(BuiltInFunctionDefinitions.NOT, expression); } /** * Offset constant to be used in the {@code preceding} clause of unbounded {@code Over} windows. * Use this constant for a time interval. Unbounded over windows start with the first row of a * partition. */ public static final ApiExpression UNBOUNDED_ROW = apiCall(BuiltInFunctionDefinitions.UNBOUNDED_ROW); /** * Offset constant to be used in the {@code preceding} clause of unbounded {@link Over} windows. * Use this constant for a row-count interval. Unbounded over windows start with the first row * of a partition. */ public static final ApiExpression UNBOUNDED_RANGE = apiCall(BuiltInFunctionDefinitions.UNBOUNDED_RANGE); /** * Offset constant to be used in the {@code following} clause of {@link Over} windows. Use this * for setting the upper bound of the window to the current row. */ public static final ApiExpression CURRENT_ROW = apiCall(BuiltInFunctionDefinitions.CURRENT_ROW); /** * Offset constant to be used in the {@code following} clause of {@link Over} windows. Use this * for setting the upper bound of the window to the sort key of the current row, i.e., all rows * with the same sort key as the current row are included in the window. */ public static final ApiExpression CURRENT_RANGE = apiCall(BuiltInFunctionDefinitions.CURRENT_RANGE); /** * Returns the current SQL date in local time zone, the return type of this expression is {@link * DataTypes#DATE()}. */ public static ApiExpression currentDate() { return apiCall(BuiltInFunctionDefinitions.CURRENT_DATE); } /** * Returns the current SQL time in local time zone, the return type of this expression is {@link * DataTypes#TIME()}. */ public static ApiExpression currentTime() { return apiCall(BuiltInFunctionDefinitions.CURRENT_TIME); } /** * Returns the current SQL timestamp in local time zone, the return type of this expression is * {@link DataTypes#TIMESTAMP_WITH_LOCAL_TIME_ZONE()}. */ public static ApiExpression currentTimestamp() { return apiCall(BuiltInFunctionDefinitions.CURRENT_TIMESTAMP); } /** * Returns the current watermark for the given rowtime attribute, or {@code NULL} if no common * watermark of all upstream operations is available at the current operation in the pipeline. * *

The function returns the watermark with the same type as the rowtime attribute, but with * an adjusted precision of 3. For example, if the rowtime attribute is {@link * DataTypes#TIMESTAMP_LTZ(int) TIMESTAMP_LTZ(9)}, the function will return {@link * DataTypes#TIMESTAMP_LTZ(int) TIMESTAMP_LTZ(3)}. * *

If no watermark has been emitted yet, the function will return {@code NULL}. Users must * take care of this when comparing against it, e.g. in order to filter out late data you can * use * *

{@code
     * WHERE CURRENT_WATERMARK(ts) IS NULL OR ts > CURRENT_WATERMARK(ts)
     * }
*/ public static ApiExpression currentWatermark(Object rowtimeAttribute) { return apiCall(BuiltInFunctionDefinitions.CURRENT_WATERMARK, rowtimeAttribute); } /** * Return the current database, the return type of this expression is {@link * DataTypes#STRING()}. */ public static ApiExpression currentDatabase() { return apiCall(BuiltInFunctionDefinitions.CURRENT_DATABASE); } /** * Returns the current SQL time in local time zone, the return type of this expression is {@link * DataTypes#TIME()}, this is a synonym for {@link Expressions#currentTime()}. */ public static ApiExpression localTime() { return apiCall(BuiltInFunctionDefinitions.LOCAL_TIME); } /** * Returns the current SQL timestamp in local time zone, the return type of this expression is * {@link DataTypes#TIMESTAMP()}. */ public static ApiExpression localTimestamp() { return apiCall(BuiltInFunctionDefinitions.LOCAL_TIMESTAMP); } /** * Converts the given date string with format 'yyyy-MM-dd' to {@link DataTypes#DATE()}. * * @param dateStr The date string. * @return The date value of {@link DataTypes#DATE()} type. */ public static ApiExpression toDate(Object dateStr) { return apiCall(BuiltInFunctionDefinitions.TO_DATE, dateStr); } /** * Converts the date string with the specified format to {@link DataTypes#DATE()}. * * @param dateStr The date string. * @param format The format of the string. * @return The date value of {@link DataTypes#DATE()} type. */ public static ApiExpression toDate(Object dateStr, Object format) { return apiCall(BuiltInFunctionDefinitions.TO_DATE, dateStr, format); } /** * Converts the given date time string with format 'yyyy-MM-dd HH:mm:ss' under the 'UTC+0' time * zone to {@link DataTypes#TIMESTAMP()}. * * @param timestampStr The date time string. * @return The timestamp value with {@link DataTypes#TIMESTAMP()} type. */ public static ApiExpression toTimestamp(Object timestampStr) { return apiCall(BuiltInFunctionDefinitions.TO_TIMESTAMP, timestampStr); } /** * Converts the given time string with the specified format under the 'UTC+0' time zone to * {@link DataTypes#TIMESTAMP()}. * * @param timestampStr The date time string. * @param format The format of the string. * @return The timestamp value with {@link DataTypes#TIMESTAMP()} type. */ public static ApiExpression toTimestamp(Object timestampStr, Object format) { return apiCall(BuiltInFunctionDefinitions.TO_TIMESTAMP, timestampStr, format); } /** * Converts a numeric type epoch time to {@link DataTypes#TIMESTAMP_LTZ(int)}. * *

The supported precision is 0 or 3: * *

    *
  • 0 means the numericEpochTime is in second. *
  • 3 means the numericEpochTime is in millisecond. *
* * @param numericEpochTime The epoch time with numeric type. * @param precision The precision to indicate the epoch time is in second or millisecond. * @return The timestamp value with {@link DataTypes#TIMESTAMP_LTZ(int)} type. */ public static ApiExpression toTimestampLtz(Object numericEpochTime, Object precision) { return apiCall(BuiltInFunctionDefinitions.TO_TIMESTAMP_LTZ, numericEpochTime, precision); } /** * Determines whether two anchored time intervals overlap. Time point and temporal are * transformed into a range defined by two time points (start, end). The function evaluates * leftEnd >= rightStart && rightEnd >= leftStart. * *

It evaluates: leftEnd >= rightStart && rightEnd >= leftStart * *

e.g. * *

{@code
     * temporalOverlaps(
     *      lit("2:55:00").toTime(),
     *      lit(1).hours(),
     *      lit("3:30:00").toTime(),
     *      lit(2).hours()
     * )
     * }
* *

leads to true */ public static ApiExpression temporalOverlaps( Object leftTimePoint, Object leftTemporal, Object rightTimePoint, Object rightTemporal) { return apiCall( BuiltInFunctionDefinitions.TEMPORAL_OVERLAPS, leftTimePoint, leftTemporal, rightTimePoint, rightTemporal); } /** * Formats a timestamp as a string using a specified format. The format must be compatible with * MySQL's date formatting syntax as used by the date_parse function. * *

For example {@code dataFormat($("time"), "%Y, %d %M")} results in strings formatted as * "2017, 05 May". * * @param timestamp The timestamp to format as string. * @param format The format of the string. * @return The formatted timestamp as string. */ public static ApiExpression dateFormat(Object timestamp, Object format) { return apiCall(BuiltInFunctionDefinitions.DATE_FORMAT, timestamp, format); } /** * Returns the (signed) number of {@link TimePointUnit} between timePoint1 and timePoint2. * *

For example, {@code timestampDiff(TimePointUnit.DAY, lit("2016-06-15").toDate(), * lit("2016-06-18").toDate()} leads to 3. * * @param timePointUnit The unit to compute diff. * @param timePoint1 The first point in time. * @param timePoint2 The second point in time. * @return The number of intervals as integer value. */ public static ApiExpression timestampDiff( TimePointUnit timePointUnit, Object timePoint1, Object timePoint2) { return apiCall( BuiltInFunctionDefinitions.TIMESTAMP_DIFF, valueLiteral(timePointUnit), timePoint1, timePoint2); } /** * Converts a datetime dateStr (with default ISO timestamp format 'yyyy-MM-dd HH:mm:ss') from * time zone tzFrom to time zone tzTo. The format of time zone should be either an abbreviation * such as "PST", a full name such as "America/Los_Angeles", or a custom ID such as "GMT-08:00". * E.g., convertTz('1970-01-01 00:00:00', 'UTC', 'America/Los_Angeles') returns '1969-12-31 * 16:00:00'. * * @param dateStr the date time string * @param tzFrom the original time zone * @param tzTo the target time zone * @return The formatted timestamp as string. */ public static ApiExpression convertTz(Object dateStr, Object tzFrom, Object tzTo) { return apiCall(BuiltInFunctionDefinitions.CONVERT_TZ, dateStr, tzFrom, tzTo); } /** * Converts unix timestamp (seconds since '1970-01-01 00:00:00' UTC) to datetime string in the * "yyyy-MM-dd HH:mm:ss" format. * * @param unixtime The unix timestamp with numeric type. * @return The formatted timestamp as string. */ public static ApiExpression fromUnixtime(Object unixtime) { return apiCall(BuiltInFunctionDefinitions.FROM_UNIXTIME, unixtime); } /** * Converts unix timestamp (seconds since '1970-01-01 00:00:00' UTC) to datetime string in the * given format. * * @param unixtime The unix timestamp with numeric type. * @param format The format of the string. * @return The formatted timestamp as string. */ public static ApiExpression fromUnixtime(Object unixtime, Object format) { return apiCall(BuiltInFunctionDefinitions.FROM_UNIXTIME, unixtime, format); } /** * Gets the current unix timestamp in seconds. This function is not deterministic which means * the value would be recalculated for each record. * * @return The current unix timestamp as bigint. */ public static ApiExpression unixTimestamp() { return apiCall(BuiltInFunctionDefinitions.UNIX_TIMESTAMP); } /** * Converts the given date time string with format 'yyyy-MM-dd HH:mm:ss' to unix timestamp (in * seconds), using the time zone specified in the table config. * * @param timestampStr The date time string. * @return The converted timestamp as bigint. */ public static ApiExpression unixTimestamp(Object timestampStr) { return apiCall(BuiltInFunctionDefinitions.UNIX_TIMESTAMP, timestampStr); } /** * Converts the given date time string with the specified format to unix timestamp (in seconds), * using the specified timezone in table config. * * @param timestampStr The date time string. * @param format The format of the date time string. * @return The converted timestamp as bigint. */ public static ApiExpression unixTimestamp(Object timestampStr, Object format) { return apiCall(BuiltInFunctionDefinitions.UNIX_TIMESTAMP, timestampStr, format); } /** Creates an array of literals. */ public static ApiExpression array(Object head, Object... tail) { return apiCallAtLeastOneArgument(BuiltInFunctionDefinitions.ARRAY, head, tail); } /** Creates a row of expressions. */ public static ApiExpression row(Object head, Object... tail) { return apiCallAtLeastOneArgument(BuiltInFunctionDefinitions.ROW, head, tail); } /** * Creates a map of expressions. * *

{@code
     * table.select(
     *     map(
     *         "key1", 1,
     *         "key2", 2,
     *         "key3", 3
     *     ))
     * }
* *

Note keys and values should have the same types for all entries. */ public static ApiExpression map(Object key, Object value, Object... tail) { return apiCallAtLeastTwoArgument(BuiltInFunctionDefinitions.MAP, key, value, tail); } /** * Creates an interval of rows. * * @see Table#window(GroupWindow) * @see Table#window(OverWindow...) */ public static ApiExpression rowInterval(Long rows) { return new ApiExpression(valueLiteral(rows)); } /** Returns a value that is closer than any other value to pi. */ public static ApiExpression pi() { return apiCall(BuiltInFunctionDefinitions.PI); } /** Returns a value that is closer than any other value to e. */ public static ApiExpression e() { return apiCall(BuiltInFunctionDefinitions.E); } /** Returns a pseudorandom double value between 0.0 (inclusive) and 1.0 (exclusive). */ public static ApiExpression rand() { return apiCall(BuiltInFunctionDefinitions.RAND); } /** * Returns a pseudorandom double value between 0.0 (inclusive) and 1.0 (exclusive) with a * initial seed. Two rand() functions will return identical sequences of numbers if they have * same initial seed. */ public static ApiExpression rand(Object seed) { return apiCall(BuiltInFunctionDefinitions.RAND, objectToExpression(seed)); } /** * Returns a pseudorandom integer value between 0 (inclusive) and the specified value * (exclusive). */ public static ApiExpression randInteger(Object bound) { return apiCall(BuiltInFunctionDefinitions.RAND_INTEGER, objectToExpression(bound)); } /** * Returns a pseudorandom integer value between 0 (inclusive) and the specified value * (exclusive) with a initial seed. Two randInteger() functions will return identical sequences * of numbers if they have same initial seed and same bound. */ public static ApiExpression randInteger(Object seed, Object bound) { return apiCall( BuiltInFunctionDefinitions.RAND_INTEGER, objectToExpression(seed), objectToExpression(bound)); } /** * Returns the string that results from concatenating the arguments. Returns NULL if any * argument is NULL. */ public static ApiExpression concat(Object string, Object... strings) { return apiCallAtLeastOneArgument(BuiltInFunctionDefinitions.CONCAT, string, strings); } /** Calculates the arc tangent of a given coordinate. */ public static ApiExpression atan2(Object y, Object x) { return apiCallAtLeastOneArgument(BuiltInFunctionDefinitions.ATAN2, y, x); } /** Returns negative numeric. */ public static ApiExpression negative(Object v) { return apiCall(BuiltInFunctionDefinitions.MINUS_PREFIX, v); } /** * Returns the string that results from concatenating the arguments and separator. Returns NULL * If the separator is NULL. * *

Note: this function does not skip empty strings. However, it does skip any NULL values * after the separator argument. */ public static ApiExpression concatWs(Object separator, Object string, Object... strings) { return apiCallAtLeastTwoArgument( BuiltInFunctionDefinitions.CONCAT_WS, separator, string, strings); } /** * Returns an UUID (Universally Unique Identifier) string (e.g., * "3d3c68f7-f608-473f-b60c-b0c44ad4cc4e") according to RFC 4122 type 4 (pseudo randomly * generated) UUID. The UUID is generated using a cryptographically strong pseudo random number * generator. */ public static ApiExpression uuid() { return apiCall(BuiltInFunctionDefinitions.UUID); } /** * Returns a null literal value of a given data type. * *

e.g. {@code nullOf(DataTypes.INT())} */ public static ApiExpression nullOf(DataType dataType) { return new ApiExpression(valueLiteral(null, dataType)); } /** * @deprecated This method will be removed in future versions as it uses the old type system. It * is recommended to use {@link #nullOf(DataType)} instead which uses the new type system * based on {@link DataTypes}. Please make sure to use either the old or the new type system * consistently to avoid unintended behavior. See the website documentation for more * information. */ public static ApiExpression nullOf(TypeInformation typeInfo) { return nullOf(TypeConversions.fromLegacyInfoToDataType(typeInfo)); } /** Calculates the logarithm of the given value. */ public static ApiExpression log(Object value) { return apiCall(BuiltInFunctionDefinitions.LOG, value); } /** Calculates the logarithm of the given value to the given base. */ public static ApiExpression log(Object base, Object value) { return apiCall(BuiltInFunctionDefinitions.LOG, base, value); } /** * Source watermark declaration for {@link Schema}. * *

This is a marker function that doesn't have concrete runtime implementation. It can only * be used as a single expression in {@link Schema.Builder#watermark(String, Expression)}. The * declaration will be pushed down into a table source that implements the {@link * SupportsSourceWatermark} interface. The source will emit system-defined watermarks * afterwards. * *

Please check the documentation whether the connector supports source watermarks. */ public static ApiExpression sourceWatermark() { return apiCall(BuiltInFunctionDefinitions.SOURCE_WATERMARK); } /** * Ternary conditional operator that decides which of two other expressions should be evaluated * based on a evaluated boolean condition. * *

e.g. ifThenElse($("f0") > 5, "A", "B") leads to "A" * * @param condition boolean condition * @param ifTrue expression to be evaluated if condition holds * @param ifFalse expression to be evaluated if condition does not hold */ public static ApiExpression ifThenElse(Object condition, Object ifTrue, Object ifFalse) { return apiCall(BuiltInFunctionDefinitions.IF, condition, ifTrue, ifFalse); } /** * Returns the first argument that is not NULL. * *

If all arguments are NULL, it returns NULL as well. The return type is the least * restrictive, common type of all of its arguments. The return type is nullable if all * arguments are nullable as well. * *

Examples: * *

{@code
     * // Returns "default"
     * coalesce(null, "default")
     * // Returns the first non-null value among f0 and f1, or "default" if f0 and f1 are both null
     * coalesce($("f0"), $("f1"), "default")
     * }
* * @param args the input expressions. */ public static ApiExpression coalesce(Object... args) { return apiCall(BuiltInFunctionDefinitions.COALESCE, args); } /** * Creates an expression that selects a range of columns. It can be used wherever an array of * expression is accepted such as function calls, projections, or groupings. * *

A range can either be index-based or name-based. Indices start at 1 and boundaries are * inclusive. * *

e.g. withColumns(range("b", "c")) or withoutColumns($("*")) */ public static ApiExpression withColumns(Object head, Object... tail) { return apiCallAtLeastOneArgument(BuiltInFunctionDefinitions.WITH_COLUMNS, head, tail); } /** * Creates an expression that selects all columns except for the given range of columns. It can * be used wherever an array of expression is accepted such as function calls, projections, or * groupings. * *

A range can either be index-based or name-based. Indices start at 1 and boundaries are * inclusive. * *

e.g. withoutColumns(range("b", "c")) or withoutColumns($("c")) */ public static ApiExpression withoutColumns(Object head, Object... tail) { return apiCallAtLeastOneArgument(BuiltInFunctionDefinitions.WITHOUT_COLUMNS, head, tail); } /** * Builds a JSON object string from a list of key-value pairs. * *

{@param keyValues} is an even-numbered list of alternating key/value pairs. Note that keys * must be non-{@code NULL} string literals, while values may be arbitrary expressions. * *

This function returns a JSON string. The {@link JsonOnNull onNull} behavior defines how to * treat {@code NULL} values. * *

Values which are created from another JSON construction function call ({@code jsonObject}, * {@code jsonArray}) are inserted directly rather than as a string. This allows building nested * JSON structures. * *

Examples: * *

{@code
     * // {}
     * jsonObject(JsonOnNull.NULL)
     * // "{\"K1\":\"V1\",\"K2\":\"V2\"}"
     * // {"K1":"V1","K2":"V2"}
     * jsonObject(JsonOnNull.NULL, "K1", "V1", "K2", "V2")
     *
     * // Expressions as values
     * jsonObject(JsonOnNull.NULL, "orderNo", $("orderId"))
     *
     * // ON NULL
     * jsonObject(JsonOnNull.NULL, "K1", nullOf(DataTypes.STRING()))   // "{\"K1\":null}"
     * jsonObject(JsonOnNull.ABSENT, "K1", nullOf(DataTypes.STRING())) // "{}"
     *
     * // {"K1":{"K2":"V"}}
     * jsonObject(JsonOnNull.NULL, "K1", jsonObject(JsonOnNull.NULL, "K2", "V"))
     * }
* * @see #jsonArray(JsonOnNull, Object...) */ public static ApiExpression jsonObject(JsonOnNull onNull, Object... keyValues) { final Object[] arguments = Stream.concat(Stream.of(onNull), Arrays.stream(keyValues)).toArray(Object[]::new); return apiCall(JSON_OBJECT, arguments); } /** * Builds a JSON object string by aggregating key-value expressions into a single JSON object. * *

The key expression must return a non-nullable character string. Value expressions can be * arbitrary, including other JSON functions. If a value is {@code NULL}, the {@link JsonOnNull * onNull} behavior defines what to do. * *

Note that keys must be unique. If a key occurs multiple times, an error will be thrown. * *

This function is currently not supported in {@code OVER} windows. * *

Examples: * *

{@code
     * // "{\"Apple\":2,\"Banana\":17,\"Orange\":0}"
     * orders.select(jsonObjectAgg(JsonOnNull.NULL, $("product"), $("cnt")))
     * }
* * @see #jsonObject(JsonOnNull, Object...) * @see #jsonArrayAgg(JsonOnNull, Object) */ public static ApiExpression jsonObjectAgg(JsonOnNull onNull, Object keyExpr, Object valueExpr) { final BuiltInFunctionDefinition functionDefinition; switch (onNull) { case ABSENT: functionDefinition = JSON_OBJECTAGG_ABSENT_ON_NULL; break; case NULL: default: functionDefinition = JSON_OBJECTAGG_NULL_ON_NULL; break; } return apiCall(functionDefinition, keyExpr, valueExpr); } /** * Serializes a value into JSON. * *

This function returns a JSON string containing the serialized value. If the value is * {@code null}, the function returns {@code null}. * *

Examples: * *

{@code
     * // null
     * jsonString(nullOf(DataTypes.INT()))
     *
     * jsonString(1)                   // "1"
     * jsonString(true)                // "true"
     * jsonString("Hello, World!")     // "\"Hello, World!\""
     * jsonString(Arrays.asList(1, 2)) // "[1,2]"
     * }
*/ public static ApiExpression jsonString(Object value) { return apiCallAtLeastOneArgument(JSON_STRING, value); } /** * Builds a JSON array string from a list of values. * *

This function returns a JSON string. The values can be arbitrary expressions. The {@link * JsonOnNull onNull} behavior defines how to treat {@code NULL} values. * *

Elements which are created from another JSON construction function call ({@code * jsonObject}, {@code jsonArray}) are inserted directly rather than as a string. This allows * building nested JSON structures. * *

Examples: * *

{@code
     * // "[]"
     * jsonArray(JsonOnNull.NULL)
     * // "[1,\"2\"]"
     * jsonArray(JsonOnNull.NULL, 1, "2")
     *
     * // Expressions as values
     * jsonArray(JsonOnNull.NULL, $("orderId"))
     *
     * // ON NULL
     * jsonArray(JsonOnNull.NULL, nullOf(DataTypes.STRING()))   // "[null]"
     * jsonArray(JsonOnNull.ABSENT, nullOf(DataTypes.STRING())) // "[]"
     *
     * // "[[1]]"
     * jsonArray(JsonOnNull.NULL, jsonArray(JsonOnNull.NULL, 1))
     * }
* * @see #jsonObject(JsonOnNull, Object...) */ public static ApiExpression jsonArray(JsonOnNull onNull, Object... values) { final Object[] arguments = Stream.concat(Stream.of(onNull), Arrays.stream(values)).toArray(Object[]::new); return apiCall(JSON_ARRAY, arguments); } /** * Builds a JSON object string by aggregating items into an array. * *

Item expressions can be arbitrary, including other JSON functions. If a value is {@code * NULL}, the {@link JsonOnNull onNull} behavior defines what to do. * *

This function is currently not supported in {@code OVER} windows, unbounded session * windows, or hop windows. * *

Examples: * *

{@code
     * // "[\"Apple\",\"Banana\",\"Orange\"]"
     * orders.select(jsonArrayAgg(JsonOnNull.NULL, $("product")))
     * }
* * @see #jsonArray(JsonOnNull, Object...) * @see #jsonObjectAgg(JsonOnNull, Object, Object) */ public static ApiExpression jsonArrayAgg(JsonOnNull onNull, Object itemExpr) { final BuiltInFunctionDefinition functionDefinition; switch (onNull) { case NULL: functionDefinition = JSON_ARRAYAGG_NULL_ON_NULL; break; case ABSENT: default: functionDefinition = JSON_ARRAYAGG_ABSENT_ON_NULL; break; } return apiCall(functionDefinition, itemExpr); } /** * A call to a function that will be looked up in a catalog. There are two kinds of functions: * *
    *
  • System functions - which are identified with one part names *
  • Catalog functions - which are identified always with three parts names (catalog, * database, function) *
* *

Moreover each function can either be a temporary function or permanent one (which is * stored in an external catalog). * *

Based on that two properties the resolution order for looking up a function based on the * provided {@code functionName} is following: * *

    *
  • Temporary system function *
  • System function *
  • Temporary catalog function *
  • Catalog function *
* * @see TableEnvironment#useCatalog(String) * @see TableEnvironment#useDatabase(String) * @see TableEnvironment#createTemporaryFunction * @see TableEnvironment#createTemporarySystemFunction */ public static ApiExpression call(String path, Object... arguments) { return new ApiExpression( ApiExpressionUtils.lookupCall( path, Arrays.stream(arguments) .map(ApiExpressionUtils::objectToExpression) .toArray(Expression[]::new))); } /** * A call to an unregistered, inline function. * *

For functions that have been registered before and are identified by a name, use {@link * #call(String, Object...)}. */ public static ApiExpression call(UserDefinedFunction function, Object... arguments) { return apiCall(function, arguments); } /** * A call to an unregistered, inline function. * *

For functions that have been registered before and are identified by a name, use {@link * #call(String, Object...)}. */ public static ApiExpression call( Class function, Object... arguments) { final UserDefinedFunction functionInstance = UserDefinedFunctionHelper.instantiateFunction(function); return apiCall(functionInstance, arguments); } /** * A call to a SQL expression. * *

The given string is parsed and translated into an {@link Expression} during planning. Only * the translated expression is evaluated during runtime. * *

Note: Currently, calls are limited to simple scalar expressions. Calls to aggregate or * table-valued functions are not supported. Sub-queries are also not allowed. */ public static ApiExpression callSql(String sqlExpression) { return apiSqlCall(sqlExpression); } private static ApiExpression apiCall(FunctionDefinition functionDefinition, Object... args) { List arguments = Stream.of(args) .map(ApiExpressionUtils::objectToExpression) .collect(Collectors.toList()); return new ApiExpression(unresolvedCall(functionDefinition, arguments)); } private static ApiExpression apiCallAtLeastOneArgument( FunctionDefinition functionDefinition, Object arg0, Object... args) { List arguments = Stream.concat(Stream.of(arg0), Stream.of(args)) .map(ApiExpressionUtils::objectToExpression) .collect(Collectors.toList()); return new ApiExpression(unresolvedCall(functionDefinition, arguments)); } private static ApiExpression apiCallAtLeastTwoArgument( FunctionDefinition functionDefinition, Object arg0, Object arg1, Object... args) { List arguments = Stream.concat(Stream.of(arg0, arg1), Stream.of(args)) .map(ApiExpressionUtils::objectToExpression) .collect(Collectors.toList()); return new ApiExpression(unresolvedCall(functionDefinition, arguments)); } private static ApiExpression apiSqlCall(String sqlExpression) { return new ApiExpression(new SqlCallExpression(sqlExpression)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy