[03.02.20] Addition of Tweet handling and utility merging and alterations to timestamp handling

This commit is contained in:
Andy Sotheran 2020-02-03 22:20:33 +00:00
parent 2406a79b66
commit 0e7fbf9408
17 changed files with 293 additions and 67 deletions

3
.gitignore vendored
View File

@ -53,3 +53,6 @@ build/
### VS Code ### ### VS Code ###
.vscode/ .vscode/
### Private DB properties file ###
*.properties

View File

@ -57,11 +57,6 @@
<artifactId>graphiql-spring-boot-starter</artifactId> <artifactId>graphiql-spring-boot-starter</artifactId>
<version>5.0.2</version> <version>5.0.2</version>
</dependency> </dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-extended-scalars</artifactId>
<version>1.0</version>
</dependency>
<!-- Local database --> <!-- Local database -->
<dependency> <dependency>
@ -82,6 +77,7 @@
<version>4.3.8.Final</version> <version>4.3.8.Final</version>
</dependency> </dependency>
<!--- Utils -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>

View File

@ -1,4 +1,4 @@
package cryptosky.me.graphql.jpa.entity; package cryptosky.me.graphql.pricing.models.entities;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

View File

@ -1,9 +1,8 @@
package cryptosky.me.graphql.jpa.entity; package cryptosky.me.graphql.pricing.models.entities;
import lombok.*; import lombok.*;
import javax.persistence.*; import javax.persistence.*;
import java.time.LocalDate;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@ -13,18 +12,15 @@ public class CryptoPriceModel {
@Id @Id
@Column(name = "ID", nullable = false) @Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.TABLE) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
@NonNull
@Column(name = "timestamp", nullable = false) @Column(name = "timestamp", nullable = false)
private String timestamp; private String timestamp;
@NonNull
@Column(name = "symbol", nullable = false) @Column(name = "symbol", nullable = false)
private String type; private String type;
@NonNull
@Column(name = "av_price", nullable = false) @Column(name = "av_price", nullable = false)
private float average_price; private float average_price;

View File

@ -1,6 +1,6 @@
package cryptosky.me.graphql.jpa.repository; package cryptosky.me.graphql.pricing.models.repositories;
import cryptosky.me.graphql.jpa.entity.BtcPriceModel; import cryptosky.me.graphql.pricing.models.entities.BtcPriceModel;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;

View File

