Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge projections #80

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
5 changes: 0 additions & 5 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ class AxonBeansEnhancementsConfiguration {
.registerPooledStreamingEventProcessor(
"project-acl-projector", { it.eventStore() }, psepConfig)
.registerPooledStreamingEventProcessor("project-projector", { it.eventStore() }, psepConfig)
.registerPooledStreamingEventProcessor(
"project-details-projector", { it.eventStore() }, psepConfig)
.registerPooledStreamingEventProcessor("task-projector", { it.eventStore() }, psepConfig)
.registerPooledStreamingEventProcessor(
"participant-projector", { it.eventStore() }, psepConfig)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.novatecgmbh.eventsourcing.axon.project.project.query

import com.novatecgmbh.eventsourcing.axon.common.api.AggregateReference
import com.novatecgmbh.eventsourcing.axon.company.company.api.CompanyId
import com.novatecgmbh.eventsourcing.axon.project.project.api.ProjectDetailsQueryResult
import com.novatecgmbh.eventsourcing.axon.project.project.api.ProjectId
import com.novatecgmbh.eventsourcing.axon.project.project.api.ProjectQueryResult
import com.novatecgmbh.eventsourcing.axon.project.project.api.ProjectStatus
Expand All @@ -25,7 +26,11 @@ class ProjectProjection(
name = "displayName", column = Column(name = "companyName", nullable = true)))
var companyReference: AggregateReference<CompanyId>,
@Column(nullable = false) @Enumerated(STRING) var status: ProjectStatus,
var actualEndDate: LocalDate? = null
var actualEndDate: LocalDate? = null,
@Column(nullable = false) var allTasksCount: Long,
@Column(nullable = false) var plannedTasksCount: Long,
@Column(nullable = false) var startedTasksCount: Long,
@Column(nullable = false) var completedTasksCount: Long,
) {
fun toQueryResult() =
ProjectQueryResult(
Expand All @@ -37,4 +42,16 @@ class ProjectProjection(
companyReference,
status,
actualEndDate)

fun toDetailedQueryResult() =
ProjectDetailsQueryResult(
identifier,
version,
name,
plannedStartDate,
deadline,
allTasksCount,
plannedTasksCount,
startedTasksCount,
completedTasksCount)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import com.novatecgmbh.eventsourcing.axon.project.authorization.acl.ProjectAclRe
import com.novatecgmbh.eventsourcing.axon.project.project.api.*
import com.novatecgmbh.eventsourcing.axon.project.project.api.ProjectStatus.DELAYED
import com.novatecgmbh.eventsourcing.axon.project.project.api.ProjectStatus.ON_TIME
import com.novatecgmbh.eventsourcing.axon.project.task.api.TaskCompletedEvent
import com.novatecgmbh.eventsourcing.axon.project.task.api.TaskCreatedEvent
import com.novatecgmbh.eventsourcing.axon.project.task.api.TaskId
import com.novatecgmbh.eventsourcing.axon.project.task.api.TaskStartedEvent
import javax.persistence.*
import org.axonframework.config.ProcessingGroup
import org.axonframework.eventhandling.EventHandler
import org.axonframework.eventhandling.ResetHandler
Expand All @@ -15,12 +20,15 @@ import org.axonframework.extensions.kotlin.emit
import org.axonframework.extensions.kotlin.queryOptional
import org.axonframework.queryhandling.QueryGateway
import org.axonframework.queryhandling.QueryUpdateEmitter
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Component
import org.springframework.stereotype.Repository

@Component
@ProcessingGroup("project-projector")
class ProjectProjector(
private val repository: ProjectProjectionRepository,
private val lookupRepository: ProjectByTaskLookupProjectionRepository,
private val aclRepository: ProjectAclRepository,
private val queryUpdateEmitter: QueryUpdateEmitter,
private val queryGateway: QueryGateway
Expand All @@ -42,7 +50,12 @@ class ProjectProjector(
company
.map { it.toAggregateReference() }
.orElse(AggregateReference(event.companyId)),
status = event.status))
status = event.status,
allTasksCount = 0,
plannedTasksCount = 0,
startedTasksCount = 0,
completedTasksCount = 0,
))
}

@EventHandler
Expand Down Expand Up @@ -81,6 +94,34 @@ class ProjectProjector(
it.version = aggregateVersion
}

