Skip to content

Commit

Permalink
Introduced join(..).on(..) clause.
Browse files Browse the repository at this point in the history
  • Loading branch information
cbuschka committed Nov 5, 2023
1 parent 4a895dd commit fb5ef6d
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 40 deletions.
11 changes: 4 additions & 7 deletions src/main/java/io/github/cbuschka/objset/BiSelect.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@

public interface BiSelect<Element1, Element2> {

<Element3, Key> TriSelect<Element1, Element2, Element3> join(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> key1Func, Function<Element3, Key> key2Func);

<Element3, Key> TriSelect<Element1, Element2, Element3> leftOuterJoin(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> key1Func, Function<Element3, Key> key2Func);

<Element3, Key> TriSelect<Element1, Element2, Element3> rightOuterJoin(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> key1Func, Function<Element3, Key> key2Func);

<Element3, Key> TriSelect<Element1, Element2, Element3> fullOuterJoin(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> key1Func, Function<Element3, Key> key2Func);
<Element3> BiSelectJoin<Element1, Element2, Element3> join(Iterable<Element3> element3s);
<Element3> BiSelectJoin<Element1, Element2, Element3> leftOuterJoin(Iterable<Element3> element3s);
<Element3> BiSelectJoin<Element1, Element2, Element3> rightOuterJoin(Iterable<Element3> element3s);
<Element3> BiSelectJoin<Element1, Element2, Element3> fullOuterJoin(Iterable<Element3> element3s);

BiStream<Element1, Element2> stream();

Expand Down
8 changes: 8 additions & 0 deletions src/main/java/io/github/cbuschka/objset/BiSelectJoin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.cbuschka.objset;

import java.util.function.BiFunction;
import java.util.function.Function;

public interface BiSelectJoin<Element1, Element2, Element3> {
<Key> FilterableTriSelect<Element1, Element2, Element3> on(BiFunction<Element1, Element2, Key> element1KeyFunc, Function<Element3, Key> element2KeyFunc);
}
11 changes: 4 additions & 7 deletions src/main/java/io/github/cbuschka/objset/UniSelect.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@
import java.util.stream.Stream;

public interface UniSelect<Element1> {
<Element2, Key> FilterableBiSelect<Element1, Element2> join(Iterable<Element2> element2s, Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc);

<Element2, Key> FilterableBiSelect<Element1, Element2> leftOuterJoin(Iterable<Element2> element2s, Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc);

<Element2, Key> FilterableBiSelect<Element1, Element2> rightOuterJoin(Iterable<Element2> element2s, Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc);

<Element2, Key> FilterableBiSelect<Element1, Element2> fullOuterJoin(Iterable<Element2> element2s, Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc);
<Element2> UniSelectJoin<Element1, Element2> join(Iterable<Element2> element2s);
<Element2> UniSelectJoin<Element1, Element2> leftOuterJoin(Iterable<Element2> element2s);
<Element2> UniSelectJoin<Element1, Element2> rightOuterJoin(Iterable<Element2> element2s);
<Element2> UniSelectJoin<Element1, Element2> fullOuterJoin(Iterable<Element2> element2s);

Stream<Element1> stream();

Expand Down
7 changes: 7 additions & 0 deletions src/main/java/io/github/cbuschka/objset/UniSelectJoin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.cbuschka.objset;

import java.util.function.Function;

public interface UniSelectJoin<Element1, Element2> {
<Key> FilterableBiSelect<Element1, Element2> on(Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc);
}
16 changes: 8 additions & 8 deletions src/main/java/io/github/cbuschka/objset/impl/BiSelectImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@ public BiStream<Element1, Element2> stream() {
}

@Override
public <Element3, Key> TriSelect<Element1, Element2, Element3> join(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> element1And2KeyFunc, Function<Element3, Key> element3KeyFunc) {
return new TriSelectImpl<>(JoinIterator.forInnerJoin(source, (t) -> element1And2KeyFunc.apply(t.element1(), t.element2()), element3s, element3KeyFunc, (left, right) -> Triple.of(left.element1(), left.element2(), right)));
public <Element3> BiSelectJoin<Element1, Element2, Element3> join(Iterable<Element3> element3s) {
return new BiSelectJoinImpl<>(JoinMode.INNER, source, element3s);
}

@Override
public <Element3, Key> TriSelect<Element1, Element2, Element3> leftOuterJoin(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> element1And2KeyFunc, Function<Element3, Key> element3KeyFunc) {
return new TriSelectImpl<>(JoinIterator.forLeftOuterJoin(source, (t) -> element1And2KeyFunc.apply(t.element1(), t.element2()), element3s, element3KeyFunc, (left, right) -> Triple.of(left.element1(), left.element2(), right)));
public <Element3> BiSelectJoin<Element1, Element2, Element3> leftOuterJoin(Iterable<Element3> element3s) {
return new BiSelectJoinImpl<>(JoinMode.LEFT_OUTER, source, element3s);
}

@Override
public <Element3, Key> TriSelect<Element1, Element2, Element3> rightOuterJoin(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> element1And2KeyFunc, Function<Element3, Key> element3KeyFunc) {
return new TriSelectImpl<>(JoinIterator.forRightOuterJoin(source, (t) -> element1And2KeyFunc.apply(t.element1(), t.element2()), element3s, element3KeyFunc, (left, rigth) -> Triple.of(left.element1(), left.element2(), rigth)));
public <Element3> BiSelectJoin<Element1, Element2, Element3> rightOuterJoin(Iterable<Element3> element3s) {
return new BiSelectJoinImpl<>(JoinMode.RIGHT_OUTER, source, element3s);
}

@Override
public <Element3, Key> TriSelect<Element1, Element2, Element3> fullOuterJoin(Iterable<Element3> element3s, BiFunction<Element1, Element2, Key> element1And2KeyFunc, Function<Element3, Key> element3KeyFunc) {
return new TriSelectImpl<>(JoinIterator.forFullOuterJoin(source, (t) -> element1And2KeyFunc.apply(t.element1(), t.element2()), element3s, element3KeyFunc, (left, rigth) -> Triple.of(left.element1(), left.element2(), rigth)));
public <Element3> BiSelectJoin<Element1, Element2, Element3> fullOuterJoin(Iterable<Element3> element3s) {
return new BiSelectJoinImpl<>(JoinMode.FULL_OUTER, source, element3s);
}
}
19 changes: 19 additions & 0 deletions src/main/java/io/github/cbuschka/objset/impl/BiSelectJoinImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.github.cbuschka.objset.impl;

import io.github.cbuschka.objset.*;
import lombok.AllArgsConstructor;

import java.util.function.BiFunction;
import java.util.function.Function;

@AllArgsConstructor
class BiSelectJoinImpl<Element1, Element2, Element3> implements BiSelectJoin<Element1, Element2, Element3> {
private final JoinMode joinMode;
private final Iterable<Pair<Element1, Element2>> source;
private final Iterable<Element3> element3s;

@Override
public <Key> FilterableTriSelect<Element1, Element2, Element3> on(BiFunction<Element1, Element2, Key> element1And2KeyFunc, Function<Element3, Key> element3KeyFunc) {
return new TriSelectImpl<>(JoinIterator.of(joinMode, source, (t) -> element1And2KeyFunc.apply(t.element1(), t.element2()), element3s, element3KeyFunc, (left, right) -> Triple.of(left.element1(), left.element2(), right)));
}
}
17 changes: 16 additions & 1 deletion src/main/java/io/github/cbuschka/objset/impl/JoinIterator.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ public abstract class JoinIterator<Left, Right, Key, Result> implements Iterator
private final BiFunction<Left, Right, Result> resultMapFunction;
private final List<Result> buffer = new LinkedList<>();

public static <Left, Right, Key, Result> Iterable<Result> of(JoinMode joinMode, Iterable<Left> lefts, Function<Left, Key> leftKeyFunction, Iterable<Right> rights, Function<Right, Key> rightKeyFunction, BiFunction<Left, Right, Result> resultMapFunction) {
switch (joinMode) {
case INNER:
return forInnerJoin(lefts, leftKeyFunction, rights, rightKeyFunction, resultMapFunction);
case FULL_OUTER:
return forFullOuterJoin(lefts, leftKeyFunction, rights, rightKeyFunction, resultMapFunction);
case LEFT_OUTER:
return forLeftOuterJoin(lefts, leftKeyFunction, rights, rightKeyFunction, resultMapFunction);
case RIGHT_OUTER:
return forRightOuterJoin(lefts, leftKeyFunction, rights, rightKeyFunction, resultMapFunction);
default:
throw new IllegalArgumentException("Invalid join mode: " + joinMode + ".");
}
}

public static <Left, Right, Key, Result> Iterable<Result> forFullOuterJoin(Iterable<Left> lefts, Function<Left, Key> leftKeyFunction, Iterable<Right> rights, Function<Right, Key> rightKeyFunction, BiFunction<Left, Right, Result> resultMapFunction) {
return () -> new FullOuterJoinIterator<>(lefts, leftKeyFunction, rights, rightKeyFunction, resultMapFunction);
}
Expand Down Expand Up @@ -60,7 +75,7 @@ public Stream<Result> stream() {

protected <Element> Map<Key, List<Element>> getElementsByKeyMap(Iterable<Element> elements, Function<Element, Key> keyFunction) {
Map<Key, List<Element>> elementsByKey = new HashMap<>();
for(Element element : elements) {
for (Element element : elements) {
Key key = keyFunction.apply(element);
elementsByKey
.computeIfAbsent(key, k -> new ArrayList<>())
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/io/github/cbuschka/objset/impl/JoinMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.cbuschka.objset.impl;

enum JoinMode {
INNER,
LEFT_OUTER,
RIGHT_OUTER,
FULL_OUTER;
}
21 changes: 11 additions & 10 deletions src/main/java/io/github/cbuschka/objset/impl/UniSelectImpl.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.github.cbuschka.objset.impl;

import io.github.cbuschka.objset.*;
import io.github.cbuschka.objset.FilterableUniSelect;
import io.github.cbuschka.objset.UniSelect;
import io.github.cbuschka.objset.UniSelectJoin;

import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
Expand All @@ -15,23 +16,23 @@ public UniSelectImpl(Iterable<Element1> elements) {
}

@Override
public <Element2, KeyType> FilterableBiSelect<Element1, Element2> join(Iterable<Element2> element2s, Function<Element1, KeyType> element1KeyFunc, Function<Element2, KeyType> element2KeyFunc) {
return new BiSelectImpl<>(JoinIterator.forInnerJoin(elements, element1KeyFunc, element2s, element2KeyFunc, Pair::of));
public <Element2> UniSelectJoin<Element1, Element2> join(Iterable<Element2> element2s) {
return new UniSelectJoinImpl<>(JoinMode.INNER, elements, element2s);
}

@Override
public <Element2, KeyType> FilterableBiSelect<Element1, Element2> leftOuterJoin(Iterable<Element2> element2s, Function<Element1, KeyType> element1KeyFunc, Function<Element2, KeyType> element2KeyFunc) {
return new BiSelectImpl<>(JoinIterator.forLeftOuterJoin(elements, element1KeyFunc, element2s, element2KeyFunc, Pair::of));
public <Element2> UniSelectJoin<Element1, Element2> leftOuterJoin(Iterable<Element2> element2s) {
return new UniSelectJoinImpl<>(JoinMode.LEFT_OUTER, elements, element2s);
}

@Override
public <Element2, Key> FilterableBiSelect<Element1, Element2> rightOuterJoin(Iterable<Element2> element2s, Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc) {
return new BiSelectImpl<>(JoinIterator.forRightOuterJoin(elements, element1KeyFunc, element2s, element2KeyFunc, Pair::of));
public <Element2> UniSelectJoin<Element1, Element2> rightOuterJoin(Iterable<Element2> element2s) {
return new UniSelectJoinImpl<>(JoinMode.RIGHT_OUTER, elements, element2s);
}

@Override
public <Element2, Key> FilterableBiSelect<Element1, Element2> fullOuterJoin(Iterable<Element2> element2s, Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc) {
return new BiSelectImpl<>(JoinIterator.forFullOuterJoin(elements, element1KeyFunc, element2s, element2KeyFunc, Pair::of));
public <Element2> UniSelectJoin<Element1, Element2> fullOuterJoin(Iterable<Element2> element2s) {
return new UniSelectJoinImpl<>(JoinMode.FULL_OUTER, elements, element2s);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.cbuschka.objset.impl;

import io.github.cbuschka.objset.FilterableBiSelect;
import io.github.cbuschka.objset.Pair;
import io.github.cbuschka.objset.UniSelectJoin;
import lombok.AllArgsConstructor;

import java.util.function.Function;

@AllArgsConstructor
class UniSelectJoinImpl<Element1, Element2> implements UniSelectJoin<Element1, Element2> {
private final JoinMode joinMode;
private final Iterable<Element1> elements;
private final Iterable<Element2> element2s;

@Override
public <Key> FilterableBiSelect<Element1, Element2> on(Function<Element1, Key> element1KeyFunc, Function<Element2, Key> element2KeyFunc) {
return new BiSelectImpl<>(JoinIterator.of(joinMode, elements, element1KeyFunc, element2s, element2KeyFunc, Pair::of));

}
}
6 changes: 3 additions & 3 deletions src/test/java/io/github/cbuschka/objset/BiOpsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void joinTwoEntities() {
givenIsPerson2WithoutAddress();

whenQueried((persons, addresses) -> ObjectQuery.selectFrom(persons)
.join(addresses, Person::getId, Address::getPersonId)
.join(addresses).on(Person::getId, Address::getPersonId)
.toList());

assertThat(result).containsExactly(Pair.of(person1, address1), Pair.of(person1, address2));
Expand All @@ -56,7 +56,7 @@ void leftOuterJoinTwoEntities() {
givenIsPerson2WithoutAddress();

whenQueried((persons, addresses) -> ObjectQuery.selectFrom(persons)
.leftOuterJoin(addresses, Person::getId, Address::getPersonId)
.leftOuterJoin(addresses).on(Person::getId, Address::getPersonId)
.toList());

assertThat(result).containsExactly(Pair.of(person1, address1), Pair.of(person1, address2),
Expand All @@ -69,7 +69,7 @@ void filteredOfTwoEntities() {
givenIsPerson2WithoutAddress();

whenQueried((persons, addresses) -> ObjectQuery.selectFrom(persons)
.leftOuterJoin(addresses, Person::getId, Address::getPersonId)
.leftOuterJoin(addresses).on(Person::getId, Address::getPersonId)
.where((i, s) -> s != address2)
.toList());

Expand Down
8 changes: 4 additions & 4 deletions src/test/java/io/github/cbuschka/objset/TriOpsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ void joinThreeEntities() {
givenPerson2WithoutAddressesAndOrder();

whenQueried((persons, addresses, orders) -> ObjectQuery.selectFrom(persons)
.join(addresses, Person::getId, Address::getPersonId)
.join(orders, (person, address) -> person.getId(), Order::getPersonId)
.join(addresses).on(Person::getId, Address::getPersonId)
.join(orders).on((person, address) -> person.getId(), Order::getPersonId)
.toList());

assertThat(result).containsExactly(Triple.of(person1, address1, order1),
Expand Down Expand Up @@ -68,8 +68,8 @@ void filteredOfThreeEntities() {
givenPerson2WithoutAddressesAndOrder();

whenQueried((persons, addresses, orders) -> ObjectQuery.selectFrom(persons)
.join(addresses, Person::getId, Address::getPersonId)
.join(orders, (person, address) -> person.getId(), Order::getPersonId)
.join(addresses).on(Person::getId, Address::getPersonId)
.join(orders).on((person, address) -> person.getId(), Order::getPersonId)
.where((i, s, ss) -> s != address2)
.toList());

Expand Down

0 comments on commit fb5ef6d

Please sign in to comment.