Back to list
WAMF

kiss-repository

by WAMF

A repository interface following the KISS (Keep It Simple, Stupid) principle.

1🍴 0📅 Jan 13, 2026

SKILL.md


name: kiss-repository description: Guide for implementing and using kiss_repository - a lightweight Dart repository pattern for data access with CRUD, streaming, and batch operations allowed-tools: Read, Grep, Glob

kiss_repository Usage Guide

A lightweight, generic repository pattern implementation for Dart following the KISS principle.

Core Concepts

Repository

The abstract base class defining all data operations. Generic type T is your domain model.

IdentifiedObject

Wraps an object with its unique string ID:

final item = IdentifiedObject('user-123', User(name: 'Alice'));
// item.id == 'user-123'
// item.object == User(name: 'Alice')

Query System

Extend Query for domain-specific filters. Implement QueryBuilder<T> to translate queries to your implementation.

Available Implementations

  • InMemoryRepository: Testing and temporary storage
  • JsonFileRepository: File-based JSON persistence

CRUD Operations

Reading Data

// Get single item by ID (throws RepositoryException.notFound if missing)
final user = await repository.get('user-123');

// Query multiple items
final users = await repository.query(query: ActiveUsersQuery());

// Get all items
final allUsers = await repository.query();

Creating Data

// Add with explicit ID
await repository.add(IdentifiedObject('user-123', user));

// Add with auto-generated ID
await repository.addAutoIdentified(
  user,
  updateObjectWithId: (user, id) => user.copyWith(id: id),
);

Updating Data

// Update with transformer function
final updated = await repository.update('user-123', (current) =>
  current.copyWith(name: 'New Name')
);

Deleting Data

await repository.delete('user-123');

Batch Operations

// Add multiple items atomically
await repository.addAll([
  IdentifiedObject('id1', item1),
  IdentifiedObject('id2', item2),
]);

// Update multiple items
await repository.updateAll([
  IdentifiedObject('id1', updatedItem1),
  IdentifiedObject('id2', updatedItem2),
]);

// Delete multiple items
await repository.deleteAll(['id1', 'id2', 'id3']);

Streaming (Real-time Updates)

// Stream single item changes
repository.stream('user-123').listen((user) {
  print('User updated: ${user.name}');
});

// Stream query results
repository.streamQuery(query: ActiveUsersQuery()).listen((users) {
  print('Active users: ${users.length}');
});

Streams emit immediately with current data (BehaviorSubject-like behavior).

Query Implementation

Define Custom Query

class UsersByRoleQuery extends Query {
  const UsersByRoleQuery(this.role);
  final String role;
}

Implement QueryBuilder

class UserQueryBuilder implements QueryBuilder<InMemoryFilterQuery<User>> {
  @override
  InMemoryFilterQuery<User> build(Query query) {
    if (query is UsersByRoleQuery) {
      return InMemoryFilterQuery<User>((user) => user.role == query.role);
    }
    return InMemoryFilterQuery<User>((user) => true);
  }
}

Error Handling

try {
  final user = await repository.get('non-existent');
} on RepositoryException catch (e) {
  switch (e.code) {
    case RepositoryErrorCode.notFound:
      // Item doesn't exist
    case RepositoryErrorCode.alreadyExists:
      // ID already in use (on add)
    case RepositoryErrorCode.unknown:
      // Other error
  }
}

Creating a Repository

InMemoryRepository

final repository = InMemoryRepository<User>(
  queryBuilder: UserQueryBuilder(),
  path: 'users',
  initialItems: [
    IdentifiedObject('user-1', User(name: 'Alice')),
  ],
);

JsonFileRepository

final repository = JsonFileRepository<User>(
  queryBuilder: UserQueryBuilder(),
  path: 'users',
  file: File('users.json'),
  fromJson: User.fromJson,
  toJson: (user) => user.toJson(),
);

Resource Management

Always dispose repositories when done:

repository.dispose();

This cleans up all internal streams and resources.

Best Practices

  1. Generate IDs outside the repository or use addAutoIdentified
  2. Use InMemoryRepository for unit tests
  3. Use JsonFileRepository for integration tests
  4. Always call dispose() when done
  5. Handle RepositoryException for error cases
  6. Use streaming for real-time UI updates
  7. Use batch operations for multiple items of same type

Score

Total Score

60/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon