Skip to content
Merged
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
11 changes: 11 additions & 0 deletions config/init_db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,14 @@ create table contact

create unique index contact_uuid_type_index
on contact (resume_uuid, type);

create table section
(
id serial primary key,
resume_uuid char(36) not null references resume (uuid) on delete cascade,
type text not null,
value text not null
);

create unique index section_idx
on section (resume_uuid, type);
126 changes: 94 additions & 32 deletions src/ru/javawebinar/basejava/storage/SqlStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
import ru.javawebinar.basejava.exception.NotExistStorageException;
import ru.javawebinar.basejava.model.ContactType;
import ru.javawebinar.basejava.model.Resume;
import ru.javawebinar.basejava.model.Section;
import ru.javawebinar.basejava.model.SectionType;
import ru.javawebinar.basejava.sql.SqlHelper;
import ru.javawebinar.basejava.util.JsonParser;

public class SqlStorage implements Storage {

Expand All @@ -38,7 +41,9 @@ public void update(Resume r) {
throw new NotExistStorageException(r.getUuid());
}
deleteContacts(conn, r);
deleteSections(conn, r);
insertContacts(conn, r);
insertSections(conn, r);
return null;
}
});
Expand All @@ -54,32 +59,48 @@ public void save(Resume r) {
ps.execute();
}
insertContacts(conn, r);
insertSections(conn, r);
return null;
});
}

@Override
public Resume get(String uuid) {
return sqlHelper.execute("SELECT * FROM resume r " +
" LEFT JOIN contact c " +
" ON r.uuid = c.resume_uuid " +
" WHERE r.uuid = ?", ps -> {
ps.setString(1, uuid);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
throw new NotExistStorageException(uuid);
return sqlHelper.transactionalExecute(conn -> {
Resume r;
try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM resume WHERE uuid = ?")) {
ps.setString(1, uuid);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
throw new NotExistStorageException(uuid);
}
r = new Resume(uuid, rs.getString("full_name"));
}
Resume resume = new Resume(uuid, rs.getString("full_name"));
do {
addContact(rs, resume);
} while (rs.next());
return resume;

try (PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM contact WHERE resume_uuid = ?")) {
ps.setString(1, uuid);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
addContact(rs, r);
}
}

try (PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM section WHERE resume_uuid = ?")) {
ps.setString(1, uuid);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
addSection(rs, r);
}
}
return r;
});
}

