mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-02 04:01:43 +02:00
222 lines
5.8 KiB
TypeScript
222 lines
5.8 KiB
TypeScript
/*
|
|
This file is part of the Notesnook project (https://notesnook.com/)
|
|
|
|
Copyright (C) 2023 Streetwriters (Private) Limited
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import { GroupOptions, MaybeDeletedItem, isDeleted } from "../types";
|
|
import EventManager from "../utils/event-manager";
|
|
import { DatabaseAccessor, DatabaseCollection, DatabaseSchema } from ".";
|
|
import { SQLCollection } from "./sql-collection";
|
|
|
|
export class SQLCachedCollection<
|
|
TCollectionType extends keyof DatabaseSchema,
|
|
T extends DatabaseSchema[TCollectionType] = DatabaseSchema[TCollectionType]
|
|
> implements DatabaseCollection<T, false>
|
|
{
|
|
private collection: SQLCollection<TCollectionType, T>;
|
|
private cache = new Map<string, MaybeDeletedItem<T> | undefined>();
|
|
// private cachedItems?: T[];
|
|
|
|
constructor(
|
|
sql: DatabaseAccessor,
|
|
type: TCollectionType,
|
|
eventManager: EventManager
|
|
) {
|
|
this.collection = new SQLCollection(sql, type, eventManager);
|
|
}
|
|
|
|
async init() {
|
|
await this.collection.init();
|
|
const records = await this.collection.records([]);
|
|
this.cache = new Map(Object.entries(records));
|
|
// const data = await this.collection.indexer.readMulti(
|
|
// this.collection.indexer.indices
|
|
// );
|
|
// this.cache = new Map(data);
|
|
}
|
|
|
|
// async add(item: MaybeDeletedItem<T>) {
|
|
// await this.collection.addItem(item);
|
|
// this.cache.set(item.id, item);
|
|
// this.invalidateCache();
|
|
// }
|
|
|
|
async clear() {
|
|
await this.collection.clear();
|
|
this.cache.clear();
|
|
}
|
|
|
|
async upsert(item: T) {
|
|
await this.collection.upsert(item);
|
|
this.cache.set(item.id, item);
|
|
}
|
|
|
|
async delete(ids: string[]) {
|
|
ids.forEach((id) => this.cache.delete(id));
|
|
await this.collection.delete(ids);
|
|
}
|
|
|
|
async softDelete(ids: string[]) {
|
|
ids.forEach((id) =>
|
|
this.cache.set(id, {
|
|
id,
|
|
deleted: true,
|
|
dateModified: Date.now(),
|
|
synced: false
|
|
})
|
|
);
|
|
await this.collection.softDelete(ids);
|
|
}
|
|
|
|
exists(id: string) {
|
|
const item = this.cache.get(id);
|
|
return !!item && !isDeleted(item);
|
|
}
|
|
|
|
count(): number {
|
|
return this.cache.size;
|
|
}
|
|
|
|
get(id: string): T | undefined {
|
|
const item = this.cache.get(id);
|
|
if (!item || isDeleted(item)) return;
|
|
return item;
|
|
}
|
|
|
|
async put(items: (T | undefined)[]): Promise<void> {
|
|
await this.collection.put(items);
|
|
for (const item of items) {
|
|
if (item) this.cache.set(item.id, item);
|
|
}
|
|
}
|
|
|
|
async update(ids: string[], partial: Partial<T>): Promise<void> {
|
|
await this.collection.update(ids, partial);
|
|
for (const id of ids) {
|
|
const item = this.cache.get(id);
|
|
if (!item) continue;
|
|
this.cache.set(id, { ...item, ...partial, dateModified: Date.now() });
|
|
}
|
|
}
|
|
|
|
ids(_options: GroupOptions): string[] {
|
|
return Array.from(this.cache.keys());
|
|
}
|
|
|
|
records(ids: string[]): Record<string, MaybeDeletedItem<T> | undefined> {
|
|
const items: Record<string, MaybeDeletedItem<T> | undefined> = {};
|
|
for (const id of ids) {
|
|
items[id] = this.cache.get(id);
|
|
}
|
|
return items;
|
|
}
|
|
|
|
items(ids?: string[]): T[] {
|
|
const items: T[] = [];
|
|
if (ids) {
|
|
for (const id of ids) {
|
|
const item = this.cache.get(id);
|
|
if (!item || isDeleted(item)) continue;
|
|
items.push(item);
|
|
}
|
|
} else {
|
|
for (const [_key, value] of this.cache) {
|
|
if (!value || isDeleted(value)) continue;
|
|
items.push(value);
|
|
}
|
|
}
|
|
return items;
|
|
}
|
|
|
|
*unsynced(chunkSize: number): IterableIterator<MaybeDeletedItem<T>[]> {
|
|
let chunk: MaybeDeletedItem<T>[] = [];
|
|
for (const [_key, value] of this.cache) {
|
|
if (value && !value.synced) {
|
|
chunk.push(value);
|
|
if (chunk.length === chunkSize) {
|
|
yield chunk;
|
|
chunk = [];
|
|
}
|
|
}
|
|
}
|
|
if (chunk.length > 0) yield chunk;
|
|
}
|
|
|
|
*stream(): IterableIterator<T> {
|
|
for (const [_key, value] of this.cache) {
|
|
if (value && !value.deleted) yield value as T;
|
|
}
|
|
}
|
|
|
|
// has(id: string) {
|
|
// return this.cache.has(id);
|
|
// }
|
|
|
|
// count() {
|
|
// return this.cache.size;
|
|
// }
|
|
|
|
// get(id: string) {
|
|
// const item = this.cache.get(id);
|
|
// if (!item || isDeleted(item)) return;
|
|
// return item;
|
|
// }
|
|
|
|
// getRaw(id: string) {
|
|
// const item = this.cache.get(id);
|
|
// return item;
|
|
// }
|
|
|
|
// raw() {
|
|
// return Array.from(this.cache.values());
|
|
// }
|
|
|
|
// items(map?: (item: T) => T | undefined) {
|
|
// if (this.cachedItems && this.cachedItems.length === this.cache.size)
|
|
// return this.cachedItems;
|
|
|
|
// this.cachedItems = [];
|
|
// this.cache.forEach((value) => {
|
|
// if (isDeleted(value)) return;
|
|
// const mapped = map ? map(value) : value;
|
|
// if (!mapped) return;
|
|
// this.cachedItems?.push(mapped);
|
|
// });
|
|
// this.cachedItems.sort((a, b) => b.dateCreated - a.dateCreated);
|
|
// return this.cachedItems;
|
|
// }
|
|
|
|
// async setItems(items: (MaybeDeletedItem<T> | undefined)[]) {
|
|
// await this.collection.setItems(items);
|
|
// for (const item of items) {
|
|
// if (item) {
|
|
// this.cache.set(item.id, item);
|
|
// }
|
|
// }
|
|
|
|
// this.invalidateCache();
|
|
// }
|
|
|
|
// *iterateSync(chunkSize: number) {
|
|
// yield* chunkedIterate(Array.from(this.cache.values()), chunkSize);
|
|
// }
|
|
|
|
// invalidateCache() {
|
|
// this.cachedItems = undefined;
|
|
// }
|
|
}
|