package com.codepoetics.octarine.joins;
import com.codepoetics.octarine.functional.tuples.T2;
import com.codepoetics.octarine.records.ListKey;
import com.codepoetics.octarine.records.Record;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
public final class RecordJoiner<K> {
private final Index<K, Record> leftIndex;
private final JoinKey<Record, K> primaryKey;
public RecordJoiner(Index<K, Record> leftIndex, JoinKey<Record, K> primaryKey) {
this.leftIndex = leftIndex;
this.primaryKey = primaryKey;
}
// Many to one
public Stream<Record> manyToOne(Collection<? extends Record> rights) {
return manyToOne(rights.stream());
}
public Stream<Record> manyToOne(Fetcher<K, Record> fetcher) {
return manyToOne(fetcher.fetch(leftIndex.keys()));
}
public Stream<Record> manyToOne(Stream<? extends Record> rights) {
return leftIndex.manyToOne(primaryKey.index(rights)).map(recordIntoRecord());
}
// Strict many to one
public Stream<Record> strictManyToOne(Collection<? extends Record> rights) {
return strictManyToOne(rights.stream());
}
public Stream<Record> strictManyToOne(Fetcher<K, Record> fetcher) {
return strictManyToOne(fetcher.fetch(leftIndex.keys()));
}
public Stream<Record> strictManyToOne(Stream<? extends Record> rights) {
return leftIndex.strictManyToOne(primaryKey.index(rights)).map(recordIntoRecord());
}
// One to many
public Stream<Record> oneToMany(Collection<? extends Record> rights, ListKey<Record> manyKey) {
return oneToMany(rights.stream(), manyKey);
}
public Stream<Record> oneToMany(Fetcher<K, Record> fetcher, ListKey<Record> manyKey) {
return oneToMany(fetcher.fetch(leftIndex.keys()), manyKey);
}
public Stream<Record> oneToMany(Stream<? extends Record> rights, ListKey<Record> manyKey) {
return leftIndex.oneToMany(primaryKey.index(rights)).map(recordsIntoRecord(manyKey));
}
// Strict one to many
public Stream<Record> strictOneToMany(Collection<? extends Record> rights, ListKey<Record> manyKey) {
return strictOneToMany(rights.stream(), manyKey);
}
public Stream<Record> strictOneToMany(Fetcher<K, Record> fetcher, ListKey<Record> manyKey) {
return strictOneToMany(fetcher.fetch(leftIndex.keys()), manyKey);
}
public Stream<Record> strictOneToMany(Stream<? extends Record> rights, ListKey<Record> manyKey) {
return leftIndex.strictOneToMany(primaryKey.index(rights)).map(recordsIntoRecord(manyKey));
}
// Strict one to one
public Stream<Record> strictOneToOne(Collection<? extends Record> rights) {
return strictOneToOne(rights.stream());
}
public Stream<Record> strictOneToOne(Fetcher<K, Record> fetcher) {
return strictOneToOne(fetcher.fetch(leftIndex.keys()));
}
public Stream<Record> strictOneToOne(Stream<? extends Record> rights) {
return leftIndex.strictOneToOne(primaryKey.index(rights)).map(recordIntoRecord());
}
private Function<T2<Record, Record>, Record> recordIntoRecord() {
return t -> t.pack(Record::with);
}
private Function<T2<Record, Set<Record>>, Record> recordsIntoRecord(ListKey<Record> key) {
return t -> t.pack((f, s) -> f.with(key.of(s)));
}
}