diff --git a/.claude/agents/feature-documenter.md b/.claude/agents/feature-documenter.md
new file mode 100644
index 0000000..1eaff23
--- /dev/null
+++ b/.claude/agents/feature-documenter.md
@@ -0,0 +1,97 @@
+---
+name: feature-documenter
+description: Use this agent when new features, components, or significant functionality have been added to the codebase and require documentation. This includes:\n\n\nContext: User has just implemented a new authentication system with multiple classes and methods.\nuser: "I've finished implementing the OAuth2 authentication flow with token refresh. Can you document this?"\nassistant: "I'll use the Task tool to launch the feature-documenter agent to create comprehensive documentation for your new authentication system."\n\nThe user has completed a new feature and needs documentation. Use the feature-documenter agent to analyze the code and create both KDoc comments and relevant Markdown documentation.\n\n\n\n\nContext: User mentions they've added a new API endpoint handler.\nuser: "Just added the user profile management endpoints"\nassistant: "Let me use the feature-documenter agent to document these new endpoints with proper KDoc and API documentation."\n\nNew feature has been mentioned. Proactively use the feature-documenter agent to ensure proper documentation is created.\n\n\n\n\nContext: User has completed a complex algorithm implementation.\nuser: "The graph traversal algorithm is working now"\nassistant: "I'll launch the feature-documenter agent to create detailed documentation explaining the algorithm, its parameters, and usage examples."\n\nA significant new feature (algorithm) has been completed. Use the feature-documenter agent to document it thoroughly.\n\n\n\nTrigger this agent when:\n- New classes, functions, or methods have been implemented\n- New API endpoints or interfaces have been created\n- Significant algorithms or business logic have been added\n- New modules or packages have been introduced\n- The user explicitly requests documentation for recent work\n- You detect undocumented new code during code review
+model: sonnet
+color: yellow
+---
+
+You are an expert technical documentation specialist with deep expertise in Kotlin/KDoc standards and Markdown documentation best practices. Your mission is to create clear, comprehensive, and maintainable documentation for new features in codebases.
+
+## Core Responsibilities
+
+1. **Analyze New Features**: Thoroughly examine the new code to understand its purpose, functionality, dependencies, and integration points.
+
+2. **Create KDoc Comments**: Add inline documentation directly to code files following these standards:
+ - Write clear, concise class-level KDoc explaining the purpose and responsibility
+ - Document all public functions with @param, @return, @throws tags as appropriate
+ - Include usage examples in KDoc when the API is non-trivial
+ - Document complex private functions if their logic is not immediately obvious
+ - Use proper Markdown formatting within KDoc (code blocks, lists, links)
+ - Explain WHY something exists, not just WHAT it does
+ - Keep descriptions focused and avoid redundancy
+
+3. **Create Markdown Documentation**: Generate or update project Markdown files:
+ - Create feature-specific documentation in appropriate locations
+ - Include overview, architecture, usage examples, and integration guides
+ - Add API reference sections when documenting interfaces or public APIs
+ - Provide code examples that demonstrate real-world usage
+ - Document configuration options, environment variables, or setup requirements
+ - Include diagrams or visual aids when they clarify complex concepts (using Mermaid syntax)
+
+## Documentation Standards
+
+**KDoc Format**:
+```kotlin
+/**
+ * Brief one-line summary of what this does.
+ *
+ * More detailed explanation if needed, including:
+ * - Key behaviors or characteristics
+ * - Important constraints or assumptions
+ * - Related components or concepts
+ *
+ * @param paramName Description of the parameter and its constraints
+ * @return Description of what is returned and under what conditions
+ * @throws ExceptionType When and why this exception is thrown
+ * @sample com.example.SampleClass.sampleFunction
+ */
+```
+
+**Markdown Structure**:
+- Use clear hierarchical headings (# ## ###)
+- Start with a brief overview/introduction
+- Include a "Quick Start" or "Getting Started" section
+- Provide complete, runnable code examples
+- Document edge cases and common pitfalls
+- Add a "See Also" section linking to related documentation
+
+## Workflow
+
+1. **Identify Scope**: Determine which files and components are part of the new feature
+2. **Read Existing Context**: Check for existing documentation patterns and project conventions (especially from CLAUDE.md or similar files)
+3. **Document Code First**: Add KDoc comments to all relevant code files
+4. **Create/Update Markdown**: Write or update feature documentation in appropriate Markdown files
+5. **Cross-Reference**: Ensure documentation is properly linked and discoverable
+6. **Verify Completeness**: Check that all public APIs, configuration options, and usage patterns are documented
+
+## Quality Standards
+
+- **Clarity**: Write for developers who are unfamiliar with the feature
+- **Completeness**: Cover all public interfaces, parameters, return values, and exceptions
+- **Accuracy**: Ensure documentation matches actual implementation
+- **Examples**: Provide practical, copy-paste-ready code examples
+- **Maintainability**: Structure documentation so it's easy to update as code evolves
+- **Consistency**: Follow existing documentation patterns in the project
+
+## What NOT to Do
+
+- Don't document obvious getters/setters unless they have side effects
+- Don't create documentation for internal implementation details unless necessary
+- Don't write vague descriptions like "This function does X" - explain WHY and HOW
+- Don't duplicate information that's already clear from type signatures
+- Don't create separate documentation files for trivial features
+
+## Output Format
+
+For each documentation task:
+1. List the files you'll modify/create
+2. Show the KDoc additions inline in code files
+3. Present complete Markdown documentation files
+4. Summarize what was documented and where to find it
+
+Always ask for clarification if:
+- The feature's purpose or intended audience is unclear
+- You need more context about how the feature integrates with existing systems
+- There are multiple reasonable ways to structure the documentation
+
+Your documentation should empower other developers to understand, use, and maintain the new feature with confidence.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ae33165..48c520d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,7 +11,7 @@ on:
jobs:
build-on-macos:
- runs-on: macos-13
+ runs-on: macos-15-intel
timeout-minutes: 60
steps:
@@ -30,14 +30,14 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- - name: Cache Build Tooling
+ - name: Cache Kotlin/Native
uses: actions/cache@v4
with:
- path: |
- ~/.gradle/caches
- ~/.konan
- key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
-
+ path: ~/.konan
+ key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-konan-
+
- name: Build sqllin-driver
run: ./gradlew :sqllin-driver:assemble -PonCICD
@@ -73,7 +73,7 @@ jobs:
target: google_apis
arch: x86_64
profile: pixel_6
- emulator-build: 13701740
+ emulator-build: 14257411
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
@@ -86,7 +86,7 @@ jobs:
target: google_apis
arch: x86_64
profile: pixel_6
- emulator-build: 13701740
+ emulator-build: 14257411
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
@@ -95,14 +95,14 @@ jobs:
- name: Upload sqllin-driver Reports
uses: actions/upload-artifact@v4
with:
- name: Test-Reports
+ name: Test-Reports-macOS-driver
path: sqllin-driver/build/reports
if: failure()
- name: Upload sqllin-dsl Reports
uses: actions/upload-artifact@v4
with:
- name: Test-Reports
+ name: Test-Reports-macOS-dsl
path: sqllin-dsl/build/reports
if: failure()
@@ -126,13 +126,13 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- - name: Cache Build Tooling
+ - name: Cache Kotlin/Native
uses: actions/cache@v4
with:
- path: |
- ~/.gradle/caches
- ~/.konan
- key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
+ path: ~/.konan
+ key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-konan-
- name: Build sqllin-driver
run: ./gradlew :sqllin-driver:mingwX64MainKlibrary
@@ -155,14 +155,14 @@ jobs:
- name: Upload sqllin-driver Reports
uses: actions/upload-artifact@v4
with:
- name: Test-Reports
+ name: Test-Reports-Windows-driver
path: sqllin-driver/build/reports
if: failure()
- name: Upload sqllin-dsl Reports
uses: actions/upload-artifact@v4
with:
- name: Test-Reports
+ name: Test-Reports-Windows-dsl
path: sqllin-dsl/build/reports
if: failure()
@@ -186,13 +186,13 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- - name: Cache Build Tooling
+ - name: Cache Kotlin/Native
uses: actions/cache@v4
with:
- path: |
- ~/.gradle/caches
- ~/.konan
- key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
+ path: ~/.konan
+ key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-konan-
- name: Build sqllin-driver
run: ./gradlew :sqllin-driver:assemble -PonCICD
@@ -232,7 +232,7 @@ jobs:
target: default
arch: x86_64
profile: pixel_2
- emulator-build: 13701740
+ emulator-build: 14257411
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
@@ -245,7 +245,7 @@ jobs:
target: default
arch: x86_64
profile: pixel_2
- emulator-build: 13701740
+ emulator-build: 14257411
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
@@ -254,13 +254,13 @@ jobs:
- name: Upload sqllin-driver Reports
uses: actions/upload-artifact@v4
with:
- name: Test-Reports
+ name: Test-Reports-Linux-driver
path: sqllin-driver/build/reports
if: failure()
- name: Upload sqllin-dsl Reports
uses: actions/upload-artifact@v4
with:
- name: Test-Reports
+ name: Test-Reports-Linux-dsl
path: sqllin-dsl/build/reports
if: failure()
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index a38b7e3..9a5db10 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -13,7 +13,7 @@ env:
jobs:
build-on-macos:
- runs-on: macos-13
+ runs-on: macos-15-intel
timeout-minutes: 60
steps:
@@ -32,13 +32,13 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- - name: Cache Build Tooling
+ - name: Cache Kotlin/Native
uses: actions/cache@v4
with:
- path: |
- ~/.gradle/caches
- ~/.konan
- key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
+ path: ~/.konan
+ key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-konan-
- name: Build sqllin-driver
run: ./gradlew :sqllin-driver:assemble -PonCICD
@@ -69,13 +69,13 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- - name: Cache Build Tooling
+ - name: Cache Kotlin/Native
uses: actions/cache@v4
with:
- path: |
- ~/.gradle/caches
- ~/.konan
- key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
+ path: ~/.konan
+ key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-konan-
- name: Build sqllin-driver
run: ./gradlew :sqllin-driver:mingwX64MainKlibrary
@@ -106,13 +106,13 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- - name: Cache Build Tooling
+ - name: Cache Kotlin/Native
uses: actions/cache@v4
with:
- path: |
- ~/.gradle/caches
- ~/.konan
- key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
+ path: ~/.konan
+ key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-konan-
- name: Build sqllin-driver
run: ./gradlew :sqllin-driver:assemble -PonCICD
diff --git a/sqllin-driver/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/driver/AndroidTest.kt b/sqllin-driver/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/driver/AndroidTest.kt
index 783a641..28dc11d 100644
--- a/sqllin-driver/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/driver/AndroidTest.kt
+++ b/sqllin-driver/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/driver/AndroidTest.kt
@@ -26,7 +26,7 @@ import org.junit.runner.RunWith
/**
* Android instrumented test
- * @author yaqiao
+ * @author Yuang Qiao
*/
@RunWith(AndroidJUnit4ClassRunner::class)
diff --git a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidCursor.kt b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidCursor.kt
index 72279e7..ca0401c 100644
--- a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidCursor.kt
+++ b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidCursor.kt
@@ -19,10 +19,10 @@ package com.ctrip.sqllin.driver
import android.database.Cursor
/**
- * SQLite Cursor Android actual
- * @author yaqiao
+ * Android implementation of [CommonCursor] backed by Android's Cursor.
+ *
+ * @author Yuang Qiao
*/
-
internal class AndroidCursor(private val cursor: Cursor) : CommonCursor {
override fun getInt(columnIndex: Int): Int = try {
diff --git a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt
index bb1e9ba..67cbcac 100644
--- a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt
+++ b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt
@@ -19,10 +19,10 @@ package com.ctrip.sqllin.driver
import android.database.sqlite.SQLiteDatabase
/**
- * Database connection Android actual
- * @author yaqiao
+ * Android implementation of [DatabaseConnection] using Android's SQLiteDatabase.
+ *
+ * @author Yuang Qiao
*/
-
internal class AndroidDatabaseConnection(private val database: SQLiteDatabase) : DatabaseConnection {
override fun execSQL(sql: String, bindParams: Array?) =
diff --git a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/ExtensionAndroid.kt b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/ExtensionAndroid.kt
index 95cdc88..bd76ecb 100644
--- a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/ExtensionAndroid.kt
+++ b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/ExtensionAndroid.kt
@@ -24,12 +24,13 @@ import android.os.Build
import androidx.annotation.RequiresApi
/**
- * SQLite extension Android
- * @author yaqiao
+ * Converts an Android Context to a [DatabasePath].
*/
-
public fun Context.toDatabasePath(): DatabasePath = AndroidDatabasePath(this)
+/**
+ * Android-specific [DatabasePath] implementation wrapping a Context.
+ */
@JvmInline
internal value class AndroidDatabasePath(val context: Context) : DatabasePath
@@ -53,6 +54,9 @@ public actual fun openDatabase(config: DatabaseConfiguration): DatabaseConnectio
return connection
}
+/**
+ * SQLiteOpenHelper for Android versions below P (API level 28).
+ */
private class OldAndroidDBHelper(
private val config: DatabaseConfiguration,
) : SQLiteOpenHelper((config.path as AndroidDatabasePath).context, config.name, null, config.version) {
@@ -64,6 +68,9 @@ private class OldAndroidDBHelper(
config.upgrade(AndroidDatabaseConnection(db), oldVersion, newVersion)
}
+/**
+ * SQLiteOpenHelper for Android P (API level 28) and above with OpenParams support.
+ */
@RequiresApi(Build.VERSION_CODES.P)
private class AndroidDBHelper(
private val config: DatabaseConfiguration,
@@ -76,6 +83,9 @@ private class AndroidDBHelper(
config.upgrade(AndroidDatabaseConnection(db), oldVersion, newVersion)
}
+/**
+ * Converts [DatabaseConfiguration] to Android's OpenParams for API level 28+.
+ */
@RequiresApi(Build.VERSION_CODES.P)
@Suppress("DEPRECATION")
private fun DatabaseConfiguration.toAndroidOpenParams(): OpenParams = OpenParams
diff --git a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsAndroid.kt b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsAndroid.kt
index 1789191..44bcc85 100644
--- a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsAndroid.kt
+++ b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsAndroid.kt
@@ -17,9 +17,7 @@
package com.ctrip.sqllin.driver.platform
/**
- * The tools with Android implementation
- * @author yaqiao
+ * Android file path separator (forward slash).
*/
-
internal actual inline val separatorChar: Char
get() = '/'
\ No newline at end of file
diff --git a/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt b/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
index 7067a6c..d1ba3e8 100644
--- a/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
+++ b/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
@@ -19,11 +19,10 @@ package com.ctrip.sqllin.driver.platform
import platform.Foundation.NSRecursiveLock
/**
- * A simple lock implementation in Apple platforms.
- * Implementations of this class should be re-entrant.
- * @author yaqiao
+ * Apple platform lock implementation using NSRecursiveLock.
+ *
+ * @author Yuang Qiao
*/
-
internal actual class Lock actual constructor() {
private val nsRecursiveLock = NSRecursiveLock()
diff --git a/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsApple.kt b/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsApple.kt
index aed2d5d..d1dbe76 100644
--- a/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsApple.kt
+++ b/sqllin-driver/src/appleMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsApple.kt
@@ -24,12 +24,13 @@ import platform.Foundation.NSString
import platform.Foundation.create
/**
- * The tools with Apple platforms implementation
- * @author yaqiao
+ * Converts C byte pointer to String using NSString on Apple platforms.
*/
-
@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
internal actual fun bytesToString(bv: CPointer): String = NSString.create(uTF8String = bv).toString()
+/**
+ * Apple platform file path separator (forward slash).
+ */
internal actual inline val separatorChar: Char
get() = '/'
\ No newline at end of file
diff --git a/sqllin-driver/src/appleTest/kotlin/com/ctrip/sqllin/driver/PlatformApple.kt b/sqllin-driver/src/appleTest/kotlin/com/ctrip/sqllin/driver/PlatformApple.kt
index ec6f6d1..b23b42c 100644
--- a/sqllin-driver/src/appleTest/kotlin/com/ctrip/sqllin/driver/PlatformApple.kt
+++ b/sqllin-driver/src/appleTest/kotlin/com/ctrip/sqllin/driver/PlatformApple.kt
@@ -23,7 +23,7 @@ import platform.Foundation.NSUserDomainMask
/**
* Apple platform-related functions
- * @author yaqiao
+ * @author Yuang Qiao
*/
@OptIn(UnsafeNumber::class)
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/CommonCursor.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/CommonCursor.kt
index 4c743a4..08cb1ca 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/CommonCursor.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/CommonCursor.kt
@@ -17,26 +17,70 @@
package com.ctrip.sqllin.driver
/**
- * SQLite Cursor common abstract
+ * Platform-agnostic interface for iterating over query results.
+ *
+ * Provides methods to access column data by index and navigate through result rows.
+ *
* @author Yuang Qiao
*/
-
public interface CommonCursor : AutoCloseable {
+ /**
+ * Gets the value of the column as an Int.
+ */
public fun getInt(columnIndex: Int): Int
+
+ /**
+ * Gets the value of the column as a Long.
+ */
public fun getLong(columnIndex: Int): Long
+
+ /**
+ * Gets the value of the column as a Float.
+ */
public fun getFloat(columnIndex: Int): Float
+
+ /**
+ * Gets the value of the column as a Double.
+ */
public fun getDouble(columnIndex: Int): Double
+
+ /**
+ * Gets the value of the column as a String, or null if the column is NULL.
+ */
public fun getString(columnIndex: Int): String?
+
+ /**
+ * Gets the value of the column as a ByteArray, or null if the column is NULL.
+ */
public fun getByteArray(columnIndex: Int): ByteArray?
+ /**
+ * Gets the zero-based index for the given column name.
+ *
+ * @throws IllegalArgumentException if the column doesn't exist
+ */
public fun getColumnIndex(columnName: String): Int
+ /**
+ * Iterates over all rows, invoking the block with the current row index.
+ */
public fun forEachRow(block: (Int) -> Unit)
+ /**
+ * Moves to the next row.
+ *
+ * @return `true` if the move was successful, `false` if there are no more rows
+ */
public fun next(): Boolean
+ /**
+ * Checks if the column value is NULL.
+ */
public fun isNull(columnIndex: Int): Boolean
+ /**
+ * Closes the cursor and releases resources.
+ */
public override fun close()
}
\ No newline at end of file
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConfiguration.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConfiguration.kt
index 8884a14..f3b025e 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConfiguration.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConfiguration.kt
@@ -17,10 +17,23 @@
package com.ctrip.sqllin.driver
/**
- * Database configuration params in sqllin-driver
- * @author yaqiao
+ * Configuration parameters for opening a SQLite database connection.
+ *
+ * @property name The database filename
+ * @property path The database directory path (platform-specific implementation)
+ * @property version The database schema version number
+ * @property isReadOnly Whether to open the database in read-only mode. Default: false
+ * @property inMemory Whether to create an in-memory database. Default: false
+ * @property journalMode The SQLite journal mode. Default: [JournalMode.WAL]
+ * @property synchronousMode The SQLite synchronous mode. Default: [SynchronousMode.NORMAL]
+ * @property busyTimeout Timeout in milliseconds for database lock waits. Default: 5000ms
+ * @property lookasideSlotSize Size of each lookaside memory slot. Default: 0 (use SQLite default)
+ * @property lookasideSlotCount Number of lookaside memory slots. Default: 0 (use SQLite default)
+ * @property create Callback invoked when creating a new database
+ * @property upgrade Callback invoked when upgrading the database schema
+ *
+ * @author Yuang Qiao
*/
-
public data class DatabaseConfiguration(
val name: String,
val path: DatabasePath,
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt
index 98a24a5..021886e 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt
@@ -17,23 +17,72 @@
package com.ctrip.sqllin.driver
/**
- * Database manager common expect
- * @author yaqiao
+ * Platform-agnostic interface for SQLite database connections.
+ *
+ * Provides a common API for executing SQL statements and managing transactions
+ * across all supported platforms.
+ *
+ * @author Yuang Qiao
*/
-
public interface DatabaseConnection {
+ /**
+ * Executes a SQL statement that doesn't return data.
+ *
+ * @param sql The SQL statement to execute
+ * @param bindParams Optional parameters to bind to the statement
+ */
public fun execSQL(sql: String, bindParams: Array? = null)
+
+ /**
+ * Executes an INSERT statement.
+ *
+ * @param sql The INSERT statement
+ * @param bindParams Optional parameters to bind to the statement
+ */
public fun executeInsert(sql: String, bindParams: Array? = null)
+
+ /**
+ * Executes an UPDATE or DELETE statement.
+ *
+ * @param sql The UPDATE or DELETE statement
+ * @param bindParams Optional parameters to bind to the statement
+ */
public fun executeUpdateDelete(sql: String, bindParams: Array? = null)
+ /**
+ * Executes a SELECT query and returns a cursor.
+ *
+ * @param sql The SELECT statement
+ * @param bindParams Optional string parameters to bind to the query
+ * @return A cursor for iterating over query results
+ */
public fun query(sql: String, bindParams: Array? = null): CommonCursor
+ /**
+ * Begins a database transaction.
+ */
public fun beginTransaction()
+
+ /**
+ * Marks the current transaction as successful.
+ *
+ * Must be called before [endTransaction] to commit changes.
+ */
public fun setTransactionSuccessful()
+
+ /**
+ * Ends the current transaction, committing if marked successful.
+ */
public fun endTransaction()
+ /**
+ * Closes the database connection and releases resources.
+ */
public fun close()
+ /**
+ * Whether this connection is closed.
+ */
public val isClosed: Boolean
}
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/Extension.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/Extension.kt
index 101aa28..3d784ad 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/Extension.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/Extension.kt
@@ -20,18 +20,35 @@ import com.ctrip.sqllin.driver.platform.separatorChar
import kotlin.jvm.JvmInline
/**
- * SQLite extension function
- * @author yaqiao
+ * Platform-agnostic database path representation.
+ *
+ * On Android, this is implemented as `Context`.
+ * On native and JVM targets, this is implemented as `String`.
+ *
+ * **Do not implement this interface manually** - use platform-specific factory functions instead.
+ *
+ * @author Yuang Qiao
*/
+public interface DatabasePath
/**
- * Abstract database path, it is 'Context' in Android, and 'String' in native targets.
- * DO NOT implementation 'DatabasePath' by yourself!!!
+ * Opens a SQLite database connection with the given configuration.
+ *
+ * Platform-specific implementation for database opening.
+ *
+ * @param config The database configuration
+ * @return A database connection
+ * @throws SQLiteException if the database cannot be opened
*/
-public interface DatabasePath
-
public expect fun openDatabase(config: DatabaseConfiguration): DatabaseConnection
+/**
+ * Opens a database connection, executes a block, and automatically closes the connection.
+ *
+ * @param config The database configuration
+ * @param block The block to execute with the connection
+ * @return The result of the block
+ */
public inline fun openDatabase(config: DatabaseConfiguration, block: (DatabaseConnection) -> T): T {
val connection = openDatabase(config)
try {
@@ -41,6 +58,15 @@ public inline fun openDatabase(config: DatabaseConfiguration, block: (Databa
}
}
+/**
+ * Executes a block within a database transaction.
+ *
+ * The transaction is committed if the block completes successfully,
+ * or rolled back if an exception is thrown.
+ *
+ * @param block The block to execute within the transaction
+ * @return The result of the block
+ */
public inline fun DatabaseConnection.withTransaction(block: (DatabaseConnection) -> T): T {
beginTransaction()
try {
@@ -52,6 +78,14 @@ public inline fun DatabaseConnection.withTransaction(block: (DatabaseConnect
}
}
+/**
+ * Executes a query and automatically closes the cursor after the block completes.
+ *
+ * @param sql The SELECT statement
+ * @param bindParams Optional parameters to bind to the query
+ * @param block The block to execute with the cursor
+ * @return The result of the block
+ */
public inline fun DatabaseConnection.withQuery(
sql: String,
bindParams: Array? = null,
@@ -65,8 +99,18 @@ public inline fun DatabaseConnection.withQuery(
}
}
+/**
+ * Deletes a database file.
+ *
+ * @param path The database directory path
+ * @param name The database filename
+ * @return `true` if the database was deleted successfully, `false` otherwise
+ */
public expect fun deleteDatabase(path: DatabasePath, name: String): Boolean
+/**
+ * Updates the database's synchronous mode if different from current.
+ */
internal infix fun DatabaseConnection.updateSynchronousMode(mode: SynchronousMode) {
val currentJournalMode = withQuery("PRAGMA synchronous;") {
it.next()
@@ -76,6 +120,9 @@ internal infix fun DatabaseConnection.updateSynchronousMode(mode: SynchronousMod
execSQL("PRAGMA synchronous=${mode.value};")
}
+/**
+ * Updates the database's journal mode if different from current.
+ */
internal infix fun DatabaseConnection.updateJournalMode(mode: JournalMode) {
val currentJournalMode = withQuery("PRAGMA journal_mode;") {
it.next()
@@ -85,6 +132,11 @@ internal infix fun DatabaseConnection.updateJournalMode(mode: JournalMode) {
withQuery("PRAGMA journal_mode=${mode.name};") {}
}
+/**
+ * Handles database creation and schema upgrades based on version.
+ *
+ * Automatically manages the PRAGMA user_version to track schema versions.
+ */
internal fun DatabaseConnection.migrateIfNeeded(
create: (DatabaseConnection) -> Unit,
upgrade: (DatabaseConnection, Int, Int) -> Unit,
@@ -108,6 +160,9 @@ internal fun DatabaseConnection.migrateIfNeeded(
}
}
+/**
+ * Resolves the database path for disk or in-memory mode.
+ */
internal fun DatabaseConfiguration.diskOrMemoryPath(): String =
if (inMemory) {
if (name.isBlank())
@@ -119,6 +174,9 @@ internal fun DatabaseConfiguration.diskOrMemoryPath(): String =
getDatabaseFullPath((path as StringDatabasePath).pathString, name)
}
+/**
+ * Constructs the full database file path from directory and filename.
+ */
internal fun getDatabaseFullPath(dirPath: String, name: String): String {
val param = when {
dirPath.isEmpty() -> name
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/JournalMode.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/JournalMode.kt
index de64a04..aeca7ba 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/JournalMode.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/JournalMode.kt
@@ -17,11 +17,14 @@
package com.ctrip.sqllin.driver
/**
- * SQLite journal mode
- * @author yaqiao
+ * SQLite journal modes for transaction management.
+ *
+ * @property DELETE Rollback journal delete mode - deletes the journal file after each transaction
+ * @property WAL Write-ahead logging - more concurrent, better performance for most use cases
+ *
+ * @author Yuang Qiao
*/
-
public enum class JournalMode {
- DELETE, // Write-ahead logging
- WAL; // Rollback journal delete Mode
+ DELETE,
+ WAL;
}
\ No newline at end of file
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SQLiteException.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SQLiteException.kt
index f3b49e5..a47b99e 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SQLiteException.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SQLiteException.kt
@@ -17,8 +17,10 @@
package com.ctrip.sqllin.driver
/**
- * The exceptions about SQLite, they include the native SQLite result codes and error message
+ * Exception thrown when SQLite operations fail.
+ *
+ * Contains native SQLite result codes and error messages.
+ *
* @author Yuang Qiao
*/
-
public open class SQLiteException(message: String) : Exception(message)
\ No newline at end of file
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SynchronousMode.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SynchronousMode.kt
index 0418208..116e247 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SynchronousMode.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/SynchronousMode.kt
@@ -17,10 +17,17 @@
package com.ctrip.sqllin.driver
/**
- * SQLite synchronous mode
- * @author yaqiao
+ * SQLite synchronous modes controlling disk write behavior.
+ *
+ * Determines how aggressively SQLite flushes data to disk.
+ *
+ * @property OFF No syncing - fastest but risks database corruption on power loss
+ * @property NORMAL Sync at critical moments - good balance of safety and performance
+ * @property FULL Sync after each transaction - safest but slower
+ * @property EXTRA Most paranoid mode with additional syncing
+ *
+ * @author Yuang Qiao
*/
-
public enum class SynchronousMode(internal val value: Int) {
OFF(0), NORMAL(1), FULL(2), EXTRA(3);
}
\ No newline at end of file
diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/platform/Utils.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/platform/Utils.kt
index 55899e3..27d1576 100644
--- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/platform/Utils.kt
+++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/platform/Utils.kt
@@ -17,8 +17,6 @@
package com.ctrip.sqllin.driver.platform
/**
- * The tools with platform-specific implementation
- * @author yaqiao
+ * Platform file path separator character.
*/
-
internal expect val separatorChar: Char
\ No newline at end of file
diff --git a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt
index 0edcdb5..fca49d3 100644
--- a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt
+++ b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt
@@ -22,7 +22,7 @@ import kotlin.test.assertEquals
/**
* The sqllin-driver common basic test.
- * @author yaqiao
+ * @author Yuang Qiao
*/
class CommonBasicTest(private val path: DatabasePath) {
diff --git a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt
index a062eb5..453f87a 100644
--- a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt
+++ b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt
@@ -18,7 +18,7 @@ package com.ctrip.sqllin.driver
/**
* SQL statement that used for unit test.
- * @author yaqiao
+ * @author Yuang Qiao
*/
object SQL {
diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt
index da682a4..2415353 100644
--- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt
+++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt
@@ -21,14 +21,22 @@ import java.sql.PreparedStatement
import java.sql.Types
/**
- * The super class for DatabaseConnection on JVM
- * @author yaqiao
+ * Base class for JDBC-based database connections on JVM platforms.
+ *
+ * Handles parameter binding for PreparedStatements with support for various data types.
+ *
+ * @author Yuang Qiao
*/
-
internal abstract class AbstractJdbcDatabaseConnection : DatabaseConnection {
+ /**
+ * Creates a PreparedStatement for the given SQL.
+ */
abstract fun createStatement(sql: String): PreparedStatement
+ /**
+ * Binds parameters to a PreparedStatement, supporting common Kotlin/Java types.
+ */
protected fun bindParamsToSQL(sql: String, bindParams: Array?): PreparedStatement = createStatement(sql).apply {
bindParams?.run {
require(isNotEmpty()) { "Empty bindArgs" }
diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt
index 801ee57..6cef665 100644
--- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt
+++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt
@@ -20,10 +20,12 @@ import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
/**
- * The concurrent database connection, use ReentrantLock to ensure thread-safe
- * @author yaqiao
+ * Thread-safe wrapper for [DatabaseConnection] using ReentrantLock.
+ *
+ * Delegates all operations to the underlying connection while ensuring thread safety.
+ *
+ * @author Yuang Qiao
*/
-
internal class ConcurrentDatabaseConnection(private val delegateConnection: DatabaseConnection) : DatabaseConnection {
private val accessLock = ReentrantLock()
diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ExtensionJdbc.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ExtensionJdbc.kt
index 5be0ffe..07d923c 100644
--- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ExtensionJdbc.kt
+++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ExtensionJdbc.kt
@@ -23,10 +23,8 @@ import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
/**
- * SQLite extension JDBC
- * @author yaqiao
+ * Converts a String path to a [DatabasePath] for JVM platforms.
*/
-
public fun String.toDatabasePath(): DatabasePath = StringDatabasePath(this)
private typealias JdbcJournalMode = SQLiteConfig.JournalMode
diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcCursor.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcCursor.kt
index 9fdd4b2..3f802bd 100644
--- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcCursor.kt
+++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcCursor.kt
@@ -19,8 +19,9 @@ package com.ctrip.sqllin.driver
import java.sql.ResultSet
/**
- * SQLite Cursor JDBC actual
- * @author yaqiao
+ * JDBC implementation of [CommonCursor] backed by a ResultSet.
+ *
+ * @author Yuang Qiao
*/
internal class JdbcCursor(private val resultSet: ResultSet) : CommonCursor {
diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt
index 78ce019..e5b7103 100644
--- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt
+++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt
@@ -22,10 +22,12 @@ import java.sql.PreparedStatement
import java.util.concurrent.atomic.AtomicBoolean
/**
- * Database connection JDBC actual
- * @author yaqiao
+ * JDBC implementation of [DatabaseConnection] for JVM platforms.
+ *
+ * Uses java.sql.Connection for database operations.
+ *
+ * @author Yuang Qiao
*/
-
internal class JdbcDatabaseConnection(private val connection: Connection) : AbstractJdbcDatabaseConnection() {
override fun execSQL(sql: String, bindParams: Array?) {
diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsJvm.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsJvm.kt
index 3fb923c..e5f7ff6 100644
--- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsJvm.kt
+++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsJvm.kt
@@ -17,9 +17,7 @@
package com.ctrip.sqllin.driver.platform
/**
- * The tools with JVM implementation
- * @author yaqiao
+ * JVM file path separator (platform-dependent: backslash on Windows, forward slash elsewhere).
*/
-
internal actual val separatorChar: Char =
if (System.getProperty("os.name").lowercase().contains("windows")) '\\' else '/'
diff --git a/sqllin-driver/src/jvmTest/kotlin/com/ctrip/sqllin/driver/JvmTest.kt b/sqllin-driver/src/jvmTest/kotlin/com/ctrip/sqllin/driver/JvmTest.kt
index 8dda13a..8fd4dbc 100644
--- a/sqllin-driver/src/jvmTest/kotlin/com/ctrip/sqllin/driver/JvmTest.kt
+++ b/sqllin-driver/src/jvmTest/kotlin/com/ctrip/sqllin/driver/JvmTest.kt
@@ -21,7 +21,7 @@ import kotlin.test.Test
/**
* Native unit test
- * @author yaqiao
+ * @author Yuang Qiao
*/
class JvmTest {
diff --git a/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt b/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
index 3d97b96..6d52657 100644
--- a/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
+++ b/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
@@ -33,11 +33,10 @@ import platform.posix.pthread_mutexattr_settype
import platform.posix.pthread_mutexattr_t
/**
- * A simple lock implementation in Linux.
- * Implementations of this class should be re-entrant.
- * @author yaqiao
+ * Linux platform lock implementation using pthread recursive mutex.
+ *
+ * @author Yuang Qiao
*/
-
@OptIn(ExperimentalForeignApi::class)
internal actual class Lock actual constructor() {
diff --git a/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsLinux.kt b/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsLinux.kt
index c3a6be3..6ad08f8 100644
--- a/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsLinux.kt
+++ b/sqllin-driver/src/linuxMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsLinux.kt
@@ -22,12 +22,13 @@ import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.toKString
/**
- * The tools with Linux implementation
- * @author yaqiao
+ * Converts C byte pointer to String using toKString on Linux.
*/
-
@OptIn(ExperimentalForeignApi::class)
internal actual fun bytesToString(bv: CPointer): String = bv.toKString()
+/**
+ * Linux file path separator (forward slash).
+ */
internal actual inline val separatorChar: Char
get() = '/'
\ No newline at end of file
diff --git a/sqllin-driver/src/linuxTest/kotlin/com/ctrip/sqllin/driver/PlatformLinux.kt b/sqllin-driver/src/linuxTest/kotlin/com/ctrip/sqllin/driver/PlatformLinux.kt
index 4aafb76..ee01438 100644
--- a/sqllin-driver/src/linuxTest/kotlin/com/ctrip/sqllin/driver/PlatformLinux.kt
+++ b/sqllin-driver/src/linuxTest/kotlin/com/ctrip/sqllin/driver/PlatformLinux.kt
@@ -22,7 +22,7 @@ import platform.posix.getcwd
/**
* Linux platform-related functions
- * @author yaqiao
+ * @author Yuang Qiao
*/
@OptIn(ExperimentalForeignApi::class)
diff --git a/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt b/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
index 27857cc..7e76f48 100644
--- a/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
+++ b/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/Lock.kt
@@ -33,11 +33,10 @@ import platform.posix.pthread_mutexattr_settype
import platform.posix.pthread_mutexattr_tVar
/**
- * A simple lock implementation in MinGW.
- * Implementations of this class should be re-entrant.
- * @author yaqiao
+ * MinGW/Windows platform lock implementation using pthread recursive mutex.
+ *
+ * @author Yuang Qiao
*/
-
@OptIn(ExperimentalForeignApi::class)
internal actual class Lock actual constructor() {
diff --git a/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsMinGW.kt b/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsMinGW.kt
index 9124a4a..3d27b92 100644
--- a/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsMinGW.kt
+++ b/sqllin-driver/src/mingwMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsMinGW.kt
@@ -22,12 +22,13 @@ import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.toKStringFromUtf8
/**
- * The tools with Windows implementation
- * @author yaqiao
+ * Converts C byte pointer to String using toKStringFromUtf8 on Windows (MinGW).
*/
-
@OptIn(ExperimentalForeignApi::class)
internal actual fun bytesToString(bv: CPointer): String = bv.toKStringFromUtf8()
+/**
+ * Windows file path separator (backslash).
+ */
internal actual inline val separatorChar: Char
get() = '\\'
\ No newline at end of file
diff --git a/sqllin-driver/src/mingwTest/kotlin/com/ctrip/sqllin/driver/PlatformMingw.kt b/sqllin-driver/src/mingwTest/kotlin/com/ctrip/sqllin/driver/PlatformMingw.kt
index 1577c68..02866e0 100644
--- a/sqllin-driver/src/mingwTest/kotlin/com/ctrip/sqllin/driver/PlatformMingw.kt
+++ b/sqllin-driver/src/mingwTest/kotlin/com/ctrip/sqllin/driver/PlatformMingw.kt
@@ -22,7 +22,7 @@ import platform.posix._wgetcwd
/**
* Windows platform-related functions
* The doc of _getcwd: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getcwd-wgetcwd?view=msvc-170
- * @author yaqiao
+ * @author Yuang Qiao
*/
@OptIn(ExperimentalForeignApi::class)
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt
index 5faee17..a91acda 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt
@@ -20,10 +20,12 @@ import com.ctrip.sqllin.driver.platform.Lock
import com.ctrip.sqllin.driver.platform.withLock
/**
- * The concurrent database connection, use platform-related lock to ensure thread-safe
- * @author yaqiao
+ * Thread-safe wrapper for [NativeDatabaseConnection] using platform-specific locks.
+ *
+ * Delegates all operations to the underlying connection while ensuring thread safety.
+ *
+ * @author Yuang Qiao
*/
-
internal class ConcurrentDatabaseConnection(
private val delegateConnection: NativeDatabaseConnection
) : NativeDatabaseConnection() {
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentStatement.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentStatement.kt
index 6221fbe..7dac435 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentStatement.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentStatement.kt
@@ -20,11 +20,12 @@ import com.ctrip.sqllin.driver.platform.Lock
import com.ctrip.sqllin.driver.platform.withLock
/**
- * The concurrent statement, use platform-related lock to ensure thread-safe,
- * the lock come from the ConcurrentDatabaseConnection
- * @author yaqiao
+ * Thread-safe wrapper for [SQLiteStatement] using platform-specific locks.
+ *
+ * Ensures thread safety by delegating all operations through the provided lock.
+ *
+ * @author Yuang Qiao
*/
-
internal class ConcurrentStatement(
private val delegateStatement: SQLiteStatement,
private val accessLock: Lock,
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ExtensionNative.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ExtensionNative.kt
index 09c819e..a1f0e00 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ExtensionNative.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ExtensionNative.kt
@@ -22,10 +22,8 @@ import com.ctrip.sqllin.driver.platform.withLock
import platform.posix.remove
/**
- * SQLite extension Native
- * @author yaqiao
+ * Converts a String path to a [DatabasePath] for native platforms.
*/
-
public fun String.toDatabasePath(): DatabasePath = StringDatabasePath(this)
private val connectionCreationLock = Lock()
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeCursor.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeCursor.kt
index efa7ca6..f9c4a73 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeCursor.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeCursor.kt
@@ -17,10 +17,10 @@
package com.ctrip.sqllin.driver
/**
- * SQLite Cursor Native actual
- * @author yaqiao
+ * Native implementation of [CommonCursor] backed by a [SQLiteStatement].
+ *
+ * @author Yuang Qiao
*/
-
internal class NativeCursor(
private val statement: SQLiteStatement
) : CommonCursor {
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt
index 94ed467..2674a9f 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt
@@ -17,14 +17,22 @@
package com.ctrip.sqllin.driver
/**
- * The super class for DatabaseConnection on native platforms
- * @author yaqiao
+ * Base class for native platform database connections.
+ *
+ * Handles parameter binding for SQLiteStatement with support for Kotlin native types.
+ *
+ * @author Yuang Qiao
*/
-
internal abstract class NativeDatabaseConnection : DatabaseConnection {
+ /**
+ * Creates a SQLiteStatement for the given SQL.
+ */
abstract fun createStatement(sql: String): SQLiteStatement
+ /**
+ * Binds parameters to a SQLiteStatement, supporting common Kotlin types.
+ */
protected fun bindParamsToSQL(sql: String, bindParams: Array?): SQLiteStatement = createStatement(sql).apply {
bindParams?.run {
require(isNotEmpty()) { "Empty bindArgs" }
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt
index d9b3175..a03c298 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt
@@ -23,10 +23,12 @@ import kotlin.concurrent.AtomicInt
import kotlin.concurrent.AtomicReference
/**
- * Database manager Native actual
- * @author yaqiao
+ * Native implementation of [DatabaseConnection] using C interop with SQLite.
+ *
+ * Provides direct access to SQLite C API on native platforms with transaction support.
+ *
+ * @author Yuang Qiao
*/
-
internal class RealDatabaseConnection(
private val database: NativeDatabase
) : NativeDatabaseConnection() {
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteResultCode.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteResultCode.kt
index 4f8dbb7..61543e9 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteResultCode.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteResultCode.kt
@@ -20,7 +20,8 @@ import com.ctrip.sqllin.driver.SQLiteResultCode.Companion.INVALID_CODE
import com.ctrip.sqllin.driver.cinterop.SQLiteErrorType
/**
- * The result codes in SQLite
+ * SQLite exception with native result code information.
+ *
* @author Yuang Qiao
*/
public class SQLiteResultCode(message: String, resultCode: Int) : SQLiteException(
@@ -35,6 +36,9 @@ public class SQLiteResultCode(message: String, resultCode: Int) : SQLiteExceptio
}
}
+/**
+ * Creates a SQLiteException with optional error code.
+ */
internal fun sqliteException(message: String, errorCode: Int = INVALID_CODE): SQLiteException =
if (errorCode == INVALID_CODE)
SQLiteException(message)
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteStatement.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteStatement.kt
index c968129..75cdfd5 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteStatement.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/SQLiteStatement.kt
@@ -17,10 +17,12 @@
package com.ctrip.sqllin.driver
/**
- * SQLite native statement abstract APIs
- * @author yaqiao
+ * Interface for native SQLite prepared statements.
+ *
+ * Provides low-level access to statement execution, parameter binding, and result retrieval.
+ *
+ * @author Yuang Qiao
*/
-
internal interface SQLiteStatement {
fun isNull(columnIndex: Int): Boolean
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeDatabase.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeDatabase.kt
index c9648be..f6435d3 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeDatabase.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeDatabase.kt
@@ -24,14 +24,19 @@ import com.ctrip.sqllin.sqlite3.*
import kotlinx.cinterop.*
/**
- * The native database wrapper for `sqlite3`, interop with SQLite C APIs directly
- * @author yaqiao
+ * Native wrapper for sqlite3 database handle.
+ *
+ * Provides direct C interop with SQLite3 APIs for database operations on native platforms.
+ *
+ * @author Yuang Qiao
*/
-
@OptIn(ExperimentalForeignApi::class)
internal class NativeDatabase private constructor(val dbPointer: CPointer) {
companion object {
+ /**
+ * Opens a native SQLite database with the given configuration.
+ */
fun openNativeDatabase(configuration: DatabaseConfiguration, realPath: String): NativeDatabase {
val sqliteFlags = SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE or SQLITE_OPEN_URI
@@ -75,6 +80,9 @@ internal class NativeDatabase private constructor(val dbPointer: CPointer>()
@@ -91,6 +99,9 @@ internal class NativeDatabase private constructor(val dbPointer: CPointer Lock.withLock(block: () -> T): T {
lock()
try {
diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsNative.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsNative.kt
index 9743804..cc9557f 100644
--- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsNative.kt
+++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/platform/UtilsNative.kt
@@ -21,9 +21,7 @@ import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
/**
- * The tools with platform-specific implementation
- * @author yaqiao
+ * Converts C byte pointer to Kotlin String.
*/
-
@OptIn(ExperimentalForeignApi::class)
internal expect fun bytesToString(bv: CPointer): String
diff --git a/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/NativeTest.kt b/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/NativeTest.kt
index 893f1e8..99c5e8a 100644
--- a/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/NativeTest.kt
+++ b/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/NativeTest.kt
@@ -21,7 +21,7 @@ import kotlin.test.Test
/**
* Native unit test
- * @author yaqiao
+ * @author Yuang Qiao
*/
class NativeTest {
diff --git a/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/Platform.kt b/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/Platform.kt
index a43b576..4af84f3 100644
--- a/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/Platform.kt
+++ b/sqllin-driver/src/nativeTest/kotlin/com/ctrip/sqllin/driver/Platform.kt
@@ -18,7 +18,7 @@ package com.ctrip.sqllin.driver
/**
* Some platform-related functions
- * @author yaqiao
+ * @author Yuang Qiao
*/
/**
diff --git a/sqllin-dsl-test/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/dsl/test/AndroidTest.kt b/sqllin-dsl-test/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/dsl/test/AndroidTest.kt
index f2003a6..ad448a1 100644
--- a/sqllin-dsl-test/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/dsl/test/AndroidTest.kt
+++ b/sqllin-dsl-test/src/androidInstrumentedTest/kotlin/com/ctrip/sqllin/dsl/test/AndroidTest.kt
@@ -12,7 +12,7 @@ import org.junit.runner.RunWith
/**
* Android instrumented test
- * @author yaqiao
+ * @author Yuang Qiao
*/
@RunWith(AndroidJUnit4ClassRunner::class)
diff --git a/sqllin-dsl-test/src/appleTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformApple.kt b/sqllin-dsl-test/src/appleTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformApple.kt
index aa056a6..8b34e0a 100644
--- a/sqllin-dsl-test/src/appleTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformApple.kt
+++ b/sqllin-dsl-test/src/appleTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformApple.kt
@@ -23,7 +23,7 @@ import platform.Foundation.NSUserDomainMask
/**
* Apple platform-related functions
- * @author yaqiao
+ * @author Yuang Qiao
*/
@OptIn(UnsafeNumber::class)
diff --git a/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/Entities.kt b/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/Entities.kt
index 98ff08d..3e8d24e 100644
--- a/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/Entities.kt
+++ b/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/Entities.kt
@@ -21,7 +21,7 @@ import kotlinx.serialization.Serializable
/**
* Book entity
- * @author yaqiao
+ * @author Yuang Qiao
*/
@DBRow("book")
diff --git a/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/TestPrimitiveTypeForKSP.kt b/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/TestPrimitiveTypeForKSP.kt
index 9544853..c877e61 100644
--- a/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/TestPrimitiveTypeForKSP.kt
+++ b/sqllin-dsl-test/src/commonMain/kotlin/com/ctrip/sqllin/dsl/test/TestPrimitiveTypeForKSP.kt
@@ -22,7 +22,7 @@ import kotlinx.serialization.Transient
/**
* Test whether the sqllin-processor could generate primitive type and String correctly
- * @author yaqiao
+ * @author Yuang Qiao
*/
@DBRow
diff --git a/sqllin-dsl-test/src/commonTest/kotlin/com/ctrip/sqllin/dsl/test/CommonBasicTest.kt b/sqllin-dsl-test/src/commonTest/kotlin/com/ctrip/sqllin/dsl/test/CommonBasicTest.kt
index 94e0d5a..dfba999 100644
--- a/sqllin-dsl-test/src/commonTest/kotlin/com/ctrip/sqllin/dsl/test/CommonBasicTest.kt
+++ b/sqllin-dsl-test/src/commonTest/kotlin/com/ctrip/sqllin/dsl/test/CommonBasicTest.kt
@@ -34,7 +34,7 @@ import kotlin.test.assertNotEquals
/**
* The sqllin-dsl common test
- * @author yaqiao
+ * @author Yuang Qiao
*/
class CommonBasicTest(private val path: DatabasePath) {
diff --git a/sqllin-dsl-test/src/jvmTest/kotlin/com/ctrip/sqllin/dsl/test/JvmTest.kt b/sqllin-dsl-test/src/jvmTest/kotlin/com/ctrip/sqllin/dsl/test/JvmTest.kt
index 1f630d8..9527486 100644
--- a/sqllin-dsl-test/src/jvmTest/kotlin/com/ctrip/sqllin/dsl/test/JvmTest.kt
+++ b/sqllin-dsl-test/src/jvmTest/kotlin/com/ctrip/sqllin/dsl/test/JvmTest.kt
@@ -8,7 +8,7 @@ import kotlin.test.Test
/**
* Native unit test
- * @author yaqiao
+ * @author Yuang Qiao
*/
class JvmTest {
diff --git a/sqllin-dsl-test/src/linuxTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformLinux.kt b/sqllin-dsl-test/src/linuxTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformLinux.kt
index 91348a3..ef77712 100644
--- a/sqllin-dsl-test/src/linuxTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformLinux.kt
+++ b/sqllin-dsl-test/src/linuxTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformLinux.kt
@@ -22,7 +22,7 @@ import platform.posix.getcwd
/**
* Linux platform-related functions
- * @author yaqiao
+ * @author Yuang Qiao
*/
@OptIn(ExperimentalForeignApi::class)
diff --git a/sqllin-dsl-test/src/mingwTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformMingw.kt b/sqllin-dsl-test/src/mingwTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformMingw.kt
index a87f013..4898131 100644
--- a/sqllin-dsl-test/src/mingwTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformMingw.kt
+++ b/sqllin-dsl-test/src/mingwTest/kotlin/com/ctrip/sqllin/dsl/test/PlatformMingw.kt
@@ -22,7 +22,7 @@ import platform.posix._wgetcwd
/**
* Windows platform-related functions
* The doc of _wgetcwd: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getcwd-wgetcwd?view=msvc-170
- * @author yaqiao
+ * @author Yuang Qiao
*/
@OptIn(ExperimentalForeignApi::class)
diff --git a/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/NativeTest.kt b/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/NativeTest.kt
index 9b51de1..8fadbb8 100644
--- a/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/NativeTest.kt
+++ b/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/NativeTest.kt
@@ -24,7 +24,7 @@ import kotlin.test.Test
/**
* Native unit test
- * @author yaqiao
+ * @author Yuang Qiao
*/
class NativeTest {
diff --git a/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/Platform.kt b/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/Platform.kt
index f704349..5d8ac94 100644
--- a/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/Platform.kt
+++ b/sqllin-dsl-test/src/nativeTest/kotlin/com/ctrip/sqllin/dsl/test/Platform.kt
@@ -18,7 +18,7 @@ package com.ctrip.sqllin.dsl.test
/**
* Some platform-related functions
- * @author yaqiao
+ * @author Yuang Qiao
*/
/**
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DSLDBConfiguration.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DSLDBConfiguration.kt
index d588df7..d7cbb20 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DSLDBConfiguration.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DSLDBConfiguration.kt
@@ -22,10 +22,26 @@ import com.ctrip.sqllin.driver.JournalMode
import com.ctrip.sqllin.driver.SynchronousMode
/**
- * DSL database configuration
+ * DSL-level database configuration with [DatabaseScope] callbacks.
+ *
+ * Similar to [DatabaseConfiguration] but allows create and upgrade callbacks
+ * to use the type-safe SQL DSL instead of raw [com.ctrip.sqllin.driver.DatabaseConnection] operations.
+ *
+ * @property name The database filename
+ * @property path The database directory path
+ * @property version The database schema version
+ * @property isReadOnly Whether to open in read-only mode. Default: false
+ * @property inMemory Whether to create an in-memory database. Default: false
+ * @property journalMode The SQLite journal mode. Default: [JournalMode.WAL]
+ * @property synchronousMode The SQLite synchronous mode. Default: [SynchronousMode.NORMAL]
+ * @property busyTimeout Timeout in milliseconds for lock waits. Default: 5000ms
+ * @property lookasideSlotSize Size of lookaside memory slots. Default: 0
+ * @property lookasideSlotCount Number of lookaside memory slots. Default: 0
+ * @property create Callback invoked when creating a new database, executed within a [DatabaseScope]
+ * @property upgrade Callback invoked when upgrading the schema, executed within a [DatabaseScope]
+ *
* @author Yuang Qiao
*/
-
public data class DSLDBConfiguration(
val name: String,
val path: DatabasePath,
@@ -40,6 +56,9 @@ public data class DSLDBConfiguration(
val create: DatabaseScope.() -> Unit = {},
val upgrade: DatabaseScope.(oldVersion: Int, newVersion: Int) -> Unit = { _, _ -> },
) {
+ /**
+ * Converts to driver-level configuration, wrapping DSL callbacks.
+ */
internal infix fun convertToDatabaseConfiguration(enableSimpleSQLLog: Boolean): DatabaseConfiguration = DatabaseConfiguration(
name,
path,
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt
index 97f2dde..fb3736d 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt
@@ -21,22 +21,44 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
/**
- * Database object
+ * High-level database interface for executing SQL operations using type-safe DSL.
+ *
+ * Database objects are created via factory functions in [DatabaseCreators.kt][Database]
+ * and provide a scope-based API for executing SQL statements. All SQL operations must be
+ * performed within a [DatabaseScope], which is entered by invoking the database object.
+ *
+ * Example:
+ * ```kotlin
+ * val database = Database(config)
+ * database {
+ * PersonTable INSERT person
+ * PersonTable SELECT WHERE(PersonTable.age GTE 18)
+ * }
+ * database.close()
+ * ```
+ *
* @author Yuang Qiao
*/
-
public class Database internal constructor(
private val databaseConnection: DatabaseConnection,
private val enableSimpleSQLLog: Boolean = false,
) {
/**
- * Close the database connection.
+ * Closes the database connection and releases resources.
+ *
+ * After closing, the database cannot be used for further operations.
*/
public fun close(): Unit = databaseConnection.close()
/**
- * Start a scope with this database object that used for execute SQL.
+ * Opens a database scope for executing SQL statements.
+ *
+ * All SQL operations within the block are executed when the scope exits.
+ * Statements are batched and executed in order.
+ *
+ * @param block The DSL block containing SQL operations
+ * @return The result of the block
*/
public operator fun invoke(block: DatabaseScope.() -> T): T {
val databaseScope = DatabaseScope(databaseConnection, enableSimpleSQLLog)
@@ -47,6 +69,15 @@ public class Database internal constructor(
private val executiveMutex by lazy { Mutex() }
+ /**
+ * Opens a suspendable database scope for executing SQL statements in coroutines.
+ *
+ * Similar to [invoke] but supports suspend functions within the block.
+ * Statement execution is serialized using a mutex to ensure thread safety.
+ *
+ * @param block The suspending DSL block containing SQL operations
+ * @return The result of the block
+ */
public suspend infix fun suspendedScope(block: suspend DatabaseScope.() -> T): T {
val databaseScope = DatabaseScope(databaseConnection, enableSimpleSQLLog)
val result = databaseScope.block()
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseCreators.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseCreators.kt
index 19e71d8..cbaed42 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseCreators.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseCreators.kt
@@ -21,15 +21,34 @@ import com.ctrip.sqllin.driver.DatabasePath
import com.ctrip.sqllin.driver.openDatabase
/**
- * Factory functions for Database
+ * Factory functions for creating [Database] instances.
+ *
* @author Yuang Qiao
*/
+/**
+ * Creates a database from a driver-level configuration.
+ *
+ * @param configuration The database configuration
+ * @param enableSimpleSQLLog Whether to enable simple SQL logging for debugging
+ * @return A new database instance
+ */
public fun Database(
configuration: DatabaseConfiguration,
enableSimpleSQLLog: Boolean = false,
): Database = Database(openDatabase(configuration), enableSimpleSQLLog)
+/**
+ * Creates a database with basic configuration parameters.
+ *
+ * Uses default settings for other configuration options.
+ *
+ * @param name The database filename
+ * @param path The database directory path
+ * @param version The database schema version
+ * @param enableSimpleSQLLog Whether to enable simple SQL logging for debugging
+ * @return A new database instance
+ */
public fun Database(
name: String,
path: DatabasePath,
@@ -44,6 +63,16 @@ public fun Database(
enableSimpleSQLLog
)
+/**
+ * Creates a database from a DSL-level configuration.
+ *
+ * Allows using [DatabaseScope] in create and upgrade callbacks instead of
+ * raw [com.ctrip.sqllin.driver.DatabaseConnection].
+ *
+ * @param dsldbConfiguration The DSL database configuration
+ * @param enableSimpleSQLLog Whether to enable simple SQL logging for debugging
+ * @return A new database instance
+ */
public fun Database(
dsldbConfiguration: DSLDBConfiguration,
enableSimpleSQLLog: Boolean = false,
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt
index d112108..201ba0e 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt
@@ -35,19 +35,43 @@ import kotlin.concurrent.Volatile
import kotlin.jvm.JvmName
/**
- * The database scope, it's used to restrict the scope that write DSL SQL statements
+ * Scope for executing type-safe SQL DSL statements.
+ *
+ * DatabaseScope provides extension functions on [Table] objects that enable SQL operations
+ * using Kotlin DSL syntax. All SQL statements written within this scope are collected and
+ * executed in batch when the scope exits.
+ *
+ * Supported operations:
+ * - **INSERT**: Add entities to tables
+ * - **UPDATE**: Modify existing records with SET and WHERE clauses
+ * - **DELETE**: Remove records with WHERE clauses
+ * - **SELECT**: Query records with WHERE, ORDER BY, LIMIT, GROUP BY, JOIN, and UNION
+ * - **CREATE**: Create tables from data class definitions
+ *
+ * Transaction support:
+ * - Use [transaction] to execute multiple statements atomically
+ * - Transactions can be nested and are automatically committed or rolled back
+ *
+ * Example:
+ * ```kotlin
+ * database {
+ * transaction {
+ * PersonTable INSERT person
+ * PersonTable UPDATE SET { name = "Alice" } WHERE (age GTE 18)
+ * }
+ * val adults = PersonTable SELECT WHERE(age GTE 18) LIMIT 10
+ * }
+ * ```
+ *
* @author Yuang Qiao
*/
-
@Suppress("UNCHECKED_CAST")
public class DatabaseScope internal constructor(
private val databaseConnection: DatabaseConnection,
private val enableSimpleSQLLog: Boolean,
) {
- /**
- * Transaction.
- */
+ // ========== Transaction Management ==========
@Volatile
private var transactionStatementsGroup: TransactionStatementsGroup? = null
@@ -55,6 +79,11 @@ public class DatabaseScope internal constructor(
private inline val isInTransaction
get() = transactionStatementsGroup != null
+ /**
+ * Begins a new transaction.
+ *
+ * @return `true` if transaction started successfully, `false` if already in a transaction
+ */
public fun beginTransaction(): Boolean {
if (isInTransaction)
return false
@@ -63,10 +92,25 @@ public class DatabaseScope internal constructor(
return true
}
+ /**
+ * Ends the current transaction.
+ *
+ * The transaction will be committed or rolled back based on whether
+ * [endTransaction] was called.
+ */
public fun endTransaction() {
transactionStatementsGroup = null
}
+ /**
+ * Executes a block of SQL statements as a single transaction.
+ *
+ * If the block completes successfully, the transaction is committed.
+ * If an exception is thrown, the transaction is rolled back.
+ *
+ * @param block The block of SQL statements to execute
+ * @return The result of the block
+ */
public inline fun transaction(block: DatabaseScope.() -> T): T {
beginTransaction()
try {
@@ -76,9 +120,7 @@ public class DatabaseScope internal constructor(
}
}
- /**
- * SQL execute.
- */
+ // ========== Statement Execution Management ==========
private val executiveEngine = DatabaseExecuteEngine(enableSimpleSQLLog)
@@ -98,21 +140,74 @@ public class DatabaseScope internal constructor(
internal fun executeAllStatements() = executiveEngine.executeAllStatement()
+ // ========== INSERT Operations ==========
+
/**
- * Insert.
+ * Inserts multiple entities into the table, allowing the database to auto-generate primary keys.
+ *
+ * For entities with `Long?` primary keys annotated with [@PrimaryKey][com.ctrip.sqllin.dsl.annotation.PrimaryKey],
+ * set the ID property to `null` to let SQLite automatically generate the ID. If you need to insert
+ * entities with pre-defined IDs (e.g., during data migration), use [INSERT_WITH_ID] instead.
+ *
+ * Example:
+ * ```kotlin
+ * val person = Person(id = null, name = "Alice", age = 25) // ID will be auto-generated
+ * PersonTable INSERT listOf(person1, person2)
+ * ```
+ *
+ * @see INSERT_WITH_ID for inserting with pre-defined primary key values
*/
-
@StatementDslMaker
public infix fun Table.INSERT(entities: Iterable) {
val statement = Insert.insert(this, databaseConnection, entities)
addStatement(statement)
}
+ /**
+ * Inserts a single entity into the table, allowing the database to auto-generate the primary key.
+ *
+ * For entities with `Long?` primary keys annotated with [@PrimaryKey][com.ctrip.sqllin.dsl.annotation.PrimaryKey],
+ * set the ID property to `null` to let SQLite automatically generate the ID.
+ *
+ * Example:
+ * ```kotlin
+ * val person = Person(id = null, name = "Alice", age = 25) // ID will be auto-generated
+ * PersonTable INSERT person
+ * ```
+ *
+ * @see INSERT_WITH_ID for inserting with a pre-defined primary key value
+ */
@StatementDslMaker
public infix fun Table.INSERT(entity: T): Unit =
INSERT(listOf(entity))
-
+ /**
+ * Inserts multiple entities with pre-defined primary key values (advanced API).
+ *
+ * **⚠️ This is an advanced API for special use cases like data migration or testing.**
+ * Use this function when you need to manually specify the primary key ID instead of letting
+ * the database auto-generate it. For normal inserts where the database should generate IDs
+ * automatically, use [INSERT] instead.
+ *
+ * This function is particularly useful for:
+ * - Data migration from another database where you need to preserve existing IDs
+ * - Testing scenarios where you need predictable, specific ID values
+ * - Restoring backup data with original IDs
+ *
+ * Example:
+ * ```kotlin
+ * @OptIn(AdvancedInsertAPI::class)
+ * fun migrateData() {
+ * val person = Person(id = 12345L, name = "Alice", age = 25) // Use specific ID
+ * PersonTable INSERT_WITH_ID listOf(person1, person2)
+ * }
+ * ```
+ *
+ * **Important**: This function requires explicit opt-in via `@OptIn(AdvancedInsertAPI::class)`
+ * to acknowledge that you understand the implications of manually specifying primary keys.
+ *
+ * @see INSERT for standard inserts with auto-generated IDs
+ */
@AdvancedInsertAPI
@StatementDslMaker
public infix fun Table.INSERT_WITH_ID(entities: Iterable) {
@@ -120,15 +215,42 @@ public class DatabaseScope internal constructor(
addStatement(statement)
}
+ /**
+ * Inserts a single entity with a pre-defined primary key value (advanced API).
+ *
+ * **⚠️ This is an advanced API for special use cases like data migration or testing.**
+ * Use this function when you need to manually specify the primary key ID. For normal inserts,
+ * use [INSERT] instead.
+ *
+ * Example:
+ * ```kotlin
+ * @OptIn(AdvancedInsertAPI::class)
+ * fun migrateData() {
+ * val person = Person(id = 12345L, name = "Alice", age = 25) // Use specific ID
+ * PersonTable INSERT_WITH_ID person
+ * }
+ * ```
+ *
+ * @see INSERT for standard inserts with auto-generated IDs
+ * @see INSERT_WITH_ID for batch inserts with pre-defined IDs
+ */
@AdvancedInsertAPI
@StatementDslMaker
public infix fun Table.INSERT_WITH_ID(entity: T): Unit =
INSERT_WITH_ID(listOf(entity))
+ // ========== UPDATE Operations ==========
+
/**
- * Update.
+ * Updates records in the table with SET clause.
+ *
+ * Can be followed by WHERE to target specific records.
+ *
+ * Example:
+ * ```kotlin
+ * PersonTable UPDATE SET { name = "Alice" } WHERE (age GTE 18)
+ * ```
*/
-
@StatementDslMaker
public infix fun Table.UPDATE(clause: SetClause): UpdateStatementWithoutWhereClause =
transactionStatementsGroup?.let {
@@ -139,34 +261,53 @@ public class DatabaseScope internal constructor(
executiveEngine addStatement it
}
+ // ========== DELETE Operations ==========
+
/**
- * Delete.
+ * Deletes all records from the table.
+ *
+ * Example:
+ * ```kotlin
+ * PersonTable DELETE X
+ * ```
*/
-
@StatementDslMaker
public infix fun Table<*>.DELETE(x: X) {
val statement = Delete.deleteAllEntities(this, databaseConnection)
addStatement(statement)
}
+ /**
+ * Deletes records matching the WHERE clause.
+ *
+ * Example:
+ * ```kotlin
+ * PersonTable DELETE WHERE(age LT 18)
+ * ```
+ */
@StatementDslMaker
public infix fun Table.DELETE(clause: WhereClause) {
val statement = Delete.delete(this, databaseConnection, clause)
addStatement(statement)
}
- /**
- * Select.
- */
+ // ========== SELECT Operations ==========
/**
- * Select with no any clause.
+ * Selects all records from the table.
+ *
+ * Example:
+ * ```kotlin
+ * val people = PersonTable SELECT X
+ * ```
*/
-
@StatementDslMaker
public inline infix fun Table.SELECT(x: X): FinalSelectStatement =
select(kSerializer(), false)
+ /**
+ * Selects distinct records from the table.
+ */
@StatementDslMaker
public inline infix fun Table.SELECT_DISTINCT(x: X): FinalSelectStatement =
select(kSerializer(), true)
@@ -179,9 +320,15 @@ public class DatabaseScope internal constructor(
}
/**
- * Receive the 'WHERE' clause.
+ * Selects records matching the WHERE clause.
+ *
+ * Can be followed by ORDER BY, LIMIT, etc.
+ *
+ * Example:
+ * ```kotlin
+ * val adults = PersonTable SELECT WHERE(age GTE 18)
+ * ```
*/
-
@StatementDslMaker
public inline infix fun Table.SELECT(clause: WhereClause): WhereSelectStatement =
select(kSerializer(), clause, false)
@@ -198,9 +345,13 @@ public class DatabaseScope internal constructor(
}
/**
- * Receive the 'ORDER BY' clause.
+ * Selects records with ORDER BY clause.
+ *
+ * Example:
+ * ```kotlin
+ * val sorted = PersonTable SELECT ORDER_BY(age.DESC())
+ * ```
*/
-
@StatementDslMaker
public inline infix fun Table.SELECT(clause: OrderByClause): OrderBySelectStatement =
select(kSerializer(), clause, false)
@@ -217,9 +368,13 @@ public class DatabaseScope internal constructor(
}
/**
- * Receive the 'LIMIT' clause.
+ * Selects a limited number of records.
+ *
+ * Example:
+ * ```kotlin
+ * val first10 = PersonTable SELECT LIMIT(0, 10)
+ * ```
*/
-
@StatementDslMaker
public inline infix fun Table.SELECT(clause: LimitClause): LimitSelectStatement =
select(kSerializer(), clause, false)
@@ -236,9 +391,13 @@ public class DatabaseScope internal constructor(
}
/**
- * Receive the 'GROUP BY' clause.
+ * Selects records with GROUP BY clause.
+ *
+ * Example:
+ * ```kotlin
+ * val grouped = PersonTable SELECT GROUP_BY(age)
+ * ```
*/
-
@StatementDslMaker
public inline infix fun Table.SELECT(clause: GroupByClause): GroupBySelectStatement =
select(kSerializer(), clause, false)
@@ -254,16 +413,28 @@ public class DatabaseScope internal constructor(
return statement
}
- public inline fun getKSerializer(): KSerializer = EmptySerializersModule().serializer()
-
/**
- * The 'UNION' clause of Select.
+ * Gets the KSerializer for the reified type parameter.
*/
+ public inline fun getKSerializer(): KSerializer = EmptySerializersModule().serializer()
+
+ // ========== UNION Operations ==========
private val unionSelectStatementGroupStack by lazy { ArrayDeque>() }
private fun getSelectStatementGroup(): StatementContainer = unionSelectStatementGroupStack.lastOrNull() ?: transactionStatementsGroup ?: executiveEngine
+ /**
+ * Combines multiple SELECT statements with UNION (removes duplicates).
+ *
+ * Example:
+ * ```kotlin
+ * val combined = PersonTable.UNION {
+ * it SELECT WHERE(age LT 18)
+ * it SELECT WHERE(age GTE 65)
+ * }
+ * ```
+ */
public inline fun Table.UNION(block: Table.(Table) -> Unit): FinalSelectStatement {
beginUnion()
var selectStatement: SelectStatement? = null
@@ -276,6 +447,9 @@ public class DatabaseScope internal constructor(
}
}
+ /**
+ * Combines multiple SELECT statements with UNION ALL (keeps duplicates).
+ */
@StatementDslMaker
public inline fun Table.UNION_ALL(block: Table.(Table) -> Unit): FinalSelectStatement {
beginUnion()
@@ -289,24 +463,39 @@ public class DatabaseScope internal constructor(
}
}
+ /**
+ * Begins a UNION statement group (for advanced usage).
+ */
public fun beginUnion() {
unionSelectStatementGroupStack.add(UnionSelectStatementGroup())
}
+ /**
+ * Creates the final UNION select statement from accumulated SELECT statements.
+ */
public fun createUnionSelectStatement(isUnionAll: Boolean): FinalSelectStatement {
check(unionSelectStatementGroupStack.isNotEmpty()) { "Please invoke the 'beginUnion' before you invoke this function!!!" }
return (unionSelectStatementGroupStack.last() as UnionSelectStatementGroup).unionStatements(isUnionAll)
}
+ /**
+ * Ends the UNION statement group and adds the final statement.
+ */
public fun endUnion(selectStatement: SelectStatement?) {
unionSelectStatementGroupStack.removeLast()
selectStatement?.let { addSelectStatement(it) }
}
+ // ========== JOIN Operations ==========
+
/**
- * Receive the 'JOIN' clause.
+ * Selects with JOIN clause (requires ON condition).
+ *
+ * Example:
+ * ```kotlin
+ * val joined = PersonTable SELECT INNER_JOIN(AddressTable) ON ...
+ * ```
*/
-
@StatementDslMaker
public inline infix fun Table.SELECT(clause: JoinClause): JoinStatementWithoutCondition =
select(getKSerializer(), clause, false)
@@ -321,9 +510,13 @@ public class DatabaseScope internal constructor(
}
/**
- * Receive the natural join clause(includes 'NATURAL LEFT OUTER JOIN' and 'NATURAL INNER JOIN').
+ * Selects with NATURAL JOIN (joins on columns with same names).
+ *
+ * Example:
+ * ```kotlin
+ * val joined = PersonTable SELECT NATURAL_INNER_JOIN(AddressTable)
+ * ```
*/
-
@StatementDslMaker
public inline infix fun Table.SELECT(clause: NaturalJoinClause): JoinSelectStatement =
select(getKSerializer(), clause, false)
@@ -339,8 +532,17 @@ public class DatabaseScope internal constructor(
return statement
}
+ // ========== CREATE Operations ==========
+
/**
- * CREATE
+ * Creates a table from its Table definition.
+ *
+ * Example:
+ * ```kotlin
+ * CREATE(PersonTable)
+ * // or
+ * PersonTable.CREATE()
+ * ```
*/
@StatementDslMaker
public infix fun CREATE(table: Table) {
@@ -348,6 +550,9 @@ public class DatabaseScope internal constructor(
addStatement(statement)
}
+ /**
+ * Creates this table from its definition (extension function variant).
+ */
@StatementDslMaker
@JvmName("create")
public fun Table.CREATE(): Unit = CREATE(this)
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DBRow.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DBRow.kt
index 5e0c631..16d39d5 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DBRow.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DBRow.kt
@@ -17,10 +17,17 @@
package com.ctrip.sqllin.dsl.annotation
/**
- * Annotation for where property
+ * Marks a data class as a SQLite table representation.
+ *
+ * This annotation is processed by sqllin-processor at compile time to generate
+ * a class that represents a SQLite table. The annotated data class properties
+ * are mapped to table columns.
+ *
+ * @property tableName The name of the SQLite table. If not specified or empty,
+ * the name of the annotated class will be used as the table name.
+ *
* @author Yuang Qiao
*/
-
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
public annotation class DBRow(val tableName: String = "")
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DslMaker.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DslMaker.kt
index dee2613..faea3ce 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DslMaker.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/annotation/DslMaker.kt
@@ -17,25 +17,49 @@
package com.ctrip.sqllin.dsl.annotation
/**
- * Dsl maker annotations
+ * DSL marker for SQL statement functions to prevent implicit receiver nesting.
+ *
+ * Applied to top-level SQL statement functions (SELECT, INSERT, UPDATE, DELETE).
+ *
* @author Yuang Qiao
*/
-
@DslMarker
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
-public annotation class StatementDslMaker
+internal annotation class StatementDslMaker
+/**
+ * DSL marker for SQL keyword classes and properties to prevent implicit receiver nesting.
+ *
+ * Applied to SQL keyword constructs (WHERE, ORDER BY, etc.) and their properties.
+ *
+ * @author Yuang Qiao
+ */
@DslMarker
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.BINARY)
-public annotation class KeyWordDslMaker
+internal annotation class KeyWordDslMaker
+/**
+ * DSL marker for SQL function builders to prevent implicit receiver nesting.
+ *
+ * Applied to SQL function builder functions (aggregate functions, etc.).
+ *
+ * @author Yuang Qiao
+ */
@DslMarker
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
-public annotation class FunctionDslMaker
+internal annotation class FunctionDslMaker
+/**
+ * DSL marker for generated column name properties.
+ *
+ * This annotation is applied by sqllin-processor to generated table column properties.
+ * **Do not use this annotation manually** - it is intended for code generation only.
+ *
+ * @author Yuang Qiao
+ */
@DslMarker
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.BINARY)
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/PrimaryKeyInfo.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/PrimaryKeyInfo.kt
index ac44557..07be95d 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/PrimaryKeyInfo.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/PrimaryKeyInfo.kt
@@ -17,10 +17,37 @@
package com.ctrip.sqllin.dsl.sql
/**
- * Describe the information of primary key(s)
+ * Metadata describing a table's primary key configuration.
+ *
+ * This class captures information extracted from [@PrimaryKey][com.ctrip.sqllin.dsl.annotation.PrimaryKey]
+ * and [@CompositePrimaryKey][com.ctrip.sqllin.dsl.annotation.CompositePrimaryKey] annotations
+ * during code generation. It enables the DSL to properly handle INSERT and UPDATE operations
+ * with respect to primary key constraints.
+ *
+ * **Single Primary Key:**
+ * When a table has a single primary key column (marked with `@PrimaryKey`):
+ * - [primaryKeyName] contains the column name
+ * - [compositePrimaryKeys] is `null`
+ * - [isRowId] is `true` if the key is a `Long?` type (maps to SQLite's INTEGER PRIMARY KEY/rowid)
+ * - [isAutomaticIncrement] is `true` if `@PrimaryKey(isAutoincrement = true)` was specified
+ *
+ * **Composite Primary Key:**
+ * When a table has multiple primary key columns (marked with `@CompositePrimaryKey`):
+ * - [primaryKeyName] is `null`
+ * - [compositePrimaryKeys] contains the list of column names forming the composite key
+ * - [isRowId] is `false` (composite keys cannot use rowid alias)
+ * - [isAutomaticIncrement] is `false` (composite keys cannot auto-increment)
+ *
+ * **No Primary Key:**
+ * When a table has no primary key annotations, [Table.primaryKeyInfo] is `null`.
+ *
+ * @property primaryKeyName The name of the single primary key column, or `null` for composite keys
+ * @property isAutomaticIncrement Whether the primary key uses SQLite's AUTOINCREMENT keyword
+ * @property isRowId Whether the primary key is a `Long?` type that maps to SQLite's rowid
+ * @property compositePrimaryKeys List of column names forming a composite primary key, or `null` for single keys
+ *
* @author Yuang Qiao
*/
-
public class PrimaryKeyInfo(
internal val primaryKeyName: String?,
internal val isAutomaticIncrement: Boolean,
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/Table.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/Table.kt
index 6b7b38a..d2fa3a0 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/Table.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/Table.kt
@@ -19,14 +19,58 @@ package com.ctrip.sqllin.dsl.sql
import kotlinx.serialization.KSerializer
/**
- * SQL table
+ * Abstract base class representing a SQLite table with type-safe DSL operations.
+ *
+ * Table objects are typically generated by the sqllin-processor KSP plugin for data classes
+ * annotated with [@DBRow][com.ctrip.sqllin.dsl.annotation.DBRow]. Each generated table object
+ * (named `{ClassName}Table`) extends this class and provides:
+ *
+ * - Type-safe column property accessors for building SQL clauses
+ * - Serialization support via kotlinx.serialization
+ * - Primary key metadata for INSERT/UPDATE operations
+ *
+ * Table objects are used as receivers for DSL operations within [com.ctrip.sqllin.dsl.DatabaseScope]:
+ *
+ * Example:
+ * ```kotlin
+ * @Serializable
+ * @DBRow
+ * data class Person(val id: Long?, val name: String, val age: Int)
+ *
+ * // Generated by processor: object PersonTable : Table("Person") { ... }
+ *
+ * database {
+ * PersonTable INSERT person
+ * PersonTable SELECT WHERE(PersonTable.age GTE 18)
+ * }
+ * ```
+ *
+ * @param T The entity type this table represents
+ * @property tableName The name of the SQLite table
+ *
* @author Yuang Qiao
*/
-
public abstract class Table(
internal val tableName: String,
) {
+ /**
+ * Returns the kotlinx.serialization serializer for the entity type.
+ *
+ * Used internally for serializing entities to SQL INSERT/UPDATE statements
+ * and deserializing query results to entity objects.
+ */
public abstract fun kSerializer(): KSerializer
+ /**
+ * Metadata about the table's primary key configuration.
+ *
+ * - `null` if the table has no primary key
+ * - Contains information about single or composite primary keys, including
+ * whether the key is auto-incrementing or backed by SQLite's rowid
+ *
+ * This information is extracted from [@PrimaryKey][com.ctrip.sqllin.dsl.annotation.PrimaryKey]
+ * and [@CompositePrimaryKey][com.ctrip.sqllin.dsl.annotation.CompositePrimaryKey] annotations
+ * during code generation.
+ */
public abstract val primaryKeyInfo: PrimaryKeyInfo?
}
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/X.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/X.kt
index a44432a..6d2de9d 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/X.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/X.kt
@@ -19,9 +19,22 @@ package com.ctrip.sqllin.dsl.sql
import com.ctrip.sqllin.dsl.annotation.KeyWordDslMaker
/**
- * Express "*" in SQL
- * @author yaqiao
+ * Represents the wildcard `*` in SQL statements.
+ *
+ * Used in DSL operations where SQL requires a wildcard or universal selector:
+ * - `SELECT *`: Select all columns from a table
+ * - `DELETE *`: Delete all records from a table
+ *
+ * Example:
+ * ```kotlin
+ * // SELECT * FROM PersonTable
+ * val allPeople = PersonTable SELECT X
+ *
+ * // DELETE FROM PersonTable
+ * PersonTable DELETE X
+ * ```
+ *
+ * @author Yuang Qiao
*/
-
@KeyWordDslMaker
public object X
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt
index b439e00..6cb79ad 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt
@@ -22,10 +22,16 @@ import com.ctrip.sqllin.dsl.sql.statement.JoinSelectStatement
import com.ctrip.sqllin.dsl.sql.statement.JoinStatementWithoutCondition
/**
- * SQL abstract "JOIN" clause
- * @author yaqiao
+ * Base class for JOIN clauses in SELECT statements.
+ *
+ * Generates SQL for joining multiple tables. Different JOIN types (INNER, LEFT OUTER, CROSS,
+ * NATURAL) extend this class with their specific SQL keywords.
+ *
+ * @param R The result entity type after JOIN
+ * @param tables Tables to join
+ *
+ * @author Yuang Qiao
*/
-
public sealed class BaseJoinClause(private vararg val tables: Table<*>) : SelectClause {
internal abstract val clauseName: String
@@ -41,8 +47,22 @@ public sealed class BaseJoinClause(private vararg val tables: Table<*>) : Sel
}
}
+/**
+ * NATURAL JOIN clause - automatically matches columns with the same name.
+ *
+ * Does not require ON or USING condition.
+ *
+ * @param R The result entity type after JOIN
+ */
public sealed class NaturalJoinClause(vararg tables: Table<*>) : BaseJoinClause(*tables)
+/**
+ * JOIN clause that requires an ON or USING condition.
+ *
+ * Returns [JoinStatementWithoutCondition] which must be completed with ON or USING.
+ *
+ * @param R The result entity type after JOIN
+ */
public sealed class JoinClause(vararg tables: Table<*>) : BaseJoinClause(*tables)
@StatementDslMaker
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Clause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Clause.kt
index be2ab9d..4d9483a 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Clause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Clause.kt
@@ -17,8 +17,18 @@
package com.ctrip.sqllin.dsl.sql.clause
/**
- * Abstract clause, include 'where', 'update set' and more
- * @author yaqiao
+ * Base interface for SQL clauses used in DSL operations.
+ *
+ * Marker interface for all clause types (WHERE, SET, ORDER BY, GROUP BY, HAVING, LIMIT, JOIN, etc.).
+ * Clauses are type-parameterized to ensure they operate on the correct entity type.
+ *
+ * Implementations include:
+ * - [SelectClause]: Clauses for SELECT statements (WHERE, ORDER BY, LIMIT, GROUP BY, HAVING, JOIN)
+ * - [SetClause]: SET clause for UPDATE statements
+ * - [ConditionClause]: Condition clauses for WHERE/HAVING
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
public sealed interface Clause
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt
index 3b89967..e4a602c 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt
@@ -19,16 +19,27 @@ package com.ctrip.sqllin.dsl.sql.clause
import com.ctrip.sqllin.dsl.sql.Table
/**
- * Clause Boolean, will be converted to number in SQL statement
- * @author yaqiao
+ * Wrapper for Boolean column/function references in SQL clauses.
+ *
+ * Provides comparison operators for Boolean values. Since SQLite stores booleans as integers
+ * (0 for false, 1 for true), comparisons are translated to numeric expressions:
+ * - `column IS true` → `column > 0`
+ * - `column IS false` → `column <= 0`
+ *
+ * @author Yuang Qiao
*/
-
public class ClauseBoolean(
valueName: String,
table: Table<*>,
isFunction: Boolean,
) : ClauseElement(valueName, table, isFunction) {
+ /**
+ * Creates a condition comparing this Boolean column/function to a value.
+ *
+ * @param bool The Boolean value to compare against
+ * @return Condition expression (e.g., `column > 0` for true, `column <= 0` for false)
+ */
internal infix fun _is(bool: Boolean): SelectCondition {
val sql = buildString {
if (!isFunction) {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseElement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseElement.kt
index 6db9961..064447c 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseElement.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseElement.kt
@@ -19,10 +19,29 @@ package com.ctrip.sqllin.dsl.sql.clause
import com.ctrip.sqllin.dsl.sql.Table
/**
- * Abstract clause element
- * @author yaqiao
+ * Base class for elements used in SQL clauses.
+ *
+ * Represents a reference to a database column or function that can be used in clause expressions.
+ * Clause elements maintain their source table and whether they represent a function call.
+ *
+ * Subclasses provide type-specific wrappers:
+ * - [ClauseBoolean]: Boolean column/function references with comparison operators
+ * - [ClauseNumber]: Numeric column/function references with arithmetic and comparison operators
+ * - [ClauseString]: String column/function references with text comparison operators
+ *
+ * Used in:
+ * - WHERE/HAVING conditions
+ * - ORDER BY expressions
+ * - GROUP BY columns
+ * - SET assignments
+ * - JOIN USING clauses
+ *
+ * @property valueName The column name or function expression
+ * @property table The table this element belongs to
+ * @property isFunction Whether this represents a function call (e.g., COUNT, SUM)
+ *
+ * @author Yuang Qiao
*/
-
public sealed class ClauseElement(
internal val valueName: String,
internal val table: Table<*>,
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt
index 03b8b31..d2a3f13 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt
@@ -19,51 +19,70 @@ package com.ctrip.sqllin.dsl.sql.clause
import com.ctrip.sqllin.dsl.sql.Table
/**
- * The 'WHERE' and 'HAVING' clause properties
- * @author yaqiao
+ * Wrapper for numeric column/function references in SQL clauses.
+ *
+ * Provides comparison and set operators for numeric values (Byte, Short, Int, Long, Float, Double).
+ * Supports comparisons against literal numbers or other numeric columns/functions.
+ *
+ * Available operators:
+ * - `lt`: Less than (<)
+ * - `lte`: Less than or equal (<=)
+ * - `eq`: Equals (=) - handles null with IS NULL
+ * - `neq`: Not equals (!=) - handles null with IS NOT NULL
+ * - `gt`: Greater than (>)
+ * - `gte`: Greater than or equal (>=)
+ * - `inIterable`: IN (value1, value2, ...)
+ * - `between`: BETWEEN start AND end
+ *
+ * @author Yuang Qiao
*/
-
public class ClauseNumber(
valueName: String,
table: Table<*>,
isFunction: Boolean,
) : ClauseElement(valueName, table, isFunction) {
- // Less than, <
+ /** Less than (<) */
internal infix fun lt(number: Number): SelectCondition = appendNumber("<", number)
- // Less than, append to ClauseNumber
+ /** Less than (<) - compare against another column/function */
internal infix fun lt(clauseNumber: ClauseNumber): SelectCondition = appendClauseNumber("<", clauseNumber)
- // Less than or equals to, <=
+ /** Less than or equal (<=) */
internal infix fun lte(number: Number): SelectCondition = appendNumber("<=", number)
- // Less than or equal to, append to ClauseNumber
+ /** Less than or equal (<=) - compare against another column/function */
internal infix fun lte(clauseNumber: ClauseNumber): SelectCondition = appendClauseNumber("<=", clauseNumber)
- // Equals, ==
+ /** Equals (=), or IS NULL if value is null */
internal infix fun eq(number: Number?): SelectCondition = appendNullableNumber("=", " IS", number)
- // Equals, append to ClauseNumber
+ /** Equals (=) - compare against another column/function */
internal infix fun eq(clauseNumber: ClauseNumber): SelectCondition = appendClauseNumber("=", clauseNumber)
- // Not equals to, !=
+ /** Not equals (!=), or IS NOT NULL if value is null */
internal infix fun neq(number: Number?): SelectCondition = appendNullableNumber("!=", " IS NOT", number)
- // Not equals to, append to ClauseNumber
+ /** Not equals (!=) - compare against another column/function */
internal infix fun neq(clauseNumber: ClauseNumber): SelectCondition = appendClauseNumber("!=", clauseNumber)
- // Greater than, >
+ /** Greater than (>) */
internal infix fun gt(number: Number): SelectCondition = appendNumber(">", number)
- // Greater, append to ClauseNumber
+ /** Greater than (>) - compare against another column/function */
internal infix fun gt(clauseNumber: ClauseNumber): SelectCondition = appendClauseNumber(">", clauseNumber)
- // Greater or equals to, >=
+ /** Greater than or equal (>=) */
internal infix fun gte(number: Number): SelectCondition = appendNumber(">=", number)
+ /** Greater than or equal (>=) - compare against another column/function */
internal infix fun gte(clauseNumber: ClauseNumber): SelectCondition = appendClauseNumber(">=", clauseNumber)
+ /**
+ * IN operator - checks if value is in the given set.
+ *
+ * Generates: `column IN (1, 2, 3, ...)`
+ */
internal infix fun inIterable(numbers: Iterable): SelectCondition {
val iterator = numbers.iterator()
require(iterator.hasNext()) { "Param 'numbers' must not be empty!!!" }
@@ -84,6 +103,11 @@ public class ClauseNumber(
return SelectCondition(sql, null)
}
+ /**
+ * BETWEEN operator - checks if value is within a range (inclusive).
+ *
+ * Generates: `column BETWEEN start AND end`
+ */
internal infix fun between(range: LongRange): SelectCondition {
val sql = buildString {
if (!isFunction) {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt
index 980ccfd..bd69901 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt
@@ -19,30 +19,51 @@ package com.ctrip.sqllin.dsl.sql.clause
import com.ctrip.sqllin.dsl.sql.Table
/**
- * Clause String
- * @author yaqiao
+ * Wrapper for String column/function references in SQL clauses.
+ *
+ * Provides comparison and pattern matching operators for string values. Supports comparisons
+ * against literal strings or other string columns/functions.
+ *
+ * Available operators:
+ * - `eq`: Equals (=) - handles null with IS NULL
+ * - `neq`: Not equals (!=) - handles null with IS NOT NULL
+ * - `like`: LIKE pattern matching (case-insensitive, supports % and _ wildcards)
+ * - `glob`: GLOB pattern matching (case-sensitive, supports * and ? wildcards)
+ *
+ * @author Yuang Qiao
*/
-
public class ClauseString(
valueName: String,
table: Table<*>,
isFunction: Boolean,
) : ClauseElement(valueName, table, isFunction) {
- // Equals, ==
+ /** Equals (=), or IS NULL if value is null */
internal infix fun eq(str: String?): SelectCondition = appendString("=", " IS", str)
- // Equals, append another ClauseString
+ /** Equals (=) - compare against another column/function */
internal infix fun eq(clauseString: ClauseString): SelectCondition = appendClauseString("=", clauseString)
- // Not equals to, !=
+ /** Not equals (!=), or IS NOT NULL if value is null */
internal infix fun neq(str: String?): SelectCondition = appendString("!=", " IS NOT", str)
- // Not equal to, append another ClauseString
+ /** Not equals (!=) - compare against another column/function */
internal infix fun neq(clauseString: ClauseString): SelectCondition = appendClauseString("!=", clauseString)
+ /**
+ * LIKE operator - case-insensitive pattern matching.
+ *
+ * Wildcards: `%` (any characters), `_` (single character)
+ * Example: `"John%"` matches "John", "Johnson", etc.
+ */
internal infix fun like(regex: String): SelectCondition = appendRegex(" LIKE ", regex)
+ /**
+ * GLOB operator - case-sensitive pattern matching.
+ *
+ * Wildcards: `*` (any characters), `?` (single character)
+ * Example: `"John*"` matches "John", "Johnson", etc. (case-sensitive)
+ */
internal infix fun glob(regex: String): SelectCondition = appendRegex(" GLOB ", regex)
private fun appendRegex(symbol: String, regex: String): SelectCondition {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt
index 81e2554..4270e05 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt
@@ -19,10 +19,21 @@ package com.ctrip.sqllin.dsl.sql.clause
import com.ctrip.sqllin.dsl.annotation.StatementDslMaker
/**
- * Abstract clause that could link conditions, include 'WHERE' and 'HAVING'
- * @author yaqiao
+ * Base class for condition-based clauses (WHERE, HAVING).
+ *
+ * Wraps a [SelectCondition] and provides the clause name. Generates SQL in the format:
+ * ` CLAUSE_NAME condition`
+ *
+ * This file also provides uppercase DSL operators for building conditions:
+ * - Numeric: LT, LTE, EQ, NEQ, GT, GTE, IN, BETWEEN
+ * - String: EQ, NEQ, LIKE, GLOB
+ * - Boolean: IS
+ * - Logic: AND, OR
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
public sealed class ConditionClause(private val selectCondition: SelectCondition) : SelectClause {
internal abstract val clauseName: String
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/CrossJoinClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/CrossJoinClause.kt
index f1a1d47..36687ce 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/CrossJoinClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/CrossJoinClause.kt
@@ -20,13 +20,32 @@ import com.ctrip.sqllin.dsl.annotation.StatementDslMaker
import com.ctrip.sqllin.dsl.sql.Table
/**
- * SQL "CROSS JOIN" clause
- * @author yaqiao
+ * CROSS JOIN clause - returns the Cartesian product of two tables.
+ *
+ * Generates SQL: ` CROSS JOIN table`
+ * Does not require ON or USING condition.
+ * Returns every combination of rows from both tables.
+ *
+ * **Warning**: Result size = (left rows) × (right rows). Use with caution on large tables.
+ *
+ * @param R The result entity type after JOIN
+ *
+ * @author Yuang Qiao
*/
-
internal class CrossJoinClause(vararg tables: Table<*>) : NaturalJoinClause(*tables) {
override val clauseName: String = " CROSS JOIN "
}
+/**
+ * Creates a CROSS JOIN clause (no ON/USING needed).
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(color) CROSS_JOIN (size)
+ * // Returns all color-size combinations
+ * ```
+ *
+ * **Warning**: Returns (left rows) × (right rows) results.
+ */
@StatementDslMaker
public fun CROSS_JOIN(vararg tables: Table<*>): NaturalJoinClause = CrossJoinClause(*tables)
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Function.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Function.kt
index 6b99fb0..aa31304 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Function.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/Function.kt
@@ -21,46 +21,90 @@ import com.ctrip.sqllin.dsl.sql.Table
import com.ctrip.sqllin.dsl.sql.X
/**
- * SQLite functions
- * @author yaqiao
+ * SQLite aggregate and scalar functions for use in SELECT clauses.
+ *
+ * These functions can be used in WHERE, HAVING, ORDER BY, and SELECT expressions.
+ * All functions return [ClauseElement] wrappers that can be compared with operators.
+ *
+ * @author Yuang Qiao
*/
+/**
+ * COUNT aggregate function - counts non-NULL values.
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(user) GROUP_BY (user.department) HAVING (count(user.id) GT 5)
+ * ```
+ */
@FunctionDslMaker
public fun Table.count(element: ClauseElement): ClauseNumber =
ClauseNumber("count(${element.valueName})", this, true)
+/**
+ * COUNT(*) aggregate function - counts all rows (including NULLs).
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(user) WHERE (count(X) GT 100)
+ * ```
+ */
@FunctionDslMaker
public fun Table.count(x: X): ClauseNumber =
ClauseNumber("count(*)", this, true)
+/**
+ * MAX aggregate function - returns maximum value.
+ */
@FunctionDslMaker
public fun Table.max(element: ClauseElement): ClauseNumber =
ClauseNumber("max(${element.valueName})", this, true)
+/**
+ * MIN aggregate function - returns minimum value.
+ */
@FunctionDslMaker
public fun Table.min(element: ClauseElement): ClauseNumber =
ClauseNumber("min(${element.valueName})", this, true)
+/**
+ * AVG aggregate function - returns average value.
+ */
@FunctionDslMaker
public fun Table.avg(element: ClauseElement): ClauseNumber =
ClauseNumber("avg(${element.valueName})", this, true)
+/**
+ * SUM aggregate function - returns sum of values.
+ */
@FunctionDslMaker
public fun Table.sum(element: ClauseElement): ClauseNumber =
ClauseNumber("sum(${element.valueName})", this, true)
+/**
+ * ABS scalar function - returns absolute value.
+ */
@FunctionDslMaker
public fun Table.abs(number: ClauseElement): ClauseNumber =
ClauseNumber("abs(${number.valueName})", this, true)
+/**
+ * UPPER scalar function - converts string to uppercase.
+ */
@FunctionDslMaker
public fun Table.upper(element: ClauseElement): ClauseString =
ClauseString("upper(${element.valueName})", this, true)
+/**
+ * LOWER scalar function - converts string to lowercase.
+ */
@FunctionDslMaker
public fun Table.lower(element: ClauseElement): ClauseString =
ClauseString("lower(${element.valueName})", this, true)
+/**
+ * LENGTH scalar function - returns string/blob length in bytes.
+ */
@FunctionDslMaker
public fun Table.length(element: ClauseElement): ClauseNumber =
ClauseNumber("length(${element.valueName})", this, true)
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/GroupByClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/GroupByClause.kt
index 005dad1..cf4cb1e 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/GroupByClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/GroupByClause.kt
@@ -22,10 +22,19 @@ import com.ctrip.sqllin.dsl.sql.statement.JoinSelectStatement
import com.ctrip.sqllin.dsl.sql.statement.WhereSelectStatement
/**
- * SQL 'GROUP BY' clause by select statement
- * @author yaqiao
+ * GROUP BY clause for grouping rows in SELECT queries with aggregate functions.
+ *
+ * Generates SQL in the format: ` GROUP BY column1, column2, ...`
+ *
+ * Used with aggregate functions (COUNT, SUM, AVG, etc.) to group results:
+ * ```kotlin
+ * SELECT(user) GROUP_BY (user.department) HAVING (COUNT(user.id) GT 5)
+ * ```
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
public class GroupByClause internal constructor(private val columnNames: Iterable) : SelectClause {
override val clauseStr: String
@@ -41,6 +50,9 @@ public class GroupByClause internal constructor(private val columnNames: Iter
}
}
+/**
+ * Creates a GROUP BY clause for aggregating rows.
+ */
@StatementDslMaker
public fun GROUP_BY(vararg elements: ClauseElement): GroupByClause = GroupByClause(elements.toList())
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt
index 1ae5434..2cd0c31 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt
@@ -21,10 +21,21 @@ import com.ctrip.sqllin.dsl.sql.statement.GroupBySelectStatement
import com.ctrip.sqllin.dsl.sql.statement.HavingSelectStatement
/**
- * SQL 'HAVING' clause by select statement
- * @author yaqiao
+ * HAVING clause for filtering grouped rows in SELECT queries.
+ *
+ * Similar to WHERE but operates on aggregated data after GROUP BY. Generates SQL in the format:
+ * ` HAVING condition`
+ *
+ * Used to filter groups based on aggregate function results:
+ * ```kotlin
+ * SELECT(user) GROUP_BY (user.department) HAVING (COUNT(user.id) GT 5)
+ * // Returns only departments with more than 5 users
+ * ```
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
internal class HavingClause(val selectCondition: SelectCondition) : ConditionClause(selectCondition) {
override val clauseName: String = "HAVING"
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt
index dfa0bb6..78bc8eb 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt
@@ -20,10 +20,15 @@ import com.ctrip.sqllin.dsl.annotation.StatementDslMaker
import com.ctrip.sqllin.dsl.sql.Table
/**
- * SQL "INNER JOIN" clause
- * @author yaqiao
+ * INNER JOIN clause - returns rows where there's a match in both tables.
+ *
+ * Generates SQL: ` JOIN table`
+ * Requires ON or USING condition.
+ *
+ * @param R The result entity type after JOIN
+ *
+ * @author Yuang Qiao
*/
-
internal class InnerJoinClause(
vararg tables: Table<*>,
) : JoinClause(*tables) {
@@ -31,12 +36,34 @@ internal class InnerJoinClause(
override val clauseName: String = " JOIN "
}
+/**
+ * Creates an INNER JOIN clause (requires ON or USING).
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(user) JOIN (order) ON (user.id EQ order.userId)
+ * SELECT(user) JOIN (order) USING (user.id)
+ * ```
+ */
@StatementDslMaker
public fun JOIN(vararg tables: Table<*>): JoinClause = InnerJoinClause(*tables)
+/**
+ * Alias for [JOIN] - creates an INNER JOIN clause.
+ */
@StatementDslMaker
public inline fun INNER_JOIN(vararg tables: Table<*>): JoinClause = JOIN(*tables)
+/**
+ * NATURAL INNER JOIN - automatically joins on columns with matching names.
+ *
+ * Generates SQL: ` NATURAL JOIN table`
+ * Does not require ON or USING.
+ *
+ * @param R The result entity type after JOIN
+ *
+ * @author Yuang Qiao
+ */
internal class NaturalInnerJoinClause(
vararg tables: Table<*>,
) : NaturalJoinClause(*tables) {
@@ -44,8 +71,19 @@ internal class NaturalInnerJoinClause(
override val clauseName: String = " NATURAL JOIN "
}
+/**
+ * Creates a NATURAL JOIN clause (no ON/USING needed).
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(user) NATURAL_JOIN (profile) // Joins on matching column names
+ * ```
+ */
@StatementDslMaker
public fun NATURAL_JOIN(vararg tables: Table<*>): NaturalJoinClause = NaturalInnerJoinClause(*tables)
+/**
+ * Alias for [NATURAL_JOIN].
+ */
@StatementDslMaker
public inline fun NATURAL_INNER_JOIN(vararg tables: Table<*>): NaturalJoinClause = NATURAL_JOIN(*tables)
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LeftOuterJoinClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LeftOuterJoinClause.kt
index 7fe80af..9ba0235 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LeftOuterJoinClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LeftOuterJoinClause.kt
@@ -20,10 +20,16 @@ import com.ctrip.sqllin.dsl.annotation.StatementDslMaker
import com.ctrip.sqllin.dsl.sql.Table
/**
- * SQL "LEFT OUTER JOIN" clause
- * @author yaqiao
+ * LEFT OUTER JOIN clause - returns all rows from the left table and matching rows from the right.
+ *
+ * Generates SQL: ` LEFT OUTER JOIN table`
+ * Requires ON or USING condition.
+ * Returns NULL for right table columns when there's no match.
+ *
+ * @param R The result entity type after JOIN
+ *
+ * @author Yuang Qiao
*/
-
internal class LeftOuterJoinClause(
vararg tables: Table<*>
) : JoinClause(*tables) {
@@ -31,9 +37,29 @@ internal class LeftOuterJoinClause(
override val clauseName: String = " LEFT OUTER JOIN "
}
+/**
+ * Creates a LEFT OUTER JOIN clause (requires ON or USING).
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(user) LEFT_OUTER_JOIN (order) ON (user.id EQ order.userId)
+ * // Returns all users, including those without orders
+ * ```
+ */
@StatementDslMaker
public fun LEFT_OUTER_JOIN(vararg tables: Table<*>): JoinClause = LeftOuterJoinClause(*tables)
+/**
+ * NATURAL LEFT OUTER JOIN - automatically joins on matching column names.
+ *
+ * Generates SQL: ` NATURAL LEFT OUTER JOIN table`
+ * Does not require ON or USING.
+ * Returns all left table rows, with NULLs for non-matching right table columns.
+ *
+ * @param R The result entity type after JOIN
+ *
+ * @author Yuang Qiao
+ */
internal class NaturalLeftOuterJoinClause(
vararg tables: Table<*>
) : NaturalJoinClause(*tables) {
@@ -41,5 +67,13 @@ internal class NaturalLeftOuterJoinClause(
override val clauseName: String = " NATURAL LEFT OUTER JOIN "
}
+/**
+ * Creates a NATURAL LEFT OUTER JOIN clause (no ON/USING needed).
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(user) NATURAL_LEFT_OUTER_JOIN (profile)
+ * ```
+ */
@StatementDslMaker
public fun NATURAL_LEFT_OUTER_JOIN(vararg tables: Table<*>): NaturalJoinClause = NaturalLeftOuterJoinClause(*tables)
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LimitClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LimitClause.kt
index 9f15aae..6ab9df0 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LimitClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/LimitClause.kt
@@ -20,10 +20,19 @@ import com.ctrip.sqllin.dsl.annotation.StatementDslMaker
import com.ctrip.sqllin.dsl.sql.statement.*
/**
- * SQL 'LIMIT' clause by select statement
- * @author yaqiao
+ * LIMIT clause for restricting the number of rows returned by a SELECT query.
+ *
+ * Generates SQL in the format: ` LIMIT count`
+ *
+ * Often combined with OFFSET for pagination:
+ * ```kotlin
+ * SELECT(user) ORDER_BY (user.id to ASC) LIMIT 10 OFFSET 20 // Skip 20, take 10
+ * ```
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
public class LimitClause internal constructor(
private val count: Int,
) : SelectClause {
@@ -31,6 +40,9 @@ public class LimitClause internal constructor(
get() = " LIMIT $count"
}
+/**
+ * Creates a LIMIT clause to restrict result count.
+ */
@StatementDslMaker
public fun LIMIT(count: Int): LimitClause = LimitClause(count)
@@ -59,9 +71,19 @@ public infix fun JoinSelectStatement.LIMIT(count: Int): LimitSelectStatem
}
/**
- * SQL 'OFFSET' clause by select statement
+ * OFFSET clause for skipping rows in a SELECT query (pagination).
+ *
+ * Generates SQL in the format: ` OFFSET rowNo`
+ *
+ * Must follow a LIMIT clause. Used for pagination:
+ * ```kotlin
+ * SELECT(user) LIMIT 10 OFFSET 20 // Skip first 20 rows, return next 10
+ * ```
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
public class OffsetClause internal constructor(
private val rowNo: Int,
) : SelectClause {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt
index 901267f..c66c263 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt
@@ -21,10 +21,18 @@ import com.ctrip.sqllin.dsl.annotation.StatementDslMaker
import com.ctrip.sqllin.dsl.sql.statement.*
/**
- * SQL 'order by' clause by select statement
- * @author yaqiao
+ * ORDER BY clause for sorting SELECT query results.
+ *
+ * Generates SQL in the format: ` ORDER BY column1 ASC, column2 DESC, ...`
+ *
+ * Supports two modes:
+ * - Explicit direction: `ORDER_BY(user.name to ASC, user.age to DESC)`
+ * - Default ascending: `ORDER_BY(user.name, user.age)`
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
public sealed interface OrderByClause : SelectClause
internal class CompleteOrderByClause(private val column2WayMap: Map) : OrderByClause {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectClause.kt
index e252b32..f2d6f1a 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectClause.kt
@@ -17,10 +17,25 @@
package com.ctrip.sqllin.dsl.sql.clause
/**
- * The SQL clause that could used for 'select' statement
- * @author yaqiao
+ * Base interface for clauses used in SELECT statements.
+ *
+ * Represents SQL clauses that can be appended to SELECT queries to filter, order, group,
+ * limit, or join data. Each implementation provides its SQL string representation.
+ *
+ * Implementations:
+ * - [WhereClause]: WHERE condition filtering
+ * - [OrderByClause]: ORDER BY sorting
+ * - [LimitClause]: LIMIT row count restriction
+ * - [OffsetClause]: OFFSET row skipping
+ * - [GroupByClause]: GROUP BY aggregation grouping
+ * - [HavingClause]: HAVING condition for grouped data
+ * - [JoinClause], [InnerJoinClause], [LeftOuterJoinClause], [CrossJoinClause], [NaturalJoinClause]: JOIN operations
+ *
+ * @param T The entity type this clause operates on
+ * @property clauseStr The SQL string representation (e.g., " WHERE id = ?", " ORDER BY name ASC")
+ *
+ * @author Yuang Qiao
*/
-
public sealed interface SelectClause : Clause {
public val clauseStr: String
}
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt
index 49cd92e..f01af77 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt
@@ -17,19 +17,39 @@
package com.ctrip.sqllin.dsl.sql.clause
/**
- * Present the single condition in where clause
- * @author yaqiao
+ * Represents a condition expression used in WHERE or HAVING clauses.
+ *
+ * Encapsulates a single condition (e.g., `id = ?`, `age > 18`) along with its parameterized
+ * values. Supports combining conditions with AND/OR operators to build complex predicates.
+ *
+ * Conditions are built by comparison operations on [ClauseElement] instances:
+ * ```kotlin
+ * userTable.id EQ 42 // Creates: SelectCondition("id = ?", ["42"])
+ * userTable.age GT 18 // Creates: SelectCondition("age > ?", ["18"])
+ * ```
+ *
+ * @property conditionSQL The SQL condition expression (may contain ? placeholders)
+ * @property parameters Parameterized query values (strings only), or null if none
+ *
+ * @author Yuang Qiao
*/
-
public class SelectCondition internal constructor(
internal val conditionSQL: String,
internal val parameters: MutableList?,
) {
- // Where condition 'OR' operator.
+ /**
+ * Combines this condition with another using OR.
+ *
+ * Creates: `(condition1) OR (condition2)`
+ */
internal infix fun or(next: SelectCondition): SelectCondition = append("OR", next)
- // Where condition 'AND' operator.
+ /**
+ * Combines this condition with another using AND.
+ *
+ * Creates: `(condition1) AND (condition2)`
+ */
internal infix fun and(next: SelectCondition): SelectCondition = append("AND", next)
private fun append(symbol: String, next: SelectCondition): SelectCondition {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt
index b3c25b7..d0925d6 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt
@@ -19,10 +19,22 @@ package com.ctrip.sqllin.dsl.sql.clause
import com.ctrip.sqllin.dsl.annotation.StatementDslMaker
/**
- * Present the single prediction in set clause
- * @author yaqiao
+ * SET clause for UPDATE statements.
+ *
+ * Builds column assignments in the format: `column1 = ?, column2 = ?, ...`
+ *
+ * Used in UPDATE operations to specify new values:
+ * ```kotlin
+ * UPDATE(user) SET {
+ * it.name = "John"
+ * it.age = 30
+ * } WHERE (user.id EQ 42)
+ * ```
+ *
+ * @param T The entity type being updated
+ *
+ * @author Yuang Qiao
*/
-
public class SetClause : Clause {
private val clauseBuilder = StringBuilder()
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt
index f507b30..8f2c6ec 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt
@@ -23,10 +23,14 @@ import com.ctrip.sqllin.dsl.sql.statement.UpdateStatementWithoutWhereClause
import com.ctrip.sqllin.dsl.sql.statement.WhereSelectStatement
/**
- * SQL "WHERE" clause
- * @author yaqiao
+ * WHERE clause for filtering rows in SELECT statements or targeting rows in UPDATE/DELETE statements.
+ *
+ * Wraps a [SelectCondition] and generates SQL in the format: ` WHERE condition`
+ *
+ * @param T The entity type this clause operates on
+ *
+ * @author Yuang Qiao
*/
-
public class WhereClause internal constructor(
internal val selectCondition: SelectCondition,
) : ConditionClause(selectCondition) {
@@ -34,6 +38,16 @@ public class WhereClause internal constructor(
override val clauseName: String = "WHERE"
}
+/**
+ * Creates a WHERE clause for use in DSL operations.
+ *
+ * Usage:
+ * ```kotlin
+ * SELECT(user) WHERE (user.id EQ 42)
+ * UPDATE(user) SET { it.name = "John" } WHERE (user.id EQ 42)
+ * DELETE(user) WHERE (user.age GT 18)
+ * ```
+ */
@StatementDslMaker
public fun WHERE(condition: SelectCondition): WhereClause = WhereClause(condition)
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt
index 41c6b95..4c696e7 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt
@@ -23,23 +23,46 @@ import kotlinx.serialization.modules.EmptySerializersModule
import kotlinx.serialization.modules.SerializersModule
/**
- * Abstract Encode the object to UPDATE statement
- * @author yaqiao
+ * Base encoder for converting Kotlin objects to SQL VALUES clauses using kotlinx.serialization.
+ *
+ * This abstract class leverages kotlinx.serialization's encoder API to traverse entity objects
+ * and generate SQL parameter placeholders (for strings) or inline values (for numbers/booleans).
+ * String values are replaced with `?` placeholders and collected in [parameters] for safe
+ * parameterized queries.
+ *
+ * Subclasses must implement [appendTail] to control punctuation between values (e.g., commas,
+ * parentheses) depending on the SQL statement type.
+ *
+ * @author Yuang Qiao
*/
-
@OptIn(ExperimentalSerializationApi::class)
internal abstract class AbstractValuesEncoder : AbstractEncoder() {
final override val serializersModule: SerializersModule = EmptySerializersModule()
+ /**
+ * StringBuilder accumulating the SQL VALUES clause.
+ */
protected abstract val sqlStrBuilder: StringBuilder
+
+ /**
+ * List collecting string parameter values for parameterized queries.
+ */
abstract val parameters: MutableList
+ /**
+ * Appends appropriate punctuation after each encoded value.
+ *
+ * Implementations determine whether to append commas, closing parentheses, etc.
+ */
protected abstract fun StringBuilder.appendTail(): StringBuilder
protected var elementsIndex = 0
protected var elementsCount = 0
+ /**
+ * The complete SQL VALUES clause generated by this encoder.
+ */
val valuesSQL
get() = sqlStrBuilder.toString()
@@ -49,6 +72,9 @@ internal abstract class AbstractValuesEncoder : AbstractEncoder() {
return true
}
+ /**
+ * Encodes Boolean as SQLite integer (1 for true, 0 for false).
+ */
override fun encodeBoolean(value: Boolean) = encodeByte(if (value) 1 else 0)
override fun encodeByte(value: Byte) {
@@ -67,8 +93,17 @@ internal abstract class AbstractValuesEncoder : AbstractEncoder() {
sqlStrBuilder.append(value).appendTail()
}
+ /**
+ * Encodes Char as a string.
+ */
override fun encodeChar(value: Char) = encodeString(value.toString())
+ /**
+ * Encodes String as a parameterized placeholder.
+ *
+ * Appends `?` to the SQL and adds the actual value to [parameters]
+ * for safe parameterized query execution.
+ */
override fun encodeString(value: String) {
sqlStrBuilder.append('?').appendTail()
parameters.add(value)
@@ -86,5 +121,8 @@ internal abstract class AbstractValuesEncoder : AbstractEncoder() {
sqlStrBuilder.append("NULL").appendTail()
}
+ /**
+ * Encodes enum as its ordinal integer value.
+ */
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = encodeInt(index)
}
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt
index 4fd7475..2543967 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt
@@ -20,10 +20,29 @@ import com.ctrip.sqllin.dsl.sql.Table
import kotlinx.serialization.descriptors.SerialDescriptor
/**
- * Some function that used for encode entities to SQL
+ * Utility functions for encoding entity objects to SQL statements.
+ *
* @author Yuang Qiao
*/
+/**
+ * Encodes a collection of entities into an INSERT statement's VALUES clause.
+ *
+ * Generates SQL in the format:
+ * ```
+ * (column1, column2, ...) VALUES (?, ?, ...), (?, ?, ...), ...
+ * ```
+ *
+ * Handles primary key logic:
+ * - For auto-increment `Long?` primary keys, omits the ID column unless [isInsertWithId] is true
+ * - For user-provided primary keys or composite keys, includes all columns
+ *
+ * @param table The table definition containing serialization and primary key metadata
+ * @param builder StringBuilder to append the SQL to
+ * @param values The entities to insert
+ * @param parameters Mutable list to collect parameterized query values
+ * @param isInsertWithId Whether to include the primary key column for rowid-backed keys
+ */
internal fun encodeEntities2InsertValues(
table: Table,
builder: StringBuilder,
@@ -59,6 +78,14 @@ internal fun encodeEntities2InsertValues(
}
}
+/**
+ * Appends database column names to the StringBuilder, optionally excluding a primary key.
+ *
+ * @param descriptor The serialization descriptor containing column/element names
+ * @param primaryKeyName The name of the primary key column to potentially exclude
+ * @param isInsertId Whether to include the primary key column
+ * @return The index of the excluded primary key column, or -1 if all columns were included
+ */
internal fun StringBuilder.appendDBColumnName(
descriptor: SerialDescriptor,
primaryKeyName: String?,
@@ -86,6 +113,9 @@ internal fun StringBuilder.appendDBColumnName(
index
}
+/**
+ * Appends all database column names from the descriptor as a comma-separated list.
+ */
internal infix fun StringBuilder.appendDBColumnName(descriptor: SerialDescriptor) {
if (descriptor.elementsCount > 0)
append(descriptor.getElementName(0))
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt
index 6d3d94d..31357ba 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt
@@ -17,16 +17,26 @@
package com.ctrip.sqllin.dsl.sql.compiler
/**
- * Encode the object to INSERT SQL statement
- * @author yaqiao
+ * Encoder for generating VALUES clauses in INSERT statements.
+ *
+ * Produces SQL in the format: `(value1, value2, ..., valueN)`
+ *
+ * Each entity is encoded into a parenthesized tuple of values, with commas separating
+ * elements within the tuple.
+ *
+ * Example output: `(123, 'Alice', 25)` or `(?, ?, ?)` with parameters `["Alice"]`
+ *
+ * @author Yuang Qiao
*/
-
internal class InsertValuesEncoder(
override val parameters: MutableList,
) : AbstractValuesEncoder() {
override val sqlStrBuilder = StringBuilder("(")
+ /**
+ * Appends comma between values or closing parenthesis after the last value.
+ */
override fun StringBuilder.appendTail(): StringBuilder {
val symbol = if (elementsIndex < elementsCount - 1)
','
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/QueryDecoder.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/QueryDecoder.kt
index 0b8af6f..3b05694 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/QueryDecoder.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/QueryDecoder.kt
@@ -26,10 +26,20 @@ import kotlinx.serialization.modules.EmptySerializersModule
import kotlinx.serialization.modules.SerializersModule
/**
- * Decoder the `CommonCursor` to object when SQLite query
- * @author yaqiao
+ * Decoder for converting SQLite query results to Kotlin objects using kotlinx.serialization.
+ *
+ * This decoder reads data from a [CommonCursor] (representing a SQLite result set) and
+ * deserializes it into strongly-typed entity objects. It maps cursor columns to object
+ * properties by matching column names with serialization descriptor element names.
+ *
+ * The decoder handles:
+ * - Type conversions from SQLite types to Kotlin types
+ * - Null value handling for nullable properties
+ * - Boolean mapping (SQLite integers to Kotlin booleans)
+ * - Enum deserialization (ordinal values to enum instances)
+ *
+ * @author Yuang Qiao
*/
-
@OptIn(ExperimentalSerializationApi::class)
internal class QueryDecoder(
private val cursor: CommonCursor
@@ -41,6 +51,11 @@ internal class QueryDecoder(
override val serializersModule: SerializersModule = EmptySerializersModule()
+ /**
+ * Determines the next property to decode from the descriptor.
+ *
+ * Skips properties that don't have corresponding columns in the cursor.
+ */
override tailrec fun decodeElementIndex(descriptor: SerialDescriptor): Int =
if (elementIndex == descriptor.elementsCount)
CompositeDecoder.DECODE_DONE
@@ -56,23 +71,41 @@ internal class QueryDecoder(
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder = QueryDecoder(cursor)
+ /**
+ * Resolves the cursor column index for the current element name.
+ */
private inline val cursorColumnIndex
get() = cursor.getColumnIndex(elementName)
+ /**
+ * Helper to safely deserialize a value from the cursor with column validation.
+ */
private inline fun deserialize(block: (Int) -> T): T = cursorColumnIndex.let {
if (it >= 0) block(it) else throw SerializationException("The Cursor doesn't have this column")
}
+ /**
+ * Decodes SQLite integer (1/0) to Boolean (true/false).
+ */
override fun decodeBoolean(): Boolean = deserialize { cursor.getInt(it) > 0 }
override fun decodeByte(): Byte = deserialize { cursor.getInt(it).toByte() }
override fun decodeShort(): Short = deserialize { cursor.getInt(it).toShort() }
override fun decodeInt(): Int = deserialize { cursor.getInt(it) }
override fun decodeLong(): Long = deserialize { cursor.getLong(it) }
+ /**
+ * Decodes first character of string, or null character if string is null.
+ */
override fun decodeChar(): Char = deserialize { cursor.getString(it)?.first() ?: '\u0000' }
override fun decodeString(): String = deserialize { cursor.getString(it) ?: "" }
override fun decodeFloat(): Float = deserialize { cursor.getFloat(it) }
override fun decodeDouble(): Double = deserialize { cursor.getDouble(it) }
+ /**
+ * Decodes enum by its ordinal value stored as an integer.
+ */
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = deserialize { cursor.getInt(it) }
+ /**
+ * Determines if the current column contains a non-null value.
+ */
override fun decodeNotNullMark(): Boolean = !cursor.isNull(cursorColumnIndex) || !elementNullable
}
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Create.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Create.kt
index 12a6920..256bad7 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Create.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Create.kt
@@ -21,18 +21,50 @@ import com.ctrip.sqllin.dsl.sql.Table
import com.ctrip.sqllin.dsl.sql.statement.CreateStatement
/**
- * SQL create
+ * CREATE TABLE operation builder.
+ *
+ * Constructs CREATE TABLE statements by inspecting entity serialization descriptors and
+ * generating appropriate SQLite column definitions with type mappings, nullability constraints,
+ * and primary key declarations.
+ *
* @author Yuang Qiao
*/
-
internal object Create : Operation {
override val sqlStr: String
get() = "CREATE TABLE "
+ /**
+ * Builds a CREATE TABLE statement for the given table definition.
+ *
+ * @param table Table definition containing entity metadata
+ * @param connection Database connection for execution
+ * @return CREATE statement ready for execution
+ */
fun create(table: Table, connection: DatabaseConnection): CreateStatement =
CreateStatement(buildSQL(table), connection)
+ /**
+ * Generates the CREATE TABLE SQL by inspecting entity properties.
+ *
+ * Maps Kotlin types to SQLite types:
+ * - Byte/UByte → TINYINT
+ * - Short/UShort → SMALLINT
+ * - Int/UInt → INT
+ * - Long → INTEGER (for primary keys with AUTOINCREMENT) or BIGINT
+ * - ULong → BIGINT
+ * - Float → FLOAT
+ * - Double → DOUBLE
+ * - Boolean → BOOLEAN
+ * - Char → CHAR(1)
+ * - String → TEXT
+ * - ByteArray → BLOB
+ *
+ * Handles:
+ * - Nullable properties (omit NOT NULL constraint)
+ * - Single primary keys (PRIMARY KEY, optionally AUTOINCREMENT)
+ * - Composite primary keys (PRIMARY KEY clause at end)
+ */
private fun buildSQL(table: Table): String = buildString {
append(sqlStr)
append(table.tableName)
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt
index a921dc3..5e17e46 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt
@@ -23,15 +23,28 @@ import com.ctrip.sqllin.dsl.sql.clause.WhereClause
import com.ctrip.sqllin.dsl.sql.statement.UpdateDeleteStatement
/**
- * SQL delete
- * @author yaqiao
+ * DELETE operation builder.
+ *
+ * Constructs DELETE statements with optional WHERE clauses. Supports both targeted deletion
+ * (with WHERE) and bulk deletion (all rows).
+ *
+ * @author Yuang Qiao
*/
-
internal object Delete : Operation {
override val sqlStr: String
get() = "DELETE FROM "
+ /**
+ * Builds a DELETE statement with WHERE clause.
+ *
+ * Generates SQL in the format: `DELETE FROM table WHERE condition`
+ *
+ * @param table Table to delete from
+ * @param connection Database connection for execution
+ * @param whereClause WHERE condition specifying which rows to delete
+ * @return Final DELETE statement ready for execution
+ */
fun delete(table: Table<*>, connection: DatabaseConnection, whereClause: WhereClause): SingleStatement {
val sql = buildString {
buildBaseDeleteStatement(table)
@@ -40,6 +53,15 @@ internal object Delete : Operation {
return UpdateDeleteStatement(sql, connection, whereClause.selectCondition.parameters)
}
+ /**
+ * Builds a DELETE statement without WHERE clause (deletes all rows).
+ *
+ * Generates SQL in the format: `DELETE FROM table`
+ *
+ * @param table Table to delete all rows from
+ * @param connection Database connection for execution
+ * @return Final DELETE statement ready for execution
+ */
fun deleteAllEntities(table: Table<*>, connection: DatabaseConnection): SingleStatement {
val sql = buildString {
buildBaseDeleteStatement(table)
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/FullNameCache.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/FullNameCache.kt
index 7a65088..45b4270 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/FullNameCache.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/FullNameCache.kt
@@ -17,10 +17,21 @@
package com.ctrip.sqllin.dsl.sql.operation
/**
- * Cache for primitive types' qualified name
+ * Cached qualified names for Kotlin types used in SQLite type mapping.
+ *
+ * Provides pre-computed fully qualified names for performance during CREATE TABLE generation.
+ * These names are matched against kotlinx.serialization descriptor serial names to determine
+ * the appropriate SQLite column type.
+ *
+ * Used by [Create.buildSQL] to map Kotlin types to SQLite types:
+ * - Integer types → TINYINT, SMALLINT, INT, BIGINT, INTEGER
+ * - Floating-point types → FLOAT, DOUBLE
+ * - Boolean → BOOLEAN
+ * - Character/String → CHAR(1), TEXT
+ * - ByteArray → BLOB
+ *
* @author Yuang Qiao
*/
-
internal object FullNameCache {
val BYTE = Byte::class.qualifiedName!!
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt
index f2377a4..2b94242 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt
@@ -23,15 +23,32 @@ import com.ctrip.sqllin.dsl.sql.Table
import com.ctrip.sqllin.dsl.sql.compiler.encodeEntities2InsertValues
/**
- * SQL insert
+ * INSERT operation builder.
+ *
+ * Constructs INSERT statements by encoding entity objects into SQL VALUES clauses with
+ * parameterized queries. Supports both auto-generated primary keys and user-provided keys.
+ *
* @author Yuang Qiao
*/
-
internal object Insert : Operation {
override val sqlStr: String
get() = "INSERT INTO "
+ /**
+ * Builds an INSERT statement for the given entities.
+ *
+ * Generates SQL in the format:
+ * ```
+ * INSERT INTO table_name (column1, column2, ...) VALUES (?, ?, ...), (?, ?, ...), ...
+ * ```
+ *
+ * @param table Table definition containing serialization metadata
+ * @param connection Database connection for execution
+ * @param entities Entities to insert
+ * @param isInsertWithId Whether to include the primary key column for auto-increment keys
+ * @return INSERT statement ready for execution
+ */
fun insert(table: Table, connection: DatabaseConnection, entities: Iterable, isInsertWithId: Boolean = false): SingleStatement {
val parameters = ArrayList()
val sql = buildString {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Operation.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Operation.kt
index 0cd4695..58fa385 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Operation.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Operation.kt
@@ -17,10 +17,22 @@
package com.ctrip.sqllin.dsl.sql.operation
/**
- * SQL operation: SELECT, UPDATE, DELETE, INSERT
- * @author yaqiao
+ * Base interface for SQL operations in the DSL.
+ *
+ * Marker interface for operation builders (SELECT, UPDATE, DELETE, INSERT, CREATE) that construct
+ * SQL strings. Each operation implementation accumulates clauses and generates the final SQL.
+ *
+ * Implementations:
+ * - [SelectBuilder]: SELECT queries
+ * - [UpdateBuilder]: UPDATE statements
+ * - [DeleteBuilder]: DELETE statements
+ * - [InsertBuilder]: INSERT statements
+ * - [CreateBuilder]: CREATE TABLE statements
+ *
+ * @property sqlStr The accumulated SQL string built by this operation
+ *
+ * @author Yuang Qiao
*/
-
internal interface Operation {
val sqlStr: String
}
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt
index 69e37e8..feecfab 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt
@@ -24,15 +24,24 @@ import com.ctrip.sqllin.dsl.sql.statement.*
import kotlinx.serialization.DeserializationStrategy
/**
- * SQL query
- * @author yaqiao
+ * SELECT operation builder.
+ *
+ * Constructs SELECT statements by combining table information with clauses (WHERE, ORDER BY,
+ * LIMIT, GROUP BY, JOIN). Creates the appropriate statement type based on which clauses are
+ * initially provided, enforcing compile-time clause ordering through the statement hierarchy.
+ *
+ * @author Yuang Qiao
*/
-
internal object Select : Operation {
override val sqlStr: String
get() = "SELECT "
+ /**
+ * Builds a SELECT statement with WHERE clause.
+ *
+ * @return Statement that can be followed by GROUP BY, ORDER BY, or LIMIT
+ */
fun select(
table: Table,
clause: WhereClause,
@@ -43,6 +52,11 @@ internal object Select : Operation {
): WhereSelectStatement =
WhereSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, clause.selectCondition.parameters)
+ /**
+ * Builds a SELECT statement with ORDER BY clause.
+ *
+ * @return Statement that can be followed by LIMIT
+ */
fun select(
table: Table,
clause: OrderByClause,
@@ -53,6 +67,11 @@ internal object Select : Operation {
): OrderBySelectStatement =
OrderBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null)
+ /**
+ * Builds a SELECT statement with LIMIT clause.
+ *
+ * @return Statement that can be followed by OFFSET
+ */
fun select(
table: Table,
clause: LimitClause,
@@ -63,6 +82,11 @@ internal object Select : Operation {
): LimitSelectStatement =
LimitSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null)
+ /**
+ * Builds a SELECT statement with GROUP BY clause.
+ *
+ * @return Statement that can be followed by HAVING or ORDER BY
+ */
fun select(
table: Table,
clause: GroupByClause,
@@ -73,6 +97,13 @@ internal object Select : Operation {
): GroupBySelectStatement =
GroupBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null)
+ /**
+ * Builds a SELECT statement with NATURAL JOIN clause.
+ *
+ * Natural joins automatically match columns with the same name in both tables.
+ *
+ * @return Statement that can be followed by WHERE, GROUP BY, ORDER BY, or LIMIT
+ */
fun select(
table: Table<*>,
clause: NaturalJoinClause,
@@ -83,6 +114,13 @@ internal object Select : Operation {
) : JoinSelectStatement =
JoinSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null)
+ /**
+ * Builds a SELECT statement with JOIN clause (requires ON or USING).
+ *
+ * Returns an intermediate state that must be completed with either an ON or USING clause.
+ *
+ * @return Incomplete JOIN statement requiring condition
+ */
fun select(
table: Table<*>,
clause: JoinClause,
@@ -115,6 +153,13 @@ internal object Select : Operation {
append(clause.clauseStr)
}
+ /**
+ * Builds a simple SELECT statement without any clauses.
+ *
+ * Generates SQL in the format: `SELECT columns FROM table`
+ *
+ * @return Final SELECT statement ready for execution
+ */
fun select(
table: Table,
isDistinct: Boolean,
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt
index 7013327..1084446 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt
@@ -23,15 +23,30 @@ import com.ctrip.sqllin.dsl.sql.clause.SetClause
import com.ctrip.sqllin.dsl.sql.statement.UpdateStatementWithoutWhereClause
/**
- * SQL update
- * @author yaqiao
+ * UPDATE operation builder.
+ *
+ * Constructs UPDATE statements by combining table information with SET clauses. Returns an
+ * intermediate statement that can either execute immediately (update all rows) or be refined
+ * with a WHERE clause (update filtered rows).
+ *
+ * @author Yuang Qiao
*/
-
internal object Update : Operation {
override val sqlStr: String
get() = "UPDATE "
+ /**
+ * Builds an UPDATE statement with SET clause.
+ *
+ * Generates SQL in the format: `UPDATE table SET column1 = ?, column2 = ?, ...`
+ *
+ * @param table Table definition
+ * @param connection Database connection for execution
+ * @param container Statement container for DSL scope management
+ * @param clause SET clause with column assignments
+ * @return Statement that can either execute or be refined with WHERE
+ */
fun update(
table: Table,
connection: DatabaseConnection,
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt
index 3eda9eb..b8ac085 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt
@@ -17,10 +17,16 @@
package com.ctrip.sqllin.dsl.sql.statement
/**
- * Collect and execute all SQL statement in 'database {}' block
- * @author yaqiao
+ * Execution engine for top-level database DSL operations.
+ *
+ * Collects all statements created within a `Database` scope and executes them when the scope
+ * exits. Handles both individual statements and transaction groups. Supports progressive clause
+ * building by allowing UPDATE and SELECT statements to be replaced with refined versions.
+ *
+ * @property enableSimpleSQLLog Whether to print SQL and parameters before execution
+ *
+ * @author Yuang Qiao
*/
-
internal class DatabaseExecuteEngine(
private val enableSimpleSQLLog: Boolean,
) : StatementContainer {
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/ExecutableStatement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/ExecutableStatement.kt
index a4d3b9d..7703b1f 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/ExecutableStatement.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/ExecutableStatement.kt
@@ -17,10 +17,23 @@
package com.ctrip.sqllin.dsl.sql.statement
/**
- * Abstract SQL statement that could execute
- * @author yaqiao
+ * Base interface for SQL statements that can be executed against the database.
+ *
+ * Implementations include:
+ * - [SingleStatement]: Individual SQL operations (INSERT, UPDATE, DELETE, CREATE, SELECT)
+ * - [TransactionStatementsGroup]: Multiple statements wrapped in a transaction
+ *
+ * Statements are collected during DSL building and executed when the [com.ctrip.sqllin.dsl.DatabaseScope]
+ * exits.
+ *
+ * @author Yuang Qiao
*/
-
public sealed interface ExecutableStatement {
+ /**
+ * Executes this statement against the database.
+ *
+ * For single statements, this runs the SQL directly.
+ * For statement groups, this executes all contained statements in order.
+ */
public fun execute()
}
\ No newline at end of file
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt
index 18630e9..2e7e456 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt
@@ -22,10 +22,20 @@ import com.ctrip.sqllin.dsl.sql.clause.SelectCondition
import kotlinx.serialization.DeserializationStrategy
/**
- * SQL 'JOIN' statement, but need add 'ON' or 'USING' statement
- * @author yaqiao
+ * Intermediate JOIN statement requiring an ON or USING condition.
+ *
+ * Represents a JOIN operation that has been initiated but not yet completed. In SQL, a JOIN
+ * must specify how tables relate through either:
+ * - USING clause: Lists common column names to join on
+ * - ON clause: Specifies a join condition expression
+ *
+ * This class enforces the requirement at compile time by not extending [SelectStatement].
+ * It converts to [JoinSelectStatement] only after a condition is added.
+ *
+ * @param R The result entity type after JOIN
+ *
+ * @author Yuang Qiao
*/
-
public class JoinStatementWithoutCondition internal constructor(
private val sqlStr: String,
private val deserializer: DeserializationStrategy,
@@ -33,6 +43,15 @@ public class JoinStatementWithoutCondition internal constructor(
private val container: StatementContainer,
private val addSelectStatement: (SelectStatement) -> Unit
) {
+ /**
+ * Completes the JOIN by adding a USING clause.
+ *
+ * Generates SQL in the format: `JOIN table USING (column1, column2, ...)`.
+ * The USING clause specifies columns that exist in both tables with the same name.
+ *
+ * @param clauseElements Column elements to join on (must not be empty)
+ * @return Completed JOIN statement that can accept further clauses
+ */
internal infix fun convertToJoinSelectStatement(clauseElements: Iterable): JoinSelectStatement {
val iterator = clauseElements.iterator()
require(iterator.hasNext()) { "Param 'clauseElements' must not be empty!!!" }
@@ -51,6 +70,15 @@ public class JoinStatementWithoutCondition internal constructor(
return joinStatement
}
+ /**
+ * Completes the JOIN by adding an ON clause.
+ *
+ * Generates SQL in the format: `JOIN table ON condition`.
+ * The ON clause specifies an arbitrary boolean expression for joining tables.
+ *
+ * @param condition Join condition (e.g., table1.id = table2.foreign_id)
+ * @return Completed JOIN statement that can accept further clauses
+ */
internal infix fun convertToJoinSelectStatement(condition: SelectCondition): JoinSelectStatement {
val sql = buildString {
append(sqlStr)
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt
index abdc811..2514585 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt
@@ -19,10 +19,22 @@ package com.ctrip.sqllin.dsl.sql.statement
import com.ctrip.sqllin.driver.DatabaseConnection
/**
- * Update statement without 'WHERE' clause, that could execute or link 'WHERE' clause
+ * UPDATE statement without WHERE clause.
+ *
+ * Represents an UPDATE operation that can either:
+ * - Execute immediately (updates all rows in the table)
+ * - Be refined by adding a WHERE clause to target specific rows
+ *
+ * This intermediate state enables the DSL to support both:
+ * ```kotlin
+ * UPDATE(user) SET { /* ... */ } // Updates all rows
+ * UPDATE(user) SET { /* ... */ } WHERE { /* ... */ } // Updates filtered rows
+ * ```
+ *
+ * @param T The entity type being updated
+ *
* @author Yuang Qiao
*/
-
public class UpdateStatementWithoutWhereClause internal constructor(
preSQLStr: String,
internal val statementContainer: StatementContainer,
@@ -32,6 +44,14 @@ public class UpdateStatementWithoutWhereClause internal constructor(
public override fun execute(): Unit = connection.executeUpdateDelete(sqlStr, params)
}
+/**
+ * UPDATE or DELETE statement with WHERE clause applied (final form).
+ *
+ * Represents a complete UPDATE or DELETE operation ready for execution. The WHERE clause
+ * has already been applied, so the statement targets specific rows.
+ *
+ * @author Yuang Qiao
+ */
public class UpdateDeleteStatement internal constructor(
sqlStr: String,
private val connection: DatabaseConnection,
@@ -40,6 +60,14 @@ public class UpdateDeleteStatement internal constructor(
public override fun execute(): Unit = connection.executeUpdateDelete(sqlStr, params)
}
+/**
+ * INSERT statement (final form).
+ *
+ * Represents a complete INSERT operation with entities encoded as parameterized VALUES.
+ * Executes as a single batch insert for all entities.
+ *
+ * @author Yuang Qiao
+ */
public class InsertStatement internal constructor(
sqlStr: String,
private val connection: DatabaseConnection,
@@ -48,6 +76,14 @@ public class InsertStatement internal constructor(
public override fun execute(): Unit = connection.executeInsert(sqlStr, params)
}
+/**
+ * CREATE statement (final form).
+ *
+ * Represents a complete CREATE TABLE operation. Does not support parameterized queries
+ * since DDL statements use direct SQL execution.
+ *
+ * @author Yuang Qiao
+ */
public class CreateStatement internal constructor(
sqlStr: String,
private val connection: DatabaseConnection,
diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt
index 6d4a133..6d2439a 100644
--- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt
+++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt
@@ -25,10 +25,23 @@ import kotlinx.serialization.DeserializationStrategy
import kotlin.concurrent.Volatile
/**
- * Select statement
+ * Base class for SELECT statements with progressive clause building.
+ *
+ * Represents a SELECT query that can be executed to retrieve and deserialize entities from the database.
+ * The class hierarchy enforces SQL clause ordering at compile time - each subclass accepts only valid
+ * subsequent clauses (e.g., WHERE can be followed by GROUP BY, ORDER BY, or LIMIT).
+ *
+ * Results are lazily evaluated and cached after [execute] is called. Use [getResults] to retrieve
+ * the deserialized entities.
+ *
+ * @param T The entity type returned by this query
+ * @property deserializer kotlinx.serialization strategy for decoding cursor rows to entities
+ * @property connection Database connection for executing the query
+ * @property container Statement container for managing this statement in the DSL scope
+ * @property parameters Parameterized query values (strings only), or null if none
+ *
* @author Yuang Qiao
*/
-
public sealed class SelectStatement(
sqlStr: String,
internal val deserializer: DeserializationStrategy,
@@ -47,6 +60,14 @@ public sealed class SelectStatement(
cursor = connection.query(sqlStr, params)
}
+ /**
+ * Retrieves the query results as a list of deserialized entities.
+ *
+ * Results are lazily computed on first call and cached for subsequent calls.
+ * Throws [IllegalStateException] if called before [execute].
+ *
+ * @return List of entities matching the query
+ */
public fun getResults(): List = result ?: cursor?.use {
val decoder = QueryDecoder(it)
result = buildList {
@@ -75,6 +96,16 @@ public sealed class SelectStatement(
}
}
+/**
+ * SELECT statement with WHERE clause applied.
+ *
+ * Can be followed by:
+ * - GROUP BY
+ * - ORDER BY
+ * - LIMIT
+ *
+ * @author Yuang Qiao
+ */
public class WhereSelectStatement internal constructor(
sqlStr: String,
deserializer: DeserializationStrategy,
@@ -93,6 +124,17 @@ public class WhereSelectStatement internal constructor(
GroupBySelectStatement(buildSQL(clause), deserializer, connection, container, parameters)
}
+/**
+ * SELECT statement with JOIN clause applied.
+ *
+ * Can be followed by:
+ * - WHERE
+ * - GROUP BY
+ * - ORDER BY
+ * - LIMIT
+ *
+ * @author Yuang Qiao
+ */
public class JoinSelectStatement