I've successfully implemented a comprehensive Room database layer with all recommended best practices. Here's everything that's been added:
- ✅ Room Database 2.6.1
- ✅ KSP (Kotlin Symbol Processing) 2.0.21
- ✅ Kotlin Coroutines 1.8.0
- ✅ KSP plugin for Room annotation processing
- ✅ Room runtime, KTX, and compiler
- ✅ Coroutines for async database operations
app/src/main/java/ug/global/temp/db/
├── entities/ # Database Models
│ ├── BaseEntity.kt (2.3KB) ← Interface for common fields
│ └── User.kt (2.5KB) ← Example user entity with best practices
│
├── dao/ # Data Access Objects
│ ├── BaseDao.kt (2.7KB) ← Generic DAO with CRUD operations
│ └── UserDao.kt (8.5KB) ← Complete example with 30+ query methods
│
├── repository/ # Repository Pattern
│ ├── BaseRepository.kt (2.9KB) ← Generic repository
│ └── UserRepository.kt (7.8KB) ← Business logic layer with validation
│
├── database/ # Database Configuration
│ ├── AppDatabase.kt (5.7KB) ← Main database class with migrations
│ └── DatabaseHelper.kt (7.2KB) ← Utilities (seed, backup, restore, stats)
│
└── converters/ # Type Converters
└── Converters.kt (3.1KB) ← Handle Date, List, Map, Boolean
Total: 10 new files, ~40KB of production-ready code
- Insert (single, multiple, list)
- Update (single, multiple)
- Delete (single, multiple)
- Upsert (insert or update)
- All with suspend functions for coroutines
Query Operations:
- Get all users (Flow for reactive updates)
- Get user by ID, email, username, token
- Search by name/username/email
- Filtered queries (verified, active, by date)
- Count and exists checks
Update Operations:
- Update auth token
- Update email verification
- Update last login
- Update profile picture
- Soft delete/restore
Transaction Examples:
- Insert and return entity with generated ID
- Update with automatic timestamp
- Register user with validation
- Login/logout with token management
- Update profile
- Email verification
- Soft delete/restore
- Error handling with Result
- Seed database with sample data
- Clear all data
- Backup/restore database
- Get database stats (size, counts)
- Export to SQL
- Database file operations
- Date ↔ Long (timestamp)
- List ↔ String (comma-separated)
- Map<String, String> ↔ String (JSON-like)
- Boolean ↔ Int
Standard fields for all entities:
id- Primary keycreatedAt- Creation timestampupdatedAt- Last update timestampisDeleted- Soft delete flag
Comprehensive 400+ line guide covering:
- Quick start examples
- How to create entities
- How to create DAOs
- Using repositories
- Database operations (CRUD)
- Migrations (with examples)
- Best practices (DO/DON'T)
- Common patterns
- Troubleshooting
- Testing
-
util/Helpers.kt
- Added
getDatabase(context)helper - Added
getUserRepository(context)helper - Easy access from anywhere in the app
- Added
-
INDEX.md
- Added DATABASE_GUIDE.md to documentation index
- Updated for developers section
// Get repository
val userRepository = Helpers.getUserRepository(this)
// Insert user
lifecycleScope.launch {
val user = User(
email = "john@example.com",
username = "johndoe",
fullName = "John Doe"
)
val userId = userRepository.insert(user)
}
// Query with Flow (reactive)
lifecycleScope.launch {
userRepository.getAllUsers().collect { users ->
// UI updates automatically when data changes
updateUI(users)
}
}
// Business logic with validation
lifecycleScope.launch {
val result = userRepository.registerUser(
email = "user@example.com",
username = "username",
fullName = "Full Name"
)
result.onSuccess { user ->
Helpers.showToast(this@Activity, "User registered!")
}.onFailure { error ->
Helpers.showToast(this@Activity, error.message ?: "Error")
}
}Implemented clean architecture with clear separation:
┌─────────────────────────────────┐
│ UI Layer (Activity/Fragment) │
└────────────┬────────────────────┘
│
↓
┌─────────────────────────────────┐
│ Repository (Business Logic) │ ← Validation, data transformation
└────────────┬────────────────────┘
│
↓
┌─────────────────────────────────┐
│ DAO (Database Access) │ ← SQL queries
└────────────┬────────────────────┘
│
↓
┌─────────────────────────────────┐
│ Room Database (SQLite) │ ← Data storage
└─────────────────────────────────┘
- ✅ Suspend functions - All database ops use coroutines
- ✅ Flow for reactive data - Auto-updates when data changes
- ✅ Repository pattern - Business logic separation
- ✅ Type safety - Compile-time SQL verification
- ✅ Soft delete - Mark as deleted instead of permanent deletion
- ✅ Timestamps - Track created/updated times
- ✅ Indices - Fast queries on frequently searched fields
- ✅ Transactions - Atomic operations
- ✅ Error handling - Result for clean error management
- ✅ Migration support - Schema versioning
- ✅ Type converters - Handle complex types
- ✅ Singleton pattern - Single database instance
1. Create Entity:
@Entity(tableName = "products", indices = [Index("sku", unique = true)])
data class Product(
@PrimaryKey(autoGenerate = true)
override val id: Long = 0,
val name: String,
val sku: String,
val price: Double,
override val createdAt: Date = Date(),
override val updatedAt: Date = Date(),
override val isDeleted: Boolean = false
) : BaseEntity2. Create DAO:
@Dao
interface ProductDao : BaseDao<Product> {
@Query("SELECT * FROM products WHERE isDeleted = 0")
fun getAllProducts(): Flow<List<Product>>
}3. Create Repository:
class ProductRepository(private val dao: ProductDao) : BaseRepository<Product>(dao) {
fun getAllProducts() = dao.getAllProducts()
}4. Add to AppDatabase:
@Database(entities = [User::class, Product::class], version = 2)
abstract class AppDatabase : RoomDatabase() {
abstract fun productDao(): ProductDao
}5. Use it:
val productRepo = ProductRepository(Helpers.getDatabase(this).productDao())- Email (unique, indexed)
- Username (unique, indexed)
- Full name, phone, bio
- Profile picture URL
- Auth token
- Email verification status
- Last login timestamp
- Created/Updated timestamps
- Soft delete flag
getDisplayName()- Returns full name or usernameisProfileComplete()- Check if all required fields filledisActive()- Check if user is verified and not deleted
seedDatabase()- Pre-populate with sample dataclearDatabase()- Remove all datagetDatabasePath()- Get database file locationgetDatabaseSize()- Get database file sizebackupDatabase()- Backup to external storagerestoreDatabase()- Restore from backupdeleteDatabase()- Delete database filegetDatabaseStats()- Get statistics (counts, size, etc.)exportToSQL()- Export data to SQL file
Check DATABASE_GUIDE.md for:
- Quick Start - Get up and running in 5 minutes
- Entity Creation - Step-by-step with examples
- DAO Queries - 20+ query patterns
- Repository Pattern - Business logic best practices
- Migrations - Handle schema changes safely
- Common Patterns - Real-world examples
- Troubleshooting - Solutions to common issues
- Testing - How to test database code
- ✅ Complete CRUD operations
- ✅ 30+ example queries
- ✅ Search functionality
- ✅ Filtering and sorting
- ✅ Pagination support (via LIMIT)
- ✅ Soft delete system
- ✅ Timestamp tracking
- ✅ Data validation
- ✅ Error handling
- ✅ Backup/restore
- ✅ Database stats
- ✅ Sample data seeding
- ✅ Type-safe queries
- ✅ Auto-completion in IDE
- ✅ Compile-time verification
- ✅ Easy to extend
- ✅ Well documented
- ✅ Best practices built-in
- ✅ Example implementations
- ✅ Comprehensive guide
-
Explore the code:
db/entities/User.kt- See entity structuredb/dao/UserDao.kt- See query examplesdb/repository/UserRepository.kt- See business logic
-
Read DATABASE_GUIDE.md - Complete usage guide
-
Try it out:
lifecycleScope.launch { // Seed sample data DatabaseHelper.seedDatabase(this@MainActivity) // Get all users userRepository.getAllUsers().collect { users -> Log.d("DB", "Users: ${users.size}") } } -
Create your own entities - Follow the patterns
-
Integrate with your API - Sync network data to database
You now have a production-ready Room database implementation with:
- ✨ 10 new files with 40KB+ of code
- ✨ Complete CRUD operations
- ✨ 30+ example query methods
- ✨ Business logic layer
- ✨ Database utilities
- ✨ Type converters
- ✨ 400+ lines of documentation
- ✨ Best practices throughout
- ✨ Easy to customize and extend
The database layer is complete and ready to use! 🚀
Check DATABASE_GUIDE.md for complete usage instructions and examples.