Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

DBFlow is an annotation-processing ORM for Android/SQLite. All SQL boilerplate is generated at compile-time by `dbflow-processor`; the runtime has near-zero reflection overhead. Models can be plain POJOs or extend `BaseModel`, and multiple SQLite databases per app are supported natively.

## Module Organization

| Module | Type | Purpose |
|--------|------|---------|
| `dbflow-core` | Java library | Core annotations (`@Database`, `@Table`, `@Column`, `@ForeignKey`, etc.) and interfaces |
| `dbflow` | Android library | Runtime: `FlowManager`, query DSL, model adapters, transactions |
| `dbflow-processor` | Java library | Annotation processor (`DBFlowProcessor.kt`) and all code generation |
| `dbflow-sqlcipher` | Android library | SQLCipher encryption support |
| `dbflow-kotlinextensions` | Android library | Kotlin DSL and extension functions |
| `dbflow-rx` / `dbflow-rx2` | Android library | RXJava 1 & 2 integration |
| `dbflow-rx-kotlinextensions` / `dbflow-rx2-kotlinextensions` | Android library | Kotlin extensions for RX modules |
| `dbflow-tests` | Android app | All tests (unit via Robolectric + instrumented) |

**SDK/tool versions** (gradle.properties): minSdk 21, targetSdk 34, Kotlin 1.9.24, AGP 8.2.2, Java 8.

## Architecture

### Annotation Processing Pipeline

`DBFlowProcessor` (extends `AbstractProcessor`) runs during `compileKotlin`/`compileJava`. For each annotated class it generates:

- `${Model}_Table` — static column name constants
- `${Model}_Adapter` — handles cursor loading, insert, update, delete, caching
- `${Database}_HolderImpl` — registry of all tables for a given `@Database`

Generated sources land in `build/generated/ap_generated_sources/`. Any annotation error fails the build entirely.

### FlowManager — Central Registry

`FlowManager` is the single entry point at runtime. It loads the generated `GeneratedDatabaseHolder` via a single reflection call during `FlowManager.init(FlowConfig)`. After that, all operations go through type-safe generated adapters — no further reflection. Required initialization:

```kotlin
FlowManager.init(FlowConfig.Builder(context).build())
```

### Query DSL

Queries are built lazily and executed only when `.query()`, `.querySingle()`, or similar terminal methods are called:

```kotlin
select(User_Table.name, User_Table.email)
.from(User::class.java)
.where(User_Table.id.eq(42))
.querySingle()
```

Models serve double duty as table references. Column constants come from the generated `${Model}_Table` class.

### Multiple Databases

Each `@Database`-annotated class is a separate SQLite file. Models declare their database via `@Table(database = MyDatabase::class)`. Migrations are scoped per database version.

## Build Commands

```bash
# Full build
./gradlew build

# Skip tests
./gradlew build -x test -x connectedAndroidTest

# Single module
./gradlew :dbflow-processor:build

# Clean
./gradlew clean build
```

## Test Commands

All tests live in `:dbflow-tests`. Unit tests use Robolectric (no emulator needed); instrumented tests require a connected device.

```bash
# All unit tests
./gradlew :dbflow-tests:test

# Single test class
./gradlew :dbflow-tests:testDebugUnitTest --tests "*.ConfigIntegrationTest"

# Single test method
./gradlew :dbflow-tests:testDebugUnitTest --tests "*.ConfigIntegrationTest.testSimpleConfig"

# Instrumented tests (device/emulator required)
./gradlew :dbflow-tests:connectedAndroidTest
```

Custom test rules: `DBFlowTestRule` (unit), `DBFlowInstrumentedTestRule` (instrumented). Base class `BaseUnitTest` sets up a test database and context.

## Lint

```bash
./gradlew lint # All modules (abortOnError = false)
./gradlew :dbflow:lint # Single module
```

## KSP Migration (current branch: `ksp-support`)

KSP migration is complete. `dbflow-tests/build.gradle` has KSP enabled and KAPT disabled. `DBFlowSymbolProcessor` implements `SymbolProcessor` and handles all annotation types. All 164 unit tests pass.

