This commit is contained in:
usbharu 2024-06-01 11:39:26 +09:00
parent 5193a3d2e3
commit 671d1e4f9e
18 changed files with 174 additions and 25 deletions

View File

@ -44,9 +44,9 @@ class Actor2 private constructor(
var followersCount: ActorRelationshipCount?,
var followingCount: ActorRelationshipCount?,
var postsCount: ActorPostsCount,
var lastPostDate: Instant? = null,
var lastPostAt: Instant? = null,
suspend: Boolean,
var lastUpdate: Instant = createdAt,
var lastUpdateAt: Instant = createdAt,
alsoKnownAs: Set<ActorId> = emptySet(),
moveTo: ActorId? = null,
) : DomainEventStorable() {
@ -142,7 +142,7 @@ class Actor2 private constructor(
followersCount = followersCount,
followingCount = followingCount,
postsCount = postsCount,
lastPostDate = lastPostDate,
lastPostAt = lastPostDate,
suspend = suspend
)
}

View File

@ -20,6 +20,9 @@ import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
class ActorDescription private constructor(val description: String, val emojis: List<EmojiId>) {
companion object {
val length = 10000
}
abstract class ActorDescriptionFactory {
protected suspend fun create(description: String, emojis: List<EmojiId>): ActorDescription =
ActorDescription(description, emojis)

View File

@ -17,4 +17,4 @@
package dev.usbharu.hideout.core.domain.model.actor
@JvmInline
value class ActorKeyId(private val keyId: String)
value class ActorKeyId(val keyId: String)

View File

@ -21,4 +21,8 @@ value class ActorName(val name: String) {
init {
}
companion object {
val length = 300
}
}

View File

@ -17,7 +17,7 @@
package dev.usbharu.hideout.core.domain.model.actor
@JvmInline
value class ActorPostsCount(private val postsCount: Int) {
value class ActorPostsCount(val postsCount: Int) {
init {
require(0 <= this.postsCount) { "Posts count must be greater than 0" }
}

View File

@ -17,4 +17,4 @@
package dev.usbharu.hideout.core.domain.model.actor
@JvmInline
value class ActorPrivateKey(private val privateKey: String)
value class ActorPrivateKey(val privateKey: String)

View File

@ -17,4 +17,4 @@
package dev.usbharu.hideout.core.domain.model.actor
@JvmInline
value class ActorPublicKey(private val publicKey: String)
value class ActorPublicKey(val publicKey: String)

View File

@ -17,11 +17,11 @@
package dev.usbharu.hideout.core.domain.model.actor
@JvmInline
value class ActorRelationshipCount(private val followersCount: Int) {
value class ActorRelationshipCount(val relationshipCount: Int) {
init {
require(0 <= followersCount) { "Followers count must be > 0" }
require(0 <= relationshipCount) { "Followers count must be > 0" }
}
operator fun inc(): ActorRelationshipCount = ActorRelationshipCount(followersCount + 1)
operator fun dec(): ActorRelationshipCount = ActorRelationshipCount(followersCount - 1)
operator fun inc(): ActorRelationshipCount = ActorRelationshipCount(relationshipCount + 1)
operator fun dec(): ActorRelationshipCount = ActorRelationshipCount(relationshipCount - 1)
}

View File

@ -20,6 +20,9 @@ import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
class ActorScreenName private constructor(val screenName: String, val emojis: List<EmojiId>) {
companion object {
val length = 300
}
abstract class ActorScreenNameFactory {
protected suspend fun create(screenName: String, emojis: List<EmojiId>): ActorScreenName =

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.domain.model.actorinstancerelationship
interface ActorInstanceRelationshipRepository {
suspend fun save(actorInstanceRelationship: ActorInstanceRelationship): ActorInstanceRelationship
suspend fun delete(actorInstanceRelationship: ActorInstanceRelationship)
}

View File

@ -19,6 +19,6 @@ package dev.usbharu.hideout.core.domain.model.deletedActor
interface DeletedActorRepository {
suspend fun save(deletedActor: DeletedActor): DeletedActor
suspend fun delete(deletedActor: DeletedActor)
suspend fun findById(id: Long): DeletedActor?
suspend fun findById(id: DeletedActorId): DeletedActor?
suspend fun findByNameAndDomain(name: String, domain: String): DeletedActor?
}

View File

@ -17,4 +17,4 @@
package dev.usbharu.hideout.core.domain.model.instance
@JvmInline
value class InstanceId(private val instanceId: Long)
value class InstanceId(val instanceId: Long)

View File

@ -17,4 +17,8 @@
package dev.usbharu.hideout.core.domain.model.shared
@JvmInline
value class Domain(val domain: String)
value class Domain(val domain: String) {
companion object {
val length = 1000
}
}

View File

@ -1,10 +1,12 @@
package dev.usbharu.hideout.core.infrastructure.exposedrepository
import dev.usbharu.hideout.core.domain.model.actor.Actor2
import dev.usbharu.hideout.core.domain.model.actor.Actor2Repository
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.actor.*
import dev.usbharu.hideout.core.domain.model.shared.Domain
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher
import dev.usbharu.hideout.core.domain.shared.repository.DomainEventPublishableRepository
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.javatime.timestamp
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Repository
@ -21,17 +23,94 @@ class ExposedActor2Repository(override val domainEventPublisher: DomainEventPubl
override suspend fun save(actor: Actor2): Actor2 {
query {
Actors2.upsert {
it[id] = actor.id.id
it[name] = actor.name.name
it[domain] = actor.domain.domain
it[screenName] = actor.screenName.screenName
it[description] = actor.description.description
it[inbox] = actor.inbox.toString()
it[outbox] = actor.outbox.toString()
it[url] = actor.outbox.toString()
it[publicKey] = actor.publicKey.publicKey
it[privateKey] = actor.privateKey?.privateKey
it[createdAt] = actor.createdAt
it[keyId] = actor.keyId.keyId
it[following] = actor.followingEndpoint?.toString()
it[followers] = actor.followersEndpoint?.toString()
it[instance] = actor.instance.instanceId
it[locked] = actor.locked
it[followingCount] = actor.followingCount?.relationshipCount
it[followersCount] = actor.followersCount?.relationshipCount
it[postsCount] = actor.postsCount.postsCount
it[lastPostAt] = actor.lastPostAt
it[lastUpdateAt] = actor.lastUpdateAt
it[suspend] = actor.suspend
it[moveTo] = actor.moveTo?.id
it[emojis] = actor.emojis.joinToString(",")
}
Actors2AlsoKnownAs.deleteWhere {
actorId eq actor.id.id
}
Actors2AlsoKnownAs.batchInsert(actor.alsoKnownAs) {
this[Actors2AlsoKnownAs.actorId] = actor.id.id
this[Actors2AlsoKnownAs.alsoKnownAs] = it.id
}
}
update(actor)
return actor
}
override suspend fun delete(actor: Actor2) {
TODO("Not yet implemented")
query {
Actors2.deleteWhere { id eq actor.id.id }
Actors2AlsoKnownAs.deleteWhere { actorId eq actor.id.id }
}
update(actor)
}
override suspend fun findById(id: ActorId): Actor2? {
TODO("Not yet implemented")
TODO()
}
}
object Actors2 : Table("actors") {
val id = long("id")
val name = varchar("name", ActorName.length)
val domain = varchar("domain", Domain.length)
val screenName = varchar("screen_name", ActorScreenName.length)
val description = varchar("description", ActorDescription.length)
val inbox = varchar("inbox", 1000).uniqueIndex()
val outbox = varchar("outbox", 1000).uniqueIndex()
val url = varchar("url", 1000).uniqueIndex()
val publicKey = varchar("public_key", 10000)
val privateKey = varchar("private_key", 100000).nullable()
val createdAt = timestamp("created_at")
val keyId = varchar("key_id", 1000)
val following = varchar("following", 1000).nullable()
val followers = varchar("followers", 1000).nullable()
val instance = long("instance").references(Instance.id)
val locked = bool("locked")
val followingCount = integer("following_count").nullable()
val followersCount = integer("followers_count").nullable()
val postsCount = integer("posts_count")
val lastPostAt = timestamp("last_post_at").nullable()
val lastUpdateAt = timestamp("last_update_at")
val suspend = bool("suspend")
val moveTo = long("move_to").references(id).nullable()
val emojis = varchar("emojis", 3000)
override val primaryKey = PrimaryKey(id)
init {
uniqueIndex(name, domain)
}
}
object Actors2AlsoKnownAs : Table("actor_alsoknwonas") {
val actorId =
long("actor_id").references(Actors2.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
val alsoKnownAs = long("alsoKnownAs").references(Actors2.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
override val primaryKey: PrimaryKey = PrimaryKey(actorId, alsoKnownAs)
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.springframework.domainevent
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEvent
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component
@Component
class SpringFrameworkDomainEventPublisher(private val applicationEventPublisher: ApplicationEventPublisher) :
DomainEventPublisher {
override suspend fun publishEvent(domainEvent: DomainEvent) {
applicationEventPublisher.publishEvent(domainEvent)
}
}

View File

@ -30,7 +30,7 @@ class MigrationLocalActorApplicationService(
private val localActorMigrationCheckDomainService: LocalActorMigrationCheckDomainService,
) {
suspend fun migration(from: Long, to: Long, executor: ActorId) {
transaction.transaction {
transaction.transaction<Unit> {
val fromActorId = ActorId(from)
val toActorId = ActorId(to)

View File

@ -45,15 +45,19 @@ create table if not exists actors
key_id varchar(1000) not null,
"following" varchar(1000) null,
followers varchar(1000) null,
"instance" bigint not null,
"instance" bigint not null,
locked boolean not null,
following_count int not null,
followers_count int not null,
posts_count int not null,
last_post_at timestamp null default null,
emojis varchar(300) not null default '',
last_update_at timestamp not null,
suspend boolean not null,
move_to bigint null default null,
emojis varchar(3000) not null default '',
unique ("name", "domain"),
constraint fk_actors_instance__id foreign key ("instance") references instance (id) on delete restrict on update restrict
constraint fk_actors_instance__id foreign key ("instance") references instance (id) on delete restrict on update restrict,
constraint fk_actors_actors__move_to foreign key ("move_to") references actors (id) on delete restrict on update restrict
);
create table if not exists user_details

View File

@ -3,7 +3,7 @@ package dev.usbharu.hideout.core.domain.model.actor
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
class Actor2Test {
class Actors2Test {
@Test
fun alsoKnownAsに自分自身が含まれてはいけない() {
val actor = TestActor2Factory.create(publicKey = ActorPublicKey(""))