Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.xlrit.gears.engine.snel.SnelFunctions Maven / Gradle / Ivy
package com.xlrit.gears.engine.snel;
import java.time.OffsetDateTime;
import java.time.temporal.Temporal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.xlrit.gears.base.function.DefaultFunctions;
import com.xlrit.gears.base.model.User;
import com.xlrit.gears.engine.meta.MetaManager;
import com.xlrit.gears.engine.meta.TypeInfo;
import static com.xlrit.gears.engine.meta.BasicTypes.*;
public class SnelFunctions {
private SnelFunctions() {}
private static final TypeInfo userType = null; // TODO actual type
public static final List asList = List.of(
// no arguments
static0("current_date", DATE, DefaultFunctions::currentDate, "CURRENT_DATE"),
static0("current_time", TIME, DefaultFunctions::currentTime, "CURRENT_TIME"),
static0("current_datetime", DATETIME, DefaultFunctions::currentDatetime, "CURRENT_TIMESTAMP"),
static0("current_user", userType, SnelFunctions::currentUserImpl, ":current_user"),
// 1 argument
static1("count", INTEGER, arg -> DefaultFunctions.count((Collection>)arg), arg -> "COUNT(" + arg.text() + ")"),
static1("uppercase", TEXT, arg -> String.valueOf(arg).toUpperCase(), arg -> "UPPER(" + arg.text() + ")"),
static1("lowercase", TEXT, arg -> String.valueOf(arg).toLowerCase(), arg -> "LOWER(" + arg.text() + ")"),
static1("date_part", DATE, OffsetDateTime.class, DefaultFunctions::datePart, arg -> "EXTRACT(date FROM " + arg.text() + ")"),
static1("time_part", TIME, OffsetDateTime.class, DefaultFunctions::timePart, arg -> "EXTRACT(time FROM " + arg.text() + ")"),
// ? arguments
staticN("concat", TEXT, SnelFunctions::concatImpl, SnelFunctions::translateConcat),
staticN("search", BOOLEAN, SnelFunctions::searchImpl, params -> "SEARCH(" + joinParams(", ", params) + ")"),
// temporal unit extractors
temporalExtractFunction("year", DefaultFunctions::year),
temporalExtractFunction("month", DefaultFunctions::month),
temporalExtractFunction("week", DefaultFunctions::week),
temporalExtractFunction("day", DefaultFunctions::day),
temporalExtractFunction("hour", DefaultFunctions::hour),
temporalExtractFunction("minute", DefaultFunctions::minute),
temporalExtractFunction("second", DefaultFunctions::second),
// misc
distinctFunction()
);
private static SnelFunction distinctFunction() {
return new SnelFunction("distinct") {
@Override
public Result invoke(List args) {
if (args.size() != 1) throw new IllegalArgumentException("Function `distinct`: requires 1 parameter");
if (!(args.get(0) instanceof List> list)) throw new IllegalArgumentException("Function `distinct`: parameter must be a list");
TypeInfo returnType = null; // TODO same as argument type
return Result.typed(returnType, DefaultFunctions.distinct(list));
}
@Override
public Fragment translate(List args) {
if (args.size() != 1) throw new IllegalArgumentException("Function `distinct`: requires 1 parameter");
return new Fragment(null, -1, "DISTINCT " + args.get(0).text());
}
};
}
public static final Map asMap =
asList.stream().collect(Collectors.toMap(SnelFunction::getName, Function.identity()));
private static User currentUserImpl() {
throw new UnsupportedOperationException();
}
@SuppressWarnings({"rawtypes", "unchecked"})
private static String concatImpl(List args) {
if (args.size() != 1 && args.size() != 2) throw new IllegalArgumentException("Function `concat`: requires 1 or 2 parameters");
if (!(args.get(0) instanceof List texts)) throw new IllegalArgumentException("Function `concat`: first parameter must be a collection");
if (args.size() == 1) return DefaultFunctions.concat(texts);
if (args.get(1) instanceof String sep) return DefaultFunctions.concat(texts, sep);
throw new IllegalArgumentException("Function `concat`: unsupported parameters: " + args);
}
private static String translateConcat(List args) {
return switch (args.size()) {
case 1 -> "CONCAT(" + args.get(0).text() + ")";
case 2 -> "CONCAT_WS(" + args.get(1).text() + ", " + args.get(0).text() + ")";
default -> throw new IllegalArgumentException("Function `concat`: unsupported parameters: " + args);
};
}
private static String searchImpl(List params) {
throw new UnsupportedOperationException();
}
private static String joinParams(String s, List params) {
return params.stream()
.map(Fragment::text)
.collect(Collectors.joining(s));
}
private static SnelFunction temporalExtractFunction(String name, Function extractor) {
return static1(
name,
INTEGER,
arg -> extractor.apply((Temporal) arg),
arg -> "EXTRACT(" + name + " from " + arg.text() + ")"
);
}
private static SnelFunction static0(String name, TypeInfo type, Supplier invoker, String translated) {
// TODO ensure there's exactly 0 arguments
return new SnelFunction(name) {
@Override
public Result invoke(List args) {
Object value = invoker.get();
return Result.typed(type, value);
}
@Override
public Fragment translate(List args) {
return new Fragment(type, -1, translated);
}
};
}
private static SnelFunction static1(String name, TypeInfo type, Class paramType, Function invoker, Function translator) {
return static1(name, type, arg -> invoker.apply(paramType.cast(arg)), translator);
}
private static SnelFunction static1(String name, TypeInfo type, Function invoker, Function translator) {
// TODO ensure there's exactly 1 argument
return new SnelFunction(name) {
@Override
public Result invoke(List args) {
Object value = invoker.apply(args.get(0));
return Result.typed(type, value);
}
@Override
public Fragment translate(List args) {
String translated = translator.apply(args.get(0));
return new Fragment(type, -1, translated);
}
};
}
private static SnelFunction staticN(String name, TypeInfo type, Function,Object> impl, Function,String> translator) {
return new SnelFunction(name) {
@Override
public Result invoke(List args) {
Object value = impl.apply(args);
return Result.typed(type, value);
}
@Override
public Fragment translate(List args) {
String translated = translator.apply(args);
return new Fragment(type, -1, translated);
}
};
}
}