@@ -8,6 +8,34 @@ import org.appdevforall.codeonthego.indexing.api.indexQuery
88import org.appdevforall.codeonthego.indexing.jvm.KtFileMetadataDescriptor.KEY_IS_INDEXED
99import org.appdevforall.codeonthego.indexing.jvm.KtFileMetadataDescriptor.KEY_PACKAGE
1010import java.io.Closeable
11+ import java.util.concurrent.CopyOnWriteArrayList
12+
13+ /* *
14+ * A completed write to a [KtFileMetadataIndex].
15+ */
16+ sealed interface KtFileMetadataWrite {
17+ /* * The record for [filePath] was inserted or replaced; its package is [packageFqName]. */
18+ data class Upserted (
19+ val filePath : String ,
20+ val packageFqName : String ,
21+ ) : KtFileMetadataWrite
22+
23+ /* * The records for [filePaths] were removed. */
24+ data class Removed (
25+ val filePaths : Collection <String >,
26+ ) : KtFileMetadataWrite
27+
28+ /* * Every record was removed. */
29+ data object Cleared : KtFileMetadataWrite
30+ }
31+
32+ /* *
33+ * Receives each [KtFileMetadataWrite] after it has been applied to the index.
34+ */
35+ fun interface KtFileMetadataWriteListener {
36+ /* * Called synchronously on the writing thread once [write] is visible to readers. */
37+ fun onWrite (write : KtFileMetadataWrite )
38+ }
1139
1240/* *
1341 * An index of [KtFileMetadata] entries, one per Kotlin source file.
@@ -40,20 +68,42 @@ class KtFileMetadataIndex(
4068 )
4169 }
4270
71+ private val listeners = CopyOnWriteArrayList <KtFileMetadataWriteListener >()
72+
73+ /* *
74+ * Registers [listener] to be told about every later write.
75+ *
76+ * Closing the returned handle unregisters it.
77+ */
78+ fun addWriteListener (listener : KtFileMetadataWriteListener ): AutoCloseable {
79+ listeners.add(listener)
80+ return AutoCloseable { listeners.remove(listener) }
81+ }
82+
83+ private fun notifyListeners (write : KtFileMetadataWrite ) {
84+ listeners.forEach { it.onWrite(write) }
85+ }
86+
4387 /* *
4488 * Insert or replace the metadata record for a single file.
4589 *
4690 * Because [KtFileMetadata.key] and [KtFileMetadata.sourceId] are both the
4791 * file path, a file has at most one row and an insert replaces it.
4892 */
49- suspend fun upsert (metadata : KtFileMetadata ) = backing.insert(metadata)
93+ suspend fun upsert (metadata : KtFileMetadata ) {
94+ backing.insert(metadata)
95+ notifyListeners(KtFileMetadataWrite .Upserted (metadata.filePath, metadata.packageFqName))
96+ }
5097
5198 /* *
5299 * Remove the metadata record for [filePath].
53100 *
54101 * No-op if the file is not in the index.
55102 */
56- suspend fun remove (filePath : String ) = backing.removeBySource(filePath)
103+ suspend fun remove (filePath : String ) {
104+ backing.removeBySource(filePath)
105+ notifyListeners(KtFileMetadataWrite .Removed (listOf (filePath)))
106+ }
57107
58108 /* *
59109 * Remove the metadata records for every path in [filePaths] as a single
@@ -63,7 +113,10 @@ class KtFileMetadataIndex(
63113 * transaction instead of N - see [Index.removeBySources]. Paths not present in
64114 * the index are ignored.
65115 */
66- suspend fun removeAll (filePaths : Collection <String >) = backing.removeBySources(filePaths)
116+ suspend fun removeAll (filePaths : Collection <String >) {
117+ backing.removeBySources(filePaths)
118+ notifyListeners(KtFileMetadataWrite .Removed (filePaths))
119+ }
67120
68121 /* *
69122 * Return the [KtFileMetadata] for [filePath], or `null` if the file is
@@ -154,7 +207,10 @@ class KtFileMetadataIndex(
154207 ).map { it.filePath }
155208
156209 /* * Remove all records from the index. */
157- suspend fun clear () = backing.clear()
210+ suspend fun clear () {
211+ backing.clear()
212+ notifyListeners(KtFileMetadataWrite .Cleared )
213+ }
158214
159215 /* * Whether the backing index still serves reads and writes. */
160216 val isOpen: Boolean
0 commit comments