modular database schema

This commit is contained in:
Michał Michaluk
2017-12-20 08:55:25 +01:00
parent a3682be9b8
commit 78409facaf
40 changed files with 365 additions and 146 deletions

View File

@@ -19,6 +19,7 @@ public abstract class JsonConverter<T> implements AttributeConverter<T, String>
.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
.registerModule(new JavaTimeModule());
private final Class<T> type;

View File

@@ -1,6 +1,6 @@
spring.main.banner-mode=off
spring.jpa.database=default
spring.jpa.generate-ddl=true
spring.jpa.generate-ddl=false
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=

View File

@@ -1,19 +1,14 @@
package pl.com.bottega.factory.stock.forecast.ressource;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import pl.com.bottega.tools.ProjectionRepository;
import java.util.List;
@Repository
@RepositoryRestResource(path = "stock-forecasts",
collectionResourceRel = "stock-forecasts",
itemResourceRel = "stock-forecast",
excerptProjection = StockForecastEntity.CollectionItem.class)
public interface StockForecastDao extends ProjectionRepository<StockForecastEntity, Long> {
public interface StockForecastDao extends ProjectionRepository<StockForecastEntity, String> {
@RestResource(path = "refNos", rel = "refNos")
List<StockForecastEntity> findByProductRefNo(String refNo);
}

View File

@@ -1,27 +1,22 @@
package pl.com.bottega.factory.stock.forecast.ressource;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.rest.core.config.Projection;
import pl.com.bottega.factory.stock.forecast.StockForecast;
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
@Entity(name = "StockForecast")
@Table(schema = "shortages_prediction")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString
public class StockForecastEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String refNo;
public StockForecastEntity(String refNo) {

View File

@@ -5,6 +5,8 @@ curl -X POST -H "Content-Type: application/json" \
-d @app-monolith/src/test/resources/examples/product-descriptions.json \
http://localhost:8080/product-descriptions
curl http://localhost:8080/stock-forecasts
curl -X POST -H "Content-Type: application/json" \
-d @app-monolith/src/test/resources/examples/delivery-definitions.json \
http://localhost:8080/delivery-definitions

View File

@@ -1,4 +1,2 @@
--create schema demands authorization postgres;
--create schema shortages authorization postgres;
--create schema products authorization postgres;
-- see schema directory

View File

@@ -0,0 +1,12 @@
--liquibase formatted sql
--changeset michaluk.michal:1.init
CREATE SEQUENCE hibernate_sequence
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
CREATE CAST (character varying AS json) WITH INOUT AS ASSIGNMENT;

View File

@@ -2,7 +2,10 @@
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
<!--<include file="/schema/product-management.sql"/>-->
<!--<include file="/schema/demand-forecasting.sql"/>-->
<!--<include file="/schema/shortages-prediction.sql"/>-->
<include file="/schema/commons.sql"/>
<include file="/schema/delivery-planning.sql"/>
<include file="/schema/demand-forecasting.sql"/>
<include file="/schema/product-management.sql"/>
<include file="/schema/production-planning.sql"/>
<include file="/schema/shortages-prediction.sql"/>
</databaseChangeLog>

View File

@@ -0,0 +1,17 @@
--liquibase formatted sql
--changeset michaluk.michal:1.init
CREATE SCHEMA delivery_planning;
CREATE TABLE delivery_planning.delivery_planner_definition (
ref_no character varying(64) NOT NULL PRIMARY KEY,
definition json NOT NULL
);
CREATE TABLE delivery_planning.delivery_forecast (
id serial NOT NULL PRIMARY KEY,
ref_no character varying(64) NOT NULL,
"time" timestamp without time zone NOT NULL,
"date" timestamp without time zone NOT NULL,
level bigint NOT NULL
);

View File

@@ -0,0 +1,46 @@
--liquibase formatted sql
--changeset michaluk.michal:1.init
CREATE SCHEMA demand_forecasting;
CREATE TABLE demand_forecasting.product_demand (
id serial NOT NULL PRIMARY KEY,
version bigint NOT NULL,
ref_no character varying(64) NOT NULL,
UNIQUE(ref_no)
);
CREATE TABLE demand_forecasting."demand" (
id serial NOT NULL PRIMARY KEY,
ref_no character varying(64) NOT NULL,
"date" timestamp without time zone NOT NULL,
value json NOT NULL,
UNIQUE(ref_no, "date")
);
CREATE TABLE demand_forecasting.current_demand (
id serial NOT NULL PRIMARY KEY,
ref_no character varying(64) NOT NULL,
"date" timestamp without time zone NOT NULL,
level bigint NOT NULL,
"schema" character varying(64) NOT NULL,
UNIQUE(ref_no, "date")
);
CREATE TABLE demand_forecasting.demand_adjustment (
id serial NOT NULL PRIMARY KEY,
customer_representative character varying(255) NOT NULL,
note character varying(255) NOT NULL,
adjustment json NOT NULL,
clean_after timestamp without time zone
);
CREATE TABLE demand_forecasting.demand_review (
id serial NOT NULL PRIMARY KEY,
ref_no character varying(64) NOT NULL,
"date" timestamp without time zone NOT NULL,
"timestamp" timestamp without time zone NOT NULL,
review json NOT NULL,
decision character varying(64),
clean_after timestamp without time zone
);

View File

@@ -1,3 +1,9 @@
--liquibase formatted sql
--changeset michaluk.michal:1.init
CREATE SCHEMA product_management;
CREATE TABLE product_management.product_description (
ref_no character varying(64) NOT NULL PRIMARY KEY,
description json NOT NULL
);

View File

@@ -0,0 +1,22 @@
--liquibase formatted sql
--changeset michaluk.michal:1.init
CREATE SCHEMA production_planning;
CREATE TABLE production_planning.production_daily_output (
id serial NOT NULL PRIMARY KEY,
ref_no character varying(64) NOT NULL,
"date" timestamp without time zone NOT NULL,
output bigint NOT NULL,
UNIQUE(ref_no, "date")
);
CREATE TABLE production_planning.production_output (
id serial NOT NULL PRIMARY KEY,
ref_no character varying(64) NOT NULL,
"start" timestamp without time zone NOT NULL,
"end" timestamp without time zone NOT NULL,
duration bigint NOT NULL,
parts_per_minute integer NOT NULL,
total bigint NOT NULL
);

View File

@@ -0,0 +1,16 @@
--liquibase formatted sql
--changeset michaluk.michal:1.init
CREATE SCHEMA shortages_prediction;
CREATE TABLE shortages_prediction.shortage (
id serial NOT NULL PRIMARY KEY,
version bigint NOT NULL,
ref_no character varying(64) NOT NULL,
shortages json NOT NULL,
UNIQUE(ref_no)
);
CREATE TABLE shortages_prediction.stock_forecast (
ref_no character varying(64) NOT NULL PRIMARY KEY
);

View File

@@ -25,6 +25,13 @@
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>

View File

@@ -17,7 +17,7 @@ public class DeliveryAutoPlannerORMRepository {
public DeliveryAutoPlanner get(String refNo) {
return new DeliveryAutoPlanner(refNo,
ofNullable(dao.findByRefNo(refNo))
ofNullable(dao.findOne(refNo))
.map(DeliveryPlannerDefinitionEntity::getDefinition)
.map(x -> x.map(DeliveriesSuggestion::timesAndFractions))
.orElse(Collections.emptyMap()));

View File

@@ -2,8 +2,8 @@ package pl.com.bottega.factory.delivery.planning.definition;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Singular;
import lombok.Value;
import pl.com.bottega.factory.demand.forecasting.Demand;
import java.time.LocalTime;
@@ -13,8 +13,8 @@ import java.util.function.Function;
import java.util.stream.Collectors;
@Builder
@Value
@AllArgsConstructor
@EqualsAndHashCode
public class DeliveryPlannerDefinition {
@Singular
private final Map<Demand.Schema, Map<LocalTime, Double>> definitions;

View File

@@ -2,7 +2,6 @@ package pl.com.bottega.factory.delivery.planning.definition;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
@Repository
@@ -10,7 +9,6 @@ import org.springframework.stereotype.Repository;
path = "delivery-definitions",
collectionResourceRel = "delivery-definitions",
itemResourceRel = "delivery-definition")
public interface DeliveryPlannerDefinitionDao extends JpaRepository<DeliveryPlannerDefinitionEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
DeliveryPlannerDefinitionEntity findByRefNo(String refNo);
public interface DeliveryPlannerDefinitionDao extends JpaRepository<DeliveryPlannerDefinitionEntity, String> {
}

View File

@@ -1,26 +1,24 @@
package pl.com.bottega.factory.delivery.planning.definition;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import pl.com.bottega.tools.JsonConverter;
import javax.persistence.*;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
@Entity(name = "DeliveryPlannerDefinition")
@Table(schema = "delivery_planning")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class DeliveryPlannerDefinitionEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String refNo;
@Column
@Convert(converter = DescriptionAsJson.class)
@Convert(converter = DefinitionAsJson.class)
private DeliveryPlannerDefinition definition;
public DeliveryPlannerDefinitionEntity(String refNo, DeliveryPlannerDefinition definition) {
@@ -28,8 +26,8 @@ public class DeliveryPlannerDefinitionEntity implements Serializable {
this.definition = definition;
}
public static class DescriptionAsJson extends JsonConverter<DeliveryPlannerDefinition> {
public DescriptionAsJson() {
public static class DefinitionAsJson extends JsonConverter<DeliveryPlannerDefinition> {
public DefinitionAsJson() {
super(DeliveryPlannerDefinition.class);
}
}

View File

@@ -1,30 +1,28 @@
package pl.com.bottega.factory.delivery.planning.projection;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Entity(name = "DeliveryForecast")
@Table(schema = "delivery_planning")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = {"refNo", "date"})
public class DeliveryForecastEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Column
private String refNo;
@Column
private LocalDate date;
@Column
private LocalDateTime time;
@Column
private long level;
DeliveryForecastEntity(String refNo, LocalDateTime time, long level) {

View File

@@ -37,7 +37,7 @@ class DemandORMRepository {
RefNoId id = root.createId();
Map<LocalDate, DemandEntity> data =
demandDao.findByProductRefNoAndDateGreaterThanEqual(refNo, LocalDate.now(clock)).stream()
demandDao.findByRefNoAndDateGreaterThanEqual(refNo, LocalDate.now(clock)).stream()
.collect(toMap(
DemandEntity::getDate,
Function.identity()

View File

@@ -1,6 +1,5 @@
package pl.com.bottega.factory.demand.forecasting.command;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -12,27 +11,22 @@ import java.io.Serializable;
import java.time.LocalDate;
@Entity(name = "DemandAdjustment")
@Table(schema = "demand_forecasting")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class DemandAdjustmentEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Column
private String note;
@Column
private String customerRepresentative;
@Column
@Setter
private LocalDate cleanAfter;
@Column(length = 4096)
@Convert(converter = AdjustDemandAsJson.class)
private AdjustDemand adjustment;
@Setter
private LocalDate cleanAfter;
public static class AdjustDemandAsJson extends JsonConverter<AdjustDemand> {
public AdjustDemandAsJson() {
super(AdjustDemand.class);

View File

@@ -1,6 +1,5 @@
package pl.com.bottega.factory.demand.forecasting.command;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -14,29 +13,22 @@ import java.time.Instant;
import java.time.LocalDate;
@Entity(name = "DemandReview")
@Table(schema = "demand_forecasting")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class DemandReviewEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Column
private String refNo;
@Column
private LocalDate date;
@Column
private Instant timestamp;
@Column
@Convert(converter = ReviewAsJson.class)
private ReviewNeeded review;
@Column
@Enumerated(EnumType.STRING)
private ReviewDecision decision;
@Column
@Setter
private LocalDate cleanAfter;

View File

@@ -10,5 +10,5 @@ import java.util.List;
@Repository
@RestResource(exported = false)
public interface DemandDao extends JpaRepository<DemandEntity, Long> {
List<DemandEntity> findByProductRefNoAndDateGreaterThanEqual(String refNo, LocalDate now);
List<DemandEntity> findByRefNoAndDateGreaterThanEqual(String refNo, LocalDate now);
}

View File

@@ -1,6 +1,8 @@
package pl.com.bottega.factory.demand.forecasting.persistence;
import lombok.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import pl.com.bottega.factory.demand.forecasting.DailyId;
import pl.com.bottega.factory.demand.forecasting.DemandValue;
import pl.com.bottega.tools.JsonConverter;
@@ -11,22 +13,18 @@ import java.io.Serializable;
import java.time.LocalDate;
@Entity(name = "Demand")
@Table(schema = "demand_forecasting")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString
public class DemandEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Column
String refNo;
@Column
private String refNo;
private LocalDate date;
@Column
@Convert(converter = DemandAsJson.class)
@Setter
@Convert(converter = DemandAsJson.class)
private DemandValue value;
public DemandEntity(String refNo, LocalDate date) {

View File

@@ -1,6 +1,5 @@
package pl.com.bottega.factory.demand.forecasting.persistence;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import pl.com.bottega.factory.product.management.RefNoId;
@@ -10,17 +9,16 @@ import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "ProductDemand")
@Table(schema = "demand_forecasting")
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class ProductDemandEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Version
private Long version;
@Column
String refNo;
private String refNo;
public ProductDemandEntity(String refNo) {
this.refNo = refNo;
@@ -33,11 +31,7 @@ public class ProductDemandEntity implements Serializable {
@Getter
static class ProductDemandEntityId extends RefNoId implements TechnicalId {
Long id;
ProductDemandEntityId(String refNo) {
super(refNo);
}
private Long id;
ProductDemandEntityId(String refNo, long id) {
super(refNo);

View File

@@ -1,6 +1,5 @@
package pl.com.bottega.factory.demand.forecasting.projection;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import pl.com.bottega.factory.demand.forecasting.Demand;
@@ -10,21 +9,17 @@ import java.io.Serializable;
import java.time.LocalDate;
@Entity(name = "CurrentDemand")
@Table(schema = "demand_forecasting")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class CurrentDemandEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Column
private String refNo;
@Column
private LocalDate date;
@Column
private long level;
@Column
@Enumerated(EnumType.STRING)
private Demand.Schema schema;

View File

@@ -0,0 +1,41 @@
package pl.com.bottega.factory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
import org.springframework.scheduling.annotation.EnableScheduling;
import pl.com.bottega.factory.demand.forecasting.DemandEvents;
import pl.com.bottega.factory.demand.forecasting.DemandedLevelsChanged;
import pl.com.bottega.factory.demand.forecasting.ReviewRequested;
import java.time.Clock;
@SpringBootApplication
@EnableScheduling
@EntityScan(
basePackageClasses = {Configuration.class, Jsr310JpaConverters.class}
)
public class Configuration {
@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
@Bean
public DemandEventsFake DemandEvents() {
return new DemandEventsFake();
}
private class DemandEventsFake implements DemandEvents {
@Override
public void emit(DemandedLevelsChanged event) {
}
@Override
public void emit(ReviewRequested event) {
}
}
}

View File

@@ -76,7 +76,7 @@ class DemandORMRepositoryTest extends Specification {
demandInDB((today.minusDays(1)): 10000, (today): 1000)
when:
def demands = demandDao.findByProductRefNoAndDateGreaterThanEqual(refNo, today)
def demands = demandDao.findByRefNoAndDateGreaterThanEqual(refNo, today)
then:
demands.size() == 1
@@ -90,7 +90,7 @@ class DemandORMRepositoryTest extends Specification {
private void demandInDB(Map<LocalDate, Long> demands) {
def root = rootDao.save(new ProductDemandEntity(refNo))
demands.each { date, level ->
def demand = new DemandEntity(root, date)
def demand = new DemandEntity(refNo, date)
demand.setValue(new DemandValue(Demand.of(level), null))
demandDao.save(demand)
}
@@ -107,6 +107,6 @@ class DemandORMRepositoryTest extends Specification {
}
private def hasAdjustment(long level) {
return { it.get().getAdjustment() == Adjustment.strong(Demand.of(level)) }
return { it.getValue().getAdjustment() == Adjustment.strong(Demand.of(level)) }
}
}

View File

@@ -20,6 +20,13 @@
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>

View File

@@ -2,7 +2,6 @@ package pl.com.bottega.factory.product.management;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
@Repository
@@ -10,7 +9,6 @@ import org.springframework.stereotype.Repository;
path = "product-descriptions",
collectionResourceRel = "product-descriptions",
itemResourceRel = "product-description")
public interface ProductDescriptionDao extends JpaRepository<ProductDescriptionEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
ProductDescriptionEntity findByRefNo(String refNo);
public interface ProductDescriptionDao extends JpaRepository<ProductDescriptionEntity, String> {
}

View File

@@ -1,29 +1,27 @@
package pl.com.bottega.factory.product.management;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import pl.com.bottega.tools.JsonConverter;
import javax.persistence.*;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
@Entity(name = "ProductDescription")
@Table(schema = "product_management")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class ProductDescriptionEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String refNo;
@Column
@Convert(converter = DescriptionAsJson.class)
ProductDescription description;
private ProductDescription description;
public ProductDescriptionEntity(String refNo, ProductDescription description) {
ProductDescriptionEntity(String refNo, ProductDescription description) {
this.refNo = refNo;
this.description = description;
}

View File

@@ -0,0 +1,21 @@
package pl.com.bottega.factory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.time.Clock;
@SpringBootApplication
@EnableScheduling
@EntityScan(
basePackageClasses = {Configuration.class, Jsr310JpaConverters.class}
)
public class Configuration {
@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
}

View File

@@ -20,6 +20,13 @@
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>

View File

@@ -1,30 +1,29 @@
package pl.com.bottega.factory.production.planning.projection;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.LocalDate;
@Entity(name = "ProductionDailyOutput")
@Table(schema = "production_planning")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class ProductionDailyOutputEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Column
private String refNo;
@Column
private LocalDate date;
@Column
private long output;
public ProductionDailyOutputEntity(String refNo, LocalDate date, long output) {
ProductionDailyOutputEntity(String refNo, LocalDate date, long output) {
this.refNo = refNo;
this.date = date;
this.output = output;

View File

@@ -1,45 +1,45 @@
package pl.com.bottega.factory.production.planning.projection;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDateTime;
@Entity(name = "ProductionOutput")
@Table(schema = "production_planning")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class ProductionOutputEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Column
private String refNo;
@Column
private LocalDateTime start;
@Column
private Duration duration;
@Column
private long duration;
private LocalDateTime end;
@Column
private int partsPerMinute;
@Column
private long total;
public ProductionOutputEntity(String refNo,
ProductionOutputEntity(String refNo,
LocalDateTime start, Duration duration,
int partsPerMinute,
long total) {
this.refNo = refNo;
this.start = start;
this.duration = duration;
this.duration = duration.getSeconds();
this.end = start.plus(duration);
this.partsPerMinute = partsPerMinute;
this.total = total;
}
public Duration getDuration() {
return Duration.ofSeconds(duration);
}
}

View File

@@ -25,6 +25,13 @@
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>

View File

@@ -14,4 +14,6 @@ import java.util.Optional;
public interface ShortagesDao extends ProjectionRepository<ShortagesEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
Optional<ShortagesEntity> findByRefNo(String refNo);
void deleteAllInBatch();
}

View File

@@ -1,6 +1,5 @@
package pl.com.bottega.factory.shortages.prediction.monitoring.persistence;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -13,21 +12,19 @@ import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "Shortage")
@Table(schema = "shortages_prediction")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class ShortagesEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue
private Long id;
@Version
private Long version;
@Column
private String refNo;
@Column(length = 1024)
@Convert(converter = ShortagesAsJson.class)
@Setter
@Convert(converter = ShortagesAsJson.class)
private Shortages shortages;
public ShortagesEntity(String refNo) {
@@ -51,7 +48,7 @@ public class ShortagesEntity implements Serializable {
@Getter
static class ShortagesEntityId extends RefNoId implements TechnicalId {
Long id;
private Long id;
ShortagesEntityId(String refNo) {
super(refNo);

View File

@@ -0,0 +1,56 @@
package pl.com.bottega.factory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
import org.springframework.scheduling.annotation.EnableScheduling;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.shortages.prediction.calculation.Forecast;
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts;
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageEvents;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageSolved;
import java.time.Clock;
@SpringBootApplication
@EnableScheduling
@EntityScan(
basePackageClasses = {Configuration.class, Jsr310JpaConverters.class}
)
public class Configuration {
@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
@Bean
public Forecasts forecasts() {
return new ForecastsFake();
}
@Bean
public ShortageEventsFake shortageEvents() {
return new ShortageEventsFake();
}
private class ShortageEventsFake implements ShortageEvents {
@Override
public void emit(NewShortage event) {
}
@Override
public void emit(ShortageSolved event) {
}
}
private class ForecastsFake implements Forecasts {
@Override
public Forecast get(RefNoId refNo, int daysAhead) {
return null;
}
}
}

View File

@@ -8,7 +8,6 @@ import pl.com.bottega.factory.shortages.prediction.Shortages
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts
import pl.com.bottega.factory.shortages.prediction.monitoring.persistence.ShortagesDao
import pl.com.bottega.factory.shortages.prediction.monitoring.persistence.ShortagesEntity
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage
import spock.lang.Specification
import javax.transaction.Transactional
@@ -27,11 +26,11 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
@Autowired
ShortagesDao dao
def forecasts = Mock(Forecasts)
def notifications = Mock(NotificationOfShortage)
def notifications = Mock(ShortageEvents)
ShortagePredictionProcessORMRepository repository
def setup() {
dao.deleteAll()
dao.deleteAllInBatch()
repository = new ShortagePredictionProcessORMRepository(
dao, forecasts, notifications
)