Skip to content

Commit

Permalink
#850 | Introduce code to join and create individual and enrolment dat…
Browse files Browse the repository at this point in the history
…a across all types
  • Loading branch information
himeshr committed Jan 21, 2025
1 parent 6c10ce0 commit 56f07b0
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableList;
import org.avni.server.domain.JoinTableConfig;
import org.avni.server.domain.metabase.*;
import org.avni.server.util.ObjectMapperSingleton;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Objects;

@Repository
public class QuestionRepository extends MetabaseConnector {
Expand Down Expand Up @@ -109,4 +111,30 @@ private MetabaseQuery createAdvancedQuery(String primaryTableName, String second
.addFilter(config.getFilters())
.build();
}

public void createQuestionForTableWithMultipleJoins(Database database, TableDetails tableDetails, List<JoinTableConfig> joinTableConfigs) {
ArrayNode joinsArray = ObjectMapperSingleton.getObjectMapper().createArrayNode();
MetabaseQueryBuilder metabaseQueryBuilder = new MetabaseQueryBuilder(database, joinsArray)
.forTable(tableDetails);

for (JoinTableConfig joinTableConfig : joinTableConfigs) {
FieldDetails joinField1 = databaseRepository.getFieldDetailsByName(database, joinTableConfig.getJoinTargetTable(), joinTableConfig.getOriginField());
FieldDetails joinField2 = databaseRepository.getFieldDetailsByName(database, Objects.isNull(joinTableConfig.getAlternateJoinSourceTable()) ?
tableDetails : joinTableConfig.getAlternateJoinSourceTable(), joinTableConfig.getDestinationField());
metabaseQueryBuilder.joinWith(joinTableConfig.getJoinTargetTable(), joinField1, joinField2);
}

MetabaseQuery query = metabaseQueryBuilder.build();

MetabaseRequestBody requestBody = new MetabaseRequestBody(
tableDetails.getDisplayName(),
query,
VisualizationType.TABLE,
tableDetails.getDescription(),
ObjectMapperSingleton.getObjectMapper().createObjectNode(),
databaseRepository.getCollectionForDatabase(database).getIdAsInt()
);

databaseRepository.postForObject(metabaseApiUrl + "/card", requestBody.toJson(), JsonNode.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.avni.server.dao.metabase.DatabaseRepository;
import org.avni.server.dao.metabase.MetabaseDashboardRepository;
import org.avni.server.dao.metabase.QuestionRepository;
import org.avni.server.domain.JoinTableConfig;
import org.avni.server.domain.metabase.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
Expand All @@ -12,15 +13,21 @@
import java.util.stream.Collectors;

@Service
public class DatabaseService implements QuestionCreationService{
public class DatabaseService implements QuestionCreationService {

private final DatabaseRepository databaseRepository;
private final MetabaseService metabaseService;
private final CollectionRepository collectionRepository;
private final QuestionRepository questionRepository;
private final MetabaseDashboardRepository metabaseDashboardRepository;

private static final String INDIVIDUAL_TABLE = "individual";
private static final String ENROLMENT_TABLE = "program_enrolment";
private static final String ADDRESS_TABLE = "Address";
private static final String SUBJECT_TYPE_TABLE = "subject_type";
private static final String PROGRAM_TABLE = "program";
private static final String GENDER_TABLE = "Gender";
private static final String PUBLIC_SCHEMA = "public";

@Autowired
public DatabaseService(DatabaseRepository databaseRepository, MetabaseService metabaseService, CollectionRepository collectionRepository, QuestionRepository questionRepository, MetabaseDashboardRepository metabaseDashboardRepository) {
Expand Down Expand Up @@ -178,15 +185,82 @@ private void createQuestionsForProgramsAndEncounters() {

private void createQuestionsForMiscSingleTables() {
ensureSyncComplete();
List<String> individualTables = Arrays.asList("address", "media", "sync_telemetry");
List<String> miscSingleTableNames = Arrays.asList("address", "media", "sync_telemetry");

List<String> filteredTables = filterOutExistingQuestions(individualTables);
List<String> filteredTables = filterOutExistingQuestions(miscSingleTableNames);

for (String tableName : filteredTables) {
createQuestionForTable(tableName);
}
}

private void createQuestionsForMiscJoinedTables() {
ensureSyncComplete();
Database database = getGlobalDatabase();
List<String> miscJoinedTables = Arrays.asList("individual_type_gender_address", "enrolment_type_individual_address");
List<String> filteredTables = filterOutExistingQuestions(miscJoinedTables);
for (String tableName : filteredTables) {
createQuestionForJoinedTable(database, tableName);
}
}

private void createQuestionForJoinedTable(Database database, String tableName) {
switch (tableName) {
case "individual_type_gender_address":
createIndividualTypeGenderAddress(database, tableName);
break;
case "enrolment_type_individual_address":
createEnrolmentTypeIndividualAddress(database, tableName);
break;
default:
break;
}
}

private void createIndividualTypeGenderAddress(Database database, String displayName) {
TableDetails fetchedEntityTableDetails = databaseRepository.findTableDetailsByName(database, new TableDetails(INDIVIDUAL_TABLE));
fetchedEntityTableDetails.setDisplayName(displayName);
fetchedEntityTableDetails.setDescription(displayName);
List<JoinTableConfig> joinTableConfigs = new ArrayList<>();

joinTableConfigs.add(configureJoinTable(database, "id", "subject_type_id", SUBJECT_TYPE_TABLE, PUBLIC_SCHEMA));
joinTableConfigs.add(configureJoinTable(database, "id", "gender_id", GENDER_TABLE, PUBLIC_SCHEMA));
joinTableConfigs.add(configureJoinTable(database, "id", "address_id", ADDRESS_TABLE, database.getName()));

questionRepository.createQuestionForTableWithMultipleJoins(database, fetchedEntityTableDetails, joinTableConfigs);
}

private void createEnrolmentTypeIndividualAddress(Database database, String displayName) {
TableDetails fetchedEntityTableDetails = databaseRepository.findTableDetailsByName(database, new TableDetails(ENROLMENT_TABLE));
fetchedEntityTableDetails.setDisplayName(displayName);
fetchedEntityTableDetails.setDescription(displayName);
List<JoinTableConfig> joinTableConfigs = new ArrayList<>();

TableDetails individualTable = databaseRepository.findTableDetailsByName(database, new TableDetails(INDIVIDUAL_TABLE));

joinTableConfigs.add(configureJoinTable(database, "id", "program_id", PROGRAM_TABLE, PUBLIC_SCHEMA));
joinTableConfigs.add(configureJoinTable(database, "id", "individual_id", INDIVIDUAL_TABLE, PUBLIC_SCHEMA));
joinTableConfigs.add(configureJoinTable(database, "id", "address_id", ADDRESS_TABLE, database.getName(), individualTable));

questionRepository.createQuestionForTableWithMultipleJoins(database, fetchedEntityTableDetails, joinTableConfigs);
}

private JoinTableConfig configureJoinTable(Database database, String targetTableJoinColumn,
String sourceTableJoinColumn, String targetTable, String targetTableSchemaName, TableDetails alternateJoinTable) {
FieldDetails fieldDetails = new FieldDetails(targetTableJoinColumn);
FieldDetails entityFieldDetails = new FieldDetails(sourceTableJoinColumn);
TableDetails fetchedTableDetails = databaseRepository.findTableDetailsByName(database, new TableDetails(targetTable, targetTableSchemaName));
return new JoinTableConfig(fetchedTableDetails, fieldDetails, entityFieldDetails, alternateJoinTable);
}

private JoinTableConfig configureJoinTable(Database database, String targetTableJoinColumn,
String sourceTableJoinColumn, String targetTable, String targetTableSchemaName) {
FieldDetails fieldDetails = new FieldDetails(targetTableJoinColumn);
FieldDetails entityFieldDetails = new FieldDetails(sourceTableJoinColumn);
TableDetails fetchedTableDetails = databaseRepository.findTableDetailsByName(database, new TableDetails(targetTable, targetTableSchemaName));
return new JoinTableConfig(fetchedTableDetails, fieldDetails, entityFieldDetails);
}

private void createCustomQuestions() {
ensureSyncComplete();
Database database = getGlobalDatabase();
Expand Down Expand Up @@ -248,6 +322,8 @@ public void addCollectionItems() {

createQuestionsForMiscSingleTables();

createQuestionsForMiscJoinedTables();

createCustomQuestions();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.avni.server.domain;

import org.avni.server.domain.metabase.FieldDetails;
import org.avni.server.domain.metabase.TableDetails;

public class JoinTableConfig {
TableDetails joinTargetTable;
FieldDetails originField;
FieldDetails destinationField;
TableDetails alternateJoinSourceTable; //Optional: to be made use of when we want to join with table other than primaryTable

public JoinTableConfig(TableDetails joinTargetTable, FieldDetails originField, FieldDetails destinationField) {
this.joinTargetTable = joinTargetTable;
this.originField = originField;
this.destinationField = destinationField;
}

public JoinTableConfig(TableDetails joinTargetTable, FieldDetails originField, FieldDetails destinationField, TableDetails alternateJoinSourceTable) {
this.joinTargetTable = joinTargetTable;
this.originField = originField;
this.destinationField = destinationField;
this.alternateJoinSourceTable = alternateJoinSourceTable;
}

public TableDetails getJoinTargetTable() {
return joinTargetTable;
}

public void setJoinTargetTable(TableDetails joinTargetTable) {
this.joinTargetTable = joinTargetTable;
}

public FieldDetails getOriginField() {
return originField;
}

public void setOriginField(FieldDetails originField) {
this.originField = originField;
}

public FieldDetails getDestinationField() {
return destinationField;
}

public void setDestinationField(FieldDetails destinationField) {
this.destinationField = destinationField;
}

public TableDetails getAlternateJoinSourceTable() {
return alternateJoinSourceTable;
}

public void setAlternateJoinSourceTable(TableDetails alternateJoinSourceTable) {
this.alternateJoinSourceTable = alternateJoinSourceTable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public MetabaseQueryBuilder forTable(TableDetails tableDetails) {
return this;
}

public MetabaseQueryBuilder joinWith(TableDetails addressTable, FieldDetails joinField1, FieldDetails joinField2) {
public MetabaseQueryBuilder joinWith(TableDetails joinTargetTable, FieldDetails joinField1, FieldDetails joinField2) {
ObjectNode joinNode = objectMapper.createObjectNode();
joinNode.put(FieldAttribute.FIELDS.getAttributeName(), FieldAttribute.ALL.getAttributeName());
joinNode.put(FieldAttribute.ALIAS.getAttributeName(), addressTable.getName());
joinNode.put(FieldAttribute.ALIAS.getAttributeName(), joinTargetTable.getName());

ArrayNode conditionArray = objectMapper.createArrayNode();
conditionArray.add(ConditionType.EQUAL.getOperator());
Expand All @@ -40,11 +40,11 @@ public MetabaseQueryBuilder joinWith(TableDetails addressTable, FieldDetails joi
ArrayNode rightField = objectMapper.createArrayNode();
rightField.add(FieldAttribute.FIELD.getAttributeName());
rightField.add(joinField1.getId());
rightField.add(objectMapper.createObjectNode().put(FieldAttribute.BASE_TYPE.getAttributeName(), FieldType.INTEGER.getTypeName()).put(FieldAttribute.JOIN_ALIAS.getAttributeName(), addressTable.getName()));
rightField.add(objectMapper.createObjectNode().put(FieldAttribute.BASE_TYPE.getAttributeName(), FieldType.INTEGER.getTypeName()).put(FieldAttribute.JOIN_ALIAS.getAttributeName(), joinTargetTable.getName()));
conditionArray.add(rightField);

joinNode.set(FieldAttribute.CONDITION.getAttributeName(), conditionArray);
joinNode.put(FieldAttribute.SOURCE_TABLE.getAttributeName(), addressTable.getId());
joinNode.put(FieldAttribute.SOURCE_TABLE.getAttributeName(), joinTargetTable.getId());
joinsArray.add(joinNode);
queryNode.set(FieldAttribute.JOINS.getAttributeName(), joinsArray);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,12 @@ public boolean nameMatches(String tableName) {
public void setName(String name) {
this.name = name;
}

public void setDescription(String description) {
this.description = description;
}

public void setDisplayName(String displayName) {
this.displayName = displayName;
}
}

0 comments on commit 56f07b0

Please sign in to comment.