Skip to content

Instantly share code, notes, and snippets.

@sberan
Created December 13, 2012 15:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sberan/4277292 to your computer and use it in GitHub Desktop.
Save sberan/4277292 to your computer and use it in GitHub Desktop.
DB query with lambda concept
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
/* Just a fake DBHandle for example's sake */
class DBHandle {
public <T> QueryBuilder<T> query(String q) {
return new QueryBuilder<>();
}
}
class QueryBuilder<T> implements MetaFunction.MapResult<T, Stream<T>> {
final Map<String, Object> params = new HashMap<>();
public <U> QueryBuilder<T> setParameter(String name, Object value) {
params.put(name, value);
return this;
}
@Override
public Stream<T> mapResult(MetaFunction<T> handler) {
//TODO: actually create the stream here
return null;
}
}
public class DBExample {
static class Something {
public Something(Integer id, String name) {
}
}
public Set<Something> doSomeDBStuff(DBHandle db) {
//the parameter type should be inferred by the time jdk8 goes live, due to JEP 101.
//for now, we need to supply it:
return db.<Something>query("select id, name from something")
.mapResult((Integer id, String name) -> new Something(id, name))
.into(new HashSet<>());
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Yo dawg, I heard u like functions
*/
public interface MetaFunction<Result> {
//set of generic functions, with increasing arity.
//these should eventually be generated at compile time, to clean up the source and make it easier to modify
interface F<R> extends MetaFunction<R> { }
interface F0<R> extends F<R> { R apply(); }
interface F1<T1, R> extends F<R> { R apply(T1 p1); }
interface F2<T1, T2, R> extends F<R> { R apply(T1 p1, T2 p); }
interface F3<T1, T2, T3, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3); }
interface F4<T1, T2, T3, T4, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4); }
interface F5<T1, T2, T3, T4, T5, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5); }
interface F6<T1, T2, T3, T4, T5, T6, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc); }
interface F7<T1, T2, T3, T4, T5, T6, T7, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7); }
interface F8<T1, T2, T3, T4, T5, T6, T7, T8, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7, T8 p8); }
interface F9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7, T8 p8, T9 p9); }
interface F10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7, T8 p8, T9 p9, T10 p10); }
/**
* Extend this to add a mapResult() method to your class which accepts function parameters with arity 0..10
*
* Eventually these could be generated for arbitrary method names via JSR-269
*/
interface MapResult<FunctionResultType, MethodResultType> {
MethodResultType mapResult(MetaFunction<FunctionResultType> handler);
default MethodResultType mapResult(F0<FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1> MethodResultType mapResult(F1<T1, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2> MethodResultType mapResult(F2<T1, T2, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3> MethodResultType mapResult(F3<T1, T2, T3, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4> MethodResultType mapResult(F4<T1, T2, T3, T4, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5> MethodResultType mapResult(F5<T1, T2, T3, T4, T5, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6> MethodResultType mapResult(F6<T1, T2, T3, T4, T5, T6, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7> MethodResultType mapResult(F7<T1, T2, T3, T4, T5, T6, T7, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7, T8> MethodResultType mapResult(F8<T1, T2, T3, T4, T5, T6, T7, T8, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7, T8, T9> MethodResultType mapResult(F9<T1, T2, T3, T4, T5, T6, T7, T8, T9, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> MethodResultType mapResult(F10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
}
/**
* Applies the function with a dynamic number of args. Shitty implementation, but hey it works.
*/
@SuppressWarnings("unchecked")
default final Result apply(Object... args) {
for(Method method : this.getClass().getDeclaredMethods()) {
if(method.getName().equals("apply") && !Arrays.deepEquals(method.getParameterTypes(), new Object[]{Object[].class})) {
try {
return (Result) method.invoke(this, args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
throw new IllegalStateException("This function class does not have an application method!");
}
}
@sberan
Copy link
Author

sberan commented Dec 14, 2012

Hey Brian, here it is! The MetaFunction stuff would hopefully be a library on its own, because I'm sure this will be a common need for library implementors. Looking forward to hearing your thoughts!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment