Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/release-sqlite-db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ jobs:

# Verify the generated database files
ls -l generators/policies/build/policies-database.db
ls -l generators/store/build/store-database.db
ls -l generators/store/build/store-database-en.db
ls -l generators/store/build/store-database-fr.db
ls -l generators/store/build/store-database-he.db

- name: Define release name
id: relname
Expand All @@ -62,4 +64,6 @@ jobs:
name: ${{ env.RELEASE_NAME }}
files: |
generators/policies/build/policies-database.db
generators/store/build/store-database.db
generators/store/build/store-database-en.db
generators/store/build/store-database-fr.db
generators/store/build/store-database-he.db
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
alias(libs.plugins.kotlinx.serialization).apply(false)
alias(libs.plugins.android.application).apply(false)
alias(libs.plugins.vannitktech.maven.publish).apply(false)
alias(libs.plugins.sql.delight).apply(false)
}

// Task to run both generators
Expand Down
120 changes: 120 additions & 0 deletions dao/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import com.vanniktech.maven.publish.SonatypeHost

plugins {
alias(libs.plugins.multiplatform)
alias(libs.plugins.android.library)
alias(libs.plugins.sql.delight)
alias(libs.plugins.vannitktech.maven.publish)
}

val ref = System.getenv("GITHUB_REF") ?: ""
version = if (ref.startsWith("refs/tags/")) {
val tag = ref.removePrefix("refs/tags/")
if (tag.startsWith("v")) tag.substring(1) else tag
} else "dev"


kotlin {
jvmToolchain(17)
androidTarget { publishLibraryVariants("release") }
jvm()


sourceSets {

androidMain.dependencies {
implementation(libs.sqldelight.android.driver)
implementation(libs.kotlinx.coroutines.android)
}

jvmMain.dependencies {
implementation(libs.sqlite.jdbc)
implementation(libs.maven.slf4j.provider)
implementation(libs.kotlinx.coroutines.swing)
}

jvmTest.dependencies {
implementation(kotlin("test"))
implementation(libs.kotlinx.coroutines.test)

}

commonMain.dependencies {
api(project(":core"))
implementation(project(":localization"))
api(libs.gplay.scrapper.core)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.kermit)
implementation(libs.platform.tools.release.fetcher)
}

}

//https://kotlinlang.org/docs/native-objc-interop.html#export-of-kdoc-comments-to-generated-objective-c-headers
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
compilations["main"].compileTaskProvider.configure {
compilerOptions {
freeCompilerArgs.add("-Xexport-kdoc")
}
}
}

}

android {
namespace = "io.github.kdroidfilter.database.dao"
compileSdk = 35

defaultConfig {
minSdk = 24
}
}

sqldelight {
databases {
create("Database") {
packageName.set("io.github.kdroidfilter.database.store")
}
}
}

mavenPublishing {
coordinates(
groupId = "io.github.kdroidfilter.database.dao",
artifactId = "core",
version = version.toString()
)

pom {
name.set("KDroid Database")
description.set("DAO of the Kdroid Database")
inceptionYear.set("2025")
url.set("https://github.com/kdroidFilter/KDroidDatabase")

licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/licenses/MIT")
}
}

developers {
developer {
id.set("kdroidfilter")
name.set("Elie Gambache")
email.set("elyahou.hadass@gmail.com")
}
}

scm {
connection.set("scm:git:git://github.com/kdroidFilter/KDroidDatabase.git")
developerConnection.set("scm:git:ssh://git@github.com/kdroidFilter/KDroidDatabase.git")
url.set("https://github.com/kdroidFilter/KDroidDatabase")
}
}

publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)

signAllPublications()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.kdroidfilter.database.dao

import com.kdroid.gplayscrapper.core.model.GooglePlayApplicationInfo

