Skip to content

Commit

Permalink
Refactor and fix orders (#18)
Browse files Browse the repository at this point in the history
* fix empty content

* refactor and fix orders

* fix wrong signal inheritance

* add simple test for files

* fix failed signals

* fix sort by signal count

* up version 0.8.0
  • Loading branch information
makeevrserg authored Nov 5, 2024
1 parent 9ceea4c commit cf68c08
Show file tree
Hide file tree
Showing 17 changed files with 568 additions and 326 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ jobs:
- name: Run SQL kenerator
uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3
with:
arguments: :modules:kenerator:sql:run
arguments: :modules:kenerator:sql:run
- name: Run test
uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3
with:
arguments: :web-api:test
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ org.gradle.parallel=true
makeevrserg.project.name=IRDBBackend
makeevrserg.project.url=https://github.com/flipperdevices/IRDB-Backend
makeevrserg.project.group=com.flipperdevices.ifrmvp.backend
makeevrserg.project.version.string=0.7.2
makeevrserg.project.version.string=0.8.0
makeevrserg.project.description=Api for IfrSample
makeevrserg.project.developers=makeevrserg|Makeev Roman|[email protected]
# Java
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.flipperdevices.ifrmvp.backend.core.logging

interface Loggable {
fun info(msg: () -> String)
fun debug(msg: () -> String)
fun error(throwable: Throwable? = null, msg: () -> String)

class Default(tag: String) : Loggable by Slf4jLoggable(tag)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.flipperdevices.ifrmvp.backend.core.logging

import org.slf4j.Logger
import org.slf4j.LoggerFactory

class Slf4jLoggable(tag: String) : Loggable {
private val logger: Logger = LoggerFactory.getLogger(tag)

override fun info(msg: () -> String) {
logger.debug(msg.invoke())
}

override fun debug(msg: () -> String) {
logger.debug(msg.invoke())
}

override fun error(throwable: Throwable?, msg: () -> String) {
if (throwable == null) logger.error(msg.invoke())
else logger.error(msg.invoke(), throwable)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.flipperdevices.ifrmvp.backend.db.signal.table

import com.flipperdevices.ifrmvp.backend.model.DeviceKey
import org.jetbrains.exposed.dao.id.LongIdTable

/**
Expand All @@ -20,16 +21,19 @@ object SignalTable : LongIdTable("SIGNAL_TABLE") {
val dutyCycle = text("duty_cycle").nullable()
val data = text("data").nullable()
val hash = text("hash")
val deviceKey = enumeration<DeviceKey>("device_key").nullable()

init {
uniqueIndex(
deviceKey,
brandId,
type,
frequency,
dutyCycle,
data
)
uniqueIndex(
deviceKey,
brandId,
type,
protocol,
Expand Down
2 changes: 0 additions & 2 deletions modules/kenerator/configuration/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ dependencies {
implementation(projects.modules.database)
implementation(projects.modules.core)
implementation(projects.modules.model)
implementation(projects.modules.database)
implementation(projects.modules.infrared)
implementation(projects.modules.kenerator.sql)
implementation(projects.modules.kenerator.paths)
}

Expand Down
1 change: 1 addition & 0 deletions modules/kenerator/sql/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {
implementation(projects.modules.database)
implementation(projects.modules.infrared)
implementation(projects.modules.kenerator.paths)
implementation(projects.modules.kenerator.configuration)
}

application {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import com.flipperdevices.ifrmvp.backend.db.signal.table.SignalKeyTable
import com.flipperdevices.ifrmvp.backend.db.signal.table.SignalNameAliasTable
import com.flipperdevices.ifrmvp.backend.db.signal.table.SignalTable
import com.flipperdevices.ifrmvp.backend.db.signal.table.UiPresetTable
import com.flipperdevices.ifrmvp.generator.config.device.api.DeviceKeyNamesProvider.Companion.getKey
import com.flipperdevices.ifrmvp.generator.config.device.api.any.AnyDeviceKeyNamesProvider
import com.flipperdevices.ifrmvp.model.IfrKeyIdentifier
import com.flipperdevices.ifrmvp.parser.util.ParserPathResolver
import com.flipperdevices.infrared.editor.encoding.InfraredRemoteEncoder.identifier
Expand All @@ -24,9 +26,11 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.JoinType
import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.batchInsert
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.or
import org.jetbrains.exposed.sql.transactions.transaction

internal class FillerController(private val database: Database) : CoroutineScope by IoCoroutineScope() {
Expand Down Expand Up @@ -115,6 +119,7 @@ internal class FillerController(private val database: Database) : CoroutineScope
this[SignalTable.dutyCycle] = rawRemote?.dutyCycle
this[SignalTable.data] = rawRemote?.data
this[SignalTable.hash] = remote.identifier.hash
this[SignalTable.deviceKey] = AnyDeviceKeyNamesProvider.getKey(remote.identifier.name)
}
// ManyToMany file to signal references
val irFileId = InfraredFileTable
Expand All @@ -124,25 +129,25 @@ internal class FillerController(private val database: Database) : CoroutineScope
.map { it[InfraredFileTable.id] }
.first()

val signalIds = signals.map {
val parsedRemote = it as? InfraredRemote.Parsed
val rawRemote = it as? InfraredRemote.Raw
val signalIds = signals.map { remote ->
val parsedRemote = remote as? InfraredRemote.Parsed
val rawRemote = remote as? InfraredRemote.Raw
SignalTable
.select(SignalTable.id)
.where { SignalTable.brandId eq brandId }
// .andWhere { SignalTable.name eq it.name }
.andWhere { SignalTable.type eq it.type }
.andWhere { SignalTable.type eq remote.type }
.andWhere { SignalTable.protocol eq parsedRemote?.protocol }
.andWhere { SignalTable.address eq parsedRemote?.address }
.andWhere { SignalTable.command eq parsedRemote?.command }
.andWhere { SignalTable.frequency eq rawRemote?.frequency }
.andWhere { SignalTable.dutyCycle eq rawRemote?.dutyCycle }
.andWhere { SignalTable.data eq rawRemote?.data }
.andWhere { SignalTable.deviceKey eq AnyDeviceKeyNamesProvider.getKey(remote.name) }
.map { it[SignalTable.id] }
.firstOrNull() ?: error(
"""
The list is emoty for brand: ${brand.name} category: ${categoryFolder} file: ${irFile.name};
name: ${it.name}
The list is empty for brand: ${brand.name} category: ${categoryFolder} file: ${irFile.name};
name: ${remote.name}
""".trimIndent()
)
}
Expand Down Expand Up @@ -201,6 +206,8 @@ internal class FillerController(private val database: Database) : CoroutineScope
.select(SignalTable.id)
.where { SignalTable.brandId eq brandId }
.andWhere { InfraredFileToSignalTable.infraredFileId eq irFileId }
.andWhere { SignalTable.deviceKey.eq(baseKey).or(SignalTable.deviceKey.isNull()) }
.orderBy(SignalTable.deviceKey to SortOrder.ASC_NULLS_LAST)
.apply {
when (keyIdentifier) {
IfrKeyIdentifier.Empty -> error("Identifying is not possible!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ data class SignalModel(
val id: Long,
@SerialName("remote")
val remote: FlipperRemote,
@SerialName("device_key")
val deviceKey: DeviceKey? = null
) {
@Serializable
data class FlipperRemote(
Expand Down
2 changes: 2 additions & 0 deletions web-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ dependencies {
// Exposed
implementation(libs.exposed.core)
implementation(libs.exposed.dao)
// test
testImplementation(kotlin("test"))
// Services
implementation(projects.modules.buildKonfig)
implementation(projects.modules.model)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.flipperdevices.ifrmvp.backend.route.signal.data

import com.flipperdevices.ifrmvp.backend.core.logging.Loggable
import com.flipperdevices.ifrmvp.backend.db.signal.table.InfraredFileTable
import com.flipperdevices.ifrmvp.backend.db.signal.table.InfraredFileToSignalTable
import com.flipperdevices.ifrmvp.backend.model.SignalRequestModel
import com.flipperdevices.ifrmvp.backend.route.signal.data.model.IncludedFile
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Join
import org.jetbrains.exposed.sql.JoinType
import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.alias
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.transactions.transaction

class IncludedFilesRepository(
private val database: Database
) : Loggable by Loggable.Default("IncludedFilesRepository") {

/**
* This is a list of files, which contains every instance of [successSignalIds]
* aka list<SignalID>().containsAll(successSignal1,successSignal2)
*/
private fun getWhiteListedFileIds(successSignalIds: List<Long>): List<Long> {
var join: Join? = null
successSignalIds.forEachIndexed { i, id ->
join = (join ?: InfraredFileToSignalTable)
.join(
otherTable = InfraredFileToSignalTable.alias("F$i"),
onColumn = InfraredFileToSignalTable.infraredFileId,
otherColumn = InfraredFileToSignalTable.alias("F$i")[InfraredFileToSignalTable.infraredFileId],
joinType = JoinType.INNER
)
}
var query = join
?.select(InfraredFileToSignalTable.infraredFileId)
?.withDistinct(true)
successSignalIds.forEachIndexed { index, id ->
query = if (index == 0) {
query?.where { InfraredFileToSignalTable.signalId eq id }
} else {
query?.andWhere {
InfraredFileToSignalTable.alias("F$index")[InfraredFileToSignalTable.signalId] eq id
}
}
}
return when {
successSignalIds.isEmpty() -> emptyList()
else -> transaction(database) {
query?.map { it[InfraredFileToSignalTable.infraredFileId].value }.orEmpty()
}
}
}

/**
* If any signal is failed then we skip this file
*/
private fun getBlackListedFileIds(failedSignalIds: List<Long>): List<Long> {
return when {
failedSignalIds.isEmpty() -> emptyList()
else -> transaction(database) {
InfraredFileToSignalTable.select(InfraredFileToSignalTable.infraredFileId)
.withDistinct(true)
.where { InfraredFileToSignalTable.signalId inList failedSignalIds }
.map { it[InfraredFileToSignalTable.infraredFileId].value }
}
}
}

/**
* Keep only those files, in which signals have been successfully passed
*
* SELECT INFRARED_FILE."id", INFRARED_FILE."signal_count"
* FROM INFRARED_FILE JOIN INFRARED_FILE_TO_SIGNAL on INFRARED_FILE_TO_SIGNAL."infrared_file_id" = INFRARED_FILE."id"
* group by INFRARED_FILE."id"
* order by INFRARED_FILE."signal_count" desc
*/
suspend fun findIncludedFiles(signalRequestModel: SignalRequestModel): List<IncludedFile> {
info { "#findIncludedFiles invoked" }

val excludedFileIds = getBlackListedFileIds(
failedSignalIds = signalRequestModel.failedResults
.map(SignalRequestModel.SignalResultData::signalId)
)
info { "#findIncludedFiles excludedFileIds: $excludedFileIds" }
val includedFileIds = getWhiteListedFileIds(
successSignalIds = signalRequestModel.successResults
.map(SignalRequestModel.SignalResultData::signalId)
)
info { "#findIncludedFiles includedFileIds: $includedFileIds" }
return transaction(database) {
InfraredFileTable
// Main query
.select(InfraredFileTable.id, InfraredFileTable.signalCount)
.groupBy(InfraredFileTable.id, InfraredFileTable.signalCount)
.orderBy(InfraredFileTable.signalCount to SortOrder.DESC)
.where { InfraredFileTable.brandId eq signalRequestModel.brandId }
.let { nextQuery ->
if (includedFileIds.isEmpty()) nextQuery
else nextQuery.andWhere { InfraredFileTable.id inList includedFileIds }
}
//[3273, 3282, 3283, 3286]
.let { nextQuery ->
if (excludedFileIds.isEmpty()) nextQuery
else nextQuery.andWhere { InfraredFileTable.id notInList excludedFileIds }
}
.map {
val file = IncludedFile(
fileId = it[InfraredFileTable.id].value,
signalCount = it[InfraredFileTable.signalCount]
)
file
}.also {

debug { "#got files: ${it.map { it.fileId }}" }
}
}
}

suspend fun findFallbackFile(signalRequestModel: SignalRequestModel): IncludedFile? {
// Getting last available file
return findIncludedFiles(
signalRequestModel = when {
signalRequestModel.skippedResults.isNotEmpty() -> {
signalRequestModel.copy(
skippedResults = signalRequestModel.skippedResults.dropLast(1)
)
}

signalRequestModel.failedResults.isNotEmpty() -> {
signalRequestModel.copy(
failedResults = signalRequestModel.failedResults.dropLast(1)
)
}

else -> {
signalRequestModel.copy(
successResults = signalRequestModel.successResults.dropLast(1)
)
}
},
).firstOrNull()
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.flipperdevices.ifrmvp.backend.route.signal.data

import com.flipperdevices.ifrmvp.backend.db.signal.table.SignalNameAliasTable
import com.flipperdevices.ifrmvp.backend.model.CategoryConfiguration
import com.flipperdevices.ifrmvp.backend.model.CategoryType
import com.flipperdevices.ifrmvp.backend.model.SignalRequestModel
import com.flipperdevices.ifrmvp.generator.config.device.api.DeviceKeyNamesProvider.Companion.getKey
import com.flipperdevices.ifrmvp.generator.config.device.api.any.AnyDeviceKeyNamesProvider
import com.flipperdevices.ifrmvp.parser.util.ParserPathResolver
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.orWhere
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction

class OrderRepository(private val database: Database) {
fun findOrder(
signalRequestModel: SignalRequestModel,
categoryType: CategoryType,
recursionLevel: Int
): CategoryConfiguration.OrderModel? {
val skippedKeys = transaction(database) {
SignalNameAliasTable
.selectAll()
.where { SignalNameAliasTable.id inList signalRequestModel.skippedResults.map(SignalRequestModel.SignalResultData::signalId) }
.orWhere { SignalNameAliasTable.id inList signalRequestModel.successResults.map(SignalRequestModel.SignalResultData::signalId) }
// .orWhere { SignalNameAliasTable.id inList signalRequestModel.failedResults.map(SignalRequestModel.SignalResultData::signalId) }
.mapNotNull {
val keyName = it[SignalNameAliasTable.signalName]
AnyDeviceKeyNamesProvider.getKey(keyName)
}.distinct()
}

return ParserPathResolver
.categoryConfiguration(categoryType.folderName)
.orders
.filter { !skippedKeys.contains(it.key) }
.getOrNull(recursionLevel)
}
}
Loading

0 comments on commit cf68c08

Please sign in to comment.