Converted to Hibernate.

This commit is contained in:
neviyn 2018-09-18 22:44:20 +01:00
parent 7cbd354c38
commit b4ca1a8fc7
21 changed files with 230 additions and 248 deletions

View File

@ -32,7 +32,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.dropwizard</groupId> <groupId>io.dropwizard</groupId>
<artifactId>dropwizard-jdbi3</artifactId> <artifactId>dropwizard-hibernate</artifactId>
<version>${dropwizard.version}</version> <version>${dropwizard.version}</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -2,11 +2,14 @@ package uk.co.neviyn.Observations;
import io.dropwizard.Application; import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle; import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.jdbi3.JdbiFactory; import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.hibernate.HibernateBundle;
import io.dropwizard.jersey.setup.JerseyEnvironment; import io.dropwizard.jersey.setup.JerseyEnvironment;
import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment; import io.dropwizard.setup.Environment;
import org.jdbi.v3.core.Jdbi; import uk.co.neviyn.Observations.core.Observation;
import uk.co.neviyn.Observations.core.Site;
import uk.co.neviyn.Observations.core.Tutor;
import uk.co.neviyn.Observations.dao.ObservationDao; import uk.co.neviyn.Observations.dao.ObservationDao;
import uk.co.neviyn.Observations.dao.SiteDao; import uk.co.neviyn.Observations.dao.SiteDao;
import uk.co.neviyn.Observations.dao.TutorDao; import uk.co.neviyn.Observations.dao.TutorDao;
@ -16,6 +19,18 @@ import uk.co.neviyn.Observations.resources.SiteResource;
public class ObservationsApplication extends Application<ObservationsConfiguration> { public class ObservationsApplication extends Application<ObservationsConfiguration> {
private final HibernateBundle<ObservationsConfiguration> hibernate = new HibernateBundle<ObservationsConfiguration>(
Observation.class,
Tutor.class,
Site.class
) {
@Override
public DataSourceFactory getDataSourceFactory(ObservationsConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new ObservationsApplication().run(args); new ObservationsApplication().run(args);
} }
@ -23,27 +38,22 @@ public class ObservationsApplication extends Application<ObservationsConfigurati
@Override @Override
public void initialize(Bootstrap<ObservationsConfiguration> bootstrap) { public void initialize(Bootstrap<ObservationsConfiguration> bootstrap) {
super.initialize(bootstrap); super.initialize(bootstrap);
bootstrap.addBundle(hibernate);
bootstrap.addBundle(new AssetsBundle("/assets/", "/", "/index.html")); bootstrap.addBundle(new AssetsBundle("/assets/", "/", "/index.html"));
} }
@Override @Override
public void run(ObservationsConfiguration observationsConfiguration, Environment environment) { public void run(ObservationsConfiguration observationsConfiguration, Environment environment) {
final JerseyEnvironment jersey = environment.jersey(); final JerseyEnvironment jersey = environment.jersey();
final JdbiFactory factory = new JdbiFactory(); TutorDao tutorDao = new TutorDao(hibernate.getSessionFactory());
final Jdbi jdbi = factory.build(environment, observationsConfiguration.getDataSourceFactory(), "database"); SiteDao siteDao = new SiteDao(hibernate.getSessionFactory());
TutorDao tutorDao = jdbi.onDemand(TutorDao.class); ObservationDao observationDao = new ObservationDao(hibernate.getSessionFactory());
SiteDao siteDao = jdbi.onDemand(SiteDao.class);
ObservationDao observationDao = jdbi.onDemand(ObservationDao.class);
jersey.register(tutorDao); jersey.register(tutorDao);
jersey.register(siteDao); jersey.register(siteDao);
jersey.register(observationDao); jersey.register(observationDao);
siteDao.createSiteTable();
tutorDao.createTutorTable();
observationDao.createObservationTable();
observationDao.createObservationTutorTable();
final TutorResource tutorResource = new TutorResource(tutorDao); final TutorResource tutorResource = new TutorResource(tutorDao);
jersey.register(tutorResource); jersey.register(tutorResource);
final ObservationResource observationResource = new ObservationResource(observationDao); final ObservationResource observationResource = new ObservationResource(observationDao, tutorDao, siteDao);
jersey.register(observationResource); jersey.register(observationResource);
final SiteResource siteResource = new SiteResource(siteDao); final SiteResource siteResource = new SiteResource(siteDao);
jersey.register(siteResource); jersey.register(siteResource);

View File

@ -1,14 +1,10 @@
package uk.co.neviyn.Observations.api; package uk.co.neviyn.Observations.api;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.sql.ResultSet;
import java.sql.SQLException;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@Data @Data
@ -18,16 +14,9 @@ public class AverageStats {
@NonNull @NonNull
@JsonProperty @JsonProperty
private float monitoring, control, conservatism, teamwork, knowledge; private double monitoring, control, conservatism, teamwork, knowledge;
@NonNull @NonNull
@JsonProperty @JsonProperty
private LocalDate date; private LocalDate date;
public static class Mapper implements RowMapper<AverageStats> {
public AverageStats map(ResultSet rs, StatementContext ctx) throws SQLException {
return new AverageStats(rs.getFloat("monitoring"), rs.getFloat("control"), rs.getFloat("conservatism"),
rs.getFloat("teamwork"), rs.getFloat("knowledge"), new LocalDate(rs.getDate("date")));
}
}
} }

View File

@ -22,7 +22,7 @@ public class AverageStatsChartJs {
private List<Dataset> datasets = new ArrayList<>(); private List<Dataset> datasets = new ArrayList<>();
public AverageStatsChartJs(List<AverageStats> inputData){ public AverageStatsChartJs(List<AverageStats> inputData){
List<Float> monitoring = new ArrayList<>(), List<Double> monitoring = new ArrayList<>(),
control = new ArrayList<>(), control = new ArrayList<>(),
conservatism = new ArrayList<>(), conservatism = new ArrayList<>(),
teamwork = new ArrayList<>(), teamwork = new ArrayList<>(),
@ -54,6 +54,6 @@ public class AverageStatsChartJs {
@NonNull @NonNull
@JsonProperty @JsonProperty
private final List<Float> data; private final List<Double> data;
} }
} }

View File

@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List; import java.util.List;
import lombok.*; import lombok.*;
import uk.co.neviyn.Observations.core.ObservationEntry;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@ -12,11 +13,11 @@ public class NewObservation {
@NonNull @NonNull
@JsonProperty @JsonProperty
private int siteId; private long siteId;
@NonNull @NonNull
@JsonProperty @JsonProperty
private List<Integer> tutorIds; private List<Long> tutorIds;
@NonNull @NonNull
@JsonProperty @JsonProperty
@ -28,6 +29,6 @@ public class NewObservation {
@NonNull @NonNull
@JsonProperty @JsonProperty
private String rawData; private List<ObservationEntry> rawData;
} }

View File

@ -0,0 +1,23 @@
package uk.co.neviyn.Observations.core;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@Data
@MappedSuperclass
@NoArgsConstructor
@AllArgsConstructor
class BaseEntity {
@NonNull
@JsonProperty
@Id
@GeneratedValue
private long id;
}

View File

@ -2,30 +2,30 @@ package uk.co.neviyn.Observations.core;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Set;
import lombok.*; import lombok.*;
import org.apache.commons.lang3.SerializationUtils;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import uk.co.neviyn.Observations.api.ObservationEntry;
import javax.persistence.*;
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "OBSERVATION")
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor(access = AccessLevel.PROTECTED)
public class Observation { public class Observation extends BaseEntity{
@NonNull
@JsonProperty @JsonProperty
private int id; @ManyToOne
@JoinColumn(name="site_id", nullable=false)
private Site site;
@NonNull
@JsonProperty @JsonProperty
private int siteId; @ManyToMany(mappedBy = "observations")
private Set<Tutor> tutors;
@NonNull @NonNull
@JsonProperty @JsonProperty
@ -41,49 +41,9 @@ public class Observation {
@NonNull @NonNull
@JsonProperty @JsonProperty
private List<ObservationEntry> rawData; private List<ObservationEntry> observations;
@NonNull @NonNull
@JsonProperty @JsonProperty
private DateTime date; private DateTime date;
public Observation(int siteId, String observed, int monitoring, int control, int conservatism, int teamwork,
int knowledge, List<ObservationEntry> rawData) {
this.siteId = siteId;
this.observed = observed;
this.monitoring = monitoring;
this.control = control;
this.conservatism = conservatism;
this.teamwork = teamwork;
this.knowledge = knowledge;
this.rawData = rawData;
}
private Observation(int id, int siteId, String observed, String type, int monitoring, int control, int conservatism,
int teamwork, int knowledge, byte[] rawData, DateTime date) {
this.id = id;
this.siteId = siteId;
this.observed = observed;
this.type = TrainingType.valueOf(type.toUpperCase());
this.monitoring = monitoring;
this.control = control;
this.conservatism = conservatism;
this.teamwork = teamwork;
this.knowledge = knowledge;
this.rawData = SerializationUtils.deserialize(rawData);
this.date = date;
}
public byte[] serializeRawData(){
return SerializationUtils.serialize((Serializable) rawData);
}
public static class Mapper implements RowMapper<Observation> {
public Observation map(ResultSet rs, StatementContext ctx) throws SQLException {
return new Observation(rs.getInt("id"), rs.getInt("siteId"), rs.getString("observed"), rs.getString("type"),
rs.getInt("monitoring"), rs.getInt("control"), rs.getInt("conservatism"), rs.getInt("teamwork"),
rs.getInt("knowledge"), rs.getBytes("rawData"), new DateTime(rs.getDate("date")));
}
}
} }

View File

@ -1,15 +1,13 @@
package uk.co.neviyn.Observations.api; package uk.co.neviyn.Observations.core;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@EqualsAndHashCode(callSuper = true)
@Data @Data
@AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class ObservationEntry { @AllArgsConstructor
public class ObservationEntry extends BaseEntity{
@NonNull @NonNull
@JsonProperty @JsonProperty

View File

@ -1,32 +1,33 @@
package uk.co.neviyn.Observations.core; package uk.co.neviyn.Observations.core;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.sql.ResultSet; import java.util.Set;
import java.sql.SQLException;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
import lombok.*;
import javax.persistence.*;
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "SITE")
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PROTECTED) public class Site extends BaseEntity {
public class Site {
@NonNull
@JsonProperty
private int id;
@NonNull @NonNull
@JsonProperty @JsonProperty
private String name; private String name;
public static class Mapper implements RowMapper<Site> { @JsonProperty
public Site map(ResultSet rs, StatementContext ctx) throws SQLException { @OneToMany(mappedBy="site")
return new Site(rs.getInt("id"), rs.getString("name")); private Set<Tutor> tutors;
}
@JsonProperty
@OneToMany(mappedBy = "site")
private Set<Observation> observations;
public Site(long id, String name) {
super(id);
this.name = name;
} }
} }

View File

@ -1,37 +1,38 @@
package uk.co.neviyn.Observations.core; package uk.co.neviyn.Observations.core;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.sql.ResultSet; import lombok.*;
import java.sql.SQLException;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
import javax.persistence.*;
import java.util.Set;
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "TUTOR")
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PROTECTED) public class Tutor extends BaseEntity {
public class Tutor {
@NonNull
@JsonProperty
private int id;
@NonNull @NonNull
@JsonProperty @JsonProperty
private String name; private String name;
@NonNull
@JsonProperty @JsonProperty
private int site; @ManyToOne
@JoinColumn(name="site_id", nullable=false)
private Site site;
public static class Mapper implements RowMapper<Tutor>{ @JsonProperty
@ManyToMany
@JoinTable(
name = "TUTOR_OBSERVATION",
joinColumns = { @JoinColumn(name = "tutor_id")},
inverseJoinColumns = { @JoinColumn(name = "observation_id")}
)
private Set<Observation> observations;
public Tutor map(ResultSet rs, StatementContext ctx) throws SQLException { public Tutor(long id, String name) {
return new Tutor(rs.getInt("id"), rs.getString("name"), rs.getInt("site")); super(id);
} this.name = name;
} }
} }

View File

@ -1,59 +1,40 @@
package uk.co.neviyn.Observations.dao; package uk.co.neviyn.Observations.dao;
import java.util.List; import io.dropwizard.hibernate.AbstractDAO;
import org.jdbi.v3.sqlobject.config.RegisterRowMapper; import org.hibernate.SessionFactory;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import org.joda.time.DateTime;
import uk.co.neviyn.Observations.api.AverageStats; import uk.co.neviyn.Observations.api.AverageStats;
import uk.co.neviyn.Observations.api.NewObservation;
import uk.co.neviyn.Observations.core.Observation; import uk.co.neviyn.Observations.core.Observation;
import uk.co.neviyn.Observations.core.Site;
@RegisterRowMapper(Observation.Mapper.class) import java.util.List;
public interface ObservationDao {
@SqlUpdate("CREATE TABLE IF NOT EXISTS observations (id INTEGER PRIMARY KEY, siteId INTEGER, " + public class ObservationDao extends AbstractDAO<Observation> {
"observed TEXT, type TEXT, monitoring INTEGER, control INTEGER, conservatism INTEGER, teamwork INTEGER, " + public ObservationDao(SessionFactory sessionFactory) {
"knowledge INTEGER, rawData BLOB, date DATE)") super(sessionFactory);
void createObservationTable(); }
@SqlUpdate("CREATE TABLE IF NOT EXISTS observation_tutor (tutorId INT NOT NULL, observationId INT NOT NULL, " + public Observation get(long id){
"FOREIGN KEY (tutorID) REFERENCES tutor(id), FOREIGN KEY (observationId) REFERENCES observations(id))") return super.get(id);
void createObservationTutorTable(); }
@SqlUpdate("INSERT INTO observations (siteId, observed, type, monitoring, control, conservatism, teamwork, knowledge, " + public Observation persist(Observation observation){
"rawData, date) VALUES (:siteId, :observed, :type, :monitoring, :control, :conservatism, :teamwork, :knowledge, " + return super.persist(observation);
":serializeRawData, :date)") }
@GetGeneratedKeys
int addObservation(@BindBean NewObservation observation, @Bind("date") DateTime date);
@SqlUpdate("INSERT INTO observation_tutor (tutorId, observationId) VALUES (:tutorId, :observationId)") public List<Observation> listAll(){
void addObservationTutor(@Bind("observationId")int observationId, @Bind("tutorId")int tutorId); return list(criteriaQuery());
}
@SqlQuery("SELECT * FROM observations WHERE date BETWEEN :startDate AND :endDate") public List<AverageStats> averageStatsForAll(){
List<Observation> observationsBetweenDates(@Bind("startDate")DateTime startDate, @Bind("endDate")DateTime endDate); final String hql = "select avg(observation.monitoring), avg(observation.control), avg(observation.conservatism), " +
"avg(observation.teamwork), avg(observation.knowledge) from observation where group by observation.date";
return currentSession().createQuery(hql, AverageStats.class).list();
}
@SqlQuery("SELECT * FROM observations LEFT JOIN observation_tutor ON observation_tutor.observationId = observations.id " + public List<AverageStats> averageStatsForSite(Site site){
"LEFT JOIN tutor ON observation_tutor.tutorId = tutor.id WHERE tutor.id = :tutorId") final String hql = "select avg(observation.monitoring), avg(observation.control), avg(observation.conservatism), " +
List<Observation> observationsByTutor(@Bind("tutorId")int tutorId); "avg(observation.teamwork), avg(observation.knowledge) from observation where observation.site = :site " +
"group by observation.date";
@SqlQuery("SELECT * FROM observations WHERE date BETWEEN :startDate AND :endDate " + return currentSession().createQuery(hql, AverageStats.class).setParameter("site", site).list();
"LEFT JOIN observation_tutor ON observation_tutor.observationId = observations.id " + }
"LEFT JOIN tutor ON observation_tutor.tutorId = tutor.id WHERE tutor.id = :tutorId")
List<Observation> observationsByTutorBetweenDates(@Bind("tutorId")int tutorId, @Bind("startDate")DateTime startDate,
@Bind("endDate")DateTime endDate);
@SqlQuery("SELECT AVG(monitoring) as monitoring, AVG(control) as control, AVG(conservatism) as conservatism, " +
"AVG(teamwork) as teamwork, AVG(knowledge) as knowledge, date FROM observations GROUP BY date ORDER BY date")
@RegisterRowMapper(AverageStats.Mapper.class)
List<AverageStats> averageObservationScoresByDay();
@SqlQuery("SELECT MIN(date) FROM observations")
DateTime earliestEntryDate();
@SqlQuery("SELECT MAX(date) FROM observations")
DateTime latestEntryDate();
} }

View File

@ -1,21 +1,21 @@
package uk.co.neviyn.Observations.dao; package uk.co.neviyn.Observations.dao;
import java.util.List; import io.dropwizard.hibernate.AbstractDAO;
import org.jdbi.v3.sqlobject.config.RegisterRowMapper; import org.hibernate.SessionFactory;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import uk.co.neviyn.Observations.core.Site; import uk.co.neviyn.Observations.core.Site;
@RegisterRowMapper(Site.Mapper.class) import java.util.List;
public interface SiteDao {
@SqlUpdate("CREATE TABLE IF NOT EXISTS site (id INTEGER PRIMARY KEY, name VARCHAR(100))") public class SiteDao extends AbstractDAO<Site> {
void createSiteTable(); public SiteDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
@SqlQuery("SELECT * FROM site") public List<Site> listAll(){
List<Site> allSites(); return list(criteriaQuery());
}
@SqlQuery("SELECT * FROM site WHERE id = :id") public Site get(long id){
Site getSiteById(@Bind("id") int id); return super.get(id);
}
} }

View File

@ -1,29 +1,21 @@
package uk.co.neviyn.Observations.dao; package uk.co.neviyn.Observations.dao;
import java.util.List; import io.dropwizard.hibernate.AbstractDAO;
import org.jdbi.v3.sqlobject.config.RegisterRowMapper; import org.hibernate.SessionFactory;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import uk.co.neviyn.Observations.core.Tutor; import uk.co.neviyn.Observations.core.Tutor;
@RegisterRowMapper(Tutor.Mapper.class) import java.util.List;
public interface TutorDao {
@SqlUpdate("CREATE TABLE IF NOT EXISTS tutor (id INTEGER PRIMARY KEY, " + public class TutorDao extends AbstractDAO<Tutor> {
"name VARCHAR(100), site INT, FOREIGN KEY (site) REFERENCES site(id))") public TutorDao(SessionFactory sessionFactory) {
void createTutorTable(); super(sessionFactory);
}
@SqlUpdate("INSERT INTO tutor(name, site) VALUES (:name, :site)") public Tutor get(long id){
@GetGeneratedKeys("id") return super.get(id);
int add(@BindBean Tutor tutor); }
@SqlQuery("SELECT * FROM tutor WHERE site = :siteId")
List<Tutor> tutorsForSite(@Bind("siteId")int siteId);
@SqlQuery("SELECT * FROM tutor")
List<Tutor> allTutors();
public List<Tutor> listAll(){
return list(criteriaQuery());
}
} }

View File

@ -1,6 +1,9 @@
package uk.co.neviyn.Observations.resources; package uk.co.neviyn.Observations.resources;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -10,6 +13,8 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import io.dropwizard.hibernate.UnitOfWork;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -18,7 +23,12 @@ import uk.co.neviyn.Observations.api.AverageStats;
import uk.co.neviyn.Observations.api.AverageStatsChartJs; import uk.co.neviyn.Observations.api.AverageStatsChartJs;
import uk.co.neviyn.Observations.api.NewObservation; import uk.co.neviyn.Observations.api.NewObservation;
import uk.co.neviyn.Observations.core.Observation; import uk.co.neviyn.Observations.core.Observation;
import uk.co.neviyn.Observations.core.Site;
import uk.co.neviyn.Observations.core.TrainingType;
import uk.co.neviyn.Observations.core.Tutor;
import uk.co.neviyn.Observations.dao.ObservationDao; import uk.co.neviyn.Observations.dao.ObservationDao;
import uk.co.neviyn.Observations.dao.SiteDao;
import uk.co.neviyn.Observations.dao.TutorDao;
@RequiredArgsConstructor @RequiredArgsConstructor
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -28,32 +38,44 @@ import uk.co.neviyn.Observations.dao.ObservationDao;
public class ObservationResource { public class ObservationResource {
private final ObservationDao dao; private final ObservationDao dao;
private final TutorDao tutorDao;
private final SiteDao siteDao;
@POST @POST
public int add(@NotNull @Valid NewObservation observation){ @UnitOfWork
final int observationId = dao.addObservation(observation, LocalDate.now().toDateTimeAtStartOfDay()); public long add(@NotNull @Valid NewObservation newObservation){
log.info("Created observation with ID " + observationId + " at " + DateTime.now().toString()); final DateTime submissionDate = LocalDate.now().toDateTimeAtStartOfDay();
for(int tutorId: observation.getTutorIds()){ Set<Tutor> tutors = new HashSet<>();
dao.addObservationTutor(observationId, tutorId); for(long l: newObservation.getTutorIds()){
tutors.add(tutorDao.get(l));
} }
return observationId; final Site site = siteDao.get(newObservation.getSiteId());
} Observation observation = new Observation();
observation.setSite(site);
@Path("/by/{tutorId}") observation.setTutors(tutors);
@GET observation.setObserved(newObservation.getObserved());
public List<Observation> observationsBy(@PathParam("tutorId") int tutorId){ observation.setType(TrainingType.valueOf(newObservation.getType()));
return dao.observationsByTutor(tutorId); observation.setMonitoring(newObservation.getMonitoring());
observation.setControl(newObservation.getControl());
observation.setConservatism(newObservation.getConservatism());
observation.setTeamwork(newObservation.getTeamwork());
observation.setKnowledge(newObservation.getKnowledge());
observation.setObservations(newObservation.getRawData());
observation.setDate(submissionDate);
observation = dao.persist(observation);
log.info("Created observation with ID " + observation.getId() + " at " + DateTime.now().toString());
return observation.getId();
} }
@Path("/average/all") @Path("/average/all")
@GET @GET
public List<AverageStats> averageObservationScores(){ public List<AverageStats> averageObservationScores(){
return dao.averageObservationScoresByDay(); return dao.averageStatsForAll();
} }
@Path("/average/all/chartjs") @Path("/average/all/chartjs")
@GET @GET
public AverageStatsChartJs averageStatsChartJs(){ public AverageStatsChartJs averageStatsChartJs(){
return new AverageStatsChartJs(dao.averageObservationScoresByDay()); return new AverageStatsChartJs(dao.averageStatsForAll());
} }
} }

View File

@ -1,7 +1,9 @@
package uk.co.neviyn.Observations.resources; package uk.co.neviyn.Observations.resources;
import io.dropwizard.hibernate.UnitOfWork;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import uk.co.neviyn.Observations.api.SelectOption; import uk.co.neviyn.Observations.api.SelectOption;
import uk.co.neviyn.Observations.core.Tutor;
import uk.co.neviyn.Observations.dao.SiteDao; import uk.co.neviyn.Observations.dao.SiteDao;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@ -9,6 +11,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
@ -20,7 +23,15 @@ public class SiteResource {
@Path("/all") @Path("/all")
@GET @GET
public List<SelectOption<Integer>> allSites() { @UnitOfWork
return dao.allSites().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()); public List<SelectOption<Long>> allSites() {
return dao.listAll().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList());
}
@Path("/{id}/tutors")
@GET
@UnitOfWork
public Set<Tutor> getSiteTutors(long id){
return dao.get(id).getTutors();
} }
} }

