Skip to content

Commit

Permalink
Merge pull request #8 from nhkhai/main
Browse files Browse the repository at this point in the history
SIS-22 & SIS-30: Removed the invalid duplicate foreign keys based on the updated ER diagram and added Spring Boot profiles support.
  • Loading branch information
nhkhai authored Mar 21, 2024
2 parents 912e849 + d01bcf2 commit 0ec8903
Show file tree
Hide file tree
Showing 18 changed files with 290 additions and 93 deletions.
6 changes: 2 additions & 4 deletions Documentation/Diagrams/Entity Relationship Diagram.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@ erDiagram
int postal_code
int mobile_number
string email
int review_id FK
}
Review {
long id PK
string category
string review_content
int rating
int customer_id FK
int product_id FK
long customer_id FK
long product_id FK
}
Product {
Expand All @@ -28,7 +27,6 @@ erDiagram
string description
double price
int stock_quantity
int review_id FK
}
Customer ||--O{ Review : "Has"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
@SpringBootApplication
public class SmartInventoryApplication {
// Name this according to your class name.
// The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
// INFO, WARN, ERROR, with each of these having a corresponding logging method:
// trace(), debug(), info(), warn(), error().
private static final Logger app_logger = LoggerFactory.getLogger(SmartInventoryApplication.class);

public static void main(String[] args) {
app_logger.info("Starting SmartInventoryApplication. ");
app_logger.info("Starting Smart Inventory Application initialization... ");

SpringApplication.run(SmartInventoryApplication.class, args);

app_logger.info("Exiting SmartInventoryApplication. ");
app_logger.info("Smart Inventory Application initialization complete! ");
}
}
8 changes: 2 additions & 6 deletions src/main/java/sg/com/smartinventory/entities/Customer.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id; // PK.
private long id; // PK. PostgreSQL bigserial data type.

@NotBlank(message = "First name is mandatory. ")
@Column(name = "first_name")
Expand All @@ -53,15 +53,12 @@ public class Customer {
@Column(name = "email")
private String email;

@Column(name = "review_id")
private int reviewId; // FK.

public Customer() {
}

// Define Constructor for DataLoader.
public Customer(String firstName, String lastName, String country, String address, int postalCode, int mobileNumber,
String email, int reviewId) {
String email) {
this();

this.firstName = firstName;
Expand All @@ -71,6 +68,5 @@ public Customer(String firstName, String lastName, String country, String addres
this.postalCode = postalCode;
this.mobileNumber = mobileNumber;
this.email = email;
this.reviewId = reviewId;
}
}
6 changes: 1 addition & 5 deletions src/main/java/sg/com/smartinventory/entities/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
private long id; // PK. PostgreSQL bigserial data type.

@Column(name = "category")
private String category;
Expand All @@ -39,9 +39,6 @@ public class Product {
@Column(name = "stock_quantity")
private int stockQuantity;

@Column(name = "review_id")
private int reviewId; // FK.

public Product() {
}

Expand All @@ -54,6 +51,5 @@ public Product(String category, String name, String description, double price, i
this.description = description;
this.price = price;
this.stockQuantity = stockQuantity;
this.reviewId = reviewId;
}
}
15 changes: 9 additions & 6 deletions src/main/java/sg/com/smartinventory/entities/Review.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Min;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -20,9 +21,9 @@
@Table(name = "review")
public class Review {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.IDENTITY) // Bigserial.
@Column(name = "id")
private Long id; // PK.
private long id; // PK. PostgreSQL bigserial data type.

@Column(name = "category")
private String category;
Expand All @@ -33,17 +34,19 @@ public class Review {
@Column(name = "rating")
private int rating;

@Min(value = 1, message = "Customer ID should start from 1. ")
@Column(name = "customer_id")
private int customerId; // FK.
private long customerId; // FK. PostgreSQL bigserial data type.

@Min(value = 1, message = "Product ID should start from 1. ")
@Column(name = "product_id")
private int productId; // FK.
private long productId; // FK. PostgreSQL bigserial data type.

public Review() {
}

// Define Constructor for DataLoader.
public Review(String category, String reviewContent, int rating, int customerId, int productId) {
public Review(String category, String reviewContent, int rating, long customerId, long productId) {
this();

this.category = category;
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/sg/com/smartinventory/utility/DataLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ public void loadData() {

// Create fake data.
customerRepository.save(new Customer("John", "Doe", "USA", "123 Main St", 123456, 12345678,
"[email protected]", 101));
"[email protected]"));

customerRepository.save(new Customer("Alice", "Smith", "Canada", "456 Maple Ave", 543210, 98765432,
"[email protected]", 102));
"[email protected]"));
customerRepository.save(new Customer("Michael", "Johnson", "UK", "789 Oak Rd", 567890, 98761234,
"[email protected]", 103));
"[email protected]"));
customerRepository.save(new Customer("Emily", "Brown", "Australia", "321 Elm St", 135790, 45678912,
"[email protected]", 104));
"[email protected]"));
customerRepository.save(new Customer("David", "Wilson", "Germany", "654 Pine Rd", 987655, 36985214,
"[email protected]", 105));
"[email protected]"));

