Skip to content

Commit 3e1b4b9

Browse files
committed
fix(index): Update index incrementally instead of recreating it every time
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
1 parent 658ef86 commit 3e1b4b9

File tree

4 files changed

+84
-41
lines changed

4 files changed

+84
-41
lines changed

src/lib/CachingTreeWrapper.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ export default class CachingTreeWrapper implements OrderFolderResource<typeof It
2626
const id = await this.innerTree.createBookmark(bookmark)
2727
const cacheId = await this.cacheTree.createBookmark(bookmark.copy(false))
2828
const cacheBookmark = this.cacheTree.bookmarksCache.findBookmark(cacheId)
29+
this.cacheTree.bookmarksCache.removeFromIndex(cacheBookmark)
2930
cacheBookmark.id = id
3031
cacheBookmark.parentId = bookmark.parentId
31-
this.cacheTree.bookmarksCache.createIndex()
32+
this.cacheTree.bookmarksCache.updateIndex(cacheBookmark)
3233
return id
3334
}
3435

@@ -46,9 +47,10 @@ export default class CachingTreeWrapper implements OrderFolderResource<typeof It
4647
const id = await this.innerTree.createFolder(folder)
4748
const cacheId = await this.cacheTree.createFolder(folder.copy(false))
4849
const cacheFolder = this.cacheTree.bookmarksCache.findFolder(cacheId)
50+
this.cacheTree.bookmarksCache.removeFromIndex(cacheFolder)
4951
cacheFolder.id = id
5052
cacheFolder.parentId = folder.parentId
51-
this.cacheTree.bookmarksCache.createIndex()
53+
this.cacheTree.bookmarksCache.updateIndex(cacheFolder)
5254
return id
5355
}
5456

