Skip to content

Commit

Permalink
[vividus] Add INNER_JOIN table transformer
Browse files Browse the repository at this point in the history
  • Loading branch information
VolhaHurynovich committed Mar 13, 2023
1 parent ae8dc94 commit e6e6f35
Show file tree
Hide file tree
Showing 6 changed files with 392 additions and 0 deletions.
94 changes: 94 additions & 0 deletions docs/modules/commons/pages/table-transformers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -516,3 +516,97 @@ Examples:
|value |1 |
|value2|0 |
----

== INNER_JOIN

`INNER_JOIN` transformer combines rows from two tables whenever there are matching values between the columns.

[cols="1,3", options="header"]
|===
|Parameter
|Description

|`leftTableJoinColumn`
|the column name for matching in the left table

|`rightTableJoinColumn`
|the column name for matching in the right table

|`tables`
|xref:ROOT:glossary.adoc#_examplestable[ExamplesTable]-s to join
|===

- `left` table is the first xref:ROOT:glossary.adoc#_examplestable[ExamplesTable] declared in `tables` parameter,
- `right` table is the second xref:ROOT:glossary.adoc#_examplestable[ExamplesTable] declared in `tables` parameter or table body put under the transformer definition.

[IMPORTANT]
====
* The number of used xref:ROOT:glossary.adoc#_examplestable[ExamplesTable]-s must be equal to 2 (`left` and `right`).
* The column names of input tables must be different (except the column names for matching).
* If any of tables is empty - the resulting table will also be empty.
====

.Usage of INNER_JOIN transformer with table body
[source,gherkin]
----
{transformer=INNER_JOIN, leftTableJoinColumn=joinID, rightTableJoinColumn=joinID, tables=/tables/some-table.table}
|joinID|column2|
|5 |row25 |
|3 |row23 |
|1 |row21 |
----

where xref:ROOT:glossary.adoc#_examplestable[ExamplesTable] from /tables/some-table.table:

[source,gherkin]
----
|joinID|column1|
|1 |row11 |
|2 |row12 |
|3 |row13 |
|4 |row14 |
----

will result in the following xref:ROOT:glossary.adoc#_examplestable[ExamplesTable]:

[source,gherkin]
----
|column1|joinID|column2|
|row11 |1 |row21 |
|row13 |3 |row23 |
----

.Usage of INNER_JOIN transformer with the same column names for matching
[source,gherkin]
----
{transformer=INNER_JOIN, leftTableJoinColumn=joinID, rightTableJoinColumn=joinID, tables= /tables/test1.table;/tables/test2.table}
----

.Usage of INNER_JOIN transformer with the different column names for matching
[source,gherkin]
----
{transformer=INNER_JOIN, leftTableJoinColumn=joinID1, rightTableJoinColumn=joinID2, tables=/tables/test1.table;/tables/test2.table}
----

.Usage of INNER_JOIN transformer with nested tables
[source,gherkin]
----
{
transformer=INNER_JOIN,
leftTableJoinColumn=joinID,
rightTableJoinColumn=joinID,
tables=
\{
transformer=FROM_EXCEL\,
path=TestTemplate.xlsx\,
sheet=Data\, addresses=A2\;A3\,
column=joinID
\};
\{
transformer=FROM_EXCEL\,
path=TestTemplate.xlsx\,
sheet=Data\, range=B2:B4\,
column=joinID
\}
}
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
|column1|joinID|column2|column3|
|row11 |1 |row21 |row31 |
|row12 |2 |row22 |row32 |
|row13 |3 |row23 |row33 |
|row133 |3 |row233 |row333 |
|row14 |4 |row24 |row34 |
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,29 @@ Examples:
|2 |
|1 |
|0 |

Scenario: Verify INNER_JOIN transformer with empty table (should not be executed)
Meta:
@requirementId 1810
Then `should` is equal to `be skipped`
Examples:
{transformer=INNER_JOIN, leftTableJoinColumn=joinID, rightTableJoinColumn=joinID1, tables=/data/for-inner-join-transformer.table}
|joinID1 |

Scenario: Verify INNER_JOIN transformer with table body
Meta:
@requirementId 1810
When I initialize scenario variable `innerJoinTable` with values:
{transformer=INNER_JOIN, leftTableJoinColumn=joinID, rightTableJoinColumn=joinID, tables=/data/for-inner-join-transformer.table}
|joinID|column4|column5|
|5 |row45 |row51 |
|3 |row43 |row53 |
|1 |row41 |row51 |
|3 |row433 |row533 |
Then `${innerJoinTable}` is equal to table:
|column1|joinID|column5|column4|column3|column2|
|row11 |1 |row51 |row41 |row31 |row21 |
|row13 |3 |row53 |row43 |row33 |row23 |
|row13 |3 |row533 |row433 |row33 |row23 |
|row133 |3 |row53 |row43 |row333 |row233 |
|row133 |3 |row533 |row433 |row333 |row233 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2019-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.transformer;

