mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
WIP on getting joins to frontend
This commit is contained in:
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class JoinGraph
|
||||||
|
{
|
||||||
|
private record Node(String tableName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private record Edge(String joinName, String leftTable, String rightTable)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static class CanonicalJoin
|
||||||
|
{
|
||||||
|
private String tableA;
|
||||||
|
private String tableB;
|
||||||
|
private String joinFieldA;
|
||||||
|
private String joinFieldB;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public CanonicalJoin(QJoinMetaData joinMetaData)
|
||||||
|
{
|
||||||
|
boolean needFlip = false;
|
||||||
|
int tableCompare = joinMetaData.getLeftTable().compareTo(joinMetaData.getRightTable());
|
||||||
|
if(tableCompare < 0)
|
||||||
|
{
|
||||||
|
needFlip = true;
|
||||||
|
}
|
||||||
|
else if(tableCompare == 0)
|
||||||
|
{
|
||||||
|
int fieldCompare = joinMetaData.getJoinOns().get(0).getLeftField().compareTo(joinMetaData.getJoinOns().get(0).getRightField());
|
||||||
|
if(fieldCompare < 0)
|
||||||
|
{
|
||||||
|
needFlip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needFlip)
|
||||||
|
{
|
||||||
|
joinMetaData = joinMetaData.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
tableA = joinMetaData.getLeftTable();
|
||||||
|
tableB = joinMetaData.getRightTable();
|
||||||
|
joinFieldA = joinMetaData.getJoinOns().get(0).getLeftField();
|
||||||
|
joinFieldB = joinMetaData.getJoinOns().get(0).getRightField();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
if(this == o)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(o == null || getClass() != o.getClass())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CanonicalJoin that = (CanonicalJoin) o;
|
||||||
|
return Objects.equals(tableA, that.tableA) && Objects.equals(tableB, that.tableB) && Objects.equals(joinFieldA, that.joinFieldA) && Objects.equals(joinFieldB, that.joinFieldB);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(tableA, tableB, joinFieldA, joinFieldB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private Set<Node> nodes = new HashSet<>();
|
||||||
|
private Set<Edge> edges = new HashSet<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public JoinGraph(QInstance qInstance)
|
||||||
|
{
|
||||||
|
Set<CanonicalJoin> usedJoins = new HashSet<>();
|
||||||
|
for(QJoinMetaData join : qInstance.getJoins().values())
|
||||||
|
{
|
||||||
|
CanonicalJoin canonicalJoin = new CanonicalJoin(join);
|
||||||
|
if(usedJoins.contains(canonicalJoin))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
usedJoins.add(canonicalJoin);
|
||||||
|
nodes.add(new Node(join.getLeftTable()));
|
||||||
|
nodes.add(new Node(join.getRightTable()));
|
||||||
|
edges.add(new Edge(join.getName(), join.getLeftTable(), join.getRightTable()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Set<String> getJoins(String tableName)
|
||||||
|
{
|
||||||
|
Set<String> rs = new HashSet<>();
|
||||||
|
Set<String> tables = new HashSet<>();
|
||||||
|
tables.add(tableName);
|
||||||
|
|
||||||
|
boolean keepGoing = true;
|
||||||
|
while(keepGoing)
|
||||||
|
{
|
||||||
|
keepGoing = false;
|
||||||
|
for(Edge edge : edges)
|
||||||
|
{
|
||||||
|
if(tables.contains(edge.leftTable) || tables.contains(edge.rightTable))
|
||||||
|
{
|
||||||
|
if(!rs.contains(edge.joinName))
|
||||||
|
{
|
||||||
|
tables.add(edge.leftTable);
|
||||||
|
tables.add(edge.rightTable);
|
||||||
|
rs.add(edge.joinName);
|
||||||
|
keepGoing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public record Something(String joinTable, List<String> joinPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Set<Something> getJoinsBetter(String tableName)
|
||||||
|
{
|
||||||
|
Set<Something> rs = new HashSet<>();
|
||||||
|
Set<String> usedEdges = new HashSet<>();
|
||||||
|
Set<String> tables = new HashSet<>();
|
||||||
|
tables.add(tableName);
|
||||||
|
doGetJoinsBetter(rs, tables, new ArrayList<>(), usedEdges);
|
||||||
|
|
||||||
|
return (rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void doGetJoinsBetter(Set<Something> rs, Set<String> tables, List<String> joinPath, Set<String> usedEdges)
|
||||||
|
{
|
||||||
|
for(Edge edge : edges)
|
||||||
|
{
|
||||||
|
if(usedEdges.contains(edge.joinName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tables.contains(edge.leftTable) || tables.contains(edge.rightTable))
|
||||||
|
{
|
||||||
|
usedEdges.add(edge.joinName);
|
||||||
|
// todo - clone list here, then recurisiv call
|
||||||
|
rs.add(new Something(tables.contains(edge.leftTable) ? edge.rightTable : edge.leftTable, joinPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,16 +23,21 @@ package com.kingsrook.qqq.backend.core.actions.metadata;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionCheckResult;
|
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionCheckResult;
|
||||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
|
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface;
|
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode;
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
||||||
@ -40,6 +45,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMe
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendReportMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendReportMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendWidgetMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendWidgetMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.MetaDataWithPermissionRules;
|
import com.kingsrook.qqq.backend.core.model.metadata.permissions.MetaDataWithPermissionRules;
|
||||||
@ -88,6 +94,9 @@ public class MetaDataAction
|
|||||||
}
|
}
|
||||||
metaDataOutput.setTables(tables);
|
metaDataOutput.setTables(tables);
|
||||||
|
|
||||||
|
// addJoinsToTables(tables);
|
||||||
|
// addJoinedTablesToTables(tables);
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// map processes to frontend metadata //
|
// map processes to frontend metadata //
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
@ -212,6 +221,149 @@ public class MetaDataAction
|
|||||||
return metaDataOutput;
|
return metaDataOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////// start v1 //////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private record JoinedTable(String joinedTableName, List<String> joinPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void addJoinedTablesToTables(Map<String, QFrontendTableMetaData> tables)
|
||||||
|
{
|
||||||
|
for(QFrontendTableMetaData table : tables.values())
|
||||||
|
{
|
||||||
|
List<JoinedTable> joinedTables = new ArrayList<>();
|
||||||
|
addJoinedTablesToTable(tables, table, joinedTables, new ArrayList<>());
|
||||||
|
|
||||||
|
if(joinedTables.size() > 0)
|
||||||
|
{
|
||||||
|
System.out.println("For [" + table.getName() + "] we have:\n " + joinedTables.stream().map(String::valueOf).collect(Collectors.joining("\n ")) + "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.out.println("No joins for [" + table.getName() + "]\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void addJoinedTablesToTable(Map<String, QFrontendTableMetaData> tables, QFrontendTableMetaData table, List<JoinedTable> joinedTables, List<String> joinPath)
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
for(QJoinMetaData join : qInstance.getJoins().values())
|
||||||
|
{
|
||||||
|
if(join.getLeftTable().equals(table.getName()))
|
||||||
|
{
|
||||||
|
String joinName = join.getName();
|
||||||
|
JoinedTable joinedTable = new JoinedTable(join.getRightTable(), joinPath);
|
||||||
|
System.out.println("Adding to [" + table.getName() + "]: " + joinedTable);
|
||||||
|
joinedTables.add(joinedTable);
|
||||||
|
|
||||||
|
ArrayList<String> subJoinPath = new ArrayList<>(joinPath);
|
||||||
|
subJoinPath.add(joinName);
|
||||||
|
addJoinedTablesToTable(tables, tables.get(join.getRightTable()), joinedTables, subJoinPath);
|
||||||
|
}
|
||||||
|
if(join.getRightTable().equals(table.getName()))
|
||||||
|
{
|
||||||
|
String joinName = join.getName() + ".flipped";
|
||||||
|
JoinedTable joinedTable = new JoinedTable(join.getLeftTable(), joinPath);
|
||||||
|
System.out.println("Adding to [" + table.getName() + "]: " + joinedTable);
|
||||||
|
joinedTables.add(joinedTable);
|
||||||
|
|
||||||
|
ArrayList<String> subJoinPath = new ArrayList<>(joinPath);
|
||||||
|
subJoinPath.add(joinName);
|
||||||
|
addJoinedTablesToTable(tables, tables.get(join.getLeftTable()), joinedTables, subJoinPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////// end v1 //////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////// start v0 //////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private record Something(String joinName, List<String> joinPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void addJoinsToTables(Map<String, QFrontendTableMetaData> tables)
|
||||||
|
{
|
||||||
|
for(QFrontendTableMetaData table : tables.values())
|
||||||
|
{
|
||||||
|
List<Something> something = new ArrayList<>();
|
||||||
|
addJoinsToTable(tables, table, something, new ArrayList<>(), new HashSet<>());
|
||||||
|
if(something.size() > 0)
|
||||||
|
{
|
||||||
|
System.out.println("For [" + table.getName() + "] we have:\n " + something.stream().map(String::valueOf).collect(Collectors.joining("\n ")) + "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.out.println("No joins for [" + table.getName() + "]\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void addJoinsToTable(Map<String, QFrontendTableMetaData> tables, QFrontendTableMetaData table, List<Something> something, List<String> joinPath, Set<String> usedJoins)
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
for(QJoinMetaData join : qInstance.getJoins().values())
|
||||||
|
{
|
||||||
|
if(join.getLeftTable().equals(table.getName()))
|
||||||
|
{
|
||||||
|
String joinName = join.getName();
|
||||||
|
if(!usedJoins.contains(joinName))
|
||||||
|
{
|
||||||
|
usedJoins.add(joinName);
|
||||||
|
something.add(new Something(joinName, joinPath));
|
||||||
|
|
||||||
|
ArrayList<String> subJoinPath = new ArrayList<>(joinPath);
|
||||||
|
subJoinPath.add(joinName);
|
||||||
|
|
||||||
|
QFrontendTableMetaData rightTable = tables.get(join.getRightTable());
|
||||||
|
addJoinsToTable(tables, rightTable, something, subJoinPath, usedJoins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(join.getRightTable().equals(table.getName()))
|
||||||
|
{
|
||||||
|
String joinName = join.getName() + ".flipped";
|
||||||
|
if(!usedJoins.contains(joinName))
|
||||||
|
{
|
||||||
|
usedJoins.add(joinName);
|
||||||
|
something.add(new Something(joinName, joinPath));
|
||||||
|
|
||||||
|
ArrayList<String> subJoinPath = new ArrayList<>(joinPath);
|
||||||
|
subJoinPath.add(joinName);
|
||||||
|
|
||||||
|
QFrontendTableMetaData leftTable = tables.get(join.getLeftTable());
|
||||||
|
addJoinsToTable(tables, leftTable, something, subJoinPath, usedJoins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////// end v0 //////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
Reference in New Issue
Block a user