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 followersCount: ActorRelationshipCount?,
var followingCount: ActorRelationshipCount?, var followingCount: ActorRelationshipCount?,
var postsCount: ActorPostsCount, var postsCount: ActorPostsCount,
var lastPostDate: Instant? = null, var lastPostAt: Instant? = null,
suspend: Boolean, suspend: Boolean,
var lastUpdate: Instant = createdAt, var lastUpdateAt: Instant = createdAt,
alsoKnownAs: Set<ActorId> = emptySet(), alsoKnownAs: Set<ActorId> = emptySet(),
moveTo: ActorId? = null, moveTo: ActorId? = null,
) : DomainEventStorable() { ) : DomainEventStorable() {
@ -142,7 +142,7 @@ class Actor2 private constructor(
followersCount = followersCount, followersCount = followersCount,
followingCount = followingCount, followingCount = followingCount,
postsCount = postsCount, postsCount = postsCount,
lastPostDate = lastPostDate, lastPostAt = lastPostDate,
suspend = suspend 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>) { class ActorDescription private constructor(val description: String, val emojis: List<EmojiId>) {
companion object {
val length = 10000
}
abstract class ActorDescriptionFactory { abstract class ActorDescriptionFactory {
protected suspend fun create(description: String, emojis: List<EmojiId>): ActorDescription = protected suspend fun create(description: String, emojis: List<EmojiId>): ActorDescription =
ActorDescription(description, emojis) ActorDescription(description, emojis)

View File

@ -17,4 +17,4 @@
package dev.usbharu.hideout.core.domain.model.actor package dev.usbharu.hideout.core.domain.model.actor
@JvmInline @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 { init {
} }
companion object {
val length = 300
}
} }

View File

@ -17,7 +17,7 @@
package dev.usbharu.hideout.core.domain.model.actor package dev.usbharu.hideout.core.domain.model.actor
@JvmInline @JvmInline
value class ActorPostsCount(private val postsCount: Int) { value class ActorPostsCount(val postsCount: Int) {
init { init {
require(0 <= this.postsCount) { "Posts count must be greater than 0" } 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 package dev.usbharu.hideout.core.domain.model.actor
@JvmInline @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 package dev.usbharu.hideout.core.domain.model.actor
@JvmInline @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 package dev.usbharu.hideout.core.domain.model.actor
@JvmInline @JvmInline
value class ActorRelationshipCount(private val followersCount: Int) { value class ActorRelationshipCount(val relationshipCount: Int) {
init { 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 inc(): ActorRelationshipCount = ActorRelationshipCount(relationshipCount + 1)
operator fun dec(): ActorRelationshipCount = ActorRelationshipCount(followersCount - 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>) { class ActorScreenName private constructor(val screenName: String, val emojis: List<EmojiId>) {
companion object {
val length = 300
}
abstract class ActorScreenNameFactory { abstract class ActorScreenNameFactory {
protected suspend fun create(screenName: String, emojis: List<EmojiId>): ActorScreenName = 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 { interface DeletedActorRepository {
suspend fun save(deletedActor: DeletedActor): DeletedActor suspend fun save(deletedActor: DeletedActor): DeletedActor
suspend fun delete(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? suspend fun findByNameAndDomain(name: String, domain: String): DeletedActor?
} }

View File

@ -17,4 +17,4 @@
package dev.usbharu.hideout.core.domain.model.instance package dev.usbharu.hideout.core.domain.model.instance
@JvmInline @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 package dev.usbharu.hideout.core.domain.model.shared
@JvmInline @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 package dev.usbharu.hideout.core.infrastructure.exposedrepository
import dev.usbharu.hideout.core.domain.model.actor.Actor2 import dev.usbharu.hideout.core.domain.model.actor.*
import dev.usbharu.hideout.core.domain.model.actor.Actor2Repository import dev.usbharu.hideout.core.domain.model.shared.Domain
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher
import dev.usbharu.hideout.core.domain.shared.repository.DomainEventPublishableRepository 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.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
@ -21,17 +23,94 @@ class ExposedActor2Repository(override val domainEventPublisher: DomainEventPubl
override suspend fun save(actor: Actor2): Actor2 { override suspend fun save(actor: Actor2): Actor2 {
query { 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) update(actor)
return actor return actor
} }
override suspend fun delete(actor: Actor2) { 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? { 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, private val localActorMigrationCheckDomainService: LocalActorMigrationCheckDomainService,
) { ) {
suspend fun migration(from: Long, to: Long, executor: ActorId) { suspend fun migration(from: Long, to: Long, executor: ActorId) {
transaction.transaction { transaction.transaction<Unit> {
val fromActorId = ActorId(from) val fromActorId = ActorId(from)
val toActorId = ActorId(to) val toActorId = ActorId(to)

View File

@ -45,15 +45,19 @@ create table if not exists actors
key_id varchar(1000) not null, key_id varchar(1000) not null,
"following" varchar(1000) null, "following" varchar(1000) null,
followers varchar(1000) null, followers varchar(1000) null,
"instance" bigint not null, "instance" bigint not null,
locked boolean not null, locked boolean not null,
following_count int not null, following_count int not null,
followers_count int not null, followers_count int not null,
posts_count int not null, posts_count int not null,
last_post_at timestamp null default 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"), 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 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.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
class Actor2Test { class Actors2Test {
@Test @Test
fun alsoKnownAsに自分自身が含まれてはいけない() { fun alsoKnownAsに自分自身が含まれてはいけない() {
val actor = TestActor2Factory.create(publicKey = ActorPublicKey("")) val actor = TestActor2Factory.create(publicKey = ActorPublicKey(""))