Files
smartfs/ts/classes/smartfs.transaction.ts

208 lines
5.1 KiB
TypeScript
Raw Permalink Normal View History

2025-11-21 18:36:31 +00:00
/**
* Transaction builder for atomic multi-file operations
*/
import type { ISmartFsProvider } from '../interfaces/mod.provider.js';
import type { ITransactionOperation, TEncoding } from '../interfaces/mod.types.js';
/**
* Transaction file operation builder
* Allows chaining file operations within a transaction
*/
class TransactionFileBuilder {
constructor(
private transaction: SmartFsTransaction,
private path: string,
) {}
/**
* Write content to the file in this transaction
* @param content - Content to write
* @param encoding - Optional encoding
*/
public write(content: string | Buffer, encoding?: TEncoding): SmartFsTransaction {
this.transaction.addOperation({
type: 'write',
path: this.path,
content,
encoding,
});
return this.transaction;
}
/**
* Append content to the file in this transaction
* @param content - Content to append
* @param encoding - Optional encoding
*/
public append(content: string | Buffer, encoding?: TEncoding): SmartFsTransaction {
this.transaction.addOperation({
type: 'append',
path: this.path,
content,
encoding,
});
return this.transaction;
}
/**
* Delete the file in this transaction
*/
public delete(): SmartFsTransaction {
this.transaction.addOperation({
type: 'delete',
path: this.path,
});
return this.transaction;
}
/**
* Copy the file to a new location in this transaction
* @param targetPath - Destination path
*/
public copy(targetPath: string): SmartFsTransaction {
this.transaction.addOperation({
type: 'copy',
path: this.path,
targetPath,
});
return this.transaction;
}
/**
* Move the file to a new location in this transaction
* @param targetPath - Destination path
*/
public move(targetPath: string): SmartFsTransaction {
this.transaction.addOperation({
type: 'move',
path: this.path,
targetPath,
});
return this.transaction;
}
}
/**
* Transaction builder class for atomic multi-file operations
* Build up a set of operations, then commit atomically
* Supports rollback on failure
*/
export class SmartFsTransaction {
private provider: ISmartFsProvider;
private operations: ITransactionOperation[] = [];
private committed = false;
private rolledBack = false;
constructor(provider: ISmartFsProvider) {
this.provider = provider;
}
/**
* Add a file operation to the transaction
* @param path - Path to the file
* @returns TransactionFileBuilder for chaining operations
*
* @example
* ```typescript
* await fs.transaction()
* .file('/file1.txt').write('content1')
* .file('/file2.txt').delete()
* .commit()
* ```
*/
public file(path: string): TransactionFileBuilder {
const normalizedPath = this.provider.normalizePath(path);
return new TransactionFileBuilder(this, normalizedPath);
}
/**
* Add an operation to the transaction (internal)
*/
public addOperation(operation: ITransactionOperation): void {
if (this.committed) {
throw new Error('Cannot add operations to a committed transaction');
}
if (this.rolledBack) {
throw new Error('Cannot add operations to a rolled back transaction');
}
this.operations.push(operation);
}
/**
* Commit the transaction
* All operations are executed atomically
* If any operation fails, all operations are rolled back
*/
public async commit(): Promise<void> {
if (this.committed) {
throw new Error('Transaction already committed');
}
if (this.rolledBack) {
throw new Error('Cannot commit a rolled back transaction');
}
if (this.operations.length === 0) {
this.committed = true;
return;
}
try {
// Prepare transaction (create backups for rollback)
const preparedOperations = await this.provider.prepareTransaction(this.operations);
this.operations = preparedOperations;
// Execute the transaction
await this.provider.executeTransaction(this.operations);
this.committed = true;
} catch (error) {
// Rollback on error
await this.rollback();
throw error;
}
}
/**
* Rollback the transaction
* Reverts all operations that have been executed
*/
public async rollback(): Promise<void> {
if (this.committed) {
throw new Error('Cannot rollback a committed transaction');
}
if (this.rolledBack) {
throw new Error('Transaction already rolled back');
}
if (this.operations.length === 0) {
this.rolledBack = true;
return;
}
await this.provider.rollbackTransaction(this.operations);
this.rolledBack = true;
}
/**
* Get all operations in the transaction
*/
public getOperations(): readonly ITransactionOperation[] {
return this.operations;
}
/**
* Check if the transaction has been committed
*/
public isCommitted(): boolean {
return this.committed;
}
/**
* Check if the transaction has been rolled back
*/
public isRolledBack(): boolean {
return this.rolledBack;
}
}