productRepository.save(new Product("Electronics", "Smartphone",
"High-end smartphone with advanced features. ", 999.99, 100, 101));
Expand Down
31 changes: 26 additions & 5 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
spring.application.name=smart-inventory

# Server Configuration.
# Server Port Configuration.
# The default server port is 8080.
server.port=9090

# Database Configuration.
# PostgreSQL
# PostgreSQL.
spring.datasource.url=jdbc:postgresql://localhost:5432/smart_inventory
# For WSL, use postgres.
# For Mac, use your Mac username.
spring.datasource.username=postgres
# Password can be blank if we set it to trust in pg_hba.conf
# Password can be blank if we set it to trust in pg_hba.conf.
spring.datasource.password=

# Database platform to use.
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

# Hibernate Database Initialization Method.
# This will drop and create tables again.
spring.jpa.hibernate.ddl-auto=create
# This can be used to update tables.
Expand All @@ -22,28 +26,45 @@ spring.jpa.hibernate.ddl-auto=create
# Application logging configuration.
# logging.level.root=INFO
# logging.file.name=logs/application.log

# Database logging configuration.
# The Spring/Hibernate classes, which generate SQL statements and set the parameters, already contain the code for logging them.
# However, the level of those log statements is set to DEBUG and TRACE respectively, which is lower than the default level in Spring Boot — INFO.
# By adding these properties, we are just setting those loggers to the required level.
# For logging statements.
# logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG

# For logging parameters of prepared statements.
# logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACE
# Set up a profile-specific configuration for tests.

# Set up a profile-specific configuration for tests. For example a <testloglevel> profile.
# logging.config=classpath:logback-testloglevel.xml

# SpringDoc Configuration.
# The OpenAPI descriptions are at /v3/api-docs, which is the default path: http://localhost:8080/v3/api-docs.
# For a custom path of the OpenAPI documentation in Json format,
# add the custom springdoc property /api-docs endpoint custom path to get the path: http://localhost:8080/api-docs.
springdoc.api-docs.path=/api-docs

# The OpenAPI definitions are in JSON format by default. For yaml format, we can obtain the definitions at: http://localhost:8080/api-docs.yaml.
# To disable api-docs springdoc-openapi endpoints.
# springdoc.api-docs.enabled=false

# The springdoc-openapi dependency already includes Swagger UI, to integrate springdoc-openapi with Swagger UI to interact with our API specification and exercise the endpoints.# We can access the API documentation at: http://localhost:8080/swagger-ui/index.html.
# Using swagger-ui properties, to customize the path of the swagger-ui API documentation swagger-ui-custom.html to get the path: http://localhost:8080/swagger-ui-custom.html.
# springdoc.swagger-ui.path=/swagger-ui-custom.html
springdoc.swagger-ui.path=/swagger-ui.html

# To sort the API paths according to their HTTP methods with the springdoc.swagger-ui.operationsSorter property.
# springdoc.swagger-ui.operationsSorter=method
# springdoc.swagger-ui.operationsSorter=method

