Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/147 improve select #150

Merged
merged 2 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/main/java/com/homihq/db2rest/mybatis/MyBatisTable.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.homihq.db2rest.mybatis;

import lombok.*;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.SqlTable;
import schemacrawler.schema.Column;
Expand All @@ -22,6 +24,8 @@ public class MyBatisTable extends SqlTable{

Table table;

boolean root;

public MyBatisTable(String schemaName, String tableName, Table table) {
super(tableName);
this.tableName = tableName;
Expand All @@ -41,4 +45,20 @@ public void addColumn(Column column) {
public void addColumn(String columnName, String alias) {
sqlColumnList.add(column(columnName).as(alias));
}

@Override
public boolean equals(Object o) {
if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

MyBatisTable table = (MyBatisTable) o;

return new EqualsBuilder().append(tableName, table.tableName).isEquals();
}

@Override
public int hashCode() {
return new HashCodeBuilder(17, 37).append(tableName).toHashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class ReadController {

@GetMapping(value = "/{tableName}" , produces = "application/json")
public Object findByJoinTable(@PathVariable String tableName,
@RequestHeader(name = "Accept-Profile") String schemaName,
@RequestHeader(name = "Accept-Profile", required = false) String schemaName,
@RequestParam(name = "select", required = false, defaultValue = "") String select,
@RequestParam(name = "filter", required = false, defaultValue = "") String filter,
Sort sort,
Expand Down
31 changes: 8 additions & 23 deletions src/main/java/com/homihq/db2rest/rest/read/ReadService.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
package com.homihq.db2rest.rest.read;

import com.homihq.db2rest.config.Db2RestConfigProperties;
import com.homihq.db2rest.rest.read.helper.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.mybatis.dynamic.sql.SqlTable;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Map;


@Service
@Slf4j
@RequiredArgsConstructor
public class ReadService {

private final JdbcTemplate jdbcTemplate;
private final SelectBuilder selectBuilder;
private final JoinBuilder joinBuilder;
private final WhereBuilder whereBuilder;
private final LimitPaginationBuilder limitPaginationBuilder;
private final SortBuilder sortBuilder;

private final Db2RestConfigProperties db2RestConfigProperties;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;

public Object findAll(String schemaName, String tableName, String select, String filter,
Pageable pageable, Sort sort) {
ReadContext ctx = ReadContext.builder().from(SqlTable.of(tableName))
ReadContext ctx = ReadContext.builder()
.pageable(pageable).sort(sort)
.schemaName(schemaName).tableName(tableName).select(select).filter(filter).build();

.schemaName(schemaName)
.tableName(tableName).select(select).filter(filter).build();

selectBuilder.build(ctx);
joinBuilder.build(ctx);
Expand All @@ -42,23 +37,13 @@ public Object findAll(String schemaName, String tableName, String select, String
sortBuilder.build(ctx);

String sql = ctx.prepareSQL();

log.info("SQL - {}", sql);

/*
Query query = createQuery(schemaName, tableName,select,filter, joinTable, pageable);

String sql = query.getSQL();
List<Object> bindValues = query.getBindValues();
Map<String,Object> bindValues = ctx.prepareParameters();

log.info("SQL - {}", sql);
log.info("Bind variables - {}", bindValues);

return jdbcTemplate.queryForList(sql, bindValues.toArray());

*/
return namedParameterJdbcTemplate.queryForList(sql, bindValues);

return new ArrayList();
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ public class JoinBuilder {
private final SchemaManager schemaManager;

public void build(ReadContext context) {

if(context.isUnion()) return;

List<MyBatisTable> tableList = context.getTables();

log.info("Table list - {}", tableList);

if(tableList.size() > 1) { //table join required
for(int i = 0 ; i < tableList.size() ; i = i + 2) {
MyBatisTable root = tableList.get(i);
Expand Down
84 changes: 72 additions & 12 deletions src/main/java/com/homihq/db2rest/rest/read/helper/ReadContext.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package com.homihq.db2rest.rest.read.helper;

import com.homihq.db2rest.exception.GenericDataAccessException;
import com.homihq.db2rest.mybatis.MyBatisTable;
import lombok.*;
import org.mybatis.dynamic.sql.BasicColumn;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.SqlCriterion;
import org.mybatis.dynamic.sql.SqlTable;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
import org.mybatis.dynamic.sql.select.SelectModel;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.mybatis.dynamic.sql.select.SelectDSL.select;

Expand All @@ -30,22 +36,19 @@ public class ReadContext {
Pageable pageable;
Sort sort;

SqlTable from;
MyBatisTable from;
List<MyBatisTable> tables;

QueryExpressionDSL<SelectModel> queryExpressionDSL;
boolean union;

QueryExpressionDSL<SelectModel> queryExpressionDSL;
SelectStatementProvider selectStatementProvider;

public void addWhereClause(SqlCriterion condition) {
queryExpressionDSL.where(condition);
}

private List<BasicColumn> getAllColumns() {
return tables.stream()
.flatMap(t -> t.getSqlColumnList().stream())
.map(t -> (BasicColumn)t)
.toList();
}


public SqlColumn<?> getSortColumn(String columnName) {
//for now just support root table
Expand All @@ -57,16 +60,73 @@ public void createSelect() {

List<BasicColumn> columns = getAllColumns();

queryExpressionDSL = select(columns).from(from);
detectUnion();

if(union) {
createUnionQuery();
}
else{
from = getRootTable();
queryExpressionDSL = select(columns).from(from, from.getAlias());
}

}

public String prepareSQL() {
private MyBatisTable getRootTable() {
return
tables.stream().filter(MyBatisTable::isRoot).findFirst()
.orElseThrow(() -> new GenericDataAccessException("Unable to detect root table."));
}

private void createUnionQuery() {

for(MyBatisTable table : tables) {

if(Objects.isNull(queryExpressionDSL)) {

queryExpressionDSL = select(getAllColumns()).from(table, table.getAlias());
}
else {
queryExpressionDSL.union().
select(getAllColumns()).from(table, table.getAlias());
}
}

return queryExpressionDSL.build().render(RenderingStrategies.SPRING_NAMED_PARAMETER).getSelectStatement();

}

private void detectUnion() {
Set<MyBatisTable> result = tables.stream()
.collect(Collectors.groupingBy(Function.identity()
, Collectors.counting()))
.entrySet().stream()
.filter(m -> m.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());

union = (this.tables.size() == result.size()) && result.size() > 1;

if(result.size() > 1 && this.tables.size() > result.size())
throw new GenericDataAccessException("Unable to create SQL. Seems union but too many tables.");
}

private List<BasicColumn> getAllColumns() {
return tables.stream()
.flatMap(t -> t.getSqlColumnList().stream())
.map(t -> (BasicColumn)t)
.toList();
}

public String prepareSQL() {

selectStatementProvider = queryExpressionDSL.build().render(RenderingStrategies.SPRING_NAMED_PARAMETER);

return this.selectStatementProvider.getSelectStatement();

}

public Map<String,Object> prepareParameters() {
return this.selectStatementProvider.getParameters();
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.homihq.db2rest.rest.read.helper;

import com.homihq.db2rest.config.Db2RestConfigProperties;
import com.homihq.db2rest.mybatis.MyBatisTable;
import com.homihq.db2rest.schema.SchemaManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
Expand All @@ -15,6 +17,7 @@
public class SelectBuilder{

private final SchemaManager schemaManager;
private final Db2RestConfigProperties db2RestConfigProperties;

public void build(ReadContext context) {
context.setTables(createTables(context));
Expand All @@ -24,30 +27,42 @@ public void build(ReadContext context) {

private List<MyBatisTable> createTables(ReadContext context) {
List<MyBatisTable> tables = new ArrayList<>();

log.info("context.select - {}", context.select);
//split to get all fragments
String [] tabCols = context.select.split(";");

int counter = 0;

log.info("tabCols - {}", tabCols.length);

//process the fragments
for(String tabCol : tabCols) {
MyBatisTable table;
List<MyBatisTable> myBatisTables;

//check for presence of open '(' and close ')' brackets
//now check for embedded table and columns.
if(tabCol.contains("(") && tabCol.contains(")")) { //join table
if(tabCol.contains("(") && tabCol.contains(")")) { //join tables

String joinTableName = tabCol.substring(0, tabCol.indexOf("("));
//look for columns
String colString = tabCol.substring(tabCol.indexOf("(") + 1 , tabCol.indexOf(")"));
table = createTable(context.schemaName, joinTableName, colString, counter);
myBatisTables = createTables(context.schemaName, joinTableName, colString, counter);
}
else{ //root table
table = createTable(context.schemaName, context.tableName, tabCol, counter);

log.info("Creating root tables");
myBatisTables = createTables(context.schemaName, context.tableName, tabCol, counter);

log.info("myBatisTables - {}", myBatisTables);

for(MyBatisTable table : myBatisTables) {
table.setRoot(true);
}

//TODO - multiple root tables and no other table = union query, else unsupported exception

}
tables.add(table);
tables.addAll(myBatisTables);

counter++;
}
Expand All @@ -56,15 +71,40 @@ private List<MyBatisTable> createTables(ReadContext context) {
return tables;
}

private MyBatisTable createTable(String schemaName, String tableName, String colStr, int counter) {

//MyBatisTable table = schemaManager.findTable(schemaName, tableName, counter);
private List<MyBatisTable> createTables(String schemaName, String tableName, String colStr, int counter) {

String sName = schemaName;
String tName = tableName;


if(!this.db2RestConfigProperties.getMultiTenancy().isEnabled()) {
String [] tableNameParts = tableName.split("|.");

if(tableNameParts.length == 2) { //table name contains schema
sName = tableNameParts[0];
tName = tableNameParts[1];
}
}

if(StringUtils.isNotBlank(sName)) {
MyBatisTable table = schemaManager.findTable(sName, tName, counter);

addColumns(table, colStr);

return List.of(table);
}
else {
List<MyBatisTable> tables = schemaManager.findTables(tName);

MyBatisTable table = schemaManager.findTable(schemaName, tableName, counter);
for(MyBatisTable table : tables) {
addColumns(table, colStr);
}

return tables;
}

addColumns(table, colStr);

return table;
}

private void addColumns(MyBatisTable table, String colStr) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class WhereBuilder{
private final SchemaManager schemaManager;

public void build(ReadContext context) {
if(context.isUnion()) return;

if(StringUtils.isNotBlank(context.filter)) {

log.info("-Creating where condition -");
Expand Down
Loading
Loading