added docs

This commit is contained in:
Mehul Ahal 2023-01-12 23:50:28 +01:00 committed by LahaLuhem
parent ffd4b3fa5b
commit 792d293dd4
13 changed files with 139 additions and 16 deletions

View file

@ -2,3 +2,45 @@
Please use this readme as your projects readme. You can find instructions for Please use this readme as your projects readme. You can find instructions for
the assignment in the [`INSTRUCTIONS.md`](INSTRUCTIONS.md) file. the assignment in the [`INSTRUCTIONS.md`](INSTRUCTIONS.md) file.
Overview
========
This project is a simple command-line application that communicates with a PostgreSQL database to retrieve data and generate reports based on that data. It's composed of several classes and packages that work together to accomplish this task.
Classes and packages
--------------------
The application's main class is `Main` class, it runs the entire application. It's composed of three services: `AppConfigService`, `DatabaseService`, and `ReportGenerationService`.
### AppConfigService
`AppConfigService` is a service class that prompts and stores the configuration that the app needs to be run with. It prompts the user for input for the country name and date, and stores them as class members.
### DatabaseService
`DatabaseService` class is responsible for maintaining the active connection between the app and the SQL Server. It also communicates with the `DatabaseApi` class to perform final CRUD operations and return any results.
### ReportGenerationService
`ReportGenerationService` generates a report from results. Since only a std-out is the only strategy, composition is preferred. It provides a single method `reportBaseResults(QueryResultsRepository queryResultsRepository)` that takes a `QueryResultsRepository` object as input and prints the results to the console. The method prints the `toString()` representation of the `QueryResultsRepository` object. It provides a basic printer and more members can be added in the future to use different strategies for printing out the received results.
### data.dtos
`data.dtos` package contains the `QueryDTO` class. This class serves as a container for storing SQL statements to be executed, along with their arguments.
### data.enums
`data.enums` package contains the `CustomPreparedStatementsRead` enum. This enum contains all the read-only prepared statements that are used throughout the application.
### data.repos
`data.repos` package contains the `QueryResultsRepository` class. This class stores the results of the executed queries, and can be used to generate a report.
### data.models
`data.models` package contains the `PersistentResultSetModel` class. This class adapts a given `ResultSet` to a `PersistentResultModel`.
### apis
`apis` package contains the `DatabaseApi` class. This class communicates with the database to perform final CRUD operations, returning any results. This class is responsible for executing SQL statements, which are passed to it in the form of a QueryDTO class. It receives a QueryDTO object and a JDBC connection, then it processes the query and returns a PreparedStatement object. This class is designed to handle any exception that may occur during the execution of the query and it can be extended in the future to handle other types of queries if needed.

BIN
docs/ClassUML.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 KiB

View file

