smithery/Kaakati

Repository Patterns

Repository interface and implementation patterns with offline-first strategies

Installation

$ npx skills add smithery/Kaakati --skill repository-patterns

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/Kaakati · top by installs.

npx skills add smithery/Kaakati

Browse all from smithery/Kaakati

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,238 B
  • docs SUMMARY.md 105 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Repository Patterns

Repository Interface (Domain Layer)

// lib/domain/repositories/user_repository.dart
import 'package:dartz/dartz.dart';
import '../../core/errors/failures.dart';
import '../entities/user.dart';

abstract class UserRepository {
  Future<Either<Failure, User>> getUser(String id);
  Future<Either<Failure, List<User>>> getAllUsers();
  Future<Either<Failure, User>> createUser(User user);
  Future<Either<Failure, User>> updateUser(User user);
  Future<Either<Failure, void>> deleteUser(String id);
}

Repository Implementation (Data Layer)

Basic Implementation

// lib/data/repositories/user_repository_impl.dart
import 'package:dartz/dartz.dart';
import '../../core/errors/failures.dart';
import '../../core/errors/exceptions.dart';
import '../../domain/entities/user.dart';
import '../../domain/repositories/user_repository.dart';
import '../providers/user_provider.dart';

class UserRepositoryImpl implements UserRepository {
  final UserProvider _provider;
  
  UserRepositoryImpl(this._provider);
  
  @override
  Future<Either<Failure, User>> getUser(String id) async {
    try {
      final model = await _provider.fetchUser(id);
      return Right(model.toEntity());
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on NetworkException {
      return Left(NetworkFailure());
    } catch (e) {
      return Left(ServerFailure('Unexpected error: $e'));
    }
  }
}

Offline-First Implementation

class UserRepositoryImpl implements UserRepository {
  final UserProvider _remoteSource;
  final UserLocalSource _localSource;
  final NetworkInfo _networkInfo;
  
  UserRepositoryImpl(
    this._remoteSource,
    this._localSource,
    this._networkInfo,
  );
  
  @override
  Future<Either<Failure, User>> getUser(String id) async {
    if (await _networkInfo.isConnected) {
      // Try remote first
      try {
        final model = await _remoteSource.fetchUser(id);
        // Cache for offline use
        await _localSource.cacheUser(model);
        return Right(model.toEntity());
      } on ServerException catch (e) {
        // Fallback to cache on server error
        return _getCachedUser(id);
      }
    } else {
      // Use cache when offline
      return _getCachedUser(id);
    }
  }
  
  Future<Either<Failure, User>> _getCachedUser(String id) async {
    try {
      final cached = await _localSource.getCachedUser(id);
      if (cached != null) {
        return Right(cached.toEntity());
      } else {
        return Left(CacheFailure('No cached data available'));
      }
    } on CacheException catch (e) {
      return Left(CacheFailure(e.message));
    }
  }
  
  @override
  Future<Either<Failure, List<User>>> getAllUsers() async {
    if (await _networkInfo.isConnected) {
      try {
        final models = await _remoteSource.fetchAllUsers();
        await _localSource.cacheUsers(models);
        return Right(models.map((m) => m.toEntity()).toList());
      } on ServerException {
        return _getCachedUsers();
      }
    } else {
      return _getCachedUsers();
    }
  }
  
  Future<Either<Failure, List<User>>> _getCachedUsers() async {
    try {
      final cached = await _localSource.getCachedUsers();
      if (cached != null && cached.isNotEmpty) {
        return Right(cached.map((m) => m.toEntity()).toList());
      } else {
        return Left(CacheFailure('No cached users'));
      }
    } on CacheException catch (e) {
      return Left(CacheFailure(e.message));
    }
  }
}

Caching Strategies

1. Cache-First (Offline-First)

// Try cache first, then network
Future<Either<Failure, User>> getUser(String id) async {
  // Check cache first
  final cached = await _localSource.getCachedUser(id);
  if (cached != null) {
    // Return cached data immediately
    _refreshInBackground(id); // Update in background
    return Right(cached.toEntity());
  }
  
  // Cache miss - fetch from network
  return _fetchFromNetwork(id);
}

2. Network-First (Fresh Data Priority)

// Try network first, fallback to cache
Future<Either<Failure, User>> getUser(String id) async {
  if (await _networkInfo.isConnected) {
    try {
      final model = await _remoteSource.fetchUser(id);
      await _localSource.cacheUser(model);
      return Right(model.toEntity());
    } catch (e) {
      return _getCachedUser(id); // Fallback
    }
  } else {
    return _getCachedUser(id);
  }
}

3. Cache-Then-Network

// Return cache immediately, then update with network data
Stream<Either<Failure, User>> getUserStream(String id) async* {
  // Emit cached data first
  final cached = await _localSource.getCachedUser(id);
  if (cached != null) {
    yield Right(cached.toEntity());
  }
  
  // Then fetch from network
  if (await _networkInfo.isConnected) {
    try {
      final model = await _remoteSource.fetchUser(id);
      await _localSource.cacheUser(model);
      yield Right(model.toEntity());
    } on ServerException catch (e) {
      yield Left(ServerFailure(e.message));
    }
  }
}