Skip to content

Commit 8a3a2a0

Browse files
committed
Fix missing version on empty scriptlets
1 parent feaa42c commit 8a3a2a0

6 files changed

Lines changed: 51 additions & 9 deletions

File tree

ad-blocking/ad-blocking-impl/src/main/java/com/duckduckgo/adblocking/impl/AdBlockingExtensionRepository.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ class RealAdBlockingExtensionRepository @Inject constructor(
3838

3939
override suspend fun storeScriptlets(version: String, scriptlets: Map<String, ByteArray>) {
4040
dao.replaceAll(
41-
scriptlets.map { (name, content) ->
42-
ScriptletEntity(name = name, version = version, content = content)
41+
version = version,
42+
scriptlets = scriptlets.map { (name, content) ->
43+
ScriptletEntity(name = name, content = content)
4344
},
4445
)
4546
}

ad-blocking/ad-blocking-impl/src/main/java/com/duckduckgo/adblocking/impl/store/AdBlockingExtensionDao.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.Flow
2626
@Dao
2727
abstract class AdBlockingExtensionDao {
2828

29-
@Query("SELECT version FROM ad_blocking_scriptlets LIMIT 1")
29+
@Query("SELECT version FROM ad_blocking_scriptlets_metadata WHERE id = ${ScriptletMetadataEntity.SINGLETON_ID}")
3030
abstract suspend fun getVersion(): String?
3131

3232
@Query("SELECT * FROM ad_blocking_scriptlets")
@@ -38,9 +38,13 @@ abstract class AdBlockingExtensionDao {
3838
@Insert(onConflict = OnConflictStrategy.REPLACE)
3939
abstract suspend fun insertScriptlets(scriptlets: List<ScriptletEntity>)
4040

41+
@Insert(onConflict = OnConflictStrategy.REPLACE)
42+
abstract suspend fun upsertMetadata(metadata: ScriptletMetadataEntity)
43+
4144
@Transaction
42-
open suspend fun replaceAll(scriptlets: List<ScriptletEntity>) {
45+
open suspend fun replaceAll(version: String, scriptlets: List<ScriptletEntity>) {
4346
deleteAllScriptlets()
4447
insertScriptlets(scriptlets)
48+
upsertMetadata(ScriptletMetadataEntity(version = version))
4549
}
4650
}

ad-blocking/ad-blocking-impl/src/main/java/com/duckduckgo/adblocking/impl/store/AdBlockingExtensionDatabase.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import androidx.room.migration.Migration
2222

2323
@Database(
2424
exportSchema = true,
25-
version = 1,
26-
entities = [ScriptletEntity::class],
25+
version = 2,
26+
entities = [ScriptletEntity::class, ScriptletMetadataEntity::class],
2727
)
2828
abstract class AdBlockingExtensionDatabase : RoomDatabase() {
2929
abstract fun adBlockingExtensionDao(): AdBlockingExtensionDao

ad-blocking/ad-blocking-impl/src/main/java/com/duckduckgo/adblocking/impl/store/ScriptletEntity.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,16 @@ import androidx.room.PrimaryKey
2222
@Entity(tableName = "ad_blocking_scriptlets")
2323
data class ScriptletEntity(
2424
@PrimaryKey val name: String,
25-
val version: String,
2625
val content: ByteArray,
2726
) {
2827
override fun equals(other: Any?): Boolean {
2928
if (this === other) return true
3029
if (other !is ScriptletEntity) return false
31-
return name == other.name && version == other.version && content.contentEquals(other.content)
30+
return name == other.name && content.contentEquals(other.content)
3231
}
3332

3433
override fun hashCode(): Int {
3534
var result = name.hashCode()
36-
result = 31 * result + version.hashCode()
3735
result = 31 * result + content.contentHashCode()
3836
return result
3937
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) 2026 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.adblocking.impl.store
18+
19+
import androidx.room.Entity
20+
import androidx.room.PrimaryKey
21+
22+
@Entity(tableName = "ad_blocking_scriptlets_metadata")
23+
data class ScriptletMetadataEntity(
24+
@PrimaryKey val id: Int = SINGLETON_ID,
25+
val version: String,
26+
) {
27+
companion object {
28+
const val SINGLETON_ID = 0
29+
}
30+
}

ad-blocking/ad-blocking-impl/src/test/java/com/duckduckgo/adblocking/impl/AdBlockingExtensionRepositoryTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import org.junit.After
2626
import org.junit.Assert.assertArrayEquals
2727
import org.junit.Assert.assertEquals
2828
import org.junit.Assert.assertNull
29+
import org.junit.Assert.assertTrue
2930
import org.junit.Before
3031
import org.junit.Test
3132
import org.junit.runner.RunWith
@@ -87,4 +88,12 @@ class AdBlockingExtensionRepositoryTest {
8788
val stored = database.adBlockingExtensionDao().scriptletsFlow().first()
8889
assertEquals(setOf("new/path.js"), stored.map { it.name }.toSet())
8990
}
91+
92+
@Test
93+
fun whenStoreScriptletsCalledWithEmptyMapThenVersionIsStillPersisted() = runTest {
94+
repository.storeScriptlets(version = "2026.3.9", scriptlets = emptyMap())
95+
96+
assertEquals("2026.3.9", repository.getStoredVersion())
97+
assertTrue(database.adBlockingExtensionDao().scriptletsFlow().first().isEmpty())
98+
}
9099
}

0 commit comments

Comments
 (0)