Skip to content

Commit c279914

Browse files
committed
fix: ensure correct parent-child mapping in copy operation(s)
1 parent d9d7ad0 commit c279914

2 files changed

Lines changed: 118 additions & 127 deletions

File tree

src/main/kotlin/com/sakethh/linkora/data/repository/MultiActionRepoImpl.kt

Lines changed: 82 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -171,89 +171,70 @@ class MultiActionRepoImpl(
171171
override suspend fun copyMultipleItems(copyItemsDTO: CopyItemsDTO): Result<CopyItemsHTTPResponseDTO> {
172172
return try {
173173
val eventTimestamp = getSystemEpochSeconds()
174-
lateinit var newGlobalSelectedLinkIds: List<Long>
175-
println("Remote Links : ${copyItemsDTO.linkIds.values}")
176-
// copy the links based on `copyItemsDTO.linkIds`
174+
lateinit var globalLinksOldToNewIdsMap: Map<Long, Long>
177175
val copiedFolderResponse = mutableListOf<CopiedFolderResponse>()
178176
transaction {
179177
val sourceGlobalSelectedLinks = LinksTable.selectAll().where {
180178
LinksTable.id inList copyItemsDTO.linkIds.values
181179
}.toList()
182180

183-
newGlobalSelectedLinkIds = LinksTable.copy(
181+
globalLinksOldToNewIdsMap = LinksTable.copy(
184182
source = sourceGlobalSelectedLinks,
185183
eventTimestamp = eventTimestamp,
186184
parentFolderId = copyItemsDTO.newParentFolderId,
187185
newLinkType = copyItemsDTO.linkType
188-
).map {
189-
it[LinksTable.id].value
190-
}
191-
192-
val sourceGlobalSelectedLinksIds = sourceGlobalSelectedLinks.map {
193-
it[LinksTable.id].value
194-
}
195-
196-
val globalOldToNewLinkIdsMap = sourceGlobalSelectedLinksIds.zip(newGlobalSelectedLinkIds).toMap()
197-
198-
insertNewLinkTags(
199-
oldToNewLinkIdsMap = globalOldToNewLinkIdsMap
200186
)
201187

188+
insertNewLinkTags(oldToNewLinkIdsMap = globalLinksOldToNewIdsMap)
189+
202190
// initially, we'll insert the root folders
203-
lateinit var copiedRootFolderIds: List<Long>
204191
val sourceRootFolders = FoldersTable.selectAll().where {
205192
FoldersTable.id.inList(copyItemsDTO.folders.map { it.currentFolder.remoteId })
206193
}.toList()
207-
val eventTimestamp = getSystemEpochSeconds()
208194

209-
copiedRootFolderIds = FoldersTable.copy(
195+
val copiedRootFolderOldToNewIdsMap = FoldersTable.copy(
210196
source = sourceRootFolders,
211197
eventTimestamp = eventTimestamp,
212198
parentFolderId = copyItemsDTO.newParentFolderId
213-
).mapIndexed { index, resultRow ->
214-
resultRow[FoldersTable.id].value.run {
215-
copiedFolderResponse.add(
216-
CopiedFolderResponse(
217-
currentFolder = CurrentFolder(
218-
localId = copyItemsDTO.folders[index].currentFolder.localId, remoteId = this
219-
), links = emptyList()
220-
)
199+
)
200+
201+
copyItemsDTO.folders.forEach { (currentFolder, _, _) ->
202+
copiedFolderResponse.add(
203+
CopiedFolderResponse(
204+
currentFolder = CurrentFolder(
205+
localId = currentFolder.localId,
206+
remoteId = copiedRootFolderOldToNewIdsMap.getValue(currentFolder.remoteId)
207+
), links = emptyList()
221208
)
222-
this
223-
}
209+
)
224210
}
225211

226212
// insert links of root folders
227-
copyItemsDTO.folders.map { it.currentFolder.remoteId }.forEachIndexed { folderIndex, folderId ->
213+
copyItemsDTO.folders.forEachIndexed { folderIndex, folder ->
228214
val sourceLinksOfRootFolder = LinksTable.selectAll().where {
229-
LinksTable.idOfLinkedFolder.eq(folderId)
215+
LinksTable.id.inList(folder.links.map { it.remoteId })
230216
}.toList()
231-
val sourceLinksIdsOfRootFolder = sourceLinksOfRootFolder.map {
232-
it[LinksTable.id].value
233-
}
234-
val eventTimestamp = getSystemEpochSeconds()
217+
235218
val newRootFolderLinkIds = LinksTable.copy(
236219
source = sourceLinksOfRootFolder,
237220
eventTimestamp = eventTimestamp,
238-
parentFolderId = copiedRootFolderIds[folderIndex]
221+
parentFolderId = copiedRootFolderOldToNewIdsMap[folder.currentFolder.remoteId]
239222
)
240223

241-
insertNewLinkTags(
242-
oldToNewLinkIdsMap = sourceLinksIdsOfRootFolder.zip(newRootFolderLinkIds.map {
243-
it[LinksTable.id].value
244-
}).toMap()
245-
)
224+
insertNewLinkTags(oldToNewLinkIdsMap = newRootFolderLinkIds)
246225

247-
newRootFolderLinkIds.mapIndexed { linkResultRowIndex, resultRow ->
248-
FolderLink(
249-
localId = copyItemsDTO.folders[folderIndex].links[linkResultRowIndex].localId,
250-
remoteId = resultRow[LinksTable.id].value
251-
)
252-
}.let {
253-
copiedFolderResponse[folderIndex] = copiedFolderResponse[folderIndex].copy(
254-
links = it
255-
)
226+
val folderLinks = folder.links.mapNotNull {
227+
val newRemoteId = newRootFolderLinkIds[it.remoteId]
228+
if (newRemoteId != null) {
229+
FolderLink(localId = it.localId, remoteId = newRemoteId)
230+
} else {
231+
println("folder.links.mapNotNull hit null")
232+
null
233+
}
256234
}
235+
copiedFolderResponse[folderIndex] = copiedFolderResponse[folderIndex].copy(
236+
links = folderLinks
237+
)
257238
}
258239

259240
fun insertChildFolders(
@@ -263,74 +244,70 @@ class MultiActionRepoImpl(
263244
val sourceFolders = FoldersTable.selectAll().where {
264245
FoldersTable.id.inList(childFolders.map { it.currentFolder.remoteId })
265246
}.toList()
266-
val eventTimestamp = getSystemEpochSeconds()
267-
FoldersTable.copy(source = sourceFolders, eventTimestamp, parentFolderId)
268-
.forEachIndexed { insertedFolderRowIndex, insertedFolderRow ->
269-
val newParentFolderId = insertedFolderRow[FoldersTable.id].value
270-
val sourceParentFolderId = sourceFolders[insertedFolderRowIndex][FoldersTable.id].value
271-
val sourceCurrentFolderLinks = LinksTable.selectAll().where {
272-
LinksTable.idOfLinkedFolder.eq(sourceParentFolderId)
273-
}
274-
val sourceCurrentFolderLinkIds = sourceCurrentFolderLinks.map {
275-
it[LinksTable.id].value
276-
}
277-
val newChildFolderLinks = LinksTable.copy(
278-
source = sourceCurrentFolderLinks.toList(),
279-
eventTimestamp = eventTimestamp,
280-
parentFolderId = newParentFolderId
281-
)
282247

283-
insertNewLinkTags(
284-
oldToNewLinkIdsMap = sourceCurrentFolderLinkIds.zip(newChildFolderLinks.map {
285-
it[LinksTable.id].value
286-
}).toMap()
287-
)
248+
val oldToNewChildFolderMap =
249+
FoldersTable.copy(source = sourceFolders, eventTimestamp, parentFolderId)
288250

289-
newChildFolderLinks.mapIndexed { insertedLinkRowIndex, insertedLinkRow ->
290-
FolderLink(
291-
localId = childFolders[insertedFolderRowIndex].links[insertedLinkRowIndex].localId,
292-
remoteId = insertedLinkRow[LinksTable.id].value
293-
)
294-
}.let {
295-
copiedFolderResponse.add(
296-
CopiedFolderResponse(
297-
currentFolder = CurrentFolder(
298-
localId = childFolders[insertedFolderRowIndex].currentFolder.localId,
299-
remoteId = newParentFolderId
300-
), links = it
301-
)
302-
)
251+
childFolders.forEach { childFolder ->
252+
val oldFolderId = childFolder.currentFolder.remoteId
253+
val newFolderId = oldToNewChildFolderMap.getValue(oldFolderId)
254+
255+
val sourceCurrentFolderLinks = LinksTable.selectAll().where {
256+
LinksTable.id.inList(childFolder.links.map { it.remoteId })
257+
}
258+
val newChildFolderLinksMap = LinksTable.copy(
259+
source = sourceCurrentFolderLinks.toList(),
260+
eventTimestamp = eventTimestamp,
261+
parentFolderId = newFolderId
262+
)
263+
264+
insertNewLinkTags(oldToNewLinkIdsMap = newChildFolderLinksMap)
265+
266+
val folderLinks = childFolder.links.mapNotNull { link ->
267+
val newRemoteId = newChildFolderLinksMap[link.remoteId]
268+
if (newRemoteId != null) {
269+
FolderLink(localId = link.localId, remoteId = newRemoteId)
270+
} else {
271+
println("childFolder.links.mapNotNull hit null")
272+
null
303273
}
304-
insertChildFolders(
305-
newParentFolderId, childFolders[insertedFolderRowIndex].childFolders
306-
)
307274
}
275+
276+
copiedFolderResponse.add(
277+
CopiedFolderResponse(
278+
currentFolder = CurrentFolder(
279+
localId = childFolder.currentFolder.localId, remoteId = newFolderId
280+
), links = folderLinks
281+
)
282+
)
283+
insertChildFolders(
284+
parentFolderId = newFolderId, childFolder.childFolders
285+
)
286+
}
308287
}
309288

310289
// insert child folders
311-
copyItemsDTO.folders.forEachIndexed { index, parentFolder ->
290+
copyItemsDTO.folders.forEach { parentFolder ->
312291
insertChildFolders(
313-
parentFolderId = copiedRootFolderIds[index], childFolders = parentFolder.childFolders
292+
parentFolderId = copiedRootFolderOldToNewIdsMap.getValue(parentFolder.currentFolder.remoteId),
293+
childFolders = parentFolder.childFolders
314294
)
315295
}
316-
317-
}.let {
318-
Result.Success(
319-
response = CopyItemsHTTPResponseDTO(
320-
folders = copiedFolderResponse.toList(), linkIds = copyItemsDTO.linkIds.run {
321-
this.toList().mapIndexed { index, pair ->
322-
pair.first to newGlobalSelectedLinkIds[index]
323-
}.toMap()
324-
}, correlation = copyItemsDTO.correlation, eventTimestamp = eventTimestamp
325-
), webSocketEvent = WebSocketEvent(
326-
operation = Route.MultiAction.COPY_EXISTING_ITEMS.name, payload = Json.encodeToJsonElement(
327-
CopyItemsSocketResponseDTO(
328-
eventTimestamp = eventTimestamp, correlation = copyItemsDTO.correlation
329-
)
296+
}
297+
Result.Success(
298+
response = CopyItemsHTTPResponseDTO(
299+
folders = copiedFolderResponse.toList(),
300+
linkIds = globalLinksOldToNewIdsMap,
301+
correlation = copyItemsDTO.correlation,
302+
eventTimestamp = eventTimestamp
303+
), webSocketEvent = WebSocketEvent(
304+
operation = Route.MultiAction.COPY_EXISTING_ITEMS.name, payload = Json.encodeToJsonElement(
305+
CopyItemsSocketResponseDTO(
306+
eventTimestamp = eventTimestamp, correlation = copyItemsDTO.correlation
330307
)
331308
)
332309
)
333-
}
310+
)
334311
} catch (e: Exception) {
335312
Result.Failure(e)
336313
}

src/main/kotlin/com/sakethh/linkora/utils/HelperFunctions.kt

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import com.sakethh.linkora.domain.tables.LinksTable
88
import org.jetbrains.exposed.v1.core.Column
99
import org.jetbrains.exposed.v1.core.ResultRow
1010
import org.jetbrains.exposed.v1.core.dao.id.LongIdTable
11-
import org.jetbrains.exposed.v1.jdbc.batchInsert
11+
import org.jetbrains.exposed.v1.jdbc.insertAndGetId
1212
import org.jetbrains.exposed.v1.jdbc.select
1313
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
1414
import kotlin.time.Clock
@@ -45,30 +45,44 @@ fun LongIdTable.checkForLWWConflictAndThrow(id: Long, timeStamp: Long, lastModif
4545
}
4646
}
4747

48-
fun FoldersTable.copy(source: List<ResultRow>, eventTimestamp: Long, parentFolderId: Long?): List<ResultRow> {
49-
return batchInsert(source) {
50-
this[folderName] = it[folderName]
51-
this[lastModified] = eventTimestamp
52-
this[note] = it[note]
53-
this[parentFolderID] = parentFolderId
54-
this[isFolderArchived] = it[isFolderArchived]
55-
}.toList()
48+
fun FoldersTable.copy(source: List<ResultRow>, eventTimestamp: Long, parentFolderId: Long?): Map<Long, Long> {
49+
val oldToNewIdMap = mutableMapOf<Long, Long>()
50+
source.forEach { sourceRow ->
51+
val oldId = sourceRow[FoldersTable.id].value
52+
val newId = insertAndGetId {
53+
it[folderName] = sourceRow[folderName]
54+
it[lastModified] = eventTimestamp
55+
it[note] = sourceRow[note]
56+
it[parentFolderID] = parentFolderId
57+
it[isFolderArchived] = sourceRow[isFolderArchived]
58+
}
59+
oldToNewIdMap[oldId] = newId.value
60+
}
61+
return oldToNewIdMap
5662
}
5763

58-
fun LinksTable.copy(source: List<ResultRow>, eventTimestamp: Long, parentFolderId: Long?, newLinkType: LinkType? = null): List<ResultRow> {
59-
return batchInsert(source) {
60-
set(lastModified, eventTimestamp)
61-
set(linkType, newLinkType?.name ?: it[linkType])
62-
set(linkTitle, it[linkTitle])
63-
set(url, it[url])
64-
set(baseURL, it[baseURL])
65-
set(imgURL, it[imgURL])
66-
set(note, it[note])
67-
set(idOfLinkedFolder, parentFolderId)
68-
set(userAgent, it[userAgent])
69-
set(mediaType, it[mediaType])
70-
set(markedAsImportant, it[markedAsImportant])
64+
fun LinksTable.copy(
65+
source: List<ResultRow>, eventTimestamp: Long, parentFolderId: Long?, newLinkType: LinkType? = null
66+
): Map<Long, Long> {
67+
val oldToNewIdMap = mutableMapOf<Long, Long>()
68+
source.forEach { sourceRow ->
69+
val oldId = sourceRow[LinksTable.id].value
70+
val newId = insertAndGetId {
71+
it[lastModified] = eventTimestamp
72+
it[linkType] = newLinkType?.name ?: sourceRow[LinksTable.linkType]
73+
it[linkTitle] = sourceRow[LinksTable.linkTitle]
74+
it[url] = sourceRow[LinksTable.url]
75+
it[baseURL] = sourceRow[LinksTable.baseURL]
76+
it[imgURL] = sourceRow[LinksTable.imgURL]
77+
it[note] = sourceRow[LinksTable.note]
78+
it[idOfLinkedFolder] = parentFolderId
79+
it[userAgent] = sourceRow[LinksTable.userAgent]
80+
it[mediaType] = sourceRow[LinksTable.mediaType]
81+
it[markedAsImportant] = sourceRow[LinksTable.markedAsImportant]
82+
}
83+
oldToNewIdMap[oldId] = newId.value
7184
}
85+
return oldToNewIdMap
7286
}
7387

7488
inline fun <T> tryAndCatchResult(init: () -> Result<T>): Result<T> {

0 commit comments

Comments
 (0)