/**
* Extended class to add additional information to the GooglePlayApplicationInfo model
*/
data class AppInfoWithExtras(
val id: Long,
val categoryLocalizedName: String,
val app: GooglePlayApplicationInfo
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package io.github.kdroidfilter.database.dao

import com.kdroid.gplayscrapper.core.model.GooglePlayApplicationInfo
import io.github.kdroidfilter.database.store.Database
import io.github.kdroidfilter.database.core.AppCategory
import io.github.kdroidfilter.database.localization.LocalizedAppCategory
import io.github.kdroidfilter.database.store.App_categories
import io.github.kdroidfilter.database.store.Applications
import io.github.kdroidfilter.database.store.Developers

/**
* Data Access Object for Applications
* Contains functions for database operations related to applications
*/
object ApplicationsDao {

/**
* Creates a GooglePlayApplicationInfo from database data
*/
fun createAppInfoFromDatabaseData(
app: Applications,
developer: Developers
): GooglePlayApplicationInfo {
return GooglePlayApplicationInfo(
appId = app.app_id,
title = app.title,
description = app.description ?: "",
descriptionHTML = app.description_html ?: "",
summary = app.summary ?: "",
installs = app.installs ?: "",
minInstalls = app.min_installs ?: 0L,
realInstalls = app.real_installs ?: 0L,
score = app.score ?: 0.0,
ratings = app.ratings ?: 0L,
reviews = app.reviews ?: 0L,
histogram = app.histogram?.removeSurrounding("[", "]")?.split(", ")?.map { it.toLongOrNull() ?: 0L } ?: emptyList(),
price = app.price ?: 0.0,
free = app.free == 1L,
currency = app.currency ?: "",
sale = app.sale == 1L,
saleTime = app.sale_time,
originalPrice = app.original_price,
saleText = app.sale_text,
offersIAP = app.offers_iap == 1L,
inAppProductPrice = app.in_app_product_price ?: "",
developer = developer.name,
developerId = developer.developer_id,
developerEmail = developer.email ?: "",
developerWebsite = developer.website ?: "",
developerAddress = developer.address ?: "",
privacyPolicy = app.privacy_policy ?: "",
genre = app.genre ?: "",
genreId = app.genre_id ?: "",
icon = app.icon ?: "",
headerImage = app.header_image ?: "",
screenshots = app.screenshots?.split(",") ?: emptyList(),
video = app.video ?: "",
videoImage = app.video_image ?: "",
contentRating = app.content_rating ?: "",
contentRatingDescription = app.content_rating_description ?: "",
adSupported = app.ad_supported == 1L,
containsAds = app.contains_ads == 1L,
released = app.released ?: "",
updated = app.updated ?: 0L,
version = app.version ?: "Varies with device",
url = app.url ?: ""
)
}

/**
* Creates an AppInfoWithExtras object from database data
* This function requires a model class AppInfoWithExtras to be defined in the DAO module
* or to be imported from another module
*/
fun <T> createAppInfoWithExtras(
app: Applications,
developer: Developers,
category: App_categories,
deviceLanguage: String,
creator: (Long, String, GooglePlayApplicationInfo) -> T
): T {
val appInfo = createAppInfoFromDatabaseData(app, developer)

val categoryEnum = AppCategory.valueOf(category.category_name)
val localizedCategoryName = LocalizedAppCategory.getLocalizedName(categoryEnum, deviceLanguage)

return creator(app.id, localizedCategoryName, appInfo)
}

/**
* Loads all applications from the database
*/
fun <T> loadApplicationsFromDatabase(
database: Database,
deviceLanguage: String,
creator: (Long, String, GooglePlayApplicationInfo) -> T
): List<T> {
// Directly use the query objects provided by the database
val applicationsQueries = database.applicationsQueries
val developersQueries = database.developersQueries
val categoriesQueries = database.app_categoriesQueries

return applicationsQueries.getAllApplications().executeAsList().map { app ->
val developer = developersQueries.getDeveloperById(app.developer_id).executeAsOne()
val category = categoriesQueries.getCategoryById(app.app_category_id).executeAsOne()

createAppInfoWithExtras(app, developer, category, deviceLanguage, creator)
}
}

/**
* Searches applications in the database
*/
fun <T> searchApplicationsInDatabase(
database: Database,
query: String,
deviceLanguage: String,
creator: (Long, String, GooglePlayApplicationInfo) -> T
): List<T> {
// Directly use the query objects provided by the database
val applicationsQueries = database.applicationsQueries
val developersQueries = database.developersQueries
val categoriesQueries = database.app_categoriesQueries

return applicationsQueries.searchApplications(query, query).executeAsList().map { app ->
val developer = developersQueries.getDeveloperById(app.developer_id).executeAsOne()
val category = categoriesQueries.getCategoryById(app.app_category_id).executeAsOne()

createAppInfoWithExtras(app, developer, category, deviceLanguage, creator)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
CREATE TABLE IF NOT EXISTS app_categories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
category_name TEXT UNIQUE NOT NULL, -- TORAH, COMMUNICATION, etc.
description TEXT,
created_at INTEGER DEFAULT (strftime('%s', 'now'))
);

-- Insert a new category
insertCategory:
INSERT INTO app_categories (category_name, description)
VALUES (?, ?);

-- Delete a category by ID
deleteCategory:
DELETE FROM app_categories
WHERE id = ?;

-- Get all categories
getAllCategories:
SELECT *
FROM app_categories;

-- Get category by ID
getCategoryById:
SELECT *
FROM app_categories
WHERE id = ?;

-- Get category by name
getCategoryByName:
SELECT *
FROM app_categories
WHERE category_name = ?;
Loading