or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

administration.mdaql-queries.mddatabase-connection.mddocument-collections.mdgraph-operations.mdindex.mdquery-execution.mdtransactions.mdviews-search.md
tile.json

transactions.mddocs/

Transactions

Database transaction support for ensuring data consistency across multiple operations with comprehensive ACID guarantees and streaming transaction management.

Capabilities

Transaction Creation and Management

Create and manage database transactions for multi-operation consistency.

/**
 * Begins a new streaming transaction
 * @param collections - Collections involved in the transaction
 * @param options - Transaction configuration options
 * @returns Promise resolving to Transaction instance
 */
beginTransaction(
  collections: TransactionCollectionOptions,
  options?: TransactionOptions
): Promise<Transaction>;

/**
 * Executes a function or code string within a single transaction
 * @param action - Function or AQL code to execute in transaction
 * @param options - Transaction execution options
 * @returns Promise resolving to action result
 */
executeTransaction<T>(
  action: string | TransactionFunction<T>,
  options?: TransactionOptions
): Promise<T>;

Usage Examples:

import { Database } from "arangojs";

const db = new Database();

// Begin streaming transaction
const trx = await db.beginTransaction({
  write: ["users", "accounts"],
  read: ["settings"]
}, {
  waitForSync: true,
  allowImplicit: false,
  lockTimeout: 30,
  maxTransactionSize: 100000
});

try {
  // Perform operations within transaction
  const user = await trx.step(() => 
    db.collection("users").save({
      name: "Alice Johnson",
      email: "alice@example.com"
    })
  );

  const account = await trx.step(() =>
    db.collection("accounts").save({
      userId: user._key,
      balance: 1000.00,
      currency: "USD"
    })
  );

  // Commit transaction
  await trx.commit();
  console.log("Transaction committed successfully");
  
} catch (error) {
  // Abort transaction on error
  await trx.abort();
  console.error("Transaction aborted:", error);
}

// Execute function in single transaction
const result = await db.executeTransaction(
  async (collections) => {
    const users = collections.users;
    const posts = collections.posts;
    
    // Create user
    const user = await users.save({
      name: "Bob Wilson",
      email: "bob@example.com"
    });
    
    // Create initial post
    const post = await posts.save({
      authorId: user._key,
      title: "Hello World",
      content: "My first post!"
    });
    
    return { user, post };
  },
  {
    write: ["users", "posts"],
    waitForSync: true
  }
);

console.log("Created user and post:", result);

Transaction Operations

Core transaction lifecycle operations and status management.

/**
 * Transaction class for managing streaming transactions
 */
class Transaction {
  /** Transaction ID */
  readonly id: string;
  
  /** Transaction status */
  readonly status: TransactionStatus;

  /**
   * Checks if the transaction exists and is active
   * @returns Promise resolving to boolean indicating existence
   */
  exists(): Promise<boolean>;

  /**
   * Gets current transaction information and status
   * @returns Promise resolving to transaction info
   */
  get(): Promise<TransactionInfo>;

  /**
   * Commits the transaction, making all changes permanent
   * @param options - Commit options
   * @returns Promise resolving to transaction info
   */
  commit(options?: TransactionCommitOptions): Promise<TransactionInfo>;

  /**
   * Aborts the transaction, rolling back all changes
   * @param options - Abort options
   * @returns Promise resolving to transaction info
   */
  abort(options?: TransactionAbortOptions): Promise<TransactionInfo>;

  /**
   * Executes a function as a step within the transaction
   * @param callback - Function to execute in transaction context
   * @returns Promise resolving to callback result
   */
  step<T>(callback: () => Promise<T>): Promise<T>;

  /**
   * Runs an action within the transaction context
   * @param action - Action to execute
   * @returns Promise resolving to action result
   */
  run<T>(action: TransactionAction<T>): Promise<T>;
}

Usage Examples:

const trx = await db.beginTransaction({
  write: ["orders", "inventory", "customers"]
});

// Check transaction status
const info = await trx.get();
console.log("Transaction status:", info.status);
console.log("Transaction size:", info.sizeInBytes);

// Execute multiple operations as steps
try {
  // Step 1: Create customer
  const customer = await trx.step(async () => {
    return await db.collection("customers").save({
      name: "John Doe",
      email: "john@example.com",
      address: "123 Main St"
    });
  });

  // Step 2: Check inventory
  const inventoryItem = await trx.step(async () => {
    return await db.collection("inventory").document("product-123");
  });

  if (inventoryItem.quantity < 1) {
    throw new Error("Insufficient inventory");
  }

  // Step 3: Create order
  const order = await trx.step(async () => {
    return await db.collection("orders").save({
      customerId: customer._key,
      productId: "product-123",
      quantity: 1,
      price: inventoryItem.price,
      status: "confirmed"
    });
  });

  // Step 4: Update inventory
  await trx.step(async () => {
    await db.collection("inventory").update("product-123", {
      quantity: inventoryItem.quantity - 1,
      lastSold: new Date()
    });
  });

  // Commit all changes
  const commitResult = await trx.commit();
  console.log("Order transaction committed:", commitResult.id);

} catch (error) {
  // Abort on any error
  await trx.abort();
  console.error("Order transaction aborted:", error.message);
}

Single-Operation Transactions

Execute single operations within transaction contexts for simpler use cases.

/**
 * Executes AQL query within a transaction
 * @param query - AQL query to execute
 * @param options - Transaction and query options
 * @returns Promise resolving to query cursor
 */
queryTransaction<T>(
  query: AqlQuery<T>,
  options?: QueryOptions & TransactionOptions
): Promise<Cursor<T>>;

Usage Examples:

// Single query transaction
const results = await db.queryTransaction(aql`
  LET customer = DOCUMENT("customers/cust123")
  LET order = {
    customerId: customer._key,
    items: [
      { productId: "prod1", quantity: 2, price: 29.99 },
      { productId: "prod2", quantity: 1, price: 49.99 }
    ],
    total: 109.97,
    createdAt: DATE_NOW()
  }
  
  INSERT order INTO orders
  
  FOR item IN order.items
    UPDATE item.productId WITH {
      stock: DOCUMENT("products", item.productId).stock - item.quantity,
      lastSold: DATE_NOW()
    } IN products
  
  RETURN NEW
`, {
  write: ["orders", "products"],
  read: ["customers"],
  waitForSync: true
});

const createdOrder = await results.next();
console.log("Created order:", createdOrder);

// Function-based single transaction
const transferResult = await db.executeTransaction(
  `
  function(params) {
    const { fromAccount, toAccount, amount } = params;
    
    // Get current balances
    const from = db.accounts.document(fromAccount);
    const to = db.accounts.document(toAccount);
    
    if (from.balance < amount) {
      throw new Error("Insufficient funds");
    }
    
    // Update balances
    db.accounts.update(fromAccount, { 
      balance: from.balance - amount,
      lastTransaction: Date.now()
    });
    
    db.accounts.update(toAccount, { 
      balance: to.balance + amount,
      lastTransaction: Date.now()
    });
    
    return { 
      fromBalance: from.balance - amount,
      toBalance: to.balance + amount,
      transferAmount: amount
    };
  }
  `,
  {
    write: ["accounts"],
    params: {
      fromAccount: "acc123",
      toAccount: "acc456", 
      amount: 250.00
    }
  }
);

console.log("Transfer completed:", transferResult);

Advanced Transaction Features

Advanced transaction features including nested transactions and savepoints.

/**
 * Creates a savepoint within the current transaction
 * @param name - Name for the savepoint
 * @returns Promise resolving to savepoint ID
 */
savepoint(name: string): Promise<string>;

/**
 * Rolls back to a specific savepoint
 * @param savepointId - ID of the savepoint to roll back to
 * @returns Promise resolving when rollback is complete
 */
rollbackToSavepoint(savepointId: string): Promise<void>;

/**
 * Gets transaction metrics and performance statistics
 * @returns Promise resolving to transaction metrics
 */
getMetrics(): Promise<TransactionMetrics>;

Usage Examples:

const trx = await db.beginTransaction({
  write: ["users", "profiles", "settings"]
});

try {
  // Create user
  const user = await trx.step(async () => {
    return await db.collection("users").save({
      username: "newuser",
      email: "user@example.com"
    });
  });

  // Create savepoint before profile creation
  const savepoint1 = await trx.savepoint("after_user_creation");

  try {
    // Create user profile
    await trx.step(async () => {
      await db.collection("profiles").save({
        userId: user._key,
        displayName: "New User",
        avatar: "/default-avatar.png"
      });
    });

    // Create another savepoint
    const savepoint2 = await trx.savepoint("after_profile_creation");

    // Try to create settings (might fail)
    await trx.step(async () => {
      await db.collection("settings").save({
        userId: user._key,
        theme: "dark",
        notifications: true
      });
    });

  } catch (profileError) {
    // Roll back to after user creation
    await trx.rollbackToSavepoint(savepoint1);
    console.log("Profile creation failed, rolled back to user creation");
    
    // Create minimal profile instead
    await trx.step(async () => {
      await db.collection("profiles").save({
        userId: user._key,
        displayName: user.username
      });
    });
  }

  // Get transaction metrics
  const metrics = await trx.getMetrics();
  console.log("Transaction size:", metrics.sizeInBytes);
  console.log("Operations count:", metrics.operationsCount);

  await trx.commit();
  
} catch (error) {
  await trx.abort();
  throw error;
}

