搜索

PythonReactSEOPDF
GitHub Skill

kmp-repository-creator

Generate Repository classes for Kotlin Multiplatform (KMP) projects using Ktor for networking and multiplatform-settings for local storage. Use when: (1) Creating data layer repositories, (2) Implementing network data fetching with Ktor, (3) Adding local caching with multiplatform-settings, (4) Writing repository unit tests, (5) Following TDD workflow for repository implementation. Triggers: repository, data layer, ktor, multiplatform-settings, network fetch, local storage, cache, data source, TDD repository, repository pattern, kmp repository.

shoheikawano☆ 3 仓库 Stars0 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

KMP Repository Creator

Generate Repository classes following TDD methodology with Ktor networking and multiplatform-settings caching.

Coding Standards

MANDATORY: Follow kotlin-compose-standards:

  • Trailing comma EXCEPT for Modifier arguments
  • New line at end of file

TDD Workflow

Always follow Red-Green-Refactor cycle:

  1. RED - Write failing test first
  2. GREEN - Implement minimal code to pass
  3. REFACTOR - Improve code while keeping tests green

See references/tdd-workflow.md for detailed TDD patterns.

Repository Structure

feature/
  data/
    repository/
      UserRepository.kt          # Interface
      UserRepositoryImpl.kt      # Implementation
    datasource/
      UserRemoteDataSource.kt    # Ktor network calls
      UserLocalDataSource.kt     # multiplatform-settings
    model/
      UserDto.kt                 # Network DTOs
  domain/
    model/
      User.kt                    # Domain models

Quick Start

1. Define Repository Interface
interface UserRepository {
    suspend fun getUser(id: String): User
    suspend fun getUsers(): List<User>
    fun observeUser(id: String): Flow<User?>
}
2. Write Tests First (TDD)
class UserRepositoryImplTest {
    private lateinit var repository: UserRepository
    private val remoteDataSource = FakeUserRemoteDataSource()
    private val localDataSource = FakeUserLocalDataSource()

    @BeforeTest
    fun setup() {
        repository = UserRepositoryImpl(remoteDataSource, localDataSource)
    }

    @Test
    fun `getUser returns cached user when available`() = runTest {
        // Given
        val cachedUser = User(id = "1", name = "John")
        localDataSource.saveUser(cachedUser)

        // When
        val result = repository.getUser("1")

        // Then
        assertEquals(cachedUser, result)
    }

    @Test
    fun `getUser fetches from remote when cache empty`() = runTest {
        // Given
        val remoteUser = UserDto(id = "1", name = "John")
        remoteDataSource.setResponse(remoteUser)

        // When
        val result = repository.getUser("1")

        // Then
        assertEquals("John", result.name)
    }

    @Test
    fun `getUser throws exception when network fails`() = runTest {
        // Given
        remoteDataSource.setError(IOException("Network error"))

        // When/Then
        assertFailsWith<IOException> {
            repository.getUser("1")
        }
    }
}
3. Implement Repository
class UserRepositoryImpl(
    private val remoteDataSource: UserRemoteDataSource,
    private val localDataSource: UserLocalDataSource,
) : UserRepository {

    override suspend fun getUser(id: String): User {
        // Try cache first
        localDataSource.getUser(id)?.let { return it }

        // Fetch from remote
        val dto = remoteDataSource.getUser(id)
        val user = dto.toDomain()
        localDataSource.saveUser(user)
        return user
    }

    override suspend fun getUsers(): List<User> {
        return remoteDataSource.getUsers().map { it.toDomain() }
    }

    override fun observeUser(id: String): Flow<User?> {
        return localDataSource.observeUser(id)
    }
}

Workflow

  1. Analyze requirements - What data? Caching strategy?
  2. Define interface - Repository contract with suspend functions
  3. Write tests - Cover cache hit, cache miss, error cases
  4. Implement minimal - Just enough to pass tests
  5. Refactor - Extract data sources, improve error handling
  6. Verify - Run tests, ensure all pass

References

File When to Read
ktor-patterns.md Network calls, error handling, serialization
multiplatform-settings.md Local storage, caching patterns
tdd-workflow.md TDD cycle, test patterns, fake implementations
testing-patterns.md Test doubles, coroutine testing

Koin Integration

Repository injected via Koin DSL:

val dataModule = module {
    // Data sources
    single { UserRemoteDataSource(get()) }
    single { UserLocalDataSource(get()) }

    // Repository
    single<UserRepository> { UserRepositoryImpl(get(), get()) }
}

ViewModel receives repository:

class UserViewModel(
    private val userRepository: UserRepository,
) : ViewModel() {

    private val _uiState = MutableStateFlow<UserUiState>(UserUiState.Loading)
    val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()

    fun loadUser(id: String) {
        viewModelScope.launch {
            _uiState.value = UserUiState.Loading
            try {
                val user = userRepository.getUser(id)
                _uiState.value = UserUiState.Success(user)
            } catch (e: Exception) {
                _uiState.value = UserUiState.Error(e.message)
            }
        }
    }
}

Best Practices

  • Repository throws exceptions for errors (ViewModel handles with try-catch)
  • Use Flow<T> for observable data
  • Keep domain models separate from DTOs
  • Cache strategy: cache-first with network fallback
  • Test all paths: success, cache hit, network error

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-01-20
索引更新时间
2026-01-26
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!