Skip to content

Commit

Permalink
Reduce repo api surface area, use Result, and polish up surrounding code
Browse files Browse the repository at this point in the history
  • Loading branch information
mattupstate committed Mar 14, 2024
1 parent d23a317 commit 4f514e9
Show file tree
Hide file tree
Showing 21 changed files with 325 additions and 321 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,21 @@ class JooqAppointmentAggregateRepository(
private val clock: Clock = Clock.systemUTC()
) : AggregateRepository<Appointment, Appointment.Id> {

override suspend fun find(id: Appointment.Id): PersistedAggregate<Appointment>? =
dsl.selectFrom(APPOINTMENTS)
.where(APPOINTMENTS.ID.eq(id.value))
.awaitFirstOrNull()?.let {
PersistedAggregate(
aggregate = Json.decodeFromString(it.aggregate.data()),
metaData = PersistenceMetaData(
createdAt = it.createdAt,
updatedAt = it.updatedAt,
revision = it.revision,
override suspend fun findById(id: Appointment.Id): Result<PersistedAggregate<Appointment>> =
runCatching {
dsl.selectFrom(APPOINTMENTS)
.where(APPOINTMENTS.ID.eq(id.value))
.awaitFirst().let {
PersistedAggregate(
aggregate = Json.decodeFromString(it.aggregate.data()),
metaData = PersistenceMetaData(
createdAt = it.createdAt,
updatedAt = it.updatedAt,
revision = it.revision,
)
)
)
}

override suspend fun get(id: Appointment.Id): PersistedAggregate<Appointment> =
getOrThrow(id) { NoSuchElementException() }

override suspend fun getOrThrow(id: Appointment.Id, block: () -> Throwable): PersistedAggregate<Appointment> =
find(id) ?: throw block()
}
}

override suspend fun exists(id: Appointment.Id): Boolean =
dsl.selectOne().from(APPOINTMENTS).where(APPOINTMENTS.ID.eq(id.value)).awaitFirstOrNull() != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class JooqClientAggregateRepository(
private val clock: Clock = Clock.systemUTC()
) : AggregateRepository<Client, Client.Id> {

override suspend fun find(id: Client.Id): PersistedAggregate<Client>? =
override suspend fun findById(id: Client.Id): Result<PersistedAggregate<Client>> = runCatching {
dsl.selectFrom(CLIENTS)
.where(CLIENTS.ID.eq(id.value))
.awaitFirstOrNull()?.let {
.awaitFirst().let {
PersistedAggregate(
aggregate = Json.decodeFromString(it.aggregate.data()),
metaData = PersistenceMetaData(
Expand All @@ -33,11 +33,7 @@ class JooqClientAggregateRepository(
)
)
}

override suspend fun get(id: Client.Id): PersistedAggregate<Client> = getOrThrow(id) { NoSuchElementException() }

override suspend fun getOrThrow(id: Client.Id, block: () -> Throwable): PersistedAggregate<Client> =
find(id) ?: throw block()
}

override suspend fun exists(id: Client.Id): Boolean =
dsl.selectOne().from(CLIENTS).where(CLIENTS.ID.eq(id.value)).awaitFirstOrNull() != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,21 @@ class JooqPracticeAggregateRepository(
private val clock: Clock = Clock.systemUTC()
) : AggregateRepository<Practice, Practice.Id> {

override suspend fun find(id: Practice.Id): PersistedAggregate<Practice>? =
dsl.selectFrom(PRACTICES)
.where(PRACTICES.ID.eq(id.value))
.awaitFirstOrNull()?.let {
PersistedAggregate(
aggregate = Json.decodeFromString(it.aggregate.data()),
metaData = PersistenceMetaData(
createdAt = it.createdAt,
updatedAt = it.updatedAt,
revision = it.revision,
override suspend fun findById(id: Practice.Id): Result<PersistedAggregate<Practice>> =
runCatching {
dsl.selectFrom(PRACTICES)
.where(PRACTICES.ID.eq(id.value))
.awaitFirst().let {
PersistedAggregate(
aggregate = Json.decodeFromString(it.aggregate.data()),
metaData = PersistenceMetaData(
createdAt = it.createdAt,
updatedAt = it.updatedAt,
revision = it.revision,
)
)
)
}

override suspend fun get(id: Practice.Id): PersistedAggregate<Practice> = getOrThrow(id) { NoSuchElementException() }

override suspend fun getOrThrow(id: Practice.Id, block: () -> Throwable): PersistedAggregate<Practice> =
find(id) ?: throw block()
}
}

override suspend fun exists(id: Practice.Id): Boolean =
dsl.selectOne().from(PRACTICES).where(PRACTICES.ID.eq(id.value)).awaitFirstOrNull() != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,21 @@ class JooqPractitionerAggregateRepository(
private val clock: Clock = Clock.systemUTC()
) : AggregateRepository<Practitioner, Practitioner.Id> {

override suspend fun find(id: Practitioner.Id): PersistedAggregate<Practitioner>? =
dsl.selectFrom(PRACTITIONERS)
.where(PRACTITIONERS.ID.eq(id.value))
.awaitFirstOrNull()?.let {
PersistedAggregate(
aggregate = Json.decodeFromString(it.aggregate.data()),
metaData = PersistenceMetaData(
createdAt = it.createdAt,
updatedAt = it.updatedAt,
revision = it.revision,
override suspend fun findById(id: Practitioner.Id): Result<PersistedAggregate<Practitioner>> =
runCatching {
dsl.selectFrom(PRACTITIONERS)
.where(PRACTITIONERS.ID.eq(id.value))
.awaitFirst().let {
PersistedAggregate(
aggregate = Json.decodeFromString(it.aggregate.data()),
metaData = PersistenceMetaData(
createdAt = it.createdAt,
updatedAt = it.updatedAt,
revision = it.revision,
)
)
)
}

override suspend fun get(id: Practitioner.Id): PersistedAggregate<Practitioner> =
getOrThrow(id) { NoSuchElementException() }

override suspend fun getOrThrow(id: Practitioner.Id, block: () -> Throwable): PersistedAggregate<Practitioner> =
find(id) ?: throw block()
}
}

override suspend fun exists(id: Practitioner.Id): Boolean =
dsl.selectOne().from(PRACTITIONERS).where(PRACTITIONERS.ID.eq(id.value)).awaitFirstOrNull() != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ class JooqAppointmentAggregateRepositoryTest : ShouldSpec({
repo.save(appointment)
repo.exists(appointment.id).shouldBeTrue()

val persistedAppointment = repo.get(appointment.id)
val persistedAppointment = repo.findById(appointment.id).getOrThrow()
persistedAppointment.aggregate.shouldBe(appointment)
persistedAppointment.metaData.revision.shouldBe(1)
persistedAppointment.metaData.createdAt.shouldBe(time.now)
persistedAppointment.metaData.updatedAt.shouldBe(time.now)
with(persistedAppointment.metaData) {
revision.shouldBe(1)
createdAt.shouldBe(time.now)
updatedAt.shouldBe(time.now)
}
}
}

Expand All @@ -59,30 +61,21 @@ class JooqAppointmentAggregateRepositoryTest : ShouldSpec({
)
updateRepo.save(expectedAppointment)

val persistedAppointment = updateRepo.get(appointment.id)
val persistedAppointment = updateRepo.findById(appointment.id).getOrThrow()
persistedAppointment.aggregate.shouldBe(expectedAppointment)
persistedAppointment.metaData.revision.shouldBe(2)
persistedAppointment.metaData.createdAt.shouldBe(createTime.now)
persistedAppointment.metaData.updatedAt.shouldBe(updateTime.now)
with(persistedAppointment.metaData) {
revision.shouldBe(2)
createdAt.shouldBe(createTime.now)
updatedAt.shouldBe(updateTime.now)
}
}
}

should("throw NoSuchElementException") {
testTransaction {
val repo = JooqAppointmentAggregateRepository(it.dsl())
shouldThrow<NoSuchElementException> {
repo.get(appointment.id)
}
}
}

should("throw user supplied exception") {
testTransaction {
val repo = JooqAppointmentAggregateRepository(it.dsl())
shouldThrow<FakeException> {
repo.getOrThrow(appointment.id) {
FakeException()
}
repo.findById(appointment.id).getOrThrow()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ class JooqClientAggregateRepositoryTest : ShouldSpec({
repo.save(client)
repo.exists(client.id).shouldBeTrue()

val persistedClient = repo.get(client.id)
val persistedClient = repo.findById(client.id).getOrThrow()
persistedClient.aggregate.shouldBe(client)
persistedClient.metaData.revision.shouldBe(1)
persistedClient.metaData.createdAt.shouldBe(time.now)
persistedClient.metaData.updatedAt.shouldBe(time.now)
with(persistedClient.metaData) {
revision.shouldBe(1)
createdAt.shouldBe(time.now)
updatedAt.shouldBe(time.now)
}
}
}

Expand All @@ -52,31 +54,23 @@ class JooqClientAggregateRepositoryTest : ShouldSpec({
val expectedClient = client.copy(gender = Gender.FEMALE)
updateRepo.save(expectedClient)

val persistedClient = updateRepo.get(client.id)
val persistedClient = updateRepo.findById(client.id).getOrThrow()
persistedClient.aggregate.shouldBe(expectedClient)
persistedClient.metaData.revision.shouldBe(2)
persistedClient.metaData.createdAt.shouldBe(createTime.now)
persistedClient.metaData.updatedAt.shouldBe(updateTime.now)
with(persistedClient.metaData) {
revision.shouldBe(2)
createdAt.shouldBe(createTime.now)
updatedAt.shouldBe(updateTime.now)
}
}
}

should("should throw NoSuchElementException") {
testTransaction {
val repo = JooqClientAggregateRepository(it.dsl())
shouldThrow<NoSuchElementException> {
repo.get(client.id)
repo.findById(client.id).getOrThrow()
}
}
}

should("should throw user supplied exception") {
testTransaction {
val repo = JooqClientAggregateRepository(it.dsl())
shouldThrow<FakeException> {
repo.getOrThrow(client.id) {
FakeException()
}
}
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class JooqPracticeAggregateRepositoryTest : ShouldSpec({
repo.save(practice)
repo.exists(practice.id).shouldBeTrue()

val persistedPractice = repo.get(practice.id)
val persistedPractice = repo.findById(practice.id).getOrThrow()
persistedPractice.aggregate.shouldBe(practice)
persistedPractice.metaData.revision.shouldBe(1)
persistedPractice.metaData.createdAt.shouldBe(time.now)
Expand All @@ -43,8 +43,8 @@ class JooqPracticeAggregateRepositoryTest : ShouldSpec({
should("update an existing aggregate and increment revision") {
testTransaction {
val createTime = timeFixtureFactory()
val createRepo = JooqPracticeAggregateRepository(it.dsl(), createTime.clock)
createRepo.save(practice)
val repo = JooqPracticeAggregateRepository(it.dsl(), createTime.clock)
repo.save(practice)

val updateTime = timeFixtureFactory()
val updateRepo = JooqPracticeAggregateRepository(it.dsl(), updateTime.clock)
Expand All @@ -53,30 +53,21 @@ class JooqPracticeAggregateRepositoryTest : ShouldSpec({
)
updateRepo.save(expectedPractice)

val persistedPractice = createRepo.get(practice.id)
val persistedPractice = repo.findById(practice.id).getOrThrow()
persistedPractice.aggregate.shouldBe(expectedPractice)
persistedPractice.metaData.revision.shouldBe(2)
persistedPractice.metaData.createdAt.shouldBe(createTime.now)
persistedPractice.metaData.updatedAt.shouldBe(updateTime.now)
with(persistedPractice.metaData) {
revision.shouldBe(2)
createdAt.shouldBe(createTime.now)
updatedAt.shouldBe(updateTime.now)
}
}
}

should("throw NoSuchElementException") {
testTransaction {
val repo = JooqPracticeAggregateRepository(it.dsl())
shouldThrow<NoSuchElementException> {
repo.get(practice.id)
}
}
}

should("throw user supplied exception") {
testTransaction {
val repo = JooqPracticeAggregateRepository(it.dsl())
shouldThrow<FakeException> {
repo.getOrThrow(practice.id) {
FakeException()
}
repo.findById(practice.id).getOrThrow()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ class JooqPractitionerAggregateRepositoryTest : ShouldSpec({
repo.save(practitioner)
repo.exists(practitioner.id).shouldBeTrue()

val persistedPractitioner = repo.get(practitioner.id)
val persistedPractitioner = repo.findById(practitioner.id).getOrThrow()
persistedPractitioner.aggregate.shouldBe(practitioner)
persistedPractitioner.metaData.revision.shouldBe(1)
persistedPractitioner.metaData.createdAt.shouldBe(time.now)
persistedPractitioner.metaData.updatedAt.shouldBe(time.now)
with(persistedPractitioner.metaData) {
revision.shouldBe(1)
createdAt.shouldBe(time.now)
updatedAt.shouldBe(time.now)
}
}
}

Expand All @@ -54,30 +56,21 @@ class JooqPractitionerAggregateRepositoryTest : ShouldSpec({
val expectedPractitioner = practitioner.copy(gender = Gender.FEMALE)
updateRepo.save(expectedPractitioner)

val persistedPractitioner = createRepo.get(practitioner.id)
val persistedPractitioner = createRepo.findById(practitioner.id).getOrThrow()
persistedPractitioner.aggregate.shouldBe(expectedPractitioner)
persistedPractitioner.metaData.revision.shouldBe(2)
persistedPractitioner.metaData.createdAt.shouldBe(createTime.now)
persistedPractitioner.metaData.updatedAt.shouldBe(updateTime.now)
with(persistedPractitioner.metaData) {
revision.shouldBe(2)
createdAt.shouldBe(createTime.now)
updatedAt.shouldBe(updateTime.now)
}
}
}

should("throw NoSuchElementException") {
testTransaction {
val repo = JooqPractitionerAggregateRepository(it.dsl())
shouldThrow<NoSuchElementException> {
repo.get(practitioner.id)
}
}
}

should("throw user supplied exception") {
testTransaction {
val repo = JooqPractitionerAggregateRepository(it.dsl())
shouldThrow<FakeException> {
repo.getOrThrow(practitioner.id) {
FakeException()
}
repo.findById(practitioner.id).getOrThrow()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.acme.core

interface AggregateRepository<T : Identifiable<I>, I> {
suspend fun find(id: I): PersistedAggregate<T>?
suspend fun get(id: I): PersistedAggregate<T>
suspend fun getOrThrow(id: I, block: () -> Throwable): PersistedAggregate<T>
suspend fun findById(id: I): Result<PersistedAggregate<T>>
suspend fun exists(id: I): Boolean
suspend fun save(aggregate: T)
}
Loading

0 comments on commit 4f514e9

Please sign in to comment.