@EventHandler
fun on(event: TaskCreatedEvent) {
lookupRepository.save(
ProjectByTaskLookupProjection(taskId = event.identifier, projectId = event.projectId))
updateProjection(event.projectId) {
it.allTasksCount++
it.plannedTasksCount++
}
}

@EventHandler
fun on(event: TaskStartedEvent) =
lookupRepository.findById(event.identifier).ifPresent { task ->
updateProjection(task.projectId) {
it.plannedTasksCount--
it.startedTasksCount++
}
}

@EventHandler
fun on(event: TaskCompletedEvent) =
lookupRepository.findById(event.identifier).ifPresent { task ->
updateProjection(task.projectId) {
it.startedTasksCount--
it.completedTasksCount++
}
}

private fun updateProjection(identifier: ProjectId, stateChanges: (ProjectProjection) -> Unit) {
repository.findById(identifier).get().also {
stateChanges.invoke(it)
Expand All @@ -97,12 +138,34 @@ class ProjectProjector(
query.projectId == project.identifier
}

queryUpdateEmitter.emit<ProjectDetailsQuery, ProjectQueryResult>(project.toQueryResult()) {
query ->
query.projectId == project.identifier
}

queryUpdateEmitter.emit<MyProjectsQuery, ProjectQueryResult>(project.toQueryResult()) { query ->
aclRepository
.findAllUserWithAccessToProject(project.identifier.identifier)
.contains(query.userId)
}
}

@ResetHandler fun reset() = repository.deleteAll()
@ResetHandler
fun reset() {
repository.deleteAll()
lookupRepository.deleteAll()
}
}

@Entity
@Table(name = "project_by_task_lookup")
class ProjectByTaskLookupProjection(
@EmbeddedId var taskId: TaskId,
@Embedded
@AttributeOverride(name = "identifier", column = Column(name = "projectId", nullable = false))
var projectId: ProjectId,
)

@Repository
interface ProjectByTaskLookupProjectionRepository :
JpaRepository<ProjectByTaskLookupProjection, TaskId>
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import org.springframework.stereotype.Component
@Component
class ProjectQueryHandler(
private val repository: ProjectProjectionRepository,
private val detailsRepository: ProjectDetailsProjectionRepository,
private val authService: ProjectAuthorizationService,
private val aclRepository: ProjectAclRepository
) {
Expand All @@ -25,16 +24,19 @@ class ProjectQueryHandler(

@QueryHandler
fun handle(query: MyProjectsQuery, @AuditUserId userId: String): Iterable<ProjectQueryResult> =
aclRepository.findAllAccessibleProjectsByUser(UserId(userId)).map { ProjectId(it) }.let {
repository.findAllByIdentifierInOrderByName(it).map(ProjectProjection::toQueryResult)
}
aclRepository
.findAllAccessibleProjectsByUser(UserId(userId))
.map { ProjectId(it) }
.let {
repository.findAllByIdentifierInOrderByName(it).map(ProjectProjection::toQueryResult)
}

@QueryHandler
fun handle(
query: ProjectDetailsQuery,
@AuditUserId userId: String
): Optional<ProjectDetailsQueryResult> =
authService.runWhenAuthorizedForProject(UserId(userId), query.projectId) {
detailsRepository.findById(query.projectId).map { it.toQueryResult() }
repository.findById(query.projectId).map { it.toDetailedQueryResult() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
drop table project_details;

alter table projects
add column all_tasks_count int8 not null,
add column completed_tasks_count int8 not null,
add column planned_tasks_count int8 not null,
add column started_tasks_count int8 not null;
Original file line number Diff line number Diff line change
Expand Up @@ -59,27 +59,18 @@ create sequence hibernate_sequence start with 1 increment by 1;
primary key (identifier)
);

create table project_details (
identifier varchar(255) not null,
all_tasks_count bigint not null,
completed_tasks_count bigint not null,
deadline date not null,
name varchar(255) not null,
planned_start_date date not null,
planned_tasks_count bigint not null,
started_tasks_count bigint not null,
version bigint not null,
primary key (identifier)
);

create table projects (
identifier varchar(255) not null,
actual_end_date date,
all_tasks_count bigint not null,
company_name varchar(255),
company_id varchar(255) not null,
completed_tasks_count bigint not null,
deadline date not null,
name varchar(255) not null,
planned_start_date date not null,
planned_tasks_count bigint not null,
started_tasks_count bigint not null,
status varchar(255) not null,
version bigint not null,
primary key (identifier)
Expand Down
Loading