@ -7,6 +7,9 @@ import services.ReportGenerationService;
import java.sql.SQLException; import java.sql.SQLException;
/**
* Entry point of the application
*/
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
final App app = new App(); final App app = new App();
@ -14,6 +17,9 @@ public class Main {
} }
} }
/**
* Responsible for the overall flow of the application. It creates and manages instances Services.
*/
class App { class App {
public App() { public App() {
databaseService = new DatabaseService(); databaseService = new DatabaseService();
@ -25,28 +31,39 @@ class App {
final private AppConfigService appConfigService; final private AppConfigService appConfigService;
final private ReportGenerationService reportGenerationService; final private ReportGenerationService reportGenerationService;
/**
* Endpoints mentioned under the `Report` section
*/
private static final CustomPreparedStatementsRead[] reportEndpoints = { private static final CustomPreparedStatementsRead[] reportEndpoints = {
CustomPreparedStatementsRead.HighestAndLowest10Vaccination, CustomPreparedStatementsRead.HighestAndLowest10Vaccination,
CustomPreparedStatementsRead.HighestInfectionsPer100K, CustomPreparedStatementsRead.HighestInfectionsPer100K,
CustomPreparedStatementsRead.CountriesLaggingBehind, CustomPreparedStatementsRead.CountriesLaggingBehind,
}; };
/**
* Endpoints mentioned under the `Query` section
*/
private static final CustomPreparedStatementsRead[] queryEndpoints = { private static final CustomPreparedStatementsRead[] queryEndpoints = {
CustomPreparedStatementsRead.DailyInfectionsAndDeathAggregate, CustomPreparedStatementsRead.DailyInfectionsAndDeathAggregate,
}; };
/**
* Responsible for the overall flow of the application.
* It retrieves data from the database using the `DatabaseService` class,
* generates reports using the `ReportGenerationService` class, and prompts the user for input using the `AppConfigService` class.
*/
public void run() { public void run() {
try { try {
QueryResultsRepository resultsRepository; QueryResultsRepository resultsRepository;
for (final CustomPreparedStatementsRead query : reportEndpoints) { for (final CustomPreparedStatementsRead query : reportEndpoints) {
resultsRepository = databaseService.executeReadReportsEndpoint(new QueryDTO(query)); resultsRepository = databaseService.executeReadReportsEndpoint(new QueryDTO(query));
reportGenerationService.reportResults(resultsRepository); reportGenerationService.reportBaseResults(resultsRepository);
} }
for(final CustomPreparedStatementsRead query: queryEndpoints) { for(final CustomPreparedStatementsRead query: queryEndpoints) {
appConfigService.promptAndSetUserArguments(); appConfigService.promptAndSetUserArguments();
resultsRepository = databaseService.executeReadReportsEndpoint(new QueryDTO(query, new Object[]{appConfigService.countryName, appConfigService.date,})); resultsRepository = databaseService.executeReadReportsEndpoint(new QueryDTO(query, new Object[]{appConfigService.countryName, appConfigService.date,}));
reportGenerationService.reportResults(resultsRepository); reportGenerationService.reportBaseResults(resultsRepository);
} }

View file

@ -8,10 +8,22 @@ import java.util.Date;
import java.util.MissingFormatArgumentException; import java.util.MissingFormatArgumentException;
/** /**
* Communicates with the database to perform final CRUD operations, returning any results. * The `DatabaseApi` class provides a way to communicate with the database to perform read operations and return the results.
* When there is a need for more than a single READ action, the Api can be abstracted, and implement into constituent action-specific APIs. * It contains a single method `performReadQuery()` that takes a `QueryDTO` and a `Connection` object as parameters and
* returns a `PreparedStatement` object. It throws `SQLException` in case of any SQL error or `MissingFormatArgumentException`
* in case of any missing argument or extra argument.
*
* The class can be abstracted and implemented into constituent action-specific APIs when there is a need for more than a single READ action.
*/ */
public class DatabaseApi { public class DatabaseApi {
/**
* Creates and executes a PreparedStatement, given the QueryDTO.
* @param queryDTO
* @param connection
* @return
* @throws MissingFormatArgumentException in case of any missing argument or extra argument.
* @throws SQLException
*/
public PreparedStatement performReadQuery(QueryDTO queryDTO, Connection connection) throws SQLException { public PreparedStatement performReadQuery(QueryDTO queryDTO, Connection connection) throws SQLException {
// Set template // Set template
PreparedStatement statement = connection.prepareStatement(queryDTO.statement().statementTemplate); PreparedStatement statement = connection.prepareStatement(queryDTO.statement().statementTemplate);

View file

@ -4,10 +4,14 @@ import data.enums.CustomPreparedStatementsRead;
/** /**
* Container for storing SQL statements to be executed, along with their aruments. * Container for storing SQL statements to be executed, along with their aruments.
* @param statement * @param statement an instance of `CustomPreparedStatementsRead` enum which contains the statement template to be executed.
* @param templateArgs * @param templateArgsn an array of `Object` representing the arguments to be used in the statement template.
*/ */
public record QueryDTO(CustomPreparedStatementsRead statement, Object[] templateArgs) { public record QueryDTO(CustomPreparedStatementsRead statement, Object[] templateArgs) {
/**
* overloaded constructor that takes only a `CustomPreparedStatementsRead` object as parameter.
* @param customPreparedStatementsRead
*/
public QueryDTO(CustomPreparedStatementsRead customPreparedStatementsRead) { public QueryDTO(CustomPreparedStatementsRead customPreparedStatementsRead) {
this(customPreparedStatementsRead, new Object[]{}); this(customPreparedStatementsRead, new Object[]{});
} }

View file

@ -2,7 +2,6 @@ package data.enums;
/** /**
* Holds prepared data for Read-based SQL queries. * Holds prepared data for Read-based SQL queries.
*
*/ */
public enum CustomPreparedStatementsRead { public enum CustomPreparedStatementsRead {
DailyInfectionsAndDeathAggregate(""" DailyInfectionsAndDeathAggregate("""

View file

@ -6,6 +6,13 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* The class `PersistentResultSetModel` adapts a given `ResultSet` to a
* PersistentResultModel. The class provides two main fields, an array of `ResultRowModel` called
* `resultRowEntries` and an array of `String` called `columnNames`.
* The factory constructor takes a `ResultSet` as a parameter, and adapts it to a `PersistentResultModel`.
* The class also provides a toString method that returns the string representation of the result set.
*/
public class PersistentResultSetModel { public class PersistentResultSetModel {
/** /**
* Factory constructor, that adapts a given ResultSet to PersistentResultModel. * Factory constructor, that adapts a given ResultSet to PersistentResultModel.
@ -36,8 +43,25 @@ public class PersistentResultSetModel {
} }
/**
* Represents all the rows of the result set.
*/
final public ResultRowModel[] resultRowEntries; final public ResultRowModel[] resultRowEntries;
/**
* Represents column names that appear in the result set.
*/
/**
* It returns the string representation of the result set in tabular format, showing the column names and rowElements.
*/
final public String[] columnNames; final public String[] columnNames;
/**
* The `ResultRowModel` class represents a single row in the result set. It contains an array of
* `Object` called `rowElements`. The class provides an implementation of the `toString()` method
* that returns the string representation of the row.
* @param rowElements The elements of the row
*/
public record ResultRowModel(Object[] rowElements){ public record ResultRowModel(Object[] rowElements){
@Override @Override
public String toString() { public String toString() {

View file

@ -8,7 +8,11 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* Stores the results obtained from executing an SQL query. * Provides a way to store and persist the results of read queries.
* It contains an `ArrayList` of `PersistentResultSetModel` called `persistentResults` and a `String` called `queryDescription`.
* The class provides a constructor that takes a `queryDescription` as a parameter and an `addResult()` method
* that takes a `ResultSet` as a parameter and adds it to the `persistentResults` list.
* The class also provides a `toString()` method that returns the string representation of the stored results and their description.
*/ */
public class QueryResultsRepository { public class QueryResultsRepository {
public QueryResultsRepository(String queryDescription) { public QueryResultsRepository(String queryDescription) {
@ -20,10 +24,13 @@ public class QueryResultsRepository {
*/ */
final private ArrayList<PersistentResultSetModel> persistentResults = new ArrayList<>(); final private ArrayList<PersistentResultSetModel> persistentResults = new ArrayList<>();
/**
* Represents a description of the query that was executed.
*/
final private String queryDescription; final private String queryDescription;
/** /**
* Adds a ResultSet to the store to persist. * Creates a PersistentResultSetModel instance from given ResultSet, and adds it to the persistentResults list
* @param resultSet * @param resultSet
* @throws SQLException * @throws SQLException
*/ */

View file

@ -1,7 +1,7 @@
package services; package services;
import data.constants.ConstFormatters; import utils.ConstFormatters;
import data.constants.ConstValues; import utils.ConstValues;
import java.text.ParseException; import java.text.ParseException;
@ -15,6 +15,10 @@ public class AppConfigService {
public String countryName; public String countryName;
public Date date; public Date date;
/**
* Prompts the user to input the country name and date, and stores the input.
* It will keep prompting the user until the date is in the correct format.
*/
public void promptAndSetUserArguments() { public void promptAndSetUserArguments() {
final Scanner scanner = new Scanner(System.in); final Scanner scanner = new Scanner(System.in);
System.out.println(ConstValues.inputCountryName); System.out.println(ConstValues.inputCountryName);

View file

@ -7,7 +7,9 @@ import data.repos.QueryResultsRepository;
import java.sql.*; import java.sql.*;
/** /**
* Stores the active connection between the app and the SQL Server. * Responsible for storing the active connection between the application and the SQL server.
* It creates the connection to the PostgreSQL server and provides a way to execute read queries and persist their results.
* It uses DatabaseApi class for performing read queries.
*/ */
public class DatabaseService { public class DatabaseService {
private static final String url = "jdbc:postgresql://localhost:5432/lunatech_covid"; private static final String url = "jdbc:postgresql://localhost:5432/lunatech_covid";
@ -23,7 +25,7 @@ public class DatabaseService {
} }
/** /**
* Fetches read-query results and packages them to persist them (and so free the connection). * Fetches read-query results and packages them to persist them (and so frees the connection).
* *
* @param queryDTO The query with its arguments. * @param queryDTO The query with its arguments.
* @return Persisting (non-lazy) results from executing the query. * @return Persisting (non-lazy) results from executing the query.

View file

@ -2,8 +2,20 @@ package services;
import data.repos.QueryResultsRepository; import data.repos.QueryResultsRepository;
/**
* Generates a report from results
*
* Since only a std-out is the only strategy, composition is preferred.
* If more strategies are needed in the future, just add in a ReporterApi that delegates the task
* to any (strategy) class that implements it.
* A basic printer is provided, more members can be added to use print out the received results differently.
*/
public class ReportGenerationService { public class ReportGenerationService {
public void reportResults(QueryResultsRepository queryResultsRepository) { /**
* Prints results to the console.
* @param queryResultsRepository
*/
public void reportBaseResults(QueryResultsRepository queryResultsRepository) {
System.out.println(queryResultsRepository); System.out.println(queryResultsRepository);
} }
} }

View file

@ -1,4 +1,4 @@
package data.constants; package utils;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;

View file

@ -1,4 +1,4 @@
package data.constants; package utils;
public class ConstValues { public class ConstValues {
//I //I