diff --git a/README.md b/README.md index be69053..317492d 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ fun sample() { } } ``` -SQLlin is able to insert Kotlin objects into database directly, and could query Kotlin objects directly from database. The serialization +SQLlin is able to insert Kotlin objects into database directly, and could query Kotlin objects from database directly. The serialization and deserialization ability based on [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization). SQLlin supports these platforms: diff --git a/sqllin-driver/README.md b/sqllin-driver/README.md index 0e49c57..f5541b0 100644 --- a/sqllin-driver/README.md +++ b/sqllin-driver/README.md @@ -4,25 +4,24 @@ ## Design -Initially, we need a multiplatform available low-level Kotlin API to call SQLite. Because we think _sqllin-dsl_ -should be platform independent. So, we need the _sqllin-driver_, and _sqllin-dsl_ based on it. Our goal is +Initially, we needed a multiplatform available low-level Kotlin APIs to call SQLite. Because we thought _sqllin-dsl_ +should be platform-independent. So, we needed _sqllin-driver_, and _sqllin-dsl_ on top of it. Our goal was writing the common APIs in Kotlin Multiplatform common source set and they have different implementations on different platforms. -In Android, not many ways to choose from. If we use the Android Framework SQLite Java APIs, everything will be simple, -but defect is many SQLite parameters cannot take effect on systems below Android P. If we writing JNI code +On Android, there are no many ways to choose from. If we use Android Framework SQLite Java APIs, everything will be simple, +but defect is many SQLite parameters cannot take effect on systems below Android P. If we write JNI code to call SQLite C functions by ourselves, above problem will be resolved, but this will lead to a bigger problem: -In systems above Android N, Google doesn't allow developers call system built-in SQLite C functions in NDK. If +On systems above Android N, Google doesn't allow developers call system built-in SQLite C functions in NDK. If we firmly choose this plan, we have to compile the SQLite source code into _sqllin-driver_, this will complicate -our project. Finally, we still choose based on Android Framework Java API. - -In Native platforms, things look different. We can call SQLite C API directly, this is a most intuitive plan. -The interoperability of Kotlin/Native with C is very perfect, but in Kotlin/Native you must use some APIs that -very difficult to understanding to interop with C, like: `memScoped`, `CPointer`, `CPointerVarOf`, `toKString`, etc.. -So, at the beginning, I chose the [SQLiter](https://github.com/touchlab/SQLiter), that's a Kotlin/Native multiplatform -library. If I use it, I can put the Kotlin-C interop translate to Kotlin language-internal calls. It is very -convenient. [SQLiter](https://github.com/touchlab/SQLiter) also is the driver that -[SQLDelight](https://github.com/cashapp/sqldelight) to call SQLite C library on native platforms. It is not only +our project. Finally, we still choose to use Android Framework Java API. + +On Native platforms, things look different. We can call SQLite C APIs directly, this is a most intuitive plan. +The interoperability of Kotlin/Native with C is perfect, but in Kotlin/Native you must use some APIs to interop with C +that very difficult to understand, like: `memScoped`, `CPointer`, `CPointerVarOf`, `toKString`, etc.. +So, at the beginning, I chose the [SQLiter](https://github.com/touchlab/SQLiter), it is a Kotlin/Native multiplatform +library. If I use it, I can put the Kotlin-C interop translate to Kotlin language-internal calling. It is very +convenient. [SQLiter](https://github.com/touchlab/SQLiter) also is the driver of [SQLDelight](https://github.com/cashapp/sqldelight) calling SQLite C library on native platforms. It not only supports iOS, but also supports all the operating systems of Apple, Linux(x64) and Windows(mingwX86, mingwX64). But a few months later. I found using [SQLiter](https://github.com/touchlab/SQLiter) also has some disadvantages. For diff --git a/sqllin-dsl/doc/advanced-query.md b/sqllin-dsl/doc/advanced-query.md index aed9ae6..ee4686c 100644 --- a/sqllin-dsl/doc/advanced-query.md +++ b/sqllin-dsl/doc/advanced-query.md @@ -2,13 +2,13 @@ 中文版请见[这里](advanced-query-cn.md) -We have learned basic query and using SQL functions in query condition. Let's learn some query’s advanced skills. +We have learned basic querying and using SQL functions in querying conditions. Let's learn some advanced skills of querying. ## Unions -The _UNION_ operator used for merge two _SELECT_ statements' results and these results must be of the same type. +The _UNION_ operator is used for merge two _SELECT_ statements' results and these results must be of the same type. -In SQL, _UNION_ operator between with the two _SELECT_ statements, but in SQLlin, we use a higher-order function to +In SQL, the _UNION_ operator between with the two _SELECT_ statements, but in SQLlin, we use a higher-order function to implement _UNION_: ```kotlin @@ -25,8 +25,8 @@ fun sample() { } ``` -You just need to write your _SELECT_ statements in `UNION {...}` block. There must be at least two _SELECT_ statements -inside the `UNION {...}` block, if not, you will get a `IllegalStateException` when runtime. +You just need to write your _SELECT_ statements in the `UNION {...}` block. There must be at least two _SELECT_ statements +inside the `UNION {...}` block, if not, you will get a `IllegalStateException` at runtime. If you want to use _UNION_ and _UNION ALL_ interchangeably, just use `UNION {...}` or `UNION_ALL {...}` block nesting: @@ -59,7 +59,7 @@ SELECT * FROM person WHERE name = "Tom" ## Subqueries -SQLlin doesn't yet support subqueries, we will develop as soon as possible. +SQLlin doesn't support subqueries yet, we will develop as soon as possible. ## Join @@ -92,7 +92,7 @@ data class CrossJoinStudent( ) ``` -The `Transcript` represents a other table. And the `Student` represents the join query results' type(so `Student` +The `Transcript` represents an other table. And the `Student` represents the join querying results' type (so `Student` doesn't need to be annotated `@DBRow`), it owns all column names that belong to `Person` and `Transcript`. ### Cross Join @@ -111,8 +111,8 @@ The `CROSS_JOIN` function receives one or multiple `Table`s as parameters. In no depended on the `Table` that be generated by _sqllin-processor_, but _JOIN_ operator will change it to specific type. In above sample, `CROSS_JOIN` changes the type to `CrossJoinStudent`. -Note, because of _CROSS JOIN_ owns feature in SQL. If the columns that be queried by _SELECT_ statement that with _CROSS JOIN_ clause include the same -name column in the two tables, this will causing the query to fail. Because of a class isn't allowed to have multiple properties those have same name, _sqllin-dsl_ +Note, because _CROSS JOIN_ owns feature in SQL. If the columns that be queried by a _SELECT_ statement that with _CROSS JOIN_ clause include the same +name columns in the two tables, this will cause the querying to fail. Because a class isn't allowed to have multiple properties those have same names, _sqllin-dsl_ doesn't support the _CROSS JOIN_ with columns of the same name. ### Inner Join @@ -130,15 +130,15 @@ fun joinSample() { ``` The `INNER_JOIN` is similar to `CROSS_JOIN`, the deference is `INNER_JOIN` need to connect a `USING` or `ON` clause. If a _INNER JOIN_ statement -without the `USING` or `ON` clause, it is incomplete, but your code still be compiled and will do nothing in runtime. +without the `USING` or `ON` clause, it is incomplete, but your code still be compiled and will do nothing at runtime. -The `NATURAL_INNER_JOIN` will produce a complete _SELECT_ statement(the same with `CROSS_JOIN`). So, you can't add `USING` or `ON` clause behind it, this is +The `NATURAL_INNER_JOIN` will produce a complete _SELECT_ statement (same with `CROSS_JOIN`). So, you can't add a `USING` or `ON` clause behind it, this is guaranteed by Kotlin compiler. -Note, the behavior of `INNER_JOIN` clause with `ON` clause is same to `CROSS_JOIN`, you can't select the column that has same name in two tables. +Note, the behavior of a `INNER_JOIN` clause with a `ON` clause is same with `CROSS_JOIN`, you can't select a column that has same name in two tables. -The `INNER_JOIN` have an alias that named `JOIN`, and `NATURAL_INNER_JOIN` also have an alias that named `NATURAL_JOIN`. That's liked you can -bypass the `INNER` keyword in SQL's inner join query. +The `INNER_JOIN` have an alias that named `JOIN`, and `NATURAL_INNER_JOIN` also have an alias that named `NATURAL_JOIN`. This is just like you can +bypass a `INNER` keyword in SQL's inner join querying. ### Left Outer Join @@ -155,8 +155,8 @@ fun joinSample() { } ``` -The `LEFT_OUTER_JOIN`'s usage is very similar to `INNER_JOIN`, the difference just is their API names. +The `LEFT_OUTER_JOIN`'s usage is very similar with `INNER_JOIN`, the difference just is their API names. ## Finally -You have learned all usage with SQLlin, enjoy it and stay concerned about SQLlin's update :) \ No newline at end of file +You have learned all usages with SQLlin, enjoy it and stay Stay tuned for SQLlin's updates :) \ No newline at end of file diff --git a/sqllin-dsl/doc/concurrency-safety.md b/sqllin-dsl/doc/concurrency-safety.md index cb65a46..70426bc 100644 --- a/sqllin-dsl/doc/concurrency-safety.md +++ b/sqllin-dsl/doc/concurrency-safety.md @@ -6,14 +6,14 @@ unpredictable consequences. So, the best way is when you want to operate your database, create a `Database` object, and when you finish your operating, close it immediately. But, that's very inconvenient, we always have to create a database connection and -close it frequently, that is a waste of resources. For example, if we are developing -an Android app, and in a single page(Activity/Fragment), we hope we can keep a -`Database` object, when we want to operate the database in background threads(or +close it frequently, this is a waste of resources. For example, if we are developing +an Android app, and in a single page (Activity/Fragment), we hope we can keep a +`Database` object, when we want to operate the database in background threads (or coroutines), just use it, and, close it in certain lifecycle -functions(`onDestroy`, `onStop`, etc..). +functions (`onDestroy`, `onStop`, etc.). -In that time, we should make sure the concurrency safety that we sharing the `Database` -object between different threads(or coroutines). So, start with the version `1.2.2`, we can +At that time, we should make sure the concurrency safety that we share the `Database` +object between different threads (or coroutines). So, start with the version `1.2.2`, we can use the new API `Database#suspendedScope` to replace the usage of `database {}`. For example, if we have some old code: diff --git a/sqllin-dsl/doc/getting-start.md b/sqllin-dsl/doc/getting-start.md index 21c14a8..74b3342 100644 --- a/sqllin-dsl/doc/getting-start.md +++ b/sqllin-dsl/doc/getting-start.md @@ -6,7 +6,7 @@ ## Installation via Maven with Gradle -Add the _sqllin-dsl_, _sqllin-driver_ and _sqllin-processor_ dependencies into your `build.gradle.kts`: +Add the dependencies of _sqllin-dsl_, _sqllin-driver_ and _sqllin-processor_ into your `build.gradle.kts`: ```kotlin plugins { @@ -47,7 +47,7 @@ dependencies { } ``` -> Note: If you want to add dependiences of SQLlin into your Kotlin/Native exectable program project, sometimes you need to add the `linkerOpts` +> Note: If you want to add dependencies of SQLlin into your Kotlin/Native executable program projects, sometimes you need to add the `linkerOpts` > of SQLite into your `build.gradle.kts` correctly. You can refer to [issue #48](https://github.com/ctripcorp/SQLlin/issues/48) to get more information. ## Creating the Database @@ -61,7 +61,7 @@ val database = Database(name = "Person.db", path = getGlobalPath(), version = 1) ``` The `DatabasePath` is the second parameter `path`'s type, it is represented differently on different platforms. -In Android, you can get it through [`Context`](https://developer.android.com/reference/android/content/Context), and you can get it through string in native platforms. +On Android, you can get it through [`Context`](https://developer.android.com/reference/android/content/Context), and you can get it through string on native platforms. For example, you can define a expect function in your common source set: ```kotlin @@ -86,7 +86,7 @@ val applicationContext: Context } ``` -In your iOS source set(similar in other Apple platforms), you can implement it by: +In your iOS source set (similar with other Apple platforms), you can implement it by: ```kotlin import com.ctrip.sqllin.driver.DatabasePath @@ -100,7 +100,7 @@ actual fun getGlobalDatabasePath(): DatabasePath = ``` -You can config more SQLite arguments when you creating the `Database` instance: +You can config more SQLite arguments when you create the `Database` instance: ```kotlin import com.ctrip.sqllin.driver.DatabaseConfiguration @@ -127,10 +127,10 @@ val database = Database( ``` Note, because of limitation by Android Framework, the `inMemory`, `busyTimeout`, `lookasideSlotSize`, `lookasideSlotCount` -only work on Android 9 and higher. And, because of [sqlite-jdbc](https://github.com/xerial/sqlite-jdbc)(SQLlin base on it on JVM) doesn't support +only work on Android 9 and higher. And, because [sqlite-jdbc](https://github.com/xerial/sqlite-jdbc)(SQLlin is based on it on JVM) doesn't support `sqlite3_config()`, the `lookasideSlotSize` and `lookasideSlotCount` don't work on JVM target. -Now, the operations that change database structure have not supported by DSL yet. So, you need to write these SQL statements by string +Now, the operations that change database structure haven't been supported by DSL yet. So, you need to write these SQL statements by string as in `create` and `upgrade` parameters. Usually, you just need to create one `Database` instance in your component lifecycle. So, you need to close database manually when the lifecycle ended: @@ -143,7 +143,7 @@ override fun onDestroy() { ## Defining Your database entity -In _sqllin-dsl_, you can insert and query objects directly. So, you need to use the correct way to define your data class. For example: +In _sqllin-dsl_, you can insert and query objects directly. So, you need to use the correct way to define your data classes. For example: ```kotlin import com.ctrip.sqllin.dsl.annotation.DBRow @@ -157,14 +157,14 @@ data class Person( ) ``` -Your database entity's property names should same with the database table's column names. The database entity cannot have properties with names different from all -column names in the table. But the count of your database entity's properties can less than the count of columns. +Your database entities' property names should be same with the database table's column names. The database entities cannot have properties with names different from all +column names in the table. But the count of your database entities' properties can less than the count of columns. The `@DBRow`'s param `tableName` represents the table name in Database, please ensure pass the correct value. If you don't pass the parameter manually, _sqllin-processor_ will use the class name as table name, for example, `Person`'s default table name is "Person". -In _sqllin-dsl_, objects serialization to SQL and deserialization from cursor depend on _kotlinx.serialization_. So, you also need to add the `@Serializable` onto your data class. +In _sqllin-dsl_, objects are serialized to SQL and deserialized from cursor depend on _kotlinx.serialization_. So, you also need to add the `@Serializable` onto your data classes. ## Next Step diff --git a/sqllin-dsl/doc/modify-database-and-transaction.md b/sqllin-dsl/doc/modify-database-and-transaction.md index 091876e..960d697 100644 --- a/sqllin-dsl/doc/modify-database-and-transaction.md +++ b/sqllin-dsl/doc/modify-database-and-transaction.md @@ -2,14 +2,14 @@ 中文版请见[这里](modify-database-and-transaction-cn.md) -In [Getting Start](getting-start.md), we have learned how to create the `Database` instance and define your database entity. Now, -we start learn how to write SQL statements with SQLlin. +In [Getting Start](getting-start.md), we have learned how to create the `Database` instance and define your database entities. Now, +we start to learn how to write SQL statements with SQLlin. ## Insert The class `Database` has overloaded function operator that type is ` Database.(Database.() -> T) -> T`. When you invoke the operator function, it will produce a _DatabaseScope_. Yeah, that is an operator function's lambda parameter. Any SQL statement -must be written in _DatabaseScope_. And, the inner SQL statements will only be executed when the _DatabaseScope_ ended. +must be written in _DatabaseScope_. And, the inner SQL statements only will be executed when the _DatabaseScope_ ended. You already know, the _INSERT_, _DELETE_, _UPDATE_ and _SELECT_ SQL statements are used for table operation. So, before you write your SQL statements, you also need to get a `Table` instance, like this: @@ -27,10 +27,10 @@ fun sample() { ``` The `PersonTable` is generated by _sqllin-processor_, because `Person` is annotated the `@DBRow` -annotation. Any class that be annotated the `@DBRow` will be generated a `Table` object, its name is +annotation. Any class that is annotated the `@DBRow` will be generated a `Table` object, its name is `class name + 'Table'`. -Now, let's do the real _INSERT_: +Now, let's do the real _INSERT_s: ```kotlin fun sample() { @@ -47,11 +47,11 @@ fun sample() { } ``` -The _INSERT_ statement could insert objects directly. You can insert one or multiple objects once. +The _INSERT_ statements could insert objects directly. You can insert one or multiple objects once. ## Delete -The _DELETE_ statement will be slightly more complex than _INSERT_. SQLlin doesn't delete objects like +The _DELETE_ statements will be slightly more complex than _INSERT_. SQLlin doesn't delete objects like [Jetpack Room](https://developer.android.com/training/data-storage/room), we use the _WHERE_ clause: ```kotlin @@ -64,11 +64,11 @@ fun sample() { } ``` -Let's understand the _WHERE_ clause. `WHERE` function receives a `ClauseCondiction` as a parameter. The `age` and `name` in the example is used for representing columns' -name, they are extension property with `Table`, their type are `ClauseElement`, and be generated by _sqllin-processor_(KSP). +Let's understand the _WHERE_ clause. `WHERE` function receives a `ClauseCondiction` as a parameter. The `age` and `name` in the example are used for representing columns' +names, they are extension property with `Table`, their type are `ClauseElement`, and they are generated by _sqllin-processor_(KSP). -The `ClauseElement` has a series of operators that used for representing the SQL operators like: `=`, `>`, `<`, `LIKE`, `IN`, `IS` etc.. When a `ClauseElement` invoke a -operator, we will get a `ClauseCondiction`. Multiple `ClauseCondiction`s would use the `AND` or `OR` operator link and produce a new `ClauseCondiction`. +The `ClauseElement` has a series of operators that used for representing the SQL operators like: `=`, `>`, `<`, `LIKE`, `IN`, `IS` etc. When a `ClauseElement` invoke a +operator, we will get a `ClauseCondiction`. Multiple `ClauseCondiction`s would use the `AND` or `OR` operator to link and produce a new `ClauseCondiction`. The chart of between SQL operators and SQLlin operators like this: @@ -104,12 +104,12 @@ fun sample() { } } ``` -The `X` is a Kotlin `object`(singleton). +The `X` is a Kotlin `object` (singleton). ## Update -The _UPDATE_ statement is similar to _DELETE_, it also use a _WHERE_ clause to limit update conditions. But, the -difference is _UPDATE_ statement owns a particular _SET_ clause: +The _UPDATE_ is similar with _DELETE_, it also use a _WHERE_ clause to limit update conditions. But, the +difference is the _UPDATE_ statement owns a particular _SET_ clause: ```kotlin fun sample() { @@ -122,14 +122,14 @@ fun sample() { ``` The _SET_ clause is different from other clauses, it receives a lambda as parameter, you can set the new value to column in the -lambda. The `age` in the set lambda is a writable property that also be generated by KSP, and it only available in _SET_ -clause, it different with `age` readonly property in _WHERE_ clause. +lambda. The `age` in the set lambda is a writable property that also be generated by KSP, and it is only available in _SET_ +clauses, it is different with readonly property `age` in _WHERE_ clauses. -You also could write the _UPDATE_ statement without _WHERE_ clause that used for update all rows, but you should use it with caution. +You also could write the _UPDATE_ statements without the _WHERE_ clause that used for update all rows, but you should use it with caution. ## Transaction -Use transaction is simple in SQLlin, you just need to use the `transaction {...}` wrap your SQL statements: +Using transaction is simple in SQLlin, you just need to use a `transaction {...}` wrap your SQL statements: ```kotlin fun sample() { @@ -149,11 +149,11 @@ fun sample() { } ``` -The `transaction {...}` is a member function in `Database`, it inside or outside of `TABLE(databaseName) {...}` doesn't matter. +The `transaction {...}` is a member function in `Database`, it is inside or outside of `TABLE(databaseName) {...}` doesn't matter. ## Next Step -You have learned how to use _INSERT_, _DELETE_ and _UPDATE_ statements. Next step you will learn _SELECT_ statement. The +You have learned how to use _INSERT_, _DELETE_ and _UPDATE_ statements. Next step you will learn _SELECT_ statements. The _SELECT_ statement is more complex than other statements, be ready :). - [Query](query.md) diff --git a/sqllin-dsl/doc/query.md b/sqllin-dsl/doc/query.md index 2a462ce..a207b26 100644 --- a/sqllin-dsl/doc/query.md +++ b/sqllin-dsl/doc/query.md @@ -2,11 +2,11 @@ 中文版请见[这里](query-cn.md) -The _SELECT_ statement is more complex than others, because _SELECT_ statement have more clauses. +The _SELECT_ statements are more complex than others, because _SELECT_ statements have more clauses. ## Basic -The simplest usage is query all data in the table: +The simplest usage is querying all data in the table: ```kotlin fun sample() { @@ -23,11 +23,11 @@ fun sample() { ``` The `X` represents without any clause, we’ve seen it in _DELETE_ statements. -The _SELECT_ statement has query results, this is another difference from other statements. So, you need to declare a variable that -type is `SelectStatement`. The generic parameter `T` is your database entity's type that you expect to deserialize. You should assign _SELECT_ statement you built to this variable. +The _SELECT_ statement owns the querying results, this is another difference with other statements. So, you need to declare a variable that +type is `SelectStatement`. The generic parameter `T` is your database entity's type that you expect to deserialize. You should assign a _SELECT_ statement you built to this variable. Note, all statements will only be executed when the _DatabaseScope_ ends, we mentioned this in the [Modify Database and Transaction](modify-database-and-transaction.md). -So, you must invoke the `getResults` function outside the `database { ... }` block, SQLlin will help you deserialize query results to objects that you expected. +So, you must invoke the `getResults` function outside the `database { ... }` block, SQLlin will help you deserialize querying results to objects that you expected. ## Single Clause diff --git a/sqllin-dsl/doc/sql-functions.md b/sqllin-dsl/doc/sql-functions.md index bbc0782..efa4c99 100644 --- a/sqllin-dsl/doc/sql-functions.md +++ b/sqllin-dsl/doc/sql-functions.md @@ -3,7 +3,7 @@ 中文版请见[这里](sql-functions-cn.md) SQLite has many built-in functions. We usually would use them in two places: after _SELECT_ keyword -or in conditions(used for _WHERE_ and _HAVING_). +or in conditions (use for _WHERE_ and _HAVING_). Using functions in conditions like this: @@ -27,7 +27,7 @@ a `ClauseElement` as the result. The functions supported by SQLlin are as follow The `count` function has a different point, it could receive `X` as parameter be used for representing `count(*)` in SQL, as shown in the example above. -SQLlin only supports using functions in conditions now. We will consider supporting the use of functions after _SELECT_ keyword in +SQLlin only supports using functions in conditions now. We will consider supporting using functions after the _SELECT_ keyword in future versions. Now, if you have similar demands, you can use [Kotlin Collections API](https://kotlinlang.org/docs/collection-aggregate.html) to handle query results: