Created
December 13, 2012 15:45
-
-
Save sberan/4277292 to your computer and use it in GitHub Desktop.
DB query with lambda concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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<>()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!"); | |
} | |
} |
I've been toying around with this concept for a possible web library, and I've been able to get it working using type inference to infer the argument types. So it ends up being the order of () rather than (()!).
I have some code very much like this which is working, I can adapt it to this case and send it your way tonight.
Please do, I'd love it!
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
I like it a lot, actually. The biggest problem I see is the interface for whatever is being passed to MapResult. It would need to be overloaded with (on the order of) (( * )! ) as far as I understand lambdas interactions with interfaces.
Do you hav a scheme in mind for how to implement this?