@Override
public void delete(String uuid) {
sqlHelper.<Void>execute("DELETE FROM resume WHERE uuid = ?", ps -> {
sqlHelper.execute("DELETE FROM resume WHERE uuid = ?", ps -> {
ps.setString(1, uuid);
if (ps.executeUpdate() == 0) {
throw new NotExistStorageException(uuid);
Expand All @@ -90,22 +111,34 @@ public void delete(String uuid) {

@Override
public List<Resume> getAllSorted() {
return sqlHelper.execute("SELECT * FROM resume r " +
" LEFT JOIN contact c " +
" ON r.uuid = c.resume_uuid" +
" ORDER BY full_name, uuid", ps -> {
ResultSet rs = ps.executeQuery();
Map<String, Resume> map = new LinkedHashMap<>();
while (rs.next()) {
String uuid = rs.getString("uuid");
Resume r = map.get(uuid);
if (r == null) {
r = new Resume(uuid, rs.getString("full_name"));
map.put(uuid, r);
return sqlHelper.transactionalExecute(conn -> {
Map<String, Resume> resumes = new LinkedHashMap<>();

try (PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM resume ORDER BY full_name, uuid")) {
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String uuid = rs.getString("uuid");
resumes.put(uuid, new Resume(uuid, rs.getString("full_name")));
}
}

try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM contact")) {
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Resume r = resumes.get(rs.getString("resume_uuid"));
addContact(rs, r);
}
}

try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM section")) {
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Resume r = resumes.get(rs.getString("resume_uuid"));
addSection(rs, r);
}
addContact(rs, r);
}
return new ArrayList<>(map.values());
return new ArrayList<>(resumes.values());
});
}

Expand All @@ -117,12 +150,19 @@ public int size() {
});
}

private void deleteContacts(Connection conn, Resume r) {
sqlHelper.execute("DELETE FROM contact WHERE resume_uuid = ?", ps -> {
private void deleteContacts(Connection conn, Resume r) throws SQLException {
deleteAttributes(conn, r, "DELETE FROM contact WHERE resume_uuid = ?");
}

private void deleteSections(Connection conn, Resume r) throws SQLException {
deleteAttributes(conn, r, "DELETE FROM section WHERE resume_uuid = ?");
}

private void deleteAttributes(Connection conn, Resume r, String query) throws SQLException {
try (PreparedStatement ps = conn.prepareStatement(query)) {
ps.setString(1, r.getUuid());
ps.execute();
return null;
});
}
}

private void insertContacts(Connection conn, Resume r) throws SQLException {
Expand All @@ -138,10 +178,32 @@ private void insertContacts(Connection conn, Resume r) throws SQLException {
}
}

private void insertSections(Connection conn, Resume r) throws SQLException {
try (PreparedStatement ps = conn.prepareStatement
("INSERT INTO section (resume_uuid, type, value) VALUES (?,?,?)")) {
for (Map.Entry<SectionType, Section> e : r.getSections().entrySet()) {
ps.setString(1, r.getUuid());
ps.setString(2, e.getKey().name());
Section section = e.getValue();
ps.setString(3, JsonParser.write(section, Section.class));
ps.addBatch();
}
ps.executeBatch();
}
}

private void addContact(ResultSet rs, Resume r) throws SQLException {
String value = rs.getString("value");
if (value != null) {
r.addContact(ContactType.valueOf(rs.getString("type")), value);
}
}

private void addSection(ResultSet rs, Resume r) throws SQLException {
String value = rs.getString("value");
if (value != null) {
SectionType type = SectionType.valueOf(rs.getString("type"));
r.addSection(type, JsonParser.read(value, Section.class));
}
}
}
14 changes: 13 additions & 1 deletion src/ru/javawebinar/basejava/util/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
public class JsonParser {

private static Gson GSON = new GsonBuilder()
.registerTypeAdapter(Section.class, new JsonSectionAdapter<>())
.registerTypeAdapter(Section.class, new JsonSectionAdapter())
.create();

public static <T> T read(Reader reader, Class<T> clazz) {
Expand All @@ -19,4 +19,16 @@ public static <T> T read(Reader reader, Class<T> clazz) {
public static <T> void write(T object, Writer writer) {
GSON.toJson(object, writer);
}

public static <T> T read(String content, Class<T> clazz) {
return GSON.fromJson(content, clazz);
}

public static <T> String write(T object) {
return GSON.toJson(object);
}

public static <T> String write(T object, Class<T> clazz) {
return GSON.toJson(object, clazz);
}
}
63 changes: 63 additions & 0 deletions test/ru/javawebinar/basejava/TestData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package ru.javawebinar.basejava;

import java.time.Month;
import java.util.UUID;
import ru.javawebinar.basejava.model.ContactType;
import ru.javawebinar.basejava.model.Organization;
import ru.javawebinar.basejava.model.Resume;
import ru.javawebinar.basejava.model.SectionLine;
import ru.javawebinar.basejava.model.SectionList;
import ru.javawebinar.basejava.model.SectionOrganization;
import ru.javawebinar.basejava.model.SectionType;

public class TestData {

public static final String UUID_1 = UUID.randomUUID().toString();
public static final String UUID_2 = UUID.randomUUID().toString();
public static final String UUID_3 = UUID.randomUUID().toString();
public static final String UUID_4 = UUID.randomUUID().toString();
public static final Resume R1;
public static final Resume R2;
public static final Resume R3;
public static final Resume R4;

static {
R1 = new Resume(UUID_1, "Name1");
R2 = new Resume(UUID_2, "Name2");
R3 = new Resume(UUID_3, "Name3");
R4 = new Resume(UUID_4, "Name4");

R1.addContact(ContactType.MOBILE_PHONE, "+79001234567");
R1.addContact(ContactType.EMAIL, "abc@mail.ru");
R4.addContact(ContactType.SKYPE, "Skype");
R4.addContact(ContactType.MOBILE_PHONE, "+76666666666");

R1.addSection(SectionType.OBJECTIVE, new SectionLine("Objective"));
R1.addSection(SectionType.PERSONAL, new SectionLine("Personal data"));
R1.addSection(SectionType.ACHIEVEMENT,
new SectionList("Achievement11", "Achievement12", "Achievement13"));
R1.addSection(SectionType.QUALIFICATION, new SectionList("Java", "git", "SQL"));
R1.addSection(SectionType.EXPERIENCE,
new SectionOrganization(
new Organization("Organization11", "http://organization11.ru",
new Organization.Position(2015, Month.JANUARY, "position11", "content11"),
new Organization.Position(2010, Month.JULY, 2014, Month.DECEMBER, "position12",
"content12"))));
R1.addSection(SectionType.EDUCATION,
new SectionOrganization(
new Organization("university", null,
new Organization.Position(2005, Month.SEPTEMBER, 2010, Month.JUNE, "aspirant",
null),
new Organization.Position(2001, Month.SEPTEMBER, 2005, Month.APRIL, "student",
"IT")),
new Organization("Organization12", "http://organization12.ru")));

R2.addContact(ContactType.MOBILE_PHONE, "1234567");
R2.addContact(ContactType.SKYPE, "@SecondMember");
R2.addSection(SectionType.EXPERIENCE,
new SectionOrganization(
new Organization("Organization21", "http://organization21.ru",
new Organization.Position(2018, Month.JULY, "position21", "content21"))));
}

}
53 changes: 2 additions & 51 deletions test/ru/javawebinar/basejava/storage/AbstractStorageTest.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package ru.javawebinar.basejava.storage;


import static ru.javawebinar.basejava.TestData.*;

import java.io.File;
import java.time.Month;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -25,55 +25,6 @@ protected AbstractStorageTest(Storage storage) {
this.storage = storage;
}

private static final String UUID_1 = UUID.randomUUID().toString();
private static final String UUID_2 = UUID.randomUUID().toString();
private static final String UUID_3 = UUID.randomUUID().toString();
private static final String UUID_4 = UUID.randomUUID().toString();
private static final Resume R1;
private static final Resume R2;
private static final Resume R3;
private static final Resume R4;

static {
R1 = new Resume(UUID_1, "Name1");
R2 = new Resume(UUID_2, "Name2");
R3 = new Resume(UUID_3, "Name3");
R4 = new Resume(UUID_4, "Name4");

R1.addContact(ContactType.MOBILE_PHONE, "+79001234567");
R1.addContact(ContactType.EMAIL, "abc@mail.ru");
R4.addContact(ContactType.SKYPE, "Skype");
R4.addContact(ContactType.MOBILE_PHONE, "+76666666666");


// R1.addSection(SectionType.OBJECTIVE, new SectionLine("Objective"));
// R1.addSection(SectionType.PERSONAL, new SectionLine("Personal data"));
// R1.addSection(SectionType.ACHIEVEMENT,
// new SectionList("Achievement11", "Achievement12", "Achievement13"));
// R1.addSection(SectionType.QUALIFICATION, new SectionList("Java", "git", "SQL"));
// R1.addSection(SectionType.EXPERIENCE,
// new SectionOrganization(
// new Organization("Organization11", "http://organization11.ru",
// new Organization.Position(2015, Month.JANUARY, "position11", "content11"),
// new Organization.Position(2010, Month.JULY, 2014, Month.DECEMBER, "position12",
// "content12"))));
// R1.addSection(SectionType.EDUCATION,
// new SectionOrganization(
// new Organization("university", null,
// new Organization.Position(2005, Month.SEPTEMBER, 2010, Month.JUNE, "aspirant",
// null),
// new Organization.Position(2001, Month.SEPTEMBER, 2005, Month.APRIL, "student",
// "IT")),
// new Organization("Organization12", "http://organization12.ru")));
//
// R2.addContact(ContactType.MOBILE_PHONE, "1234567");
// R2.addContact(ContactType.SKYPE, "@SecondMember");
// R2.addSection(SectionType.EXPERIENCE,
// new SectionOrganization(
// new Organization("Organization21", "http://organization21.ru",
// new Organization.Position(2018, Month.JULY, "position21", "content21"))));
}

@BeforeEach
public void setUp() {
storage.clear();
Expand Down
30 changes: 30 additions & 0 deletions test/ru/javawebinar/basejava/util/JsonParserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ru.javawebinar.basejava.util;

import static org.junit.jupiter.api.Assertions.*;
import static ru.javawebinar.basejava.TestData.R1;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import ru.javawebinar.basejava.model.Resume;
import ru.javawebinar.basejava.model.Section;
import ru.javawebinar.basejava.model.SectionLine;

class JsonParserTest {

@Test
void testResume() {
String json = JsonParser.write(R1);
System.out.println(json);
Resume resume = JsonParser.read(json, Resume.class);
Assertions.assertEquals(R1, resume);
}

@Test
void testSection() {
Section section = new SectionLine("Personal1");
String json = JsonParser.write(section, Section.class);
System.out.println(json);
Section section2 = JsonParser.read(json, Section.class);
Assertions.assertEquals(section, section2);
}
}