src/lib/Tree.ts

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class Bookmark<L extends TItemLocation> {
3939
public location: L
4040
public isRoot = false
4141
private hashValue: Record<string, string>
42+
public index: IItemIndex<L>
4243

4344
constructor({
4445
id,
@@ -194,8 +195,9 @@ export class Bookmark<L extends TItemLocation> {
194195
return result
195196
}
196197

197-
createIndex(): any {
198-
return { [this.id]: this }
198+
createIndex(): IItemIndex<L> {
199+
this.index = { bookmark: {[this.id]: this}, folder: {} }
200+
return this.index
199201
}
200202

201203
// TODO: Make this return the correct type based on the type param
@@ -258,7 +260,7 @@ export class Folder<L extends TItemLocation> {
258260
public isRoot = false
259261
public loaded = true
260262
public location: L
261-
private index: IItemIndex<L>
263+
public index: IItemIndex<L>
262264

263265
constructor({
264266
id,
@@ -363,7 +365,7 @@ export class Folder<L extends TItemLocation> {
363365
): Promise<void> {
364366
await Parallel.each(
365367
this.children,
366-
async (item) => {
368+
async(item) => {
367369
await fn(item, this)
368370
if (item.type === 'folder') {
369371
// give the browser time to breathe
@@ -560,24 +562,43 @@ export class Folder<L extends TItemLocation> {
560562
createIndex(): IItemIndex<L> {
561563
this.index = {
562564
folder: { [this.id]: this },
563-
bookmark: this.children
564-
.filter((child) => child instanceof Bookmark)
565-
.reduce((obj, child) => {
566-
obj[child.id] = child
567-
return obj
568-
}, {}),
565+
bookmark: {}
569566
}
570567

571-
this.children
572-
.filter((child) => child instanceof Folder)
573-
.map((child) => child.createIndex())
574-
.forEach((subIndex) => {
568+
for (const child of this.children) {
569+
if (child instanceof Bookmark) {
570+
this.index.bookmark[child.id] = child
571+
} else if (child instanceof Folder) {
572+
const subIndex = child.createIndex()
575573
Object.assign(this.index.folder, subIndex.folder)
576574
Object.assign(this.index.bookmark, subIndex.bookmark)
577-
})
575+
}
576+
}
577+
578578
return this.index
579579
}
580580

581+
updateIndex(item: TItem<L>) {
582+
const itemIndex = item.index || item.createIndex()
583+
let currentItem = item
584+
while (currentItem) {
585+
Object.assign(currentItem.index.folder, itemIndex.folder)
586+
Object.assign(currentItem.index.bookmark, itemIndex.bookmark)
587+
currentItem = this.index.folder[currentItem.parentId]
588+
}
589+
}
590+
591+
removeFromIndex(item: TItem<L>) {
592+
if (!item) return
593+
if (item.parentId) {
594+
let parentFolder = this.index.folder[item.parentId]
595+
while (parentFolder) {
596+
delete parentFolder.index[item.type][item.id]
597+
parentFolder = this.index.folder[parentFolder.parentId]
598+
}
599+
}
600+
}
601+
581602
inspect(depth = 0): string {
582603
return (
583604
Array(depth < 0 ? 0 : depth)
@@ -618,13 +639,13 @@ export class Folder<L extends TItemLocation> {
618639
...obj,
619640
children: obj.children
620641
? obj.children.map((child) => {
621-
// Firefox seems to set 'url' even for folders
622-
if ('url' in child && typeof child.url === 'string') {
623-
return Bookmark.hydrate(child)
624-
} else {
625-
return Folder.hydrate(child)
626-
}
627-
})
642+
// Firefox seems to set 'url' even for folders
643+
if ('url' in child && typeof child.url === 'string') {
644+
return Bookmark.hydrate(child)
645+
} else {
646+
return Folder.hydrate(child)
647+
}
648+
})
628649
: null,
629650
})
630651
}

src/lib/adapters/Caching.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export default class CachingAdapter implements Adapter, BulkImportResource<TItem
8080
throw new UnknownCreateTargetError()
8181
}
8282
foundFolder.children.push(bm)
83-
this.bookmarksCache.createIndex()
83+
this.bookmarksCache.updateIndex(bm)
8484
return bm.id
8585
}
8686

@@ -111,7 +111,8 @@ export default class CachingAdapter implements Adapter, BulkImportResource<TItem
111111
)
112112
foundNewFolder.children.push(foundBookmark)
113113
foundBookmark.parentId = newBm.parentId
114-
this.bookmarksCache.createIndex()
114+
this.bookmarksCache.removeFromIndex(foundBookmark)
115+
this.bookmarksCache.updateIndex(newBm)
115116
}
116117

117118
async removeBookmark(bookmark:Bookmark<TItemLocation>): Promise<void> {
@@ -131,7 +132,7 @@ export default class CachingAdapter implements Adapter, BulkImportResource<TItem
131132
foundOldFolder.children.indexOf(foundBookmark),
132133
1
133134
)
134-
this.bookmarksCache.createIndex()
135+
this.bookmarksCache.removeFromIndex(bookmark)
135136
}
136137

137138
async createFolder(folder:Folder<TItemLocation>): Promise<string|number> {
@@ -142,7 +143,7 @@ export default class CachingAdapter implements Adapter, BulkImportResource<TItem
142143
throw new UnknownCreateTargetError()
143144
}
144145
foundParentFolder.children.push(newFolder)
145-
this.bookmarksCache.createIndex()
146+
this.bookmarksCache.updateIndex(newFolder)
146147
return newFolder.id
147148
}
148149

@@ -167,9 +168,10 @@ export default class CachingAdapter implements Adapter, BulkImportResource<TItem
167168
}
168169
foundOldParentFolder.children.splice(foundOldParentFolder.children.indexOf(oldFolder), 1)
169170
foundNewParentFolder.children.push(oldFolder)
171+
this.bookmarksCache.removeFromIndex(oldFolder)
170172
oldFolder.title = folder.title
171173
oldFolder.parentId = folder.parentId
172-
this.bookmarksCache.createIndex()
174+
this.bookmarksCache.updateIndex(oldFolder)
173175
}
174176

175177
async orderFolder(id:string|number, order:Ordering<TItemLocation>):Promise<void> {
@@ -218,7 +220,7 @@ export default class CachingAdapter implements Adapter, BulkImportResource<TItem
218220
return
219221
}
220222
foundOldFolder.children.splice(foundOldFolder.children.indexOf(oldFolder), 1)
221-
this.bookmarksCache.createIndex()
223+
this.bookmarksCache.removeFromIndex(oldFolder)
222224
}
223225

224226
async bulkImportFolder(id:string|number, folder:Folder<TItemLocation>):Promise<Folder<TItemLocation>> {
@@ -237,7 +239,8 @@ export default class CachingAdapter implements Adapter, BulkImportResource<TItem
237239
// insert into tree
238240
foundFolder.children = imported.children
239241
// good as new
240-
this.bookmarksCache.createIndex()
242+
foundFolder.createIndex()
243+
this.bookmarksCache.updateIndex(foundFolder)
241244
return imported
242245
}
243246

src/lib/adapters/NextcloudBookmarks.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ export default class NextcloudBookmarksAdapter implements Adapter, BulkImportRes
408408
}
409409
folder.children = children
410410
folder.loaded = true
411-
this.tree.createIndex()
411+
folder.createIndex()
412+
this.tree.updateIndex(folder)
412413
return folder.copy(true).children
413414
}
414415