import static org.apache.commons.lang3.Validate.isTrue;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.jbehave.core.model.ExamplesTable;
import org.jbehave.core.model.ExamplesTable.TableProperties;
import org.jbehave.core.model.TableParsers;
import org.vividus.util.ExamplesTableProcessor;

public class InnerJoinTableTransformer extends AbstractTableLoadingTransformer
{
public InnerJoinTableTransformer()
{
super(false);
}

@Override
public String transform(String tableAsString, TableParsers tableParsers, TableProperties properties)
{
List<ExamplesTable> tables = loadTables(tableAsString, properties);
isTrue(tables.size() == 2, "Please, specify only two ExamplesTable-s");
ExamplesTable leftTable = tables.get(0);
ExamplesTable rightTable = tables.get(1);
String leftTableJoinColumn = properties.getMandatoryNonBlankProperty("leftTableJoinColumn", String.class);
String rightTableJoinColumn = properties.getMandatoryNonBlankProperty("rightTableJoinColumn", String.class);
isTrue(leftTable.getHeaders().contains(leftTableJoinColumn),
"The left table doesn't contain the following column: %s", leftTableJoinColumn);
isTrue(rightTable.getHeaders().contains(rightTableJoinColumn),
"The right table doesn't contain the following column: %s", rightTableJoinColumn);
Set<String> repeatingKeys = leftTable.getHeaders().stream()
.filter(e -> !e.equals(leftTableJoinColumn) && rightTable.getHeaders().contains(e))
.collect(Collectors.toSet());
isTrue(repeatingKeys.isEmpty(), "Tables must contain different columns (except joint column),"
+ " but found the same columns: %s", repeatingKeys);

ExamplesTable resultTable = innerJoin(leftTable, rightTable, leftTableJoinColumn, rightTableJoinColumn);
return resultTable.isEmpty() ? getEmptyTableWithHeaders(tables, properties) : resultTable.asString();
}

private static ExamplesTable innerJoin(ExamplesTable leftTable, ExamplesTable rightTable,
String leftTableJoinColumn, String rightTableJoinColumn)
{
List<Map<String, String>> leftRows = leftTable.getRows();
List<Map<String, String>> rightRows = rightTable.getRows();
Map<String, List<Map<String, String>>> rightByColumn = rightRows.stream()
.collect(Collectors.groupingBy(m -> m.get(rightTableJoinColumn)));
List<Map<String, String>> examplesTableRows = leftRows.stream()
.filter(row -> rightByColumn.containsKey(row.get(leftTableJoinColumn)))
.flatMap(leftRow -> rightByColumn.get(leftRow.get(leftTableJoinColumn)).stream()
.map(rightRow -> {
Map<String, String> jointRow = new HashMap<>();
jointRow.putAll(leftRow);
jointRow.putAll(rightRow);
return jointRow;
})).collect(Collectors.toList());
return ExamplesTable.empty().withRows(examplesTableRows);
}

private static String getEmptyTableWithHeaders(List<ExamplesTable> tables, TableProperties tableProperties)
{
Set<String> headers = tables.stream().map(ExamplesTable::getHeaders)
.flatMap(List::stream).collect(Collectors.toSet());
return ExamplesTableProcessor.buildExamplesTable(headers, List.of(), tableProperties);
}
}
1 change: 1 addition & 0 deletions vividus/src/main/resources/org/vividus/spring-vividus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
<bean id="DISTINCTING" class="org.vividus.transformer.DistinctingTableTransformer" />
<bean id="FILTERING" class="org.vividus.transformer.FilteringTableTransformer" />
<bean id="INDEXING" class="org.vividus.transformer.IndexingTableTransformer" />
<bean id="INNER_JOIN" class="org.vividus.transformer.InnerJoinTableTransformer" />
<bean id="ITERATING" class="org.vividus.transformer.IteratingTableTransformer" />
<bean id="JOINING" class="org.vividus.transformer.JoiningTableTransformer" />
<bean id="MERGING" class="org.vividus.transformer.MergingTableTransformer" />
Expand Down
Loading

0 comments on commit e6e6f35

Please sign in to comment.