Skip to content

Commit ed3370b

Browse files
committed
Prepare migration to SQLDelight version of libpretixsync
1 parent 2a3bc01 commit ed3370b

File tree

10 files changed

+239
-18
lines changed

10 files changed

+239
-18
lines changed

pretixscan/app/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ apply from: '../libpretixsync-repo/libpretixsync/versions.gradle'
1717
android {
1818
namespace 'eu.pretix.pretixscan.droid'
1919

20-
compileSdkVersion 33
20+
compileSdkVersion 34
2121

2222
defaultConfig {
2323
applicationId "eu.pretix.pretixscan.droid"
2424
minSdkVersion 21
25-
targetSdkVersion 33
25+
targetSdkVersion 34
2626
versionCode 94
2727
versionName "2.8.2"
2828
vectorDrawables.useSupportLibrary = true
@@ -159,6 +159,7 @@ dependencies {
159159
implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_kotlin_version"
160160
implementation "net.i2p.crypto:eddsa:$eddsa_version"
161161
implementation "com.google.protobuf:protobuf-javalite:$protobuf_version"
162+
implementation "app.cash.sqldelight:android-driver:$sqldelight_version"
162163

163164
implementation 'com.facebook.soloader:soloader:0.10.5'
164165
debugImplementation 'com.facebook.flipper:flipper:0.191.0'

pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/PretixScan.kt

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import android.database.sqlite.SQLiteException
44
import android.os.Build
55
import androidx.appcompat.app.AppCompatDelegate
66
import androidx.multidex.MultiDexApplication
7+
import androidx.sqlite.db.SupportSQLiteDatabase
8+
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
79
import com.facebook.flipper.android.AndroidFlipperClient
810
import com.facebook.flipper.core.FlipperClient
911
import com.facebook.soloader.SoLoader
@@ -13,14 +15,21 @@ import eu.pretix.libpretixsync.check.OnlineCheckProvider
1315
import eu.pretix.libpretixsync.check.ProxyCheckProvider
1416
import eu.pretix.libpretixsync.check.TicketCheckProvider
1517
import eu.pretix.libpretixsync.db.Migrations
18+
import eu.pretix.libpretixsync.sqldelight.AndroidUtilDateAdapter
19+
import eu.pretix.libpretixsync.sqldelight.BigDecimalAdapter
20+
import eu.pretix.libpretixsync.sqldelight.SyncDatabase
1621
import eu.pretix.pretixscan.droid.connectivity.ConnectivityHelper
1722
import eu.pretix.pretixscan.utils.KeystoreHelper
23+
import eu.pretix.pretixscan.utils.createSyncDatabase
24+
import eu.pretix.pretixscan.utils.readVersionPragma
1825
import io.requery.BlockingEntityStore
1926
import io.requery.Persistable
2027
import io.requery.sql.EntityDataStore
2128
import net.zetetic.database.sqlcipher.SQLiteConnection
2229
import net.zetetic.database.sqlcipher.SQLiteDatabase
2330
import net.zetetic.database.sqlcipher.SQLiteDatabaseHook
31+
import net.zetetic.database.sqlcipher.SupportOpenHelperFactory
32+
import java.nio.charset.StandardCharsets
2433
import java.util.concurrent.locks.ReentrantLock
2534

2635

@@ -105,6 +114,57 @@ class PretixScan : MultiDexApplication() {
105114
return dataStore!!
106115
}
107116

117+
val db: SyncDatabase by lazy {
118+
// Access data to init schema through requery if it hasn't been created already
119+
data.raw("PRAGMA user_version;").first()
120+
121+
val dbPass = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) KeystoreHelper.secureValue(KEYSTORE_PASSWORD, true)
122+
else KEYSTORE_PASSWORD
123+
124+
val androidDriver = if (BuildConfig.DEBUG) {
125+
AndroidSqliteDriver(
126+
schema = SyncDatabase.Schema,
127+
context = this.applicationContext,
128+
name = "default",
129+
callback = object : AndroidSqliteDriver.Callback(SyncDatabase.Schema) {
130+
override fun onOpen(db: SupportSQLiteDatabase) {
131+
db.setForeignKeyConstraintsEnabled(true)
132+
}
133+
},
134+
)
135+
} else {
136+
System.loadLibrary("sqlcipher")
137+
AndroidSqliteDriver(
138+
schema = SyncDatabase.Schema,
139+
context = this.applicationContext,
140+
name = "default",
141+
callback = object : AndroidSqliteDriver.Callback(SyncDatabase.Schema) {
142+
override fun onOpen(db: SupportSQLiteDatabase) {
143+
db.setForeignKeyConstraintsEnabled(true)
144+
}
145+
},
146+
factory = SupportOpenHelperFactory(dbPass.toByteArray())
147+
)
148+
}
149+
150+
// Uncomment LogSqliteDriver for verbose logging
151+
val driver = if(BuildConfig.DEBUG) {
152+
// LogSqliteDriver(androidDriver) {
153+
// Log.d("SQLDelight", it)
154+
// }
155+
androidDriver
156+
} else {
157+
androidDriver
158+
}
159+
160+
createSyncDatabase(
161+
driver = driver,
162+
version = readVersionPragma(driver),
163+
dateAdapter = AndroidUtilDateAdapter(),
164+
bigDecimalAdapter = BigDecimalAdapter(),
165+
)
166+
}
167+
108168
override fun onCreate() {
109169
super.onCreate()
110170

@@ -140,7 +200,7 @@ class PretixScan : MultiDexApplication() {
140200
}
141201
fallback = AsyncCheckProvider(conf, data)
142202
}
143-
return OnlineCheckProvider(conf, AndroidHttpClientFactory(this), data, fileStorage, fallback, fallbackTimeout)
203+
return OnlineCheckProvider(conf, AndroidHttpClientFactory(this), data, db, fileStorage, fallback, fallbackTimeout)
144204
}
145205
}
146206

pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/db/SqlCipherConnection.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ internal class SqlCipherConnection(val database: SQLiteDatabase) : BaseConnectio
107107

108108
@Throws(SQLException::class)
109109
override fun isClosed(): Boolean {
110-
return !database.isOpen()
110+
return !database.isOpen
111111
}
112112

113113
@Throws(SQLException::class)
114114
override fun isReadOnly(): Boolean {
115-
return database.isReadOnly()
115+
return database.isReadOnly
116116
}
117117

118118
@Throws(SQLException::class)

pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/db/SqlCipherDatabaseSource.kt

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
package eu.pretix.pretixscan.droid.db
1919

2020
import android.content.Context
21+
import eu.pretix.pretixscan.utils.DatabaseProvider
2122
import io.requery.android.DefaultMapping
2223
import io.requery.android.LoggingListener
23-
import io.requery.android.sqlite.DatabaseProvider
2424
import io.requery.android.sqlite.SchemaUpdater
2525
import io.requery.meta.EntityModel
2626
import io.requery.sql.Configuration
@@ -81,17 +81,18 @@ open class SqlCipherDatabaseSource(context: Context,
8181
}
8282
}
8383

84-
override fun getConfiguration(): Configuration {
85-
if (_configuration == null) {
86-
val builder = ConfigurationBuilder(this, model)
87-
.setMapping(mapping)
88-
.setPlatform(platform)
89-
.setBatchUpdateSize(1000)
90-
onConfigure(builder)
91-
_configuration = builder.build()
84+
override val configuration: Configuration
85+
get() {
86+
if (_configuration == null) {
87+
val builder = ConfigurationBuilder(this, model)
88+
.setMapping(mapping)
89+
.setPlatform(platform)
90+
.setBatchUpdateSize(1000)
91+
onConfigure(builder)
92+
_configuration = builder.build()
93+
}
94+
return _configuration!!
9295
}
93-
return _configuration!!
94-
}
9596

9697
override fun onCreate(db: SQLiteDatabase) {
9798
this.db = db
@@ -117,7 +118,7 @@ open class SqlCipherDatabaseSource(context: Context,
117118
override fun getConnection(): Connection {
118119
synchronized(this) {
119120
if (db == null) {
120-
db = getWritableDatabase()
121+
db = writableDatabase
121122
}
122123
return getConnection(db!!)
123124
}

pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/CheckInListSelectActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class CheckInListSelectActivity : MorphingDialogActivity() {
5454
api,
5555
AndroidSentryImplementation(),
5656
(application as PretixScan).data,
57+
(application as PretixScan).db,
5758
(application as PretixScan).fileStorage,
5859
1000L,
5960
1000L,

pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/MainActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ class MainActivity : AppCompatActivity(), ReloadableActivity, ScannerView.Result
535535
api,
536536
AndroidSentryImplementation(),
537537
(application as PretixScan).data,
538+
(application as PretixScan).db,
538539
(application as PretixScan).fileStorage,
539540
60000L,
540541
5 * 60000L,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package eu.pretix.pretixscan.utils
2+
3+
import io.requery.sql.Configuration
4+
import io.requery.sql.ConnectionProvider
5+
import io.requery.sql.TableCreationMode
6+
7+
/**
8+
* Converted copy of io.requery.android.sqlite.DatabaseProvider.
9+
*
10+
* The original is written in Java and causes platform declaration clashes with newer
11+
* androidx.sqlite versions.
12+
*/
13+
interface DatabaseProvider<T> : ConnectionProvider, AutoCloseable {
14+
open fun setLoggingEnabled(enable: Boolean)
15+
16+
/**
17+
* Sets the [TableCreationMode] to use when the database is created or upgraded.
18+
*
19+
* @param mode to use
20+
*/
21+
open fun setTableCreationMode(mode: TableCreationMode)
22+
23+
/**
24+
* @return [Configuration] used by the provider
25+
*/
26+
val configuration: Configuration
27+
28+
/**
29+
* Callback for when the database schema is to be created.
30+
*
31+
* @param db instance
32+
*/
33+
fun onCreate(db: T)
34+
35+
/**
36+
* Callback for when the database should be configured.
37+
*
38+
* @param db instance
39+
*/
40+
fun onConfigure(db: T)
41+
42+
/**
43+
* Callback for when the database should be upgraded from an previous version to a new version.
44+
*
45+
* @param db instance
46+
*/
47+
fun onUpgrade(db: T, oldVersion: Int, newVersion: Int)
48+
49+
/**
50+
* @return read only database instance
51+
*/
52+
val readableDatabase: T
53+
54+
/**
55+
* @return readable and writable database instance
56+
*/
57+
val writableDatabase: T
58+
59+
/**
60+
* closes the database.
61+
*/
62+
override fun close()
63+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package eu.pretix.pretixscan.utils
2+
3+
import app.cash.sqldelight.ColumnAdapter
4+
import app.cash.sqldelight.TransacterImpl
5+
import app.cash.sqldelight.db.QueryResult
6+
import app.cash.sqldelight.db.SqlDriver
7+
import eu.pretix.libpretixsync.sqldelight.CheckIn
8+
import eu.pretix.libpretixsync.sqldelight.Closing
9+
import eu.pretix.libpretixsync.sqldelight.Event
10+
import eu.pretix.libpretixsync.sqldelight.Receipt
11+
import eu.pretix.libpretixsync.sqldelight.ReceiptLine
12+
import eu.pretix.libpretixsync.sqldelight.ReceiptPayment
13+
import eu.pretix.libpretixsync.sqldelight.SubEvent
14+
import eu.pretix.libpretixsync.sqldelight.SyncDatabase
15+
import java.math.BigDecimal
16+
import java.util.Date
17+
18+
fun createSyncDatabase(
19+
driver: SqlDriver,
20+
version: Long?,
21+
dateAdapter: ColumnAdapter<Date, String>,
22+
bigDecimalAdapter: ColumnAdapter<BigDecimal, Double>,
23+
): SyncDatabase {
24+
// TODO: Check DB migrations
25+
if (version == null || version == 0L) {
26+
try {
27+
val t = object : TransacterImpl(driver) {}
28+
t.transaction {
29+
SyncDatabase.Schema.create(driver)
30+
}
31+
} catch (e: Throwable) {
32+
e.printStackTrace()
33+
throw e
34+
}
35+
}
36+
37+
return SyncDatabase(
38+
driver = driver,
39+
CheckInAdapter =
40+
CheckIn.Adapter(
41+
datetimeAdapter = dateAdapter,
42+
),
43+
ClosingAdapter =
44+
Closing.Adapter(
45+
cash_countedAdapter = bigDecimalAdapter,
46+
datetimeAdapter = dateAdapter,
47+
payment_sumAdapter = bigDecimalAdapter,
48+
payment_sum_cashAdapter = bigDecimalAdapter,
49+
),
50+
EventAdapter =
51+
Event.Adapter(
52+
date_fromAdapter = dateAdapter,
53+
date_toAdapter = dateAdapter,
54+
),
55+
ReceiptLineAdapter =
56+
ReceiptLine.Adapter(
57+
cart_expiresAdapter = dateAdapter,
58+
createdAdapter = dateAdapter,
59+
custom_price_inputAdapter = bigDecimalAdapter,
60+
listed_priceAdapter = bigDecimalAdapter,
61+
priceAdapter = bigDecimalAdapter,
62+
price_after_voucherAdapter = bigDecimalAdapter,
63+
tax_rateAdapter = bigDecimalAdapter,
64+
tax_valueAdapter = bigDecimalAdapter,
65+
),
66+
ReceiptAdapter =
67+
Receipt.Adapter(
68+
datetime_closedAdapter = dateAdapter,
69+
datetime_openedAdapter = dateAdapter,
70+
),
71+
ReceiptPaymentAdapter =
72+
ReceiptPayment.Adapter(
73+
amountAdapter = bigDecimalAdapter,
74+
),
75+
SubEventAdapter =
76+
SubEvent.Adapter(
77+
date_fromAdapter = dateAdapter,
78+
date_toAdapter = dateAdapter,
79+
),
80+
)
81+
}
82+
83+
fun readVersionPragma(driver: SqlDriver): Long? {
84+
return driver.executeQuery(
85+
identifier = null,
86+
sql = "PRAGMA user_version;",
87+
mapper = { cursor ->
88+
cursor.next()
89+
QueryResult.Value(cursor.getLong(0))
90+
},
91+
parameters = 0,
92+
).value
93+
}

pretixscan/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ plugins {
33
id 'com.android.application' version '8.4.2' apply false
44
id 'org.jetbrains.kotlin.android' version "1.9.23" apply false
55
id 'com.google.protobuf' version '0.9.4' apply false
6+
id 'app.cash.sqldelight' version '2.0.2' apply false
67
}
78

89
allprojects {

pretixscan/libpretixsync-repo

Submodule libpretixsync-repo updated 125 files

0 commit comments

Comments
 (0)