trail-sense-database-persistence
Add new Room database persistence to Trail-Sense Android app. Use when the user asks to create, add, or implement database persistence for a model, including Entity, DAO, Repository, and AppDatabase migration. Covers entity-to-model mapping, index configuration, and standard CRUD operations.
Install
mkdir -p .claude/skills/trail-sense-database-persistence && curl -L -o skill.zip "https://mcp.directory/api/skills/download/4634" && unzip -o skill.zip -d .claude/skills/trail-sense-database-persistence && rm skill.zipInstalls to .claude/skills/trail-sense-database-persistence
About this skill
Trail-Sense Database Persistence
Add Room database persistence for a domain model following Trail-Sense patterns.
File Locations
app/src/main/java/com/kylecorry/trail_sense/tools/{toolName}/
├── domain/
│ └── {Model}.kt # Domain model (if not already exists)
└── infrastructure/persistence/
├── {Model}Entity.kt # Room entity
├── {Model}Dao.kt # DAO interface
└── {Model}Repo.kt # Repository
Also update:
app/src/main/java/com/kylecorry/trail_sense/main/persistence/AppDatabase.ktapp/src/main/java/com/kylecorry/trail_sense/main/persistence/Converters.kt(if new types needed){ToolName}ToolRegistration.kt- register repo singleton
Workflow
- Create Entity with mapping functions
- Create DAO interface
- Add DAO to AppDatabase and create migration
- Create Repository
- Register repo singleton in ToolRegistration
1. Entity
package com.kylecorry.trail_sense.tools.{toolname}.infrastructure.persistence
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import com.kylecorry.trail_sense.tools.{toolname}.domain.{Model}
@Entity(
tableName = "{table_name}", // plural, lowercase, snake_case
indices = [
// Add indices for foreign keys and frequently queried columns
// Index(value = ["parent_id"]),
// Index(value = ["time"])
]
)
data class {Model}Entity(
@ColumnInfo(name = "column_name") val property: Type,
// ... other properties
) {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id")
var id: Long = 0
fun to{Model}(): {Model} {
return {Model}(
id = id,
// Map entity properties to domain model
)
}
companion object {
fun from(model: {Model}): {Model}Entity {
return {Model}Entity(
// Map domain model properties to entity
).also {
it.id = model.id
}
}
}
}
Index Guidelines
Add indices for:
- Foreign key columns (e.g.,
parent_id,group_id) - Time-based columns if queried by time range
- Columns used in WHERE clauses frequently
- Composite indices for multi-column filters:
Index(value = ["col1", "col2"])
Type Mapping
Instant-> stored asLong(epoch millis), converter existsDuration-> stored asLong(millis), converter existsCoordinate-> split intolatitude: Double,longitude: DoubleDistance-> store asFloatin meters- Enums with
idproperty -> use existing converters or add toConverters.kt AppColor-> converter exists- Lists/collections -> join to comma-separated string, parse in mapping
2. DAO
package com.kylecorry.trail_sense.tools.{toolname}.infrastructure.persistence
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Query
import androidx.room.Upsert
import kotlinx.coroutines.flow.Flow
@Dao
interface {Model}Dao {
@Query("SELECT * FROM {table_name}")
fun getAll(): Flow<List<{Model}Entity>>
@Query("SELECT * FROM {table_name}")
suspend fun getAllSync(): List<{Model}Entity>
@Query("SELECT * FROM {table_name} WHERE _id = :id LIMIT 1")
suspend fun get(id: Long): {Model}Entity?
@Upsert
suspend fun upsert(entity: {Model}Entity): Long
@Delete
suspend fun delete(entity: {Model}Entity)
}
Optional DAO Methods
// Filter by parent/group
@Query("SELECT * FROM {table_name} WHERE parent_id IS :parentId")
suspend fun getAllInGroup(parentId: Long?): List<{Model}Entity>
// Time-based cleanup
@Query("DELETE FROM {table_name} WHERE time < :minEpochMillis")
suspend fun deleteOlderThan(minEpochMillis: Long)
// Get latest
@Query("SELECT * FROM {table_name} ORDER BY _id DESC LIMIT 1")
suspend fun getLast(): {Model}Entity?
3. AppDatabase Updates
Add Entity to Database
In AppDatabase.kt, add entity to @Database annotation:
@Database(
entities = [..., {Model}Entity::class],
version = {NEXT_VERSION}, // Increment from current
exportSchema = false
)
Add DAO Accessor
abstract fun {model}Dao(): {Model}Dao
Add Migration
Inside buildDatabase(), add migration before the return Room.databaseBuilder:
val MIGRATION_{PREV}_{NEXT} = object : Migration({PREV}, {NEXT}) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("""
CREATE TABLE IF NOT EXISTS `{table_name}` (
`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`column_name` TEXT NOT NULL,
`nullable_column` TEXT DEFAULT NULL
-- Match column types: TEXT, INTEGER, REAL
-- NOT NULL for non-nullable, DEFAULT NULL for nullable
)
""".trimIndent())
// Add indices if defined in entity
// db.execSQL("CREATE INDEX IF NOT EXISTS index_{table_name}_{column} ON {table_name}({column})")
}
}
Register Migration
Add to .addMigrations():
.addMigrations(
...,
MIGRATION_{PREV}_{NEXT}
)
4. Repository
package com.kylecorry.trail_sense.tools.{toolname}.infrastructure.persistence
import android.annotation.SuppressLint
import android.content.Context
import com.kylecorry.luna.coroutines.onIO
import com.kylecorry.trail_sense.main.persistence.AppDatabase
import com.kylecorry.trail_sense.tools.{toolname}.domain.{Model}
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
class {Model}Repo private constructor(context: Context) {
private val dao = AppDatabase.getInstance(context).{model}Dao()
fun getAll(): Flow<List<{Model}>> = dao.getAll()
.map { it.map { entity -> entity.to{Model}() } }
.flowOn(Dispatchers.IO)
suspend fun getAllSync(): List<{Model}> = onIO {
dao.getAllSync().map { it.to{Model}() }
}
suspend fun get(id: Long): {Model}? = onIO {
dao.get(id)?.to{Model}()
}
suspend fun add(model: {Model}): Long = onIO {
dao.upsert({Model}Entity.from(model))
}
suspend fun delete(model: {Model}) = onIO {
dao.delete({Model}Entity.from(model))
}
companion object {
@SuppressLint("StaticFieldLeak")
private var instance: {Model}Repo? = null
@Synchronized
fun getInstance(context: Context): {Model}Repo {
if (instance == null) {
instance = {Model}Repo(context.applicationContext)
}
return instance!!
}
}
}
5. Register Singleton in ToolRegistration
In {ToolName}ToolRegistration.kt, add the repo to singletons:
object {ToolName}ToolRegistration : ToolRegistration {
override fun getTool(context: Context): Tool {
return Tool(
// ... other properties
singletons = listOf(
{Model}Repo::getInstance
),
// ...
)
}
}
SQL Type Reference
| Kotlin Type | SQLite Type | Notes |
|---|---|---|
Long, Int | INTEGER | |
Double, Float | REAL | |
String | TEXT | |
Boolean | INTEGER | 0/1 |
Instant | INTEGER | epoch millis |
| Enums | INTEGER | via id property |
| Nullable | Add DEFAULT NULL |
More by kylecorry31
View all skills by kylecorry31 →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversBuild persistent semantic networks for enterprise & engineering data management. Enable data persistence and memory acro
MCP Toolbox for Databases by Google. An open-source server that lets AI agents query Cloud SQL, Spanner, AlloyDB, and ot
Claude Context offers semantic code search and indexing with vector embeddings and AST-based code splitting. Natural lan
Mobile Next offers fast, seamless mobile automation for iOS and Android. Automate apps, extract data, and simplify mobil
Cipher empowers agents with persistent memory using vector databases and embeddings for seamless context retention and t
Connect Supabase projects to AI with Supabase MCP Server. Standardize LLM communication for secure, efficient developmen
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.