**Key KSP implementation notes:**
- `DBFlowSymbolProcessor` runs two rounds: round 1 processes all annotations and writes non-holder files; if `@ManyToMany` join tables were generated, round 2 picks them up and writes the database registry + holder.
- Database registry files (`${Database}_Database.java`) are written **after** all table adapters so that `hasGlobalTypeConverters` is accurate (it's populated during `checkNeedsReferences()` in `onWriteDefinition`).
- KSP type mapping lives in `KspExtensions.kt` — Kotlin primitives, arrays (`ByteArray` → `byte[]`), and class types all have explicit mappings.
- `@MultiCacheField`/`@ModelCacheField` fields live in companion objects; the KSP path scans companion object declarations explicitly.
- `@OneToMany` methods are scanned in `createColumnDefinitionsFromKsp` via `KSFunctionDeclaration`; `OneToManyDefinition.kspInit()` initializes from KSP data.
- Java-origin fields (e.g. generated join table classes) use `VisibleScopeColumnAccessor` directly; Kotlin-origin fields without `@JvmField` use `PrivateScopeColumnAccessor` with getter/setter generation.

## Key Files for Architecture

- `dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java` — central registry
- `dbflow/src/main/java/com/raizlabs/android/dbflow/structure/BaseModel.java` — base model implementation
- `dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/DBFlowProcessor.kt` — main annotation processor entry point
- `dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/` — all annotations
55 changes: 17 additions & 38 deletions android-artifacts.gradle
Original file line number Diff line number Diff line change
@@ -1,43 +1,22 @@
apply plugin: 'com.github.dcendents.android-maven'
install {
repositories.mavenInstaller {
pom {
project {
packaging bt_packaging
name bt_name
url bt_siteUrl
licenses {
license {
name bt_licenseName
url bt_licenseUrl
}
}
scm {
connection bt_gitUrl
developerConnection bt_gitUrl
url bt_siteUrl
}
}
apply plugin: 'maven-publish'

android {
publishing {
singleVariant('release') {
withSourcesJar()
}
}
}

task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}

task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
from components.release
groupId = project.group
artifactId = project.name
version = rootProject.version
}
}
}
}

artifacts {
//archives javadocJar
archives sourcesJar
}
11 changes: 5 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
buildscript {
ext.kotlin_version = '1.1.51'
ext.kotlin_version = '1.9.24'
repositories {
jcenter()
mavenCentral()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.3'
classpath 'com.android.tools.build:gradle:8.2.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:${kotlin_version}-1.0.20"
}
}

allprojects {
repositories {
jcenter()
mavenCentral()
google()
maven { url "https://www.jitpack.io" }
}
Expand Down
4 changes: 2 additions & 2 deletions dbflow-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apply plugin: 'java'

project.ext.artifactId = bt_name

targetCompatibility = JavaVersion.VERSION_1_7
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8

apply from: '../java-artifacts.gradle'
20 changes: 9 additions & 11 deletions dbflow-kotlinextensions/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,32 @@ apply plugin: 'kotlin-android'

project.ext.artifactId = bt_name


android {
compileSdkVersion Integer.valueOf(dbflow_target_sdk)
buildToolsVersion dbflow_build_tools_version
namespace "com.raizlabs.android.dbflow.kotlinextensions"

defaultConfig {
minSdkVersion dbflow_min_sdk
targetSdkVersion Integer.valueOf(dbflow_target_sdk)
}
buildTypes {
debug {
minifyEnabled false
}
release {
minifyEnabled false
}
debug { minifyEnabled false }
release { minifyEnabled false }
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions { jvmTarget = '1.8' }
}

dependencies {
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
api project("${dbflow_project_prefix}dbflow-core")
api project("${dbflow_project_prefix}dbflow")
}

apply from: '../kotlin-artifacts.gradle'


2 changes: 1 addition & 1 deletion dbflow-kotlinextensions/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<manifest package="com.raizlabs.android.dbflow.kotlinextensions">
<manifest>

<application/>

Expand Down
16 changes: 11 additions & 5 deletions dbflow-processor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ project.ext.artifactId = bt_name
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8

compileKotlin { kotlinOptions.jvmTarget = "1.8" }
compileTestKotlin { kotlinOptions.jvmTarget = "1.8" }

dependencies {
compile project("${dbflow_project_prefix}dbflow-core")
compile 'com.squareup:javapoet:1.9.0'
compile 'com.github.agrosner:KPoet:1.0.0'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
implementation project("${dbflow_project_prefix}dbflow-core")
implementation 'com.squareup:javapoet:1.13.0'
implementation 'com.github.agrosner:KPoet:1.0.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

// KAPT (current)
compileOnly 'org.glassfish:javax.annotation:10.0-b28'

testImplementation 'junit:junit:4.12'
// KSP API — needed to implement a KSP SymbolProcessor
compileOnly "com.google.devtools.ksp:symbol-processing-api:${kotlin_version}-1.0.20"

testImplementation 'junit:junit:4.13.2'
}

apply from: '../java-artifacts.gradle'
Loading