@@ -435,10 +436,14 @@ export default class NextcloudBookmarksAdapter implements Adapter, BulkImportRes
435436
throw new UnexpectedServerResponseError()
436437
}
437438

438-
parentFolder.children.push(
439-
new Folder({ id: json.item.id, title, parentId, location: ItemLocation.SERVER })
440-
)
441-
this.tree.createIndex()
439+
const newFolder = new Folder({
440+
id: json.item.id,
441+
title,
442+
parentId,
443+
location: ItemLocation.SERVER,
444+
})
445+
parentFolder.children.push(newFolder)
446+
this.tree.updateIndex(newFolder)
442447
return json.item.id
443448
}
444449

@@ -500,7 +505,8 @@ export default class NextcloudBookmarksAdapter implements Adapter, BulkImportRes
500505
}
501506
const imported = recurseChildren(json.data, parentId, folder.title, folder.parentId)
502507
parentFolder.children = imported.copy(true).children
503-
this.tree.createIndex()
508+
parentFolder.createIndex()
509+
this.tree.updateIndex(parentFolder)
504510
return imported
505511
}
506512

@@ -536,9 +542,10 @@ export default class NextcloudBookmarksAdapter implements Adapter, BulkImportRes
536542
throw new UnknownMoveTargetError()
537543
}
538544
newParentFolder.children.push(oldFolder)
545+
this.tree.removeFromIndex(oldFolder)
539546
oldFolder.title = folder.title
540547
oldFolder.parentId = folder.parentId
541-
this.tree.createIndex()
548+
this.tree.updateIndex(oldFolder)
542549
}
543550

544551
async orderFolder(id:string|number, order:Ordering<typeof ItemLocation.SERVER>):Promise<void> {
@@ -573,7 +580,7 @@ export default class NextcloudBookmarksAdapter implements Adapter, BulkImportRes
573580
parent.children = parent.children.filter(
574581
(child) => String(child.id) !== String(id)
575582
)
576-
this.tree.createIndex()
583+
this.tree.removeFromIndex(oldFolder)
577584
}
578585
}
579586

@@ -691,7 +698,7 @@ export default class NextcloudBookmarksAdapter implements Adapter, BulkImportRes
691698
this.list && this.list.push(upstreamMark)
692699
if (this.tree) {
693700
newParentFolder.children.push(upstreamMark)
694-
this.tree.createIndex()
701+
this.tree.updateIndex(upstreamMark)
695702
}
696703

697704
return bm.id
@@ -742,11 +749,21 @@ export default class NextcloudBookmarksAdapter implements Adapter, BulkImportRes
742749
throw e
743750
}
744751

752+
if (oldParentId) {
753+
const oldParentFolder = this.tree.findFolder(oldParentId)
754+
const oldBm = oldParentFolder.findBookmark(newBm.id)
755+
oldParentFolder.children = oldParentFolder.children.filter(
756+
(item) => !(item.type === 'bookmark' && item.id === newBm.id)
757+
)
758+
if (oldBm && this.tree) {
759+
this.tree.removeFromIndex(oldBm)
760+
}
761+
}
745762
if (!newFolder.children.find(item => String(item.id) === String(newBm.id) && item.type === 'bookmark')) {
746763
newFolder.children.push(newBm)
747764
}
748765
newBm.id = upstreamId + ';' + newBm.parentId
749-
this.tree.createIndex()
766+
this.tree.updateIndex(newBm)
750767

751768
return newBm.id
752769
})

0 commit comments

Comments
 (0)