Implement database access (with migrations)

This commit is contained in:
2019-01-26 22:58:53 -06:00
parent e19339d808
commit 7cab0a39e5
67 changed files with 1826 additions and 136 deletions

View File

@@ -67,6 +67,7 @@ dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation files("../core/build/libs/core-jvm.jar")
implementation "com.facebook.react:react-native:0.57.8"
implementation 'org.sqldroid:sqldroid:1.0.3'
implementation project(':react-native-svg')
testImplementation 'junit:junit:4.12'

View File

@@ -1,3 +1,22 @@
#
# Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
#
# This file is part of Loop Habit Tracker.
#
# Loop Habit Tracker is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Loop Habit Tracker is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.habits
import junit.framework.Assert.*
import org.isoron.uhabits.utils.*
import org.junit.*
class AndroidDatabaseTest : BaseTest() {
@Test
fun testUsage() {
val dbFile = fileOpener.openUserFile("test.sqlite3")
if (dbFile.exists()) dbFile.delete()
val db = databaseOpener.open(dbFile)
var stmt = db.prepareStatement("drop table if exists demo")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("begin")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("create table if not exists demo(key int, value text)")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("insert into demo(key, value) values (?1, ?2)")
stmt.bindInt(1, 42)
stmt.bindText(2, "Hello World")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("select * from demo where key > ?1")
stmt.bindInt(1, 10)
var result = stmt.step()
assertEquals(result, StepResult.ROW)
assertEquals(stmt.getInt(0), 42)
assertEquals(stmt.getText(1), "Hello World")
result = stmt.step()
assertEquals(result, StepResult.DONE)
stmt.finalize()
stmt = db.prepareStatement("drop table demo")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("commit")
stmt.step()
stmt.finalize()
db.close()
dbFile.delete()
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.habits
import org.junit.Test
import org.junit.Assert.*
import java.io.*
class AndroidFilesTest : BaseTest() {
@Test
fun testUserFiles() {
val file = File(context.filesDir, "test.txt")
file.writeText("Hello world!")
val af = fileOpener.openUserFile("test.txt")
assertTrue(af.exists())
af.delete()
assertFalse(af.exists())
}
@Test
fun testResourceFiles() {
val file = fileOpener.openResourceFile("migrations/010.sql")
val lines = file.readLines()
assertEquals("delete from Score", lines[0])
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.habits
import android.support.test.*
open class BaseTest {
val context = InstrumentationRegistry.getTargetContext()
val fileOpener = AndroidFileOpener(context)
val databaseOpener = AndroidDatabaseOpener()
}

1
android/src/main/assets Symbolic link
View File

@@ -0,0 +1 @@
../../../core/assets/main/

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.habits
import org.isoron.uhabits.database.*
import org.isoron.uhabits.utils.*
import java.sql.*
class AndroidDatabaseOpener : DatabaseOpener {
override fun open(file: UserFile): Database {
val platformFile = file as AndroidUserFile
DriverManager.registerDriver(Class.forName("org.sqldroid.SQLDroidDriver").newInstance() as Driver)
val conn = DriverManager.getConnection("jdbc:sqlite:${platformFile.file.absolutePath}")
return JavaDatabase(conn, AndroidLog())
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.habits
import android.content.*
import org.isoron.uhabits.utils.*
import java.io.*
import java.util.*
class AndroidFileOpener(val context: Context) : FileOpener {
override fun openUserFile(filename: String): UserFile {
return AndroidUserFile(File(context.filesDir, filename))
}
override fun openResourceFile(filename: String): ResourceFile {
return AndroidResourceFile(context, filename)
}
}
class AndroidResourceFile(val context: Context,
val filename: String) : ResourceFile {
override fun readLines(): List<String> {
val asset = context.assets.open(filename)
val reader = BufferedReader(InputStreamReader(asset))
val lines = ArrayList<String>()
while (true) {
val line = reader.readLine() ?: break
lines.add(line)
}
return lines
}
}
class AndroidUserFile(val file: File) : UserFile {
override fun delete() {
file.delete()
}
override fun exists(): Boolean {
return file.exists()
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.habits
import org.isoron.uhabits.utils.*
class AndroidLog : Log {
override fun debug(msg: String) {
android.util.Log.d("LOOP", msg)
}
override fun info(msg: String) {
android.util.Log.i("LOOP", msg)
}
}

View File

@@ -24,24 +24,17 @@ import com.facebook.react.modules.core.DeviceEventManagerModule.*
import org.isoron.uhabits.*
class CoreModule(
private val context: ReactApplicationContext
) : ReactContextBaseJavaModule(context) {
class CoreModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
private var backend = Backend(AndroidDatabaseOpener(),
AndroidFileOpener(context),
AndroidLog())
private var backend = Backend()
private lateinit var emitter: RCTDeviceEventEmitter
override fun initialize() {
super.initialize()
emitter = context.getJSModule(RCTDeviceEventEmitter::class.java)
backend.createHabit("Wake up early")
backend.createHabit("Wash clothes")
backend.createHabit("Exercise")
backend.createHabit("Meditate")
backend.createHabit("Take vitamins")
backend.createHabit("Write 'the quick brown fox jumps over the lazy dog' daily")
backend.createHabit("Write journal")
backend.createHabit("Study French")
}
override fun getName(): String {
@@ -50,15 +43,17 @@ class CoreModule(
@ReactMethod
fun requestHabitList() {
val params = Arguments.createArray()
for ((id, data) in backend.getHabitList()) {
params.pushMap(Arguments.createMap().apply {
putString("key", id.toString())
putString("name", data["name"] as String)
putInt("color", data["color"] as Int)
val result = backend.getHabitList()
val data = Arguments.createArray()
for (r in result) {
data.pushMap(Arguments.createMap().apply {
for ((key, value) in r) {
if (value is String) putString(key, value)
else if (value is Int) putInt(key, value)
}
})
}
emitter.emit("onHabitList", params)
emitter.emit("onHabitList", data)
}
@ReactMethod