Skip to content

Commit e048923

Browse files
committed
update
1 parent c669f3f commit e048923

File tree

2 files changed

+135
-97
lines changed

2 files changed

+135
-97
lines changed

docs/src/.vuepress/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export default defineUserConfig({
3333

3434
sidebar: [
3535
{ text: 'Home', link: '/' },
36-
"/0.language/",
3736
"/1.overview/",
37+
"/0.language/",
3838
"/2.configure/",
3939
"/3.ui/",
4040
"/4.nav/",

docs/src/9.database/README.md

Lines changed: 134 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,86 @@ plugins {
9191
```
9292
#### Create the native SQL driver factory and use it for creating the DB with `actual`/`expect` kotlin keywords
9393

94+
``` kotlin Platform.jvm.kt (desktopMain)
95+
actual suspend fun provideDbDriver(
96+
schema: SqlSchema<QueryResult.AsyncValue<Unit>>
97+
): SqlDriver {
98+
return JdbcSqliteDriver("jdbc:sqlite:quiz.db", Properties())
99+
.also { schema.create(it).await() }
100+
101+
}
102+
```
103+
104+
105+
``` kotlin Platform.ios.kt (iosMain)
106+
actual suspend fun provideDbDriver(
107+
schema: SqlSchema<QueryResult.AsyncValue<Unit>>
108+
): SqlDriver {
109+
return NativeSqliteDriver(schema.synchronous(), "quiz.db")
110+
}
111+
```
112+
113+
``` kotlin Platform.android.kt (androidMain)
114+
actual suspend fun provideDbDriver(
115+
schema: SqlSchema<QueryResult.AsyncValue<Unit>>
116+
): SqlDriver {
117+
return AndroidSqliteDriver(schema.synchronous(), QuizApp.context(), "quiz.db")
118+
}
119+
```
120+
121+
122+
``` kotlin Platform.js.kt (wasmjsMain)
123+
actual suspend fun provideDbDriver(schema: SqlSchema<QueryResult.AsyncValue<Unit>>): SqlDriver {
124+
return WebWorkerDriver(
125+
jsWorker()
126+
)
127+
}
128+
fun jsWorker(): Worker =
129+
js("""new Worker(new URL("./sqljs.worker.js", import.meta.url))""")
130+
```
131+
132+
for the WebWorker you need to create a webpack.config.d/config.js file in the root of your project and a webpack.config.d/sqljs-config.js for the web worker to be able to use the sql wasm library.
133+
134+
``` js webpack.config.d/config.js
135+
const TerserPlugin = require("terser-webpack-plugin");
136+
137+
config.optimization = config.optimization || {};
138+
config.optimization.minimize = true;
139+
config.optimization.minimizer = [
140+
new TerserPlugin({
141+
terserOptions: {
142+
mangle: true, // Note: By default, mangle is set to true.
143+
compress: false, // Disable the transformations that reduce the code size.
144+
output: {
145+
beautify: false,
146+
},
147+
},
148+
}),
149+
];
150+
```
151+
152+
``` js webpack.config.d/sqljs-config.js
153+
// {project}/webpack.config.d/sqljs.js
154+
config.resolve = {
155+
fallback: {
156+
fs: false,
157+
path: false,
158+
crypto: false,
159+
}
160+
};
161+
162+
const CopyWebpackPlugin = require('copy-webpack-plugin');
163+
config.plugins.push(
164+
new CopyWebpackPlugin({
165+
patterns: [
166+
'../../node_modules/sql.js/dist/sql-wasm.wasm'
167+
]
168+
})
169+
);
170+
171+
```
172+
173+
94174
#### Read carefully the modelisation UML below
95175

96176
![diagram SQL ](../assets/images/diagramme_sql.png)
@@ -107,7 +187,6 @@ Your repository handle the following cases :
107187
* if there is network and db data are younger than 5 min : return on the flow the db data
108188
* if there is network and db data are older than 5 min : retourn on the flow the network data and reset db data
109189

110-
111190
## 🎯 Solutions
112191

113192
::: details QuizDatabase.sq (ressources of commonMain)*
@@ -125,7 +204,6 @@ CREATE TABLE questions (
125204
correctAnswerId INTEGER NOT NULL
126205
);
127206

128-
129207
CREATE TABLE answers (
130208
id INTEGER NOT NULL,
131209
label TEXT NOT NULL,
@@ -137,8 +215,6 @@ CREATE TABLE questions (
137215
ON DELETE CASCADE
138216
);
139217

140-
141-
142218
selectUpdateTimestamp:
143219
SELECT *
144220
FROM update_time;
@@ -173,133 +249,95 @@ CREATE TABLE questions (
173249
```
174250
:::
175251

176-
::: details network/QuizDB.kt (commonMain)
252+
::: details data/datasources (commonMain)
177253
``` kotlin
178-
package network
179-
180-
181-
import app.cash.sqldelight.async.coroutines.awaitAsList
182-
import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull
183-
import app.cash.sqldelight.db.SqlDriver
184-
import com.myapplication.common.cache.Database
185-
import kotlinx.coroutines.CoroutineScope
186-
import network.data.Answer
187-
import network.data.Question
188-
189-
class QuizDbDataSource(private val sqlDriver: SqlDriver, private val coroutineScope: CoroutineScope) {
254+
class SqlDelightDataSource(private val database: Database) {
190255

191-
private var database=Database(sqlDriver)
192-
private var quizQueries=database.quizDatabaseQueries
193256

257+
private var quizQueries = database.quizQuestionQueries
194258

195-
suspend fun getUpdateTimeStamp():Long = quizQueries.selectUpdateTimestamp().awaitAsOneOrNull()?.timestamprequest ?: 0L
259+
suspend fun getAllQuestions(): List<Question> {
260+
return quizQueries.selectAllQuestionsWithAnswers().awaitAsList()
196261

262+
.groupBy { it.question_id }
263+
.map { (questionId, rowList) ->
197264

198-
suspend fun setUpdateTimeStamp(timeStamp:Long) {
199-
quizQueries.deleteTimeStamp()
200-
quizQueries.insertTimeStamp(timeStamp)
265+
Question(
266+
id = questionId,
267+
label = rowList.first().label,
268+
correctAnswerId = rowList.first().correctAnswerId,
269+
answers = rowList.map { answer ->
270+
Answer(
271+
id = answer.id_,
272+
label = answer.label_
273+
)
274+
}
275+
)
276+
}
201277
}
202278

203-
suspend fun getAllQuestions(): List<Question> {
204-
return quizQueries.selectAllQuestionsWithAnswers().awaitAsList()
205-
206-
.groupBy {it.question_id }
207-
.map { (questionId, rowList) ->
208279

209-
Question(
210-
id = questionId,
211-
label = rowList.first().label,
212-
correctAnswerId = rowList.first().correctAnswerId,
213-
answers = rowList.map { answer ->
214-
Answer(
215-
id = answer.id_,
216-
label = answer.label_
217-
)
218-
}
219-
)
220-
}
221-
}
222-
223-
224-
225-
suspend fun insertQuestions(questions:List<Question>) {
280+
suspend fun insertQuestions(questions: List<Question>) {
226281
quizQueries.deleteQuestions();
227282
quizQueries.deleteAnswers()
228-
questions.forEach {question ->
283+
questions.forEach { question ->
229284
quizQueries.insertQuestion(question.id, question.label, question.correctAnswerId)
230-
question.answers.forEach {answer ->
231-
quizQueries.insertAnswer(answer.id,answer.label,question.id)
285+
question.answers.forEach { answer ->
286+
quizQueries.insertAnswer(answer.id, answer.label, question.id)
232287
}
233288
}
234289
}
290+
291+
suspend fun resetQuestions() {
292+
quizQueries.deleteQuestions()
293+
quizQueries.deleteAnswers()
294+
}
235295
}
236296
```
237297
:::
238298

239299
::: details QuizRepository.kt
240300
```kotlin
241-
package network
242-
243-
import app.cash.sqldelight.db.SqlDriver
244-
import kotlinx.coroutines.CoroutineScope
245-
import kotlinx.coroutines.Dispatchers
246-
import kotlinx.coroutines.flow.MutableStateFlow
247-
import kotlinx.coroutines.flow.update
248-
import kotlinx.coroutines.launch
249-
import kotlinx.datetime.Clock
250-
import network.data.Question
251-
252-
253-
class QuizRepository(sqlDriver: SqlDriver) {
254-
301+
class QuizRepository {
255302
private val mockDataSource = MockDataSource()
256-
private val quizAPI = QuizApiDatasource()
257-
private val coroutineScope = CoroutineScope(Dispatchers.Main)
258-
private var quizDB = QuizDbDataSource(sqlDriver,coroutineScope)
303+
private val quizApiDatasource = QuizApiDatasource()
304+
private var quizKStoreDataSource = KStoreDataSource(AppInitializer.getKStoreInstance())
305+
private var sqlDelightDataSource = SqlDelightDataSource(AppInitializer.getDatabase()!!)
259306

260-
private var _questionState= MutableStateFlow(listOf<Question>())
261-
val questionState get() = _questionState
307+
private suspend fun fetchQuiz(): List<Question> = quizApiDatasource.getAllQuestions().questions
262308

263-
init {
264-
updateQuiz()
265-
}
266-
267-
private suspend fun fetchQuiz(): List<Question> = quizAPI.getAllQuestions().questions
309+
@OptIn(ExperimentalTime::class)
310+
private suspend fun fetchAndStoreQuiz(): List<Question> {
311+
sqlDelightDataSource.resetQuestions()
268312

269-
private suspend fun fetchAndStoreQuiz(): List<Question>{
270-
val questions = fetchQuiz()
271-
quizDB.insertQuestions(questions)
272-
quizDB.setUpdateTimeStamp(Clock.System.now().epochSeconds)
313+
val questions = fetchQuiz()
314+
sqlDelightDataSource.insertQuestions(questions)
315+
quizKStoreDataSource.setUpdateTimeStamp(Clock.System.now().epochSeconds)
273316
return questions
274317
}
275-
private fun updateQuiz(){
276-
277-
278-
coroutineScope.launch {
279-
_questionState.update {
280-
try {
281-
val lastRequest = quizDB.getUpdateTimeStamp()
282-
if(lastRequest == 0L || lastRequest - Clock.System.now().epochSeconds > 300000){
283-
fetchAndStoreQuiz()
284-
}else{
285-
quizDB.getAllQuestions()
286-
}
287-
} catch (e: NullPointerException) {
288-
fetchAndStoreQuiz()
289-
} catch (e: Exception) {
290-
e.printStackTrace()
291-
mockDataSource.generateDummyQuestionsList()
292-
}
293318

319+
@OptIn(ExperimentalTime::class)
320+
suspend fun updateQuiz(): List<Question> {
321+
try {
322+
val lastRequest = quizKStoreDataSource.getUpdateTimeStamp()
323+
return if (lastRequest == 0L || lastRequest - Clock.System.now().epochSeconds > 300000) {
324+
fetchAndStoreQuiz()
325+
} else {
326+
//quizKStoreDataSource.getAllQuestions()
327+
sqlDelightDataSource.getAllQuestions()
294328
}
329+
} catch (e: NullPointerException) {
330+
return fetchAndStoreQuiz()
331+
} catch (e: Exception) {
332+
e.printStackTrace()
333+
return mockDataSource.generateDummyQuestionsList()
295334
}
296335
}
336+
297337
}
298338
```
299339
:::
300340

301-
302-
303341
::: tip More databases options
304342
For not using SQLight ORM, you can use [`Realm kotlin`](https://github.com/realm/realm-kotlin) or [KStore](https://github.com/xxfast/KStore)
305343
:::

0 commit comments

Comments
 (0)