# Profile management.
# Spring Boot will always read the application.properties file.
# Other's profile files, such as application-development.properties only will complement and replace the properties defined before.
# The application.properties, and just this file, must have this line.
# [email protected]@
# Set the default active profile.
# Use the command to activate: mvn spring-boot:run -Dspring.profiles.active=development.
spring.profiles.active=development
# Set the default default profile. This is the profile that is used on any bean if you don't specify the @Profile annotation to be a certain profile.
# spring.profiles.default=development
32 changes: 20 additions & 12 deletions src/main/resources/logback-spring.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring Boot uses Logback as the logging library with preconfigured defaults. To customize it,
use logback-spring.xml instead of the normal Java logback.xml. This is parsed by Spring Boot before
it configures Logback and provides some extra XML elements that we can use for more dynamic logging
configurations. It supports Spring Profiles the <springProfile> element to configure the logging
for
different profiles. -->
<configuration>
<!-- Define a common variable -->
<property name="AppLogPath" value="./logs" />
Expand Down Expand Up @@ -48,21 +54,23 @@
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- Set root log level to "INFO" -->
<root level="info">
<!-- Reference the "Console" appender for console output -->
<appender-ref ref="Console" />
<!-- <appender-ref ref="Console2" /> -->
<!-- Reference the "File" appender for file output -->
<appender-ref ref="File" />
<!-- Reference the "RollingFile" appender for file output -->
<!-- <appender-ref ref="RollingFile" /> -->
</root>
<!-- LOG "sg.com.smartinventory*" at "TRACE" level -->
<!--
<springProfile name="development">
<!-- Set root log level to "INFO" -->
<root level="info">
<!-- Reference the "Console" appender for console output -->
<appender-ref ref="Console" />
<!-- <appender-ref ref="Console2" /> -->
<!-- Reference the "File" appender for file output -->
<appender-ref ref="File" />
<!-- Reference the "RollingFile" appender for file output -->
<!-- <appender-ref ref="RollingFile" /> -->
</root>
<!-- LOG "sg.com.smartinventory*" at "TRACE" level -->
<!--
<logger name="sg.com.smartinventory" level="trace" additivity="false">
<appender-ref ref="RollingFile" />
<appender-ref ref="Console" />
</logger>
-->
</springProfile>
</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
Expand All @@ -16,7 +18,6 @@

import com.fasterxml.jackson.databind.ObjectMapper;

import sg.com.smartinventory.SmartInventoryApplication;
import sg.com.smartinventory.entities.Customer;

@SpringBootTest
Expand All @@ -28,7 +29,10 @@ public class CustomerControllerTest {
@Autowired
private ObjectMapper objectMapper;

// Name this according to your class name.
/// Name this according to your class name.
// The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
// INFO, WARN, ERROR, with each of these having a corresponding logging method:
// trace(), debug(), info(), warn(), error().
private static final Logger test_logger = LoggerFactory.getLogger(CustomerControllerTest.class);

@DisplayName("Create customer")
Expand All @@ -38,9 +42,8 @@ public void createCustomerTest() throws Exception {

// Step 1: Create a Customer object
Customer newCustomer = Customer.builder().firstName("Jackie").lastName("Chan").country("Hong Kong")
.address("123 HK St")
.postalCode(654321).mobileNumber(87654321).email("[email protected]")
.reviewId(110).build();
.address("123 HK St").postalCode(654321).mobileNumber(87654321)
.email("[email protected]").build();

// Step 2: Convert the Java object to JSON using ObjectMapper.
String newCustomerAsJSON = objectMapper.writeValueAsString(newCustomer);
Expand All @@ -51,7 +54,8 @@ public void createCustomerTest() throws Exception {
.content(newCustomerAsJSON);

// Step 4: Perform the request and get the response and assert.
mockMvc.perform(request).andExpect(status().isCreated())
mockMvc.perform(request)
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.firstName").value("Jackie"))
.andExpect(jsonPath("$.lastName").value("Chan"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
Expand All @@ -26,13 +29,21 @@ public class ProductControllerTest {
@Autowired
private ObjectMapper objectMapper;

/// Name this according to your class name.
// The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
// INFO, WARN, ERROR, with each of these having a corresponding logging method:
// trace(), debug(), info(), warn(), error().
private static final Logger test_logger = LoggerFactory.getLogger(CustomerControllerTest.class);

@DisplayName("Create product")
@Test
public void createProductTest() throws Exception {
test_logger.info("Starting test: createProductTest. ");

// Step 1: Create a Product object
Product newProduct = Product.builder().category("Electronics").name("Smartphone")
.description("High-end smartphone with advanced features. ")
.price(999.99).stockQuantity(100).reviewId(101).build();
.price(999.99).stockQuantity(100).build();

// Step 2: Convert the Java object to JSON using ObjectMapper.
String newProductAsJSON = objectMapper.writeValueAsString(newProduct);
Expand All @@ -43,9 +54,12 @@ public void createProductTest() throws Exception {
.content(newProductAsJSON);

// Step 4: Perform the request and get the response and assert.
mockMvc.perform(request).andExpect(status().isCreated())
mockMvc.perform(request)
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.category").value("Electronics"))
.andExpect(jsonPath("$.name").value("Smartphone"));

test_logger.info("Ending test: createProductTest. ");
}
}
Loading

0 comments on commit 0ec8903

Please sign in to comment.