Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
build/
.gradle/
.idea/

.vscode/
/.classpath
/.project
/bin/
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation('org.springframework.boot:spring-boot-starter-test')
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.flywaydb:flyway-core')
runtimeOnly('com.h2database:h2')
}

test {
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/wilkins/showcase/controller/JsonUser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.wilkins.showcase.controller;

import com.wilkins.showcase.domain.User;

import java.time.LocalDateTime;

public record JsonUser(String externalId, String name, LocalDateTime createdAt) {
public static JsonUser from(User user) {
return new JsonUser(user.getExternalId(), user.getName(), user.getCreatedAt());
}
}
29 changes: 29 additions & 0 deletions src/main/java/com/wilkins/showcase/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.wilkins.showcase.controller;

import com.wilkins.showcase.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
@RequestMapping("/users")
public class UserController {

private final UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

@PostMapping
ResponseEntity<JsonUser> createUser(@RequestBody String name) {
return Optional.of(userService.create(name))
.map(JsonUser::from)
.map(ResponseEntity::ok)
.orElseThrow();
}
}
85 changes: 85 additions & 0 deletions src/main/java/com/wilkins/showcase/domain/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.wilkins.showcase.domain;

import jakarta.persistence.*;
import org.hibernate.annotations.CreationTimestamp;

import java.time.LocalDateTime;
import java.util.Comparator;

import static java.util.UUID.randomUUID;

@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String externalId;
private String name;
@CreationTimestamp
private LocalDateTime createdAt;

public User() {
}

public User(Long id, String externalId, String name, LocalDateTime createdAt) {
this.id = id;
this.externalId = externalId;
this.name = name;
this.createdAt = createdAt;
}

public static User with(String name) {
return new User(null, randomUUID().toString(), name, null);
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getExternalId() {
return externalId;
}

public void setExternalId(String externalId) {
this.externalId = externalId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public LocalDateTime getCreatedAt() {
return createdAt;
}

public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}

public static Comparator<User> userComparator() {
return (a, b) -> {
if (!a.getId().equals(b.getId())) {
return a.getId().compareTo(b.getId());
}
if (!a.getExternalId().equals(b.getExternalId())) {
return a.getExternalId().compareTo(b.getExternalId());
}
if (!a.getName().equals(b.getName())) {
return a.getName().compareTo(b.getName());
}
if (!a.getCreatedAt().isEqual(b.getCreatedAt())) {
return a.getCreatedAt().compareTo(b.getCreatedAt());
}
return 0;
};
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/wilkins/showcase/service/DefaultUserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.wilkins.showcase.service;

import com.wilkins.showcase.domain.User;
import org.springframework.stereotype.Component;

@Component
public record DefaultUserService(UserRepository userRepository) implements UserService {
@Override
public User create(String name) {
return userRepository.save(User.with(name));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.wilkins.showcase.service;

import com.wilkins.showcase.domain.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends CrudRepository<User, Long> {
}
7 changes: 7 additions & 0 deletions src/main/java/com/wilkins/showcase/service/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.wilkins.showcase.service;

import com.wilkins.showcase.domain.User;

public interface UserService {
User create(String name);
}
8 changes: 8 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
spring:
h2:
console:
enabled: true
datasource:
url: jdbc:h2:mem:showcase
username: showcase
password: Passw0rd!
7 changes: 7 additions & 0 deletions src/main/resources/db/migration/V0__add_user_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
create table users
(
id bigint not null auto_increment,
external_id varchar(120) not null,
name varchar(120),
created_at timestamp not null default (current_timestamp)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.wilkins.showcase.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.time.LocalDateTime;

import static com.wilkins.showcase.domain.User.userComparator;
import static org.assertj.core.api.Assertions.assertThat;


@SpringBootTest
public class DefaultUserServiceIntegrationTest {

@Autowired
UserService underTest;
@Autowired
UserRepository userRepository;

@BeforeEach
void beforeEach() {
userRepository.deleteAll();
}

@Test
void canCreateUser() {
var bobFish = underTest.create("bob fish");

assertThat(bobFish.getCreatedAt()).isBeforeOrEqualTo(LocalDateTime.now());
assertThat(bobFish.getId()).isNotEqualTo(0);

assertThat(userRepository.findAll()).hasSize(1);
assertThat(userRepository.findById(bobFish.getId()))
.usingValueComparator(userComparator())
.hasValue(bobFish);
}
}