mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 19:49:54 +02:00
core: add support for nested transactions
This commit is contained in:
@@ -71,6 +71,7 @@ import { Kysely, Transaction, sql } from "kysely";
|
||||
import { CachedCollection } from "../database/cached-collection";
|
||||
import { Vaults } from "../collections/vaults";
|
||||
import { KVStorage } from "../database/kv";
|
||||
import { QueueValue } from "../utils/queue-value";
|
||||
|
||||
type EventSourceConstructor = new (
|
||||
uri: string,
|
||||
@@ -126,7 +127,7 @@ class Database {
|
||||
|
||||
private _sql?: Kysely<DatabaseSchema>;
|
||||
sql: DatabaseAccessor = () => {
|
||||
if (this._transaction) return this._transaction;
|
||||
if (this._transaction) return this._transaction.value;
|
||||
|
||||
if (!this._sql)
|
||||
throw new Error(
|
||||
@@ -138,23 +139,27 @@ class Database {
|
||||
private _kv?: KVStorage;
|
||||
kv: KVStorageAccessor = () => this._kv || new KVStorage(this.sql);
|
||||
|
||||
private _transaction?: Transaction<DatabaseSchema>;
|
||||
private transactionMutex = new Mutex();
|
||||
transaction = (
|
||||
executor: (tr: Transaction<DatabaseSchema>) => void | Promise<void>
|
||||
private _transaction?: QueueValue<Transaction<DatabaseSchema>>;
|
||||
transaction = async (
|
||||
executor: (tr: Transaction<DatabaseSchema>) => Promise<void>
|
||||
) => {
|
||||
return this.transactionMutex.runExclusive(() =>
|
||||
this.sql()
|
||||
.transaction()
|
||||
.execute(async (tr) => {
|
||||
this._transaction = tr;
|
||||
await executor(tr);
|
||||
this._transaction = undefined;
|
||||
})
|
||||
.finally(() => {
|
||||
this._transaction = undefined;
|
||||
})
|
||||
);
|
||||
if (this._transaction) {
|
||||
await executor(this._transaction.use()).finally(() =>
|
||||
this._transaction?.discard()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return this.sql()
|
||||
.transaction()
|
||||
.execute(async (tr) => {
|
||||
this._transaction = new QueueValue(
|
||||
tr,
|
||||
() => (this._transaction = undefined)
|
||||
);
|
||||
await executor(this._transaction.use());
|
||||
})
|
||||
.finally(() => this._transaction?.discard());
|
||||
};
|
||||
|
||||
options!: Options;
|
||||
|
||||
35
packages/core/src/utils/queue-value.ts
Normal file
35
packages/core/src/utils/queue-value.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
export class QueueValue<T> {
|
||||
#counter: number;
|
||||
constructor(readonly value: T, private readonly destructor: () => void) {
|
||||
this.#counter = 0;
|
||||
}
|
||||
|
||||
use() {
|
||||
this.#counter++;
|
||||
return this.value;
|
||||
}
|
||||
|
||||
discard() {
|
||||
this.#counter--;
|
||||
if (this.#counter === 0) this.destructor();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user