From de870a15673ce14c5cf62afa09577206f89d5bb1 Mon Sep 17 00:00:00 2001 From: Om Bhardwaj <115864495+ombhardwajj@users.noreply.github.com> Date: Sat, 7 Sep 2024 12:25:55 +0530 Subject: [PATCH] avniproject#762 | Working code with MetabaseQueryBuilder and QuestionCreationService --- .../dao/metabase/CollectionRepository.java | 6 +- .../dao/metabase/DatabaseRepository.java | 63 ++++--- .../metabase/CollectionInfoResponse.java | 56 +++++++ ...tion.java => CreateCollectionRequest.java} | 4 +- .../avni/server/domain/metabase/Database.java | 3 + .../domain/metabase/DatabaseDetails.java | 3 + .../metabase/MetabaseCollectionInfo.java | 37 ----- .../server/domain/metabase/MetabaseQuery.java | 22 +-- .../domain/metabase/MetabaseQueryBuilder.java | 54 +++--- .../domain/metabase/MetabaseRequestBody.java | 2 +- .../AddressQuestionCreationService.java | 26 ++- .../service/metabase/DatabaseService.java | 156 ++++-------------- .../service/metabase/MetabaseService.java | 12 +- .../metabase/QuestionCreationService.java | 2 +- ...a => CreateCollectionRequestUtilTest.java} | 2 +- 15 files changed, 213 insertions(+), 235 deletions(-) create mode 100644 avni-server-api/src/main/java/org/avni/server/domain/metabase/CollectionInfoResponse.java rename avni-server-api/src/main/java/org/avni/server/domain/metabase/{Collection.java => CreateCollectionRequest.java} (73%) delete mode 100644 avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseCollectionInfo.java rename avni-server-api/src/test/java/org/avni/server/util/{CollectionUtilTest.java => CreateCollectionRequestUtilTest.java} (93%) diff --git a/avni-server-api/src/main/java/org/avni/server/dao/metabase/CollectionRepository.java b/avni-server-api/src/main/java/org/avni/server/dao/metabase/CollectionRepository.java index 50c28e816..ac07057c2 100644 --- a/avni-server-api/src/main/java/org/avni/server/dao/metabase/CollectionRepository.java +++ b/avni-server-api/src/main/java/org/avni/server/dao/metabase/CollectionRepository.java @@ -1,6 +1,6 @@ package org.avni.server.dao.metabase; -import org.avni.server.domain.metabase.Collection; +import org.avni.server.domain.metabase.CreateCollectionRequest; import org.avni.server.domain.metabase.CollectionResponse; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.stereotype.Repository; @@ -11,8 +11,8 @@ public CollectionRepository(RestTemplateBuilder restTemplateBuilder) { super(restTemplateBuilder); } - public CollectionResponse save(Collection collection) { + public CollectionResponse save(CreateCollectionRequest createCollectionRequest) { String url = metabaseApiUrl + "/collection"; - return postForObject(url, collection, CollectionResponse.class); + return postForObject(url, createCollectionRequest, CollectionResponse.class); } } diff --git a/avni-server-api/src/main/java/org/avni/server/dao/metabase/DatabaseRepository.java b/avni-server-api/src/main/java/org/avni/server/dao/metabase/DatabaseRepository.java index 45a2f511f..25e532b04 100644 --- a/avni-server-api/src/main/java/org/avni/server/dao/metabase/DatabaseRepository.java +++ b/avni-server-api/src/main/java/org/avni/server/dao/metabase/DatabaseRepository.java @@ -8,7 +8,6 @@ import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.stereotype.Repository; import com.fasterxml.jackson.databind.ObjectMapper; - import java.util.List; @Repository @@ -26,28 +25,52 @@ public Database save(Database database) { return database; } - public Database getDatabaseByName(String databaseName) { + public Database getDatabaseById(Database database) { + int id = database.getId(); + String url = metabaseApiUrl + "/database/" + id; + try { + String jsonResponse = getForObject(url, String.class); + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(jsonResponse, Database.class); + } catch (Exception e) { + throw new RuntimeException("Failed to retrieve database with ID " + id, e); + } + } + + public Database getDatabaseByName(String name) { String url = metabaseApiUrl + "/database"; + String jsonResponse = getForObject(url, String.class); + try { - List databases = objectMapper.readValue(jsonResponse, new TypeReference>() {}); - return databases.stream() - .filter(db -> db.getName().equals(databaseName)) - .findFirst() - .orElseThrow(() -> new RuntimeException("Database with name " + databaseName + " not found.")); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(jsonResponse); + JsonNode dataArray = rootNode.path("data"); + + for (JsonNode dbNode : dataArray) { + Database db = objectMapper.treeToValue(dbNode, Database.class); + if (db.getName().equals(name)) { + return db; + } + } + throw new RuntimeException("Database with name " + name + " not found."); } catch (Exception e) { throw new RuntimeException("Failed to retrieve database", e); } } - public MetabaseCollectionInfo getCollectionByName(String collectionName) { + public CollectionInfoResponse getCollectionByName(String collectionName) { String url = metabaseApiUrl + "/collection"; - String jsonResponse = getForObject(url, String.class); - try { - List collections = objectMapper.readValue(jsonResponse, new TypeReference>() {}); + String jsonResponse = getForObject(url, String.class); + + ObjectMapper objectMapper = new ObjectMapper(); + List collections = objectMapper.readValue( + jsonResponse, new TypeReference>() {} + ); + return collections.stream() - .filter(coll -> coll.getName().equals(collectionName)) + .filter(collection -> collection.getName().equals(collectionName)) .findFirst() .orElseThrow(() -> new RuntimeException("Collection with name " + collectionName + " not found.")); } catch (Exception e) { @@ -55,13 +78,13 @@ public MetabaseCollectionInfo getCollectionByName(String collectionName) { } } - public void createQuestionForTable(Database database, TableDetails tableDetails, String addressTableName, String addressField, String tableField) throws Exception { - TableDetails addressTableDetails = getTableDetailsByDisplayName(database, addressTableName); + public void createQuestionForTable(Database database, TableDetails tableDetails, String addressTableName, String addressField, String tableField) { + TableDetails addressTableDetails = getTableDetailsByName(database, addressTableName); FieldDetails joinField1 = getFieldDetailsByName(database, addressTableName, addressField); FieldDetails joinField2 = getFieldDetailsByName(database, tableDetails.getName(), tableField); ArrayNode joinsArray = objectMapper.createArrayNode(); - MetabaseQuery query = new MetabaseQueryBuilder(database, joinsArray) + MetabaseQuery query = new MetabaseQueryBuilder(database, joinsArray, objectMapper) .forTable(tableDetails) .joinWith(addressTableDetails, joinField1, joinField2) .build(); @@ -72,7 +95,7 @@ public void createQuestionForTable(Database database, TableDetails tableDetails, VisualizationType.TABLE, null, objectMapper.createObjectNode(), - getCollectionByName(database.getName()).getId(), + getCollectionByName(database.getName()).getIdAsInt(), CardType.QUESTION ); @@ -111,16 +134,16 @@ public List getFields(Database database) { } } - public TableDetails getTableDetailsByDisplayName(Database database, String tableName) { + public TableDetails getTableDetailsByName(Database database, String tableName) { MetabaseDatabaseInfo databaseInfo = getDatabaseDetails(database); return databaseInfo.getTables().stream() - .filter(tableDetail -> tableDetail.nameMatches(tableName)) + .filter(tableDetail -> tableDetail.getName().equalsIgnoreCase(tableName)) .findFirst() .orElseThrow(() -> new RuntimeException("Table with name " + tableName + " not found.")); } - public DatabaseSyncStatus getInitialSyncStatus(int databaseId) { - String url = metabaseApiUrl + "/database/" + databaseId; + public DatabaseSyncStatus getInitialSyncStatus(Database database) { + String url = metabaseApiUrl + "/database/" + database.getId(); String jsonResponse = getForObject(url, String.class); try { return objectMapper.readValue(jsonResponse, DatabaseSyncStatus.class); diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/CollectionInfoResponse.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/CollectionInfoResponse.java new file mode 100644 index 000000000..322aff320 --- /dev/null +++ b/avni-server-api/src/main/java/org/avni/server/domain/metabase/CollectionInfoResponse.java @@ -0,0 +1,56 @@ +package org.avni.server.domain.metabase; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CollectionInfoResponse { + + private String name; + private String id; + private boolean isPersonal; + + public CollectionInfoResponse() { + } + + public CollectionInfoResponse(@JsonProperty("name") String name, + @JsonProperty("id") Object id, + @JsonProperty("is_personal") boolean isPersonal) { + this.name = name; + this.isPersonal = isPersonal; + + if (id instanceof Integer) { + this.id = String.valueOf(id); + } else { + this.id = id.toString(); + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public int getIdAsInt() { + try { + return Integer.parseInt(id); + } catch (NumberFormatException e) { + throw new RuntimeException("Failed to convert id to integer: " + id, e); + } + } + + public boolean isPersonal() { + return isPersonal; + } + + public void setPersonal(boolean personal) { + isPersonal = personal; + } +} diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/Collection.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/CreateCollectionRequest.java similarity index 73% rename from avni-server-api/src/main/java/org/avni/server/domain/metabase/Collection.java rename to avni-server-api/src/main/java/org/avni/server/domain/metabase/CreateCollectionRequest.java index 3b24bfa2c..b9fc8e6c2 100644 --- a/avni-server-api/src/main/java/org/avni/server/domain/metabase/Collection.java +++ b/avni-server-api/src/main/java/org/avni/server/domain/metabase/CreateCollectionRequest.java @@ -1,10 +1,10 @@ package org.avni.server.domain.metabase; -public class Collection { +public class CreateCollectionRequest { private String name; private String description; - public Collection(String name, String description) { + public CreateCollectionRequest(String name, String description) { this.name = name; this.description = description; } diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/Database.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/Database.java index 86b0ce604..009f07762 100644 --- a/avni-server-api/src/main/java/org/avni/server/domain/metabase/Database.java +++ b/avni-server-api/src/main/java/org/avni/server/domain/metabase/Database.java @@ -1,5 +1,8 @@ package org.avni.server.domain.metabase; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) public class Database { private Integer id; private String name; diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/DatabaseDetails.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/DatabaseDetails.java index 5844499a2..519f002e6 100644 --- a/avni-server-api/src/main/java/org/avni/server/domain/metabase/DatabaseDetails.java +++ b/avni-server-api/src/main/java/org/avni/server/domain/metabase/DatabaseDetails.java @@ -1,5 +1,8 @@ package org.avni.server.domain.metabase; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) public class DatabaseDetails { private String host; private String port; diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseCollectionInfo.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseCollectionInfo.java deleted file mode 100644 index e67046408..000000000 --- a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseCollectionInfo.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.avni.server.domain.metabase; - -public class MetabaseCollectionInfo { - private String name; - private int id; - private boolean isPersonal; - - public MetabaseCollectionInfo(String name, int id, boolean isPersonal) { - this.name = name; - this.id = id; - this.isPersonal = isPersonal; - } - - public String getName() { - return name; - } - - public int getId() { - return id; - } - - public boolean isPersonal() { - return isPersonal; - } - - public void setName(String name) { - this.name = name; - } - - public void setId(int id) { - this.id = id; - } - - public void setPersonal(boolean personal) { - isPersonal = personal; - } -} diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQuery.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQuery.java index 5b2db827c..8323d79b0 100644 --- a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQuery.java +++ b/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQuery.java @@ -1,28 +1,20 @@ package org.avni.server.domain.metabase; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; public class MetabaseQuery { - private final Database database; - private final ArrayNode joins; + private final int databaseId; + private final ObjectNode queryNode; - public MetabaseQuery(Database database, ArrayNode joins) { - this.database = database; - this.joins = joins; + public MetabaseQuery(int databaseId, ObjectNode queryNode) { + this.databaseId = databaseId; + this.queryNode = queryNode; } public int getDatabaseId() { - return database.getId(); + return databaseId; } - - public ObjectNode toJson(ObjectMapper objectMapper) { - ObjectNode queryNode = objectMapper.createObjectNode(); - queryNode.put("database", database.getId()); - queryNode.set("joins", joins); - queryNode.put("type", "query"); + public ObjectNode toJson() { return queryNode; } } diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQueryBuilder.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQueryBuilder.java index 28460c685..e48ab94bc 100644 --- a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQueryBuilder.java +++ b/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseQueryBuilder.java @@ -1,41 +1,57 @@ -// to be completed package org.avni.server.domain.metabase; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; public class MetabaseQueryBuilder { private final Database database; - private ArrayNode joins; + private final ArrayNode joinsArray; + private final ObjectMapper objectMapper; + private ObjectNode queryNode; - public MetabaseQueryBuilder(Database database, ArrayNode joins) { + public MetabaseQueryBuilder(Database database, ArrayNode joinsArray, ObjectMapper objectMapper) { this.database = database; - this.joins = joins; + this.joinsArray = joinsArray; + this.objectMapper = objectMapper; + this.queryNode = objectMapper.createObjectNode(); } public MetabaseQueryBuilder forTable(TableDetails tableDetails) { - // code to be added + queryNode.put("source-table", tableDetails.getId()); + queryNode.put("database", database.getId()); return this; } - - public MetabaseQueryBuilder joinWith(TableDetails joinTable, FieldDetails originField, FieldDetails destinationField) { - // Build the join condition and add to the joins array - ObjectMapper objectMapper = new ObjectMapper(); - ArrayNode joinCondition = objectMapper.createArrayNode(); - - joinCondition.add(ConditionType.EQUAL.getOperator()); - joinCondition.add(objectMapper.createArrayNode().add("field").add(originField.getId())); - joinCondition.add(objectMapper.createArrayNode().add("field").add(destinationField.getId())); - - joins.add(joinCondition); + public MetabaseQueryBuilder joinWith(TableDetails addressTable, FieldDetails joinField1, FieldDetails joinField2) { + ObjectNode joinNode = objectMapper.createObjectNode(); + joinNode.put("fields", "all"); + joinNode.put("alias", addressTable.getName()); + joinNode.put("source-table", addressTable.getId()); + + ArrayNode conditionArray = objectMapper.createArrayNode(); + conditionArray.add("="); + + ArrayNode leftField = objectMapper.createArrayNode(); + leftField.add("field"); + leftField.add(joinField1.getId()); + leftField.add(objectMapper.createObjectNode().put("base-type", "type/Integer")); + conditionArray.add(leftField); + + ArrayNode rightField = objectMapper.createArrayNode(); + rightField.add("field"); + rightField.add(joinField2.getId()); + rightField.add(objectMapper.createObjectNode().put("base-type", "type/Integer").put("join-alias", addressTable.getName())); + conditionArray.add(rightField); + + joinNode.set("condition", conditionArray); + joinsArray.add(joinNode); + queryNode.set("joins", joinsArray); return this; } - public MetabaseQuery build() { - return new MetabaseQuery(database, joins); + queryNode.put("type", "query"); + return new MetabaseQuery(database.getId(), queryNode); } } diff --git a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseRequestBody.java b/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseRequestBody.java index 68b3e4572..d5ab1fbc1 100644 --- a/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseRequestBody.java +++ b/avni-server-api/src/main/java/org/avni/server/domain/metabase/MetabaseRequestBody.java @@ -32,7 +32,7 @@ public ObjectNode toJson(ObjectMapper objectMapper) { ObjectNode datasetQueryNode = objectMapper.createObjectNode(); datasetQueryNode.put("database", datasetQuery.getDatabaseId()); datasetQueryNode.put("type", "query"); - datasetQueryNode.set("query", datasetQuery.toJson(objectMapper)); + datasetQueryNode.set("query", datasetQuery.toJson()); rootNode.set("dataset_query", datasetQueryNode); rootNode.put("display", display.toString()); diff --git a/avni-server-api/src/main/java/org/avni/server/service/metabase/AddressQuestionCreationService.java b/avni-server-api/src/main/java/org/avni/server/service/metabase/AddressQuestionCreationService.java index fca124e07..4c59f3636 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/metabase/AddressQuestionCreationService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/metabase/AddressQuestionCreationService.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.avni.server.dao.metabase.DatabaseRepository; import org.avni.server.domain.metabase.*; import org.springframework.beans.factory.annotation.Autowired; @@ -30,13 +29,32 @@ public AddressQuestionCreationService(@Lazy DatabaseService databaseService, Dat @Override public void createQuestionForTable(String tableName, String addressTableName, String addressField, String tableField) throws Exception { Database database = databaseService.getGlobalDatabase(); - TableDetails tableDetails = databaseRepository.getTableDetailsByDisplayName(database, tableName); + TableDetails tableDetails = databaseRepository.getTableDetailsByName(database, tableName); databaseRepository.createQuestionForTable(database, tableDetails, addressTableName, addressField, tableField); } @Override - public void createQuestionForTable(String tableName, String schema) { - // to be added + public void createQuestionForTable(String tableName, String schema) throws Exception { + Database database = databaseService.getGlobalDatabase(); + TableDetails tableDetails = databaseRepository.getTableDetailsByName(database, tableName); + + ArrayNode joinsArray = objectMapper.createArrayNode(); + + MetabaseQuery query = new MetabaseQueryBuilder(database, joinsArray, objectMapper) + .forTable(tableDetails) + .build(); + + MetabaseRequestBody requestBody = new MetabaseRequestBody( + tableName, + query, + VisualizationType.TABLE, + null, + objectMapper.createObjectNode(), + databaseService.getCollectionId(), + CardType.QUESTION + ); + databaseRepository.postForObject(metabaseApiUrl + "/card", requestBody.toJson(objectMapper), JsonNode.class); } + } diff --git a/avni-server-api/src/main/java/org/avni/server/service/metabase/DatabaseService.java b/avni-server-api/src/main/java/org/avni/server/service/metabase/DatabaseService.java index 586529ace..c30b1350a 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/metabase/DatabaseService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/metabase/DatabaseService.java @@ -2,8 +2,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.avni.server.dao.metabase.DatabaseRepository; import org.avni.server.domain.metabase.*; import org.springframework.beans.factory.annotation.Autowired; @@ -12,10 +10,6 @@ import java.util.Arrays; import java.util.ArrayList; import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.avni.server.util.S; @Service public class DatabaseService { @@ -42,8 +36,8 @@ public DatabaseService(DatabaseRepository databaseRepository, ObjectMapper objec } public Database getGlobalDatabase() { - int databaseId = metabaseService.getGlobalDatabaseId(); - return databaseRepository.getDatabaseByName(String.valueOf(databaseId)); + Database globalDatabase = metabaseService.getGlobalDatabase(); + return databaseRepository.getDatabaseById(globalDatabase); } public int getDatabaseId() { @@ -60,81 +54,16 @@ public int getCollectionId() { return collectionId; } - public int getTableIdByDisplayName(String tableName) { - MetabaseDatabaseInfo databaseInfo = databaseRepository.getDatabaseDetails(getGlobalDatabase()); - List tables = databaseInfo.getTables(); - - for (TableDetails table : tables) { - if (tableName.equals(table.getDisplayName())) { - return table.getId(); - } - } - return -1; - } - - public int getTableIdByDisplayName(String tableName, String schema) { - MetabaseDatabaseInfo databaseInfo = databaseRepository.getDatabaseDetails(getGlobalDatabase()); - List tables = databaseInfo.getTables(); - - for (TableDetails table : tables) { - String tableSchema = table.getSchema(); - - boolean schemaMatches = schema.equals("public") - ? "public".equals(tableSchema) - : !"public".equals(tableSchema); - - if (tableName.equals(table.getDisplayName()) && schemaMatches) { - return table.getId(); - } - } - return -1; - } - - public TableDetails getTableDetailsByDisplayName(String tableName) { - MetabaseDatabaseInfo databaseInfo = databaseRepository.getDatabaseDetails(getGlobalDatabase()); - List tables = databaseInfo.getTables(); - - // Handle Optional properly - Optional tableDetailsOptional = tables.stream() - .filter(tableDetail -> tableDetail.nameMatches(tableName)) - .findFirst(); - - return tableDetailsOptional.orElseThrow(() -> - new RuntimeException("Table not found: " + tableName)); - } - - - private String createRequestBodyForDataset(int sourceTableId) { - return "{\"database\":" + getDatabaseId() + ",\"query\":{\"source-table\":" + sourceTableId + "},\"type\":\"query\",\"parameters\":[]}"; - } - - public int getFieldIdByTableNameAndFieldName(String tableName, String fieldName) { - List fieldsList = databaseRepository.getFields(getGlobalDatabase()); - String snakeCaseTableName = S.toSnakeCase(tableName); - - for (FieldDetails field : fieldsList) { - if (snakeCaseTableName.equals(field.getTableName()) && fieldName.equals(field.getName())) { - return field.getId(); - } - } - return -1; - } - public SyncStatus getInitialSyncStatus() { - DatabaseSyncStatus databaseSyncStatus = databaseRepository.getInitialSyncStatus(getDatabaseId()); + Database globalDatabase = metabaseService.getGlobalDatabase(); + DatabaseSyncStatus databaseSyncStatus = databaseRepository.getInitialSyncStatus(globalDatabase); String status = databaseSyncStatus.getInitialSyncStatus(); return SyncStatus.fromString(status); } - - private DatasetResponse getTableMetadata(Database database) { - TableDetails metadataTable = databaseRepository.getTableDetailsByDisplayName(database, "table_metadata"); - return databaseRepository.findAll(metadataTable, database); - } - public List getSubjectTypeNames() { Database database = getGlobalDatabase(); - TableDetails metadataTable = databaseRepository.getTableDetailsByDisplayName(database, "table_metadata"); + TableDetails metadataTable = databaseRepository.getTableDetailsByName(database, "table_metadata"); DatasetResponse datasetResponse = databaseRepository.findAll(metadataTable, database); List> rows = datasetResponse.getData().getRows(); @@ -158,7 +87,7 @@ public List getSubjectTypeNames() { public List getProgramAndEncounterNames() { Database database = getGlobalDatabase(); - TableDetails metadataTable = databaseRepository.getTableDetailsByDisplayName(database, "table_metadata"); + TableDetails metadataTable = databaseRepository.getTableDetailsByName(database, "table_metadata"); DatasetResponse datasetResponse = databaseRepository.findAll(metadataTable, database); List> rows = datasetResponse.getData().getRows(); @@ -176,57 +105,14 @@ public List getProgramAndEncounterNames() { return programNames; } - - - private List extractTableNames(JsonNode databaseDetails) { - List tableNames = new ArrayList<>(); - JsonNode tablesArray = databaseDetails.path("tables"); - for (JsonNode tableNode : tablesArray) { - tableNames.add(tableNode.path("display_name").asText()); - } - return tableNames; - } - - private void createQuestionForTable(String tableName, String schema) { - int tableId = getTableIdByDisplayName(tableName, schema); - - ObjectNode datasetQuery = objectMapper.createObjectNode(); - datasetQuery.put("database", getDatabaseId()); - datasetQuery.put("type", "query"); - - ObjectNode query = objectMapper.createObjectNode(); - query.put("source-table", tableId); - datasetQuery.set("query", query); - - ObjectNode body = objectMapper.createObjectNode(); - body.put("name", tableName); - body.set("dataset_query", datasetQuery); - body.put("display", "table"); - body.putNull("description"); - body.set("visualization_settings", objectMapper.createObjectNode()); - body.put("collection_id", getCollectionId()); - body.putNull("collection_position"); - body.putNull("result_metadata"); - - databaseRepository.postForObject( - metabaseApiUrl + "/card", - body, - JsonNode.class - ); - } - public void createQuestionsForSubjectTypes() throws Exception { SyncStatus syncStatus = getInitialSyncStatus(); if (syncStatus != SyncStatus.COMPLETE) { throw new RuntimeException("Database sync is not complete. Cannot create questions."); } - - Database database = getGlobalDatabase(); List subjectTypeNames = getSubjectTypeNames(); for (String subjectTypeName : subjectTypeNames) { - TableDetails subjectTable = databaseRepository.getTableDetailsByDisplayName(database, subjectTypeName); - addressQuestionCreationService.createQuestionForTable(subjectTypeName, "Address", "id", "address_id"); } } @@ -237,31 +123,45 @@ public void createQuestionsForProgramsAndEncounters() throws Exception { throw new RuntimeException("Database sync is not complete. Cannot create questions."); } - Database database = getGlobalDatabase(); - List programAndEncounterNames = getProgramAndEncounterNames(); for (String programName : programAndEncounterNames) { - TableDetails programTable = databaseRepository.getTableDetailsByDisplayName(database, programName); addressQuestionCreationService.createQuestionForTable(programName, "Address", "id", "address_id"); } } - public void createQuestionsForIndividualTables() throws Exception { + public void createQuestionsForIndividualTables() { SyncStatus syncStatus = getInitialSyncStatus(); if (syncStatus != SyncStatus.COMPLETE) { throw new RuntimeException("Database sync is not complete. Cannot create questions."); } Database database = getGlobalDatabase(); - List tablesToCreateQuestionsFor = Arrays.asList("Address", "Media", "Sync Telemetry"); - for (String tableName : tablesToCreateQuestionsFor) { - TableDetails tableDetails = databaseRepository.getTableDetailsByDisplayName(database, tableName); - databaseRepository.createQuestionForTable(database, tableDetails, "Address", "id", "address_id"); + List individualTables = Arrays.asList("address", "media", "sync_telemetry"); // Adjust these as needed + + for (String tableName : individualTables) { + TableDetails tableDetails = databaseRepository.getTableDetailsByName(database, tableName); + + MetabaseQuery query = new MetabaseQueryBuilder(database, objectMapper.createArrayNode(), objectMapper) + .forTable(tableDetails) + .build(); + + MetabaseRequestBody requestBody = new MetabaseRequestBody( + tableName, + query, + VisualizationType.TABLE, + null, + objectMapper.createObjectNode(), + databaseRepository.getCollectionByName(database.getName()).getIdAsInt(), + CardType.QUESTION + ); + + databaseRepository.postForObject(metabaseApiUrl + "/card", requestBody.toJson(objectMapper), JsonNode.class); } } + public void createQuestions() throws Exception { createQuestionsForSubjectTypes(); diff --git a/avni-server-api/src/main/java/org/avni/server/service/metabase/MetabaseService.java b/avni-server-api/src/main/java/org/avni/server/service/metabase/MetabaseService.java index 4ac97ec05..746267e41 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/metabase/MetabaseService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/metabase/MetabaseService.java @@ -23,7 +23,7 @@ public class MetabaseService { private final CollectionPermissionsRepository collectionPermissionsRepository; private final CollectionRepository collectionRepository; private Database globalDatabase; - private MetabaseCollectionInfo globalCollection; + private CollectionInfoResponse globalCollection; @Autowired public MetabaseService(OrganisationService organisationService, @@ -50,8 +50,8 @@ public void setupMetabase() { Database database = databaseRepository.save(new Database(name, "postgres", new DatabaseDetails(avniDatabase, dbUser))); this.globalDatabase = database; - CollectionResponse metabaseCollection = collectionRepository.save(new Collection(name, name + " collection")); - this.globalCollection = new MetabaseCollectionInfo(null, metabaseCollection.getId(), false); + CollectionResponse metabaseCollection = collectionRepository.save(new CreateCollectionRequest(name, name + " collection")); + this.globalCollection = new CollectionInfoResponse(null, metabaseCollection.getId(), false); Group metabaseGroup = groupPermissionsRepository.save(new Group(name)); @@ -81,6 +81,10 @@ public int getGlobalCollectionId() { Organisation currentOrganisation = organisationService.getCurrentOrganisation(); globalCollection = databaseRepository.getCollectionByName(currentOrganisation.getName() + " collection"); } - return globalCollection.getId(); + return globalCollection.getIdAsInt(); + } + + public Database getGlobalDatabase() { + return globalDatabase; } } diff --git a/avni-server-api/src/main/java/org/avni/server/service/metabase/QuestionCreationService.java b/avni-server-api/src/main/java/org/avni/server/service/metabase/QuestionCreationService.java index 58babec9f..121bfe158 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/metabase/QuestionCreationService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/metabase/QuestionCreationService.java @@ -2,5 +2,5 @@ public interface QuestionCreationService { void createQuestionForTable(String tableName, String addressTableName, String addressField, String tableField) throws Exception; - void createQuestionForTable(String tableName, String schema); + void createQuestionForTable(String tableName, String schema) throws Exception; } diff --git a/avni-server-api/src/test/java/org/avni/server/util/CollectionUtilTest.java b/avni-server-api/src/test/java/org/avni/server/util/CreateCollectionRequestUtilTest.java similarity index 93% rename from avni-server-api/src/test/java/org/avni/server/util/CollectionUtilTest.java rename to avni-server-api/src/test/java/org/avni/server/util/CreateCollectionRequestUtilTest.java index d6219aa2f..b0928ecb8 100644 --- a/avni-server-api/src/test/java/org/avni/server/util/CollectionUtilTest.java +++ b/avni-server-api/src/test/java/org/avni/server/util/CreateCollectionRequestUtilTest.java @@ -5,7 +5,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -public class CollectionUtilTest { +public class CreateCollectionRequestUtilTest { @Test public void hasOnlyTrailingEmptyStrings() { assertTrue(CollectionUtil.hasOnlyTrailingEmptyStrings(Arrays.asList("a", "b", "")));