mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 19:49:54 +02:00
core: allow only 1 transaction at a time
This commit is contained in:
@@ -36,7 +36,12 @@ export class Attachments implements ICollection {
|
||||
key: Cipher<"base64"> | null = null;
|
||||
readonly collection: SQLCollection<"attachments", Attachment>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "attachments", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"attachments",
|
||||
db.eventManager
|
||||
);
|
||||
this.key = null;
|
||||
|
||||
EV.subscribe(
|
||||
|
||||
@@ -39,7 +39,12 @@ export class Colors implements ICollection {
|
||||
name = "colors";
|
||||
readonly collection: SQLCollection<"colors", Color>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "colors", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"colors",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
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 { getId } from "../utils/id";
|
||||
import { Tag } from "../types";
|
||||
import Database from "../api";
|
||||
import { ICollection } from "./collection";
|
||||
import { SQLCollection } from "../database/sql-collection";
|
||||
|
||||
export class Tags implements ICollection {
|
||||
name = "tags";
|
||||
readonly collection: SQLCollection<"tags", Tag>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "tags", db.eventManager);
|
||||
}
|
||||
|
||||
init() {
|
||||
return this.collection.init();
|
||||
}
|
||||
|
||||
tag(id: string) {
|
||||
return this.collection.get(id);
|
||||
}
|
||||
|
||||
// find(idOrTitle: string) {
|
||||
// return this.all.find(
|
||||
// (tag) => tag.title === idOrTitle || tag.id === idOrTitle
|
||||
// );
|
||||
// }
|
||||
|
||||
async add(item: Partial<Tag>) {
|
||||
if (item.remote)
|
||||
throw new Error("Please use db.tags.merge to merge remote tags.");
|
||||
|
||||
const id = item.id || getId(item.dateCreated);
|
||||
const oldTag = await this.tag(id);
|
||||
|
||||
item.title = item.title ? Tags.sanitize(item.title) : item.title;
|
||||
if (!item.title && !oldTag?.title) throw new Error("Title is required.");
|
||||
|
||||
await this.collection.upsert({
|
||||
id,
|
||||
dateCreated: item.dateCreated || oldTag?.dateCreated || Date.now(),
|
||||
dateModified: item.dateModified || oldTag?.dateModified || Date.now(),
|
||||
title: item.title || oldTag?.title || "",
|
||||
type: "tag",
|
||||
remote: false
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
// get raw() {
|
||||
// return this.collection.raw();
|
||||
// }
|
||||
|
||||
// get all() {
|
||||
// return this.collection.items();
|
||||
// }
|
||||
|
||||
async remove(...ids: string[]) {
|
||||
await this.db.transaction(async () => {
|
||||
await this.db.relations.unlinkOfType("tag", ids);
|
||||
await this.collection.softDelete(ids);
|
||||
});
|
||||
}
|
||||
|
||||
exists(id: string) {
|
||||
return this.collection.exists(id);
|
||||
}
|
||||
|
||||
static sanitize(title: string) {
|
||||
return title.replace(/^\s+|\s+$/gm, "");
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,12 @@ export class Content implements ICollection {
|
||||
name = "content";
|
||||
readonly collection: SQLCollection<"content", ContentItem>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "content", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"content",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
@@ -31,7 +31,12 @@ export class NoteHistory implements ICollection {
|
||||
sessionContent = new SessionContent(this.db);
|
||||
readonly collection: SQLCollection<"notehistory", HistorySession>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "notehistory", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"notehistory",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
@@ -31,7 +31,12 @@ export class Notebooks implements ICollection {
|
||||
*/
|
||||
collection: SQLCollection<"notebooks", TrashOrItem<Notebook>>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "notebooks", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"notebooks",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
@@ -47,7 +47,12 @@ export class Notes implements ICollection {
|
||||
collection: SQLCollection<"notes", TrashOrItem<Note>>;
|
||||
totalNotes = 0;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "notes", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"notes",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
@@ -30,7 +30,12 @@ export class Relations implements ICollection {
|
||||
name = "relations";
|
||||
readonly collection: SQLCollection<"relations", Relation>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "relations", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"relations",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
@@ -39,7 +39,12 @@ export class Reminders implements ICollection {
|
||||
name = "reminders";
|
||||
readonly collection: SQLCollection<"reminders", Reminder>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "reminders", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"reminders",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
@@ -37,6 +37,7 @@ export class SessionContent implements ICollection {
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"sessioncontent",
|
||||
db.eventManager
|
||||
);
|
||||
|
||||
@@ -69,6 +69,7 @@ export class Settings implements ICollection {
|
||||
constructor(db: Database) {
|
||||
this.collection = new SQLCachedCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"settings",
|
||||
db.eventManager
|
||||
);
|
||||
|
||||
@@ -36,6 +36,7 @@ export class Shortcuts implements ICollection {
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCachedCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"shortcuts",
|
||||
db.eventManager
|
||||
);
|
||||
|
||||
@@ -28,7 +28,12 @@ export class Tags implements ICollection {
|
||||
name = "tags";
|
||||
readonly collection: SQLCollection<"tags", Tag>;
|
||||
constructor(private readonly db: Database) {
|
||||
this.collection = new SQLCollection(db.sql, "tags", db.eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
db.sql,
|
||||
db.transaction,
|
||||
"tags",
|
||||
db.eventManager
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { GroupOptions, MaybeDeletedItem, isDeleted } from "../types";
|
||||
import EventManager from "../utils/event-manager";
|
||||
import { DatabaseAccessor, DatabaseCollection, DatabaseSchema } from ".";
|
||||
import { SQLCollection } from "./sql-collection";
|
||||
import { Transaction } from "kysely";
|
||||
|
||||
export class SQLCachedCollection<
|
||||
TCollectionType extends keyof DatabaseSchema,
|
||||
@@ -33,10 +34,18 @@ export class SQLCachedCollection<
|
||||
|
||||
constructor(
|
||||
sql: DatabaseAccessor,
|
||||
startTransaction: (
|
||||
executor: (tr: Transaction<DatabaseSchema>) => void | Promise<void>
|
||||
) => Promise<void>,
|
||||
type: TCollectionType,
|
||||
eventManager: EventManager
|
||||
) {
|
||||
this.collection = new SQLCollection(sql, type, eventManager);
|
||||
this.collection = new SQLCollection(
|
||||
sql,
|
||||
startTransaction,
|
||||
type,
|
||||
eventManager
|
||||
);
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
ExpressionOrFactory,
|
||||
SelectQueryBuilder,
|
||||
SqlBool,
|
||||
Transaction,
|
||||
sql
|
||||
} from "kysely";
|
||||
import { VirtualizedGrouping } from "../utils/virtualized-grouping";
|
||||
@@ -52,6 +53,9 @@ export class SQLCollection<
|
||||
{
|
||||
constructor(
|
||||
private readonly db: DatabaseAccessor,
|
||||
private readonly startTransaction: (
|
||||
executor: (tr: Transaction<DatabaseSchema>) => void | Promise<void>
|
||||
) => Promise<void>,
|
||||
private readonly type: TCollectionType,
|
||||
private readonly eventManager: EventManager
|
||||
) {}
|
||||
@@ -151,16 +155,14 @@ export class SQLCollection<
|
||||
|
||||
if (entries.length <= 0) return;
|
||||
|
||||
await this.db()
|
||||
.transaction()
|
||||
.execute(async (tx) => {
|
||||
for (const chunk of toChunks(entries, 200)) {
|
||||
await tx
|
||||
.replaceInto<keyof DatabaseSchema>(this.type)
|
||||
.values(chunk)
|
||||
.execute();
|
||||
}
|
||||
});
|
||||
await this.startTransaction(async (tx) => {
|
||||
for (const chunk of toChunks(entries, 200)) {
|
||||
await tx
|
||||
.replaceInto<keyof DatabaseSchema>(this.type)
|
||||
.values(chunk)
|
||||
.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async update(ids: string[], partial: Partial<SQLiteItem<T>>) {
|
||||
|
||||
Reference in New Issue
Block a user