Creating interfaces for multiple EventStores
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip01Core.store
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
|
||||
interface IEventStore {
|
||||
fun insert(event: Event): Boolean
|
||||
|
||||
interface ITransaction {
|
||||
fun insert(event: Event): Boolean
|
||||
}
|
||||
|
||||
fun transaction(body: ITransaction.() -> Unit)
|
||||
|
||||
fun <T : Event> query(filter: Filter): List<T>
|
||||
|
||||
fun <T : Event> query(filters: List<Filter>): List<T>
|
||||
|
||||
fun <T : Event> query(
|
||||
filter: Filter,
|
||||
onEach: (T) -> Unit,
|
||||
)
|
||||
|
||||
fun <T : Event> query(
|
||||
filters: List<Filter>,
|
||||
onEach: (T) -> Unit,
|
||||
)
|
||||
|
||||
fun count(filter: Filter): Int
|
||||
|
||||
fun count(filters: List<Filter>): Int
|
||||
|
||||
fun delete(filter: Filter)
|
||||
|
||||
fun delete(filters: List<Filter>)
|
||||
|
||||
fun deleteExpiredEvents()
|
||||
|
||||
fun close()
|
||||
}
|
||||
+22
-22
@@ -175,10 +175,10 @@ class EventIndexesModule(
|
||||
return makeQueryIn(rowIdSubQuery.sql)
|
||||
}
|
||||
|
||||
fun query(
|
||||
fun <T : Event> query(
|
||||
filter: Filter,
|
||||
db: SQLiteDatabase,
|
||||
): List<Event> {
|
||||
): List<T> {
|
||||
val rowIdSubQuery = prepareRowIDSubQueries(filter)
|
||||
|
||||
return if (rowIdSubQuery == null) {
|
||||
@@ -188,10 +188,10 @@ class EventIndexesModule(
|
||||
}
|
||||
}
|
||||
|
||||
fun query(
|
||||
fun <T : Event> query(
|
||||
filter: Filter,
|
||||
db: SQLiteDatabase,
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) {
|
||||
val rowIdSubQuery = prepareRowIDSubQueries(filter) ?: return db.runQueryEmitting(makeEverythingQuery(), onEach = onEach)
|
||||
|
||||
@@ -205,10 +205,10 @@ class EventIndexesModule(
|
||||
return makeQueryIn(unions)
|
||||
}
|
||||
|
||||
fun query(
|
||||
fun <T : Event> query(
|
||||
filters: List<Filter>,
|
||||
db: SQLiteDatabase,
|
||||
): List<Event> {
|
||||
): List<T> {
|
||||
val rowIdSubQueries = filters.mapNotNull { prepareRowIDSubQueries(it) }
|
||||
|
||||
if (rowIdSubQueries.isEmpty()) return db.runQuery(makeEverythingQuery())
|
||||
@@ -219,10 +219,10 @@ class EventIndexesModule(
|
||||
return db.runQuery(makeQueryIn(unions), args)
|
||||
}
|
||||
|
||||
fun query(
|
||||
fun <T : Event> query(
|
||||
filters: List<Filter>,
|
||||
db: SQLiteDatabase,
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) {
|
||||
val rowIdSubQueries = filters.mapNotNull { prepareRowIDSubQueries(it) }
|
||||
|
||||
@@ -244,20 +244,20 @@ class EventIndexesModule(
|
||||
ORDER BY created_at DESC, id
|
||||
""".trimIndent()
|
||||
|
||||
private fun SQLiteDatabase.runQuery(
|
||||
private fun <T : Event> SQLiteDatabase.runQuery(
|
||||
sql: String,
|
||||
args: List<String> = emptyList(),
|
||||
): List<Event> =
|
||||
): List<T> =
|
||||
rawQuery(sql, args.toTypedArray()).use { cursor ->
|
||||
parseResults(cursor)
|
||||
}
|
||||
|
||||
private fun parseResults(cursor: Cursor): List<Event> {
|
||||
val events = ArrayList<Event>()
|
||||
private fun <T : Event> parseResults(cursor: Cursor): List<T> {
|
||||
val events = ArrayList<T>()
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
events.add(
|
||||
EventFactory.create(
|
||||
EventFactory.create<T>(
|
||||
cursor.getString(0).intern(),
|
||||
cursor.getString(1).intern(),
|
||||
cursor.getLong(2),
|
||||
@@ -272,21 +272,21 @@ class EventIndexesModule(
|
||||
return events
|
||||
}
|
||||
|
||||
private fun SQLiteDatabase.runQueryEmitting(
|
||||
private fun <T : Event> SQLiteDatabase.runQueryEmitting(
|
||||
sql: String,
|
||||
args: List<String> = emptyList(),
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) = rawQuery(sql, args.toTypedArray()).use { cursor ->
|
||||
emitResults(cursor, onEach)
|
||||
}
|
||||
|
||||
private fun emitResults(
|
||||
private fun <T : Event> emitResults(
|
||||
cursor: Cursor,
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) {
|
||||
while (cursor.moveToNext()) {
|
||||
onEach(
|
||||
EventFactory.create(
|
||||
EventFactory.create<T>(
|
||||
cursor.getString(0).intern(),
|
||||
cursor.getString(1).intern(),
|
||||
cursor.getLong(2),
|
||||
@@ -347,18 +347,18 @@ class EventIndexesModule(
|
||||
fun delete(
|
||||
filter: Filter,
|
||||
db: SQLiteDatabase,
|
||||
): Int? {
|
||||
val rowIdQuery = prepareRowIDSubQueries(filter) ?: return null
|
||||
): Int {
|
||||
val rowIdQuery = prepareRowIDSubQueries(filter) ?: return 0
|
||||
return db.runDelete(rowIdQuery.sql, rowIdQuery.args)
|
||||
}
|
||||
|
||||
fun delete(
|
||||
filters: List<Filter>,
|
||||
db: SQLiteDatabase,
|
||||
): Int? {
|
||||
): Int {
|
||||
val rowIdSubqueries = filters.mapNotNull { prepareRowIDSubQueries(it) }
|
||||
|
||||
if (rowIdSubqueries.isEmpty()) return null
|
||||
if (rowIdSubqueries.isEmpty()) return 0
|
||||
|
||||
val unions = rowIdSubqueries.joinToString(" UNION ") { it.sql }
|
||||
val args = rowIdSubqueries.flatMap { it.args }
|
||||
|
||||
+16
-19
@@ -23,6 +23,7 @@ package com.vitorpamplona.quartz.nip01Core.store.sqlite
|
||||
import android.content.Context
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.store.IEventStore
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.EventIndexesModule.IndexingStrategy
|
||||
|
||||
class EventStore(
|
||||
@@ -30,40 +31,36 @@ class EventStore(
|
||||
dbName: String? = "events.db",
|
||||
val relayUrl: String? = "wss://quartz.local",
|
||||
val tagIndexStrategy: IndexingStrategy = IndexingStrategy(),
|
||||
) {
|
||||
) : IEventStore {
|
||||
val store = SQLiteEventStore(context, dbName, relayUrl, tagIndexStrategy)
|
||||
|
||||
fun insert(event: Event) = store.insertEvent(event)
|
||||
override fun insert(event: Event) = store.insertEvent(event)
|
||||
|
||||
interface ITransaction {
|
||||
fun insert(event: Event): Boolean
|
||||
}
|
||||
override fun transaction(body: IEventStore.ITransaction.() -> Unit) = store.transaction(body)
|
||||
|
||||
fun transaction(body: ITransaction.() -> Unit) = store.transaction(body)
|
||||
override fun <T : Event> query(filter: Filter) = store.query<T>(filter)
|
||||
|
||||
fun query(filter: Filter) = store.query(filter)
|
||||
override fun <T : Event> query(filters: List<Filter>) = store.query<T>(filters)
|
||||
|
||||
fun query(filters: List<Filter>) = store.query(filters)
|
||||
|
||||
fun query(
|
||||
override fun <T : Event> query(
|
||||
filter: Filter,
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) = store.query(filter, onEach)
|
||||
|
||||
fun query(
|
||||
override fun <T : Event> query(
|
||||
filters: List<Filter>,
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) = store.query(filters, onEach)
|
||||
|
||||
fun count(filter: Filter) = store.count(filter)
|
||||
override fun count(filter: Filter) = store.count(filter)
|
||||
|
||||
fun count(filters: List<Filter>) = store.count(filters)
|
||||
override fun count(filters: List<Filter>) = store.count(filters)
|
||||
|
||||
fun delete(filter: Filter) = store.delete(filter)
|
||||
override fun delete(filter: Filter) = store.delete(filter)
|
||||
|
||||
fun delete(filters: List<Filter>) = store.delete(filters)
|
||||
override fun delete(filters: List<Filter>) = store.delete(filters)
|
||||
|
||||
fun deleteExpiredEvents() = store.deleteExpiredEvents()
|
||||
override fun deleteExpiredEvents() = store.deleteExpiredEvents()
|
||||
|
||||
fun close() = store.close()
|
||||
override fun close() = store.close()
|
||||
}
|
||||
|
||||
+14
-9
@@ -29,6 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.isEphemeral
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.store.IEventStore
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.EventIndexesModule.IndexingStrategy
|
||||
import com.vitorpamplona.quartz.nip40Expiration.isExpired
|
||||
|
||||
@@ -117,7 +118,7 @@ class SQLiteEventStore(
|
||||
|
||||
inner class Transaction(
|
||||
val db: SQLiteDatabase,
|
||||
) : EventStore.ITransaction {
|
||||
) : IEventStore.ITransaction {
|
||||
override fun insert(event: Event): Boolean {
|
||||
if (event.isExpired()) throw SQLiteConstraintException("blocked: Cannot insert an expired event")
|
||||
if (event.kind.isEphemeral()) return false
|
||||
@@ -139,27 +140,31 @@ class SQLiteEventStore(
|
||||
}
|
||||
}
|
||||
|
||||
fun query(filter: Filter): List<Event> = eventIndexModule.query(filter, readableDatabase)
|
||||
fun <T : Event> query(filter: Filter): List<T> = eventIndexModule.query(filter, readableDatabase)
|
||||
|
||||
fun query(filters: List<Filter>): List<Event> = eventIndexModule.query(filters, readableDatabase)
|
||||
fun <T : Event> query(filters: List<Filter>): List<T> = eventIndexModule.query(filters, readableDatabase)
|
||||
|
||||
fun query(
|
||||
fun <T : Event> query(
|
||||
filter: Filter,
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) = eventIndexModule.query(filter, readableDatabase, onEach)
|
||||
|
||||
fun query(
|
||||
fun <T : Event> query(
|
||||
filters: List<Filter>,
|
||||
onEach: (Event) -> Unit,
|
||||
onEach: (T) -> Unit,
|
||||
) = eventIndexModule.query(filters, readableDatabase, onEach)
|
||||
|
||||
fun count(filter: Filter): Int = eventIndexModule.count(filter, readableDatabase)
|
||||
|
||||
fun count(filters: List<Filter>): Int = eventIndexModule.count(filters, readableDatabase)
|
||||
|
||||
fun delete(filter: Filter): Int? = eventIndexModule.delete(filter, writableDatabase)
|
||||
fun delete(filter: Filter) {
|
||||
eventIndexModule.delete(filter, writableDatabase)
|
||||
}
|
||||
|
||||
fun delete(filters: List<Filter>): Int? = eventIndexModule.delete(filters, writableDatabase)
|
||||
fun delete(filters: List<Filter>) {
|
||||
eventIndexModule.delete(filters, writableDatabase)
|
||||
}
|
||||
|
||||
fun delete(id: HexKey): Int = writableDatabase.delete("event_headers", "id = ?", arrayOf(id))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user