@ -1,11 +1,11 @@
package cryptosky.me.graphql.mutation; package cryptosky.me.graphql.pricing.mutations;
import com.coxautodev.graphql.tools.GraphQLMutationResolver; import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import cryptosky.me.graphql.jpa.entity.BtcPriceModel; import cryptosky.me.graphql.pricing.models.entities.BtcPriceModel;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import cryptosky.me.graphql.service.BtcPriceService; import cryptosky.me.graphql.pricing.service.BtcPriceService;
@Component @Component
public class BtcPriceMutation implements GraphQLMutationResolver { public class BtcPriceMutation implements GraphQLMutationResolver {

View File

@ -1,13 +1,11 @@
package cryptosky.me.graphql.query; package cryptosky.me.graphql.pricing.queries;
import com.coxautodev.graphql.tools.GraphQLQueryResolver; import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import cryptosky.me.graphql.jpa.entity.BtcPriceModel; import cryptosky.me.graphql.pricing.models.entities.BtcPriceModel;
import cryptosky.me.graphql.jpa.entity.CryptoPriceModel; import cryptosky.me.graphql.pricing.service.BtcPriceService;
import cryptosky.me.graphql.service.BtcPriceService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.OffsetDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;

View File

@ -1,25 +1,21 @@
package cryptosky.me.graphql.service; package cryptosky.me.graphql.pricing.service;
import cryptosky.me.graphql.jpa.entity.BtcPriceModel; import cryptosky.me.graphql.pricing.models.entities.BtcPriceModel;
import cryptosky.me.graphql.jpa.repository.BtcPriceRepository; import cryptosky.me.graphql.pricing.models.repositories.BtcPriceRepository;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cryptosky.me.helpers.Utils.distinctByKey; import static cryptosky.me.helpers.Utils.format;
@Service @Service
public class BtcPriceService { public class BtcPriceService {
private final BtcPriceRepository btcPriceRepository; private final BtcPriceRepository btcPriceRepository;
DateTimeFormatter format = DateTimeFormatter.ISO_DATE_TIME;//ofPattern("dd-MM-yy HH:mm");
public BtcPriceService(final BtcPriceRepository btcPriceRepository) { public BtcPriceService(final BtcPriceRepository btcPriceRepository) {
this.btcPriceRepository = btcPriceRepository; this.btcPriceRepository = btcPriceRepository;
} }
@ -29,7 +25,7 @@ public class BtcPriceService {
final float h_price, final float l_price, final float c_price, final float volume ) { final float h_price, final float l_price, final float c_price, final float volume ) {
final BtcPriceModel btcPrice = new BtcPriceModel(); final BtcPriceModel btcPrice = new BtcPriceModel();
btcPrice.setTimestamp(LocalDate.parse(createdDate, format).toString()); btcPrice.setTimestamp(format(createdDate).toString());
btcPrice.setType(type); btcPrice.setType(type);
btcPrice.setAverage_price(av_price); btcPrice.setAverage_price(av_price);
btcPrice.setHigh_price(h_price); btcPrice.setHigh_price(h_price);
@ -37,7 +33,6 @@ public class BtcPriceService {
btcPrice.setClose_price(c_price); btcPrice.setClose_price(c_price);
btcPrice.setVolume(volume); btcPrice.setVolume(volume);
return this.btcPriceRepository.save(btcPrice); return this.btcPriceRepository.save(btcPrice);
} }
@ -64,15 +59,15 @@ public class BtcPriceService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Optional<BtcPriceModel> getPriceForCreatedDate( final String createdDate ) { public Optional<BtcPriceModel> getPriceForCreatedDate( final String createdDate ) {
return this.btcPriceRepository.findAll().stream() return this.btcPriceRepository.findAll().stream()
.filter(createdDateList -> createdDateList.getTimestamp().equals(LocalDate.parse(createdDate, format))) .filter(createdDateList -> createdDateList.getTimestamp().equals(format(createdDate)))
.findFirst(); .findFirst();
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<BtcPriceModel> getPriceBetweenDates( final String startDate, final String endDate ) { public List<BtcPriceModel> getPriceBetweenDates( final String startDate, final String endDate ) {
return this.btcPriceRepository.findAll().stream() return this.btcPriceRepository.findAll().stream()
.filter(createdDateList -> LocalDate.parse(createdDateList.getTimestamp(), format).isBefore(LocalDate.parse(endDate, format))) .filter(createdDateList -> format(createdDateList.getTimestamp()).isBefore(format(endDate)))
.filter(createdDateList -> LocalDate.parse(createdDateList.getTimestamp(), format).isAfter(LocalDate.parse(startDate, format))) .filter(createdDateList -> format(createdDateList.getTimestamp()).isAfter(format(startDate)))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }

View File

@ -0,0 +1,44 @@
package cryptosky.me.graphql.tweets.models.entities;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Table(name = "tweet_data")
@Entity
public class TweetModel {
@Id
@Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "timestamp",nullable = false)
private String timestamp;
@Column(name = "raw_tweet", nullable = false)
private String rawTweet;
@Column(name = "sentiment")
private float sentimentScore;
@Column(name = "pos")
private float positiveScore;
@Column(name = "neu")
private float neutralScore;
@Column(name = "neg")
private float negativeScore;
@Column(name = "compound", nullable = false)
private float compoundScore;
}

View File

@ -0,0 +1,9 @@
package cryptosky.me.graphql.tweets.models.repositories;
import cryptosky.me.graphql.tweets.models.entities.TweetModel;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TweetRepository extends JpaRepository<TweetModel, Integer> {
}

View File

@ -0,0 +1,22 @@
package cryptosky.me.graphql.tweets.mutations;
import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import cryptosky.me.graphql.tweets.models.entities.TweetModel;
import cryptosky.me.graphql.tweets.service.TweetService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TweetMutation implements GraphQLMutationResolver {
@Autowired
TweetService tweetService;
public TweetModel createTweet( final String createdDate, final String rawTweet, final float sentimentScore,
final float positiveScore, final float neutralScore, final float negativeScore,
final float compoundScore ) {
return this.tweetService.createTweet( createdDate, rawTweet, sentimentScore, positiveScore, neutralScore,
negativeScore,compoundScore );
}
}

View File

@ -0,0 +1,33 @@
package cryptosky.me.graphql.tweets.queries;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import cryptosky.me.graphql.tweets.models.entities.TweetModel;
import cryptosky.me.graphql.tweets.service.TweetService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
public class TweetQuery implements GraphQLQueryResolver {
@Autowired
private TweetService tweetService;
public Optional<TweetModel> getCurrentTweet() {
return this.tweetService.getCurrentTweet();
}
public List<TweetModel> getAllTweets( final int count ) {
return this.tweetService.getAllTweets(count);
}
public List<TweetModel> getTweetsForDay( final String startDate, final String endDate ) {
return this.tweetService.getTweetsForDay(startDate, endDate);
}
public List<TweetModel> getTweetsForPeriod( final String startDate, final String endDate ) {
return this.tweetService.getTweetsForPeriod( startDate, endDate );
}
}

View File

@ -0,0 +1,102 @@
package cryptosky.me.graphql.tweets.service;
import cryptosky.me.graphql.tweets.models.entities.TweetModel;
import cryptosky.me.graphql.tweets.models.repositories.TweetRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static cryptosky.me.helpers.Utils.format;
@Service
public class TweetService {
private final TweetRepository tweetRepository;
public TweetService( final TweetRepository tweetRepository ) {
this.tweetRepository = tweetRepository;
}
@Transactional
public TweetModel createTweet( final String createdDate, final String rawTweet, final float sentimentScore,
final float positiveScore, final float neutralScore, final float negativeScore,
final float compoundScore ) {
final TweetModel tweetModel = TweetModel.builder()
.timestamp(format(createdDate).toString())
.rawTweet(rawTweet)
.sentimentScore(sentimentScore)
.positiveScore(positiveScore)
.negativeScore(negativeScore)
.neutralScore(neutralScore)
.compoundScore(compoundScore)
.build();
return this.tweetRepository.save(tweetModel);
}
@Transactional(readOnly = true)
public Optional<TweetModel> getCurrentTweet() {
return this.tweetRepository.findAll().stream().findFirst();
}
@Transactional(readOnly = true)
public List<TweetModel> getAllTweets( final int count ) {
return this.tweetRepository.findAll().stream()
.limit(count)
.collect(Collectors.toList());
}
@Transactional(readOnly = true)
public List<TweetModel> getTweetsForDay( final String startDate, final String endDate ) {
LocalDateTime r_start = format(startDate);
LocalDateTime r_end = format(endDate);
r_start = r_start.toLocalDate().atStartOfDay();
r_end = r_end.toLocalDate().atTime(LocalTime.MAX);
if ( r_end.isAfter(r_start) ) {
if ( r_end.equals(r_start.toLocalDate().atTime(LocalTime.MAX))) {
LocalDateTime finalR_end = r_end;
LocalDateTime finalR_start = r_start;
return this.tweetRepository.findAll().stream()
.filter(createdDateList -> format(createdDateList.getTimestamp()).isBefore(finalR_end))
.filter(createdDateList -> format(createdDateList.getTimestamp()).isAfter(finalR_start))
.collect(Collectors.toList());
} else {
// Logger
throw new DateTimeException(r_start +" and "+ r_end +" are not on the same day");
}
} else {
// Logger
throw new DateTimeException("End Date "+ r_end +" is not after "+ r_start);
}
}
@Transactional(readOnly = true)
public List<TweetModel> getTweetsForPeriod( final String startDate, final String endDate ) {
LocalDateTime r_start = format(startDate);
LocalDateTime r_end = format(endDate);
r_start = r_start.toLocalDate().atStartOfDay();
r_end = r_end.toLocalDate().atTime(LocalTime.MAX);
if ( r_end.isAfter(r_start) ) {
LocalDateTime finalR_end = r_end;
LocalDateTime finalR_start = r_start;
return this.tweetRepository.findAll().stream()
.filter(createdDateList -> format(createdDateList.getTimestamp()).isBefore(finalR_end))
.filter(createdDateList -> format(createdDateList.getTimestamp()).isAfter(finalR_start))
.collect(Collectors.toList());
} else {
// Logger
throw new DateTimeException("End Date "+ r_end +" is not after "+ r_start);
}
}
}

View File

@ -1,5 +1,9 @@
package cryptosky.me.helpers; package cryptosky.me.helpers;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function; import java.util.function.Function;
@ -12,4 +16,10 @@ public class Utils {
Map<Object, Boolean> seen = new ConcurrentHashMap<>(); Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
} }
public static LocalDateTime format(String T) {
DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX")
.withZone(ZoneId.of("UTC"));
return LocalDateTime.parse(T, F);
}
} }

View File

@ -1,10 +1,10 @@
#server.port=9090 server.port=9090
##spring.jpa.database=POSTGRESQL spring.jpa.database=POSTGRESQL
##spring.datasource.platform=postgres spring.datasource.platform=postgres
##spring.datasource.url=jdbc:postgresql://localhost:5432/postgres spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
##spring.datasource.username=postgres spring.datasource.username=postgres
##spring.datasource.password=***** spring.datasource.password=*****
##spring.jpa.show-sql=true spring.jpa.show-sql=true
##spring.jpa.generate-ddl=true spring.jpa.generate-ddl=true
##spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.hibernate.ddl-auto=create-drop
##spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

View File

@ -1,22 +0,0 @@
type BtcPrice {
id: ID!,
timestamp: String!,
type: String,
average_price: Float!,
high_price: Float,
low_price: Float,
close_price: Float,
volume: Float
}
type Query {
allPrices(count: Int):[BtcPrice],
pricesBetweenCounts(startCount: Int, endCount: Int):[BtcPrice]
latest:BtcPrice,
priceForCreatedDate(createdDate: String):BtcPrice,
priceBetweenDates(startDate: String, endDate: String):[BtcPrice]
}
type Mutation {
createBtc(createdDate: String!, type: String!, average_price: Float!, high_price: Float, low_price: Float, close_price: Float, volume: Float):BtcPrice
}

View File

@ -0,0 +1,40 @@
type BtcPrice {
id: ID!,
timestamp: String!,
type: String,
average_price: Float!,
high_price: Float,
low_price: Float,
close_price: Float,
volume: Float
}
type tweetModel {
id: ID!,
timestamp: String!,
rawTweet: String,
sentimentScore: Float!,
positiveScore: Float,
neutralScore: Float,
negativeScore: Float,
compoundScore: Float!
}
type Query {
allPrices(count: Int):[BtcPrice],
pricesBetweenCounts(startCount: Int, endCount: Int):[BtcPrice]
latest:BtcPrice,
priceForCreatedDate(createdDate: String):BtcPrice,
priceBetweenDates(startDate: String, endDate: String):[BtcPrice],
################################################################
currentTweet:tweetModel,
allTweets(count: Int):[tweetModel],
tweetsForDay(startDate: String, endDate: String):[tweetModel],
tweetsForPeriod(startDate: String, endDate: String):[tweetModel]
}
type Mutation {
createBtc(createdDate: String!, type: String!, average_price: Float!, high_price: Float, low_price: Float, close_price: Float, volume: Float):BtcPrice
createTweet(createdDate: String!, rawTweet: String!, sentimentScore: Float!, positiveScore: Float, neutralScore: Float, negativeScore: Float, compoundScore: Float!):tweetModel
}