Transaction Monitoring

Monitor transaction performance and resource usage.

/**
 * Lists all currently running transactions
 * @returns Promise resolving to array of running transactions
 */
listRunningTransactions(): Promise<RunningTransaction[]>;

/**
 * Gets transaction history and statistics
 * @param options - History retrieval options
 * @returns Promise resolving to transaction history
 */
getTransactionHistory(options?: TransactionHistoryOptions): Promise<TransactionHistory>;

Usage Examples:

// Monitor running transactions
const runningTransactions = await db.listRunningTransactions();
for (const trx of runningTransactions) {
  console.log(`Transaction ${trx.id}:`);
  console.log(`  Status: ${trx.status}`);
  console.log(`  Size: ${trx.sizeInBytes} bytes`);
  console.log(`  Runtime: ${trx.runTime}s`);
  
  // Abort long-running transactions if needed
  if (trx.runTime > 300) { // 5 minutes
    const transaction = new Transaction(trx.id);
    await transaction.abort();
    console.log(`Aborted long-running transaction ${trx.id}`);
  }
}

// Get transaction history for analysis
const history = await db.getTransactionHistory({
  limit: 100,
  minRunTime: 1.0, // Only transactions that took > 1 second
  includeAborted: true
});

console.log(`Analyzed ${history.transactions.length} transactions`);
console.log(`Average runtime: ${history.averageRunTime}s`);
console.log(`Success rate: ${history.successRate * 100}%`);

Types

class Transaction {
  readonly id: string;
  readonly status: TransactionStatus;
  exists(): Promise<boolean>;
  get(): Promise<TransactionInfo>;
  commit(options?: TransactionCommitOptions): Promise<TransactionInfo>;
  abort(options?: TransactionAbortOptions): Promise<TransactionInfo>;
  step<T>(callback: () => Promise<T>): Promise<T>;
  run<T>(action: TransactionAction<T>): Promise<T>;
}

interface TransactionCollectionOptions {
  read?: string | string[];
  write?: string | string[];
  exclusive?: string | string[];
}

interface TransactionOptions {
  waitForSync?: boolean;
  allowImplicit?: boolean;
  lockTimeout?: number;
  maxTransactionSize?: number;
  intermediateCommitCount?: number;
  intermediateCommitSize?: number;
  skipFastLockRound?: boolean;
}

type TransactionStatus = "running" | "committed" | "aborted";

interface TransactionInfo {
  id: string;
  status: TransactionStatus;
  sizeInBytes: number;
  lockTimeout: number;
  runTime: number;
  state: {
    running: boolean;
    writing: boolean;
  };
}

interface TransactionCommitOptions {
  waitForSync?: boolean;
}

interface TransactionAbortOptions {
  waitForSync?: boolean;
}

type TransactionFunction<T> = (
  collections: Record<string, any>
) => T | Promise<T>;

type TransactionAction<T> = () => T | Promise<T>;

interface TransactionMetrics {
  sizeInBytes: number;
  operationsCount: number;
  collectionsRead: string[];
  collectionsWritten: string[];
  runTime: number;
  peakMemoryUsage: number;
}

interface RunningTransaction {
  id: string;
  database: string;
  user: string;
  status: TransactionStatus;
  sizeInBytes: number;
  runTime: number;
  lockTimeout: number;
  collections: {
    read: string[];
    write: string[];
    exclusive: string[];
  };
}

interface TransactionHistory {
  transactions: Array<{
    id: string;
    status: TransactionStatus;
    runTime: number;
    sizeInBytes: number;
    startTime: string;
    endTime: string;
  }>;
  totalCount: number;
  averageRunTime: number;
  successRate: number;
}

interface TransactionHistoryOptions {
  limit?: number;
  offset?: number;
  minRunTime?: number;
  maxRunTime?: number;
  includeAborted?: boolean;
  startDate?: Date;
  endDate?: Date;
}