View File

@ -9,6 +9,8 @@ import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import io.dropwizard.hibernate.UnitOfWork;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import uk.co.neviyn.Observations.api.SelectOption; import uk.co.neviyn.Observations.api.SelectOption;
import uk.co.neviyn.Observations.core.Tutor; import uk.co.neviyn.Observations.core.Tutor;
@ -23,20 +25,11 @@ public class TutorResource {
@Path("/all") @Path("/all")
@GET @GET
@UnitOfWork
public List<Tutor> allTutors() { public List<Tutor> allTutors() {
List<Tutor> tutors = dao.allTutors(); List<Tutor> tutors = dao.listAll();
if (tutors != null && !tutors.isEmpty()) if (tutors != null && !tutors.isEmpty())
return tutors; return tutors;
throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND); throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND);
} }
@Path("/site/{id}")
@GET
public List<SelectOption<Integer>> tutorsForSite(@PathParam("id") int siteId) {
List<Tutor> tutors = dao.tutorsForSite(siteId);
if (tutors != null && !tutors.isEmpty()) {
return tutors.stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList());
}
throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND);
}
} }

View File

@ -3,8 +3,10 @@ package uk.co.neviyn.Observations.api;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.dropwizard.jackson.Jackson; import io.dropwizard.jackson.Jackson;
import org.junit.Test; import org.junit.Test;
import uk.co.neviyn.Observations.core.ObservationEntry;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import static io.dropwizard.testing.FixtureHelpers.fixture; import static io.dropwizard.testing.FixtureHelpers.fixture;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -13,8 +15,8 @@ public class NewObservationTest {
private static final ObjectMapper mapper = Jackson.newObjectMapper(); private static final ObjectMapper mapper = Jackson.newObjectMapper();
private final NewObservation newObservation = new NewObservation(1, Arrays.asList(1, 2, 3), "A random thing made for testing.", private final NewObservation newObservation = new NewObservation(1, Arrays.asList(1L, 2L, 3L), "A random thing made for testing.",
"INITIAL", 1, 2, 3, 4, 5, "{\"data\":\"Looks like there's nothing here.\"}"); "INITIAL", 1, 2, 3, 4, 5, Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")));
@Test @Test
public void serializesToJson() throws Exception { public void serializesToJson() throws Exception {

View File

@ -5,7 +5,6 @@ import io.dropwizard.jackson.Jackson;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.Test; import org.junit.Test;
import uk.co.neviyn.Observations.api.ObservationEntry;
import java.util.Collections; import java.util.Collections;
@ -16,7 +15,7 @@ import static org.junit.Assert.*;
public class ObservationTest { public class ObservationTest {
private static final ObjectMapper mapper = Jackson.newObjectMapper(); private static final ObjectMapper mapper = Jackson.newObjectMapper();
private final Observation observation = new Observation(1, 1, "Just a test observation", TrainingType.INITIAL, 1, 2, 3, private final Observation observation = new Observation(null, null, "Just a test observation", TrainingType.INITIAL, 1, 2, 3,
4, 5, Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")), DateTime.parse("2018-09-18T00:00:00.000Z") 4, 5, Collections.singletonList(new ObservationEntry("MONITORING", 5, "some", "another sum")), DateTime.parse("2018-09-18T00:00:00.000Z")
); );

View File

@ -8,5 +8,5 @@
"conservatism":3, "conservatism":3,
"teamwork":4, "teamwork":4,
"knowledge":5, "knowledge":5,
"rawData":"{\"data\":\"Looks like there's nothing here.\"}" "rawData":[{"type":"MONITORING","rating":5,"strengths":"some","improvements":"another sum"}]
} }

View File

@ -1,6 +1,5 @@
{ {
"id":1, "id":0,
"siteId":1,
"observed":"Just a test observation", "observed":"Just a test observation",
"type":"INITIAL", "type":"INITIAL",
"monitoring":1, "monitoring":1,
@ -8,7 +7,7 @@
"conservatism":3, "conservatism":3,
"teamwork":4, "teamwork":4,
"knowledge":5, "knowledge":5,
"rawData":[{ "observations":[{
"type": "MONITORING", "type": "MONITORING",
"rating":5, "rating":5,
"strengths":"some", "strengths":"some",

View File

@ -76,7 +76,7 @@ export default {
...mapMutations(["setSite", "setDescription", "setType", "setTutors"]), ...mapMutations(["setSite", "setDescription", "setType", "setTutors"]),
getTutors: function() { getTutors: function() {
if (this.site != null) { if (this.site != null) {
Vue.axios.get("/api/tutor/site/" + this.site).then(response => { Vue.axios.get("/api/site/" + this.site + "/tutors").then(response => {
this.tutorOptions = response.data; this.tutorOptions = response.data;
this.loadingTutors = false; this.loadingTutors = false;
}); });