Skip to content

Commit

Permalink
Added support for Site location (#8)
Browse files Browse the repository at this point in the history
* Added site location data
  • Loading branch information
petrmac authored Oct 28, 2024
1 parent 08d6f6d commit a29c576
Show file tree
Hide file tree
Showing 17 changed files with 175 additions and 39 deletions.
10 changes: 9 additions & 1 deletion graphql-queries/queries/createSiteMutation.graphql
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
mutation {
createSite(createSiteInput: {
name: "Hangar Ostrava" ,
sectors: ["Tibet", "Nose", "Beast"]
sectors: ["Tibet", "Nose", "Beast"],
location: {
latitude: 49.8358758,
longitude: 18.2925403
}
}) {
id
name
Expand All @@ -12,5 +16,9 @@ mutation {
gradeSystem
}
sectors
location {
latitude
longitude
}
}
}
4 changes: 4 additions & 0 deletions graphql-queries/queries/sitesQuery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@
gradeSystem
}
sectors
location {
latitude
longitude
}
}
}
13 changes: 8 additions & 5 deletions src/main/java/com/petrmacek/cragdb/crags/SiteAggregate.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.petrmacek.cragdb.crags.api.command.CreateSiteCommand;
import com.petrmacek.cragdb.crags.api.event.RouteAddedEvent;
import com.petrmacek.cragdb.crags.api.event.SiteCreatedEvent;
import com.petrmacek.cragdb.crags.api.model.Location;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand Down Expand Up @@ -35,6 +36,7 @@ public class SiteAggregate {
private UUID siteId;
private String name;
private Set<String> sectors;
private Location location;

@AggregateMember
private List<UUID> routesIds;
Expand All @@ -51,18 +53,19 @@ public SiteAggregate(CreateSiteCommand cmd) {
log.info("Creating SiteAggregate... '{}'", cmd);

Assert.notNull(cmd.siteId(), () -> "ID should not be null");
Assert.notNull(cmd.name(), () -> "Name should not be null");
Assert.notNull(cmd.data().name(), () -> "Name should not be null");

AggregateLifecycle.apply(new SiteCreatedEvent(cmd.siteId(), cmd.name(), cmd.sectors()));
AggregateLifecycle.apply(new SiteCreatedEvent(cmd.siteId(), cmd.data()));
}

@EventSourcingHandler
private void on(SiteCreatedEvent event) {
log.info("Site created: '{}', name: '{}'", event.siteId(), event.name());
log.info("Site created: '{}', name: '{}'", event.siteId(), event.data());

siteId = event.siteId();
name = event.name();
sectors = event.sectors();
name = event.data().name();
sectors = event.data().sectors();
location = event.data().location();
}

@CommandHandler
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.petrmacek.cragdb.crags.api.command;

import com.petrmacek.cragdb.crags.api.model.SiteData;
import org.axonframework.modelling.command.TargetAggregateIdentifier;

import java.util.Set;
import java.util.UUID;

public record CreateSiteCommand(@TargetAggregateIdentifier UUID siteId, String name, Set<String> sectors) {
public record CreateSiteCommand(@TargetAggregateIdentifier UUID siteId, SiteData data) {
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.petrmacek.cragdb.crags.api.event;

import com.petrmacek.cragdb.crags.api.model.SiteData;
import org.axonframework.serialization.Revision;

import java.util.Set;
import java.util.UUID;

@Revision("1.0")
public record SiteCreatedEvent(UUID siteId, String name, Set<String> sectors) {
public record SiteCreatedEvent(UUID siteId, SiteData data) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.petrmacek.cragdb.crags.api.model;

public record Location(double latitude, double longitude) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.petrmacek.cragdb.crags.api.model;

import java.util.Set;

public record SiteData(String name, Set<String> sectors, Location location) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public Mono<Site> createSite(@InputArgument CreateSiteInput createSiteInput) {
log.info("Received request to create new site: '{}'", createSiteInput.getName());

UUID siteId = UUID.randomUUID();
CreateSiteCommand createSiteCommand = new CreateSiteCommand(siteId, createSiteInput.getName(), Set.copyOf(createSiteInput.getSectors()));
var data = dtoMapper.mapSiteData(createSiteInput);
CreateSiteCommand createSiteCommand = new CreateSiteCommand(siteId, data);

return commandGateway.send(createSiteCommand)
.doOnSubscribe(sub -> log.info("Sending CreateSiteCommand"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import com.petrmacek.cragdb.crags.RouteAggregate;
import com.petrmacek.cragdb.crags.SiteAggregate;
import com.petrmacek.cragdb.crags.api.model.GradeSystem;
import com.petrmacek.cragdb.crags.api.model.grade.French;
import com.petrmacek.cragdb.crags.api.model.grade.Grade;
import com.petrmacek.cragdb.crags.api.model.grade.UIAA;
import com.petrmacek.cragdb.crags.api.model.grade.YDS;
import com.petrmacek.cragdb.crags.api.model.SiteData;
import com.petrmacek.cragdb.generated.types.CreateSiteInput;
import com.petrmacek.cragdb.generated.types.Route;
import com.petrmacek.cragdb.generated.types.Site;
import org.mapstruct.Mapper;
Expand All @@ -24,6 +22,8 @@ public interface DtoMapper {
@Mapping(target = "routes", ignore = true)
Site mapSite(SiteAggregate site);

SiteData mapSiteData(CreateSiteInput site);

@Mapping(target = "grade", source = "grade.value")
@Mapping(target = "gradeSystem", source = "grade.system")
Route mapRoute(RouteAggregate route);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.data.annotation.Version;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.types.GeographicPoint2d;

import java.util.Set;
import java.util.UUID;
Expand All @@ -21,6 +22,7 @@ public class SiteEntity {
private String name;
private Set<String> sectors;
private long lastUpdateEpoch;
private GeographicPoint2d location;

@Version
private Long version;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.petrmacek.cragdb.crags.SiteAggregate;
import com.petrmacek.cragdb.crags.api.event.SiteCreatedEvent;
import com.petrmacek.cragdb.crags.api.model.Location;
import com.petrmacek.cragdb.crags.api.query.GetSiteQuery;
import com.petrmacek.cragdb.crags.api.query.GetSitesQuery;
import lombok.RequiredArgsConstructor;
Expand All @@ -10,6 +11,7 @@
import org.axonframework.eventhandling.SequenceNumber;
import org.axonframework.eventhandling.Timestamp;
import org.axonframework.queryhandling.QueryHandler;
import org.springframework.data.neo4j.types.GeographicPoint2d;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand All @@ -24,7 +26,7 @@ public class SiteProjector {

@EventHandler
public void on(SiteCreatedEvent event, @Timestamp Instant timestamp, @SequenceNumber long sequenceNumber) {
log.info("MATERIALIZATION: Creating site: '{}', name: '{}'", event.siteId(), event.name());
log.info("MATERIALIZATION: Creating site: '{}', name: '{}'", event.siteId(), event.data());

// Check if the site already exists
siteRepository.existsById(event.siteId())
Expand All @@ -36,9 +38,10 @@ public void on(SiteCreatedEvent event, @Timestamp Instant timestamp, @SequenceNu
// If site doesn't exist, create and save it
SiteEntity site = SiteEntity.builder()
.id(event.siteId())
.name(event.name())
.sectors(event.sectors())
.name(event.data().name())
.sectors(event.data().sectors())
.version(sequenceNumber)
.location(new GeographicPoint2d(event.data().location().latitude(), event.data().location().longitude()))
.lastUpdateEpoch(timestamp.toEpochMilli())
.build();
return siteRepository.save(site)
Expand Down Expand Up @@ -69,6 +72,7 @@ private static SiteAggregate mapSiteAggregate(final SiteEntity siteEntity) {
return SiteAggregate.builder()
.siteId(siteEntity.getId())
.name(siteEntity.getName())
.location(new Location(siteEntity.getLocation().getLatitude(), siteEntity.getLocation().getLongitude()))
.sectors(siteEntity.getSectors())
.version(siteEntity.getVersion())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@


import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.data.repository.query.Param;
import reactor.core.publisher.Flux;

import java.util.UUID;

public interface SiteRepository extends ReactiveNeo4jRepository<SiteEntity, UUID> {

@Query("MATCH (s:Site) " +
"WHERE point.distance(point({longitude: $longitude, latitude: $latitude}), s.location) <= $distance " +
"RETURN s")
Flux<SiteEntity> findAllWithinDistance(
@Param("longitude") double longitude,
@Param("latitude") double latitude,
@Param("distance") double distance);
}
12 changes: 12 additions & 0 deletions src/main/resources/schema/site.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,21 @@ type Site {
name: String!
routes: [Route]
sectors: [String!]
location: Location
}

type Location {
latitude: Float!
longitude: Float!
}

input CreateSiteInput {
name: String!
sectors: [String!]
location: LocationInput
}

input LocationInput {
latitude: Float!
longitude: Float!
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import com.petrmacek.cragdb.crags.api.command.CreateSiteCommand
import com.petrmacek.cragdb.crags.api.event.RouteAddedEvent
import com.petrmacek.cragdb.crags.api.event.SiteCreatedEvent
import com.petrmacek.cragdb.crags.api.model.GradeSystem
import com.petrmacek.cragdb.crags.api.model.Location
import com.petrmacek.cragdb.crags.api.model.RouteData
import com.petrmacek.cragdb.crags.api.model.SiteData
import com.petrmacek.cragdb.crags.api.model.grade.French
import org.axonframework.test.aggregate.AggregateTestFixture
import org.axonframework.test.aggregate.FixtureConfiguration
Expand All @@ -28,11 +30,14 @@ class SiteAggregateSpec extends Specification {
def siteId = UUID.fromString("f5838853-b6f0-4b2f-81aa-6dd8ac97d34d")
def siteName = "Tendon Hlubina"
def sectors = Set.of("Sector 1", "Sector 2", "Sector 3")
def location = new Location(49.8210403, 18.2774736)

def data = new SiteData(siteName, sectors, location)

expect:
fixture.givenNoPriorActivity()
.when(new CreateSiteCommand(siteId, siteName, sectors))
.expectEvents(new SiteCreatedEvent(siteId, siteName, sectors))
.when(new CreateSiteCommand(siteId, data))
.expectEvents(new SiteCreatedEvent(siteId, data))
}

def "should emit RouteAddedEvent when AddRouteCommand is sent"() {
Expand All @@ -41,14 +46,17 @@ class SiteAggregateSpec extends Specification {
def routeId = UUID.randomUUID()
def siteName = "Tendon Hlubina"
def sectors = Set.of("Sector 1", "Sector 2", "Sector 3")
def location = new Location(49.8210403, 18.2774736)

def data = new SiteData(siteName, sectors, location)
def routeData1 = RouteData.builder()
.name("Yoga master")
.grade(French.F6a)
.gradeSystem(GradeSystem.French)
.build()

expect:
fixture.givenCommands(new CreateSiteCommand(siteId, siteName, sectors))
fixture.givenCommands(new CreateSiteCommand(siteId, data))
.when(new AddRouteCommand(siteId, routeId, "Sector 1", routeData1))
.expectEvents(new RouteAddedEvent(siteId, routeId, "Sector 1", routeData1))
}
Expand All @@ -59,14 +67,17 @@ class SiteAggregateSpec extends Specification {
def routeId = UUID.randomUUID()
def siteName = "Tendon Hlubina"
def sectors = Set.of("Sector 1", "Sector 2", "Sector 3")
def location = new Location(49.8210403, 18.2774736)

def data = new SiteData(siteName, sectors, location)
def routeData1 = RouteData.builder()
.name("Krkavčí matka")
.grade(French.F7a)
.gradeSystem(GradeSystem.French)
.build()

expect:
fixture.givenCommands(new CreateSiteCommand(siteId, siteName, sectors))
fixture.givenCommands(new CreateSiteCommand(siteId, data))
.when(new AddRouteCommand(siteId, routeId, "Sector 1", routeData1))
.expectEvents(new RouteAddedEvent(siteId, routeId, "Sector 1", routeData1))
}
Expand Down
Loading

0 comments on commit a29c576

Please sign in to comment.