or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ai-integration.mdclient-management.mdconfiguration-options.mddata-types.mderror-handling.mdindex.mdquery-execution.mdschema-introspection.mdtransaction-management.md

transaction-management.mddocs/

0

# Transaction Management

1

2

Transaction handling with context managers, retry logic, isolation level control, and automatic rollback on errors.

3

4

## Capabilities

5

6

### Transaction Context Managers

7

8

Create and manage database transactions using Python context managers for automatic commit/rollback handling.

9

10

```python { .api }

11

def transaction(

12

*,

13

options: Optional[TransactionOptions] = None,

14

retry_options: Optional[RetryOptions] = None

15

) -> ContextManager:

16

"""

17

Create a transaction context manager for synchronous operations.

18

19

Parameters:

20

- options: Transaction configuration options

21

- retry_options: Retry policy for transaction conflicts

22

23

Returns:

24

Context manager that automatically commits on success or rolls back on error

25

26

Usage:

27

with client.transaction() as tx:

28

tx.execute("INSERT User { name := 'Alice' }")

29

tx.execute("INSERT User { name := 'Bob' }")

30

# Automatically commits if no exceptions

31

"""

32

33

def transaction(

34

*,

35

options: Optional[TransactionOptions] = None,

36

retry_options: Optional[RetryOptions] = None

37

) -> AsyncContextManager:

38

"""

39

Create an async transaction context manager.

40

41

Parameters: Same as synchronous version

42

43

Returns:

44

Async context manager for transaction handling

45

46

Usage:

47

async with client.transaction() as tx:

48

await tx.execute("INSERT User { name := 'Alice' }")

49

await tx.execute("INSERT User { name := 'Bob' }")

50

# Automatically commits if no exceptions

51

"""

52

```

53

54

### Transaction Options

55

56

Configuration options for controlling transaction behavior.

57

58

```python { .api }

59

class TransactionOptions:

60

"""

61

Transaction configuration options.

62

63

Controls isolation level, read-only mode, and deferrable transactions.

64

"""

65

66

def __init__(

67

self,

68

isolation: IsolationLevel = IsolationLevel.Serializable,

69

readonly: bool = False,

70

deferrable: bool = False

71

):

72

"""

73

Create transaction options.

74

75

Parameters:

76

- isolation: Transaction isolation level

77

- readonly: Whether transaction is read-only

78

- deferrable: Whether transaction can be deferred

79

"""

80

81

@classmethod

82

def defaults(cls) -> TransactionOptions:

83

"""Get default transaction options."""

84

85

def start_transaction_query(self) -> str:

86

"""Generate START TRANSACTION query with options."""

87

88

class IsolationLevel:

89

"""

90

Transaction isolation levels.

91

92

EdgeDB currently supports only Serializable isolation.

93

"""

94

Serializable = "SERIALIZABLE"

95

```

96

97

### Retry Configuration

98

99

Configuration for automatic retry of transactions on conflicts.

100

101

```python { .api }

102

class RetryOptions:

103

"""

104

Configuration for transaction retry logic.

105

106

Defines retry attempts and backoff strategy for handling

107

transaction conflicts and temporary failures.

108

"""

109

110

def __init__(

111

self,

112

attempts: int,

113

backoff: Callable[[int], float]

114

):

115

"""

116

Create retry options.

117

118

Parameters:

119

- attempts: Maximum number of retry attempts

120

- backoff: Function that takes attempt number and returns delay in seconds

121

"""

122

123

@classmethod

124

def defaults(cls) -> RetryOptions:

125

"""Get default retry options (3 attempts with exponential backoff)."""

126

127

def with_rule(

128

self,

129

condition: RetryCondition,

130

attempts: Optional[int] = None,

131

backoff: Optional[Callable[[int], float]] = None

132

) -> RetryOptions:

133

"""

134

Create retry options with specific rule.

135

136

Parameters:

137

- condition: Condition that triggers retry

138

- attempts: Number of retry attempts for this condition

139

- backoff: Backoff function for this condition

140

141

Returns:

142

New RetryOptions with added rule

143

"""

144

145

def get_rule_for_exception(self, exc: Exception) -> Optional[Any]:

146

"""Get retry rule for specific exception."""

147

148

class RetryCondition:

149

"""

150

Conditions that trigger transaction retry.

151

"""

152

TransactionConflict = "transaction_conflict"

153

NetworkError = "network_error"

154

155

def default_backoff(attempt: int) -> float:

156

"""

157

Default exponential backoff algorithm.

158

159

Parameters:

160

- attempt: Attempt number (0-based)

161

162

Returns:

163

Delay in seconds before next retry

164

"""

165

```

166

167

### Transaction State

168

169

Transaction lifecycle state management.

170

171

```python { .api }

172

class TransactionState(Enum):

173

"""

174

Transaction lifecycle states.

175

"""

176

NEW = "new"

177

STARTED = "started"

178

COMMITTED = "committed"

179

ROLLEDBACK = "rolledback"

180

FAILED = "failed"

181

182

class BaseTransaction:

183

"""

184

Base transaction implementation.

185

186

Provides transaction lifecycle management and state tracking.

187

"""

188

189

def start(self) -> None:

190

"""Start the transaction."""

191

192

def commit(self) -> None:

193

"""Commit the transaction."""

194

195

def rollback(self) -> None:

196

"""Roll back the transaction."""

197

198

@property

199

def state(self) -> TransactionState:

200

"""Current transaction state."""

201

```

202

203

## Usage Examples

204

205

### Basic Transactions

206

207

```python

208

import edgedb

209

210

client = edgedb.create_client()

211

212

# Synchronous transaction

213

with client.transaction() as tx:

214

# All operations in this block are part of the transaction

215

tx.execute("INSERT User { name := 'Alice', email := 'alice@example.com' }")

216

tx.execute("INSERT User { name := 'Bob', email := 'bob@example.com' }")

217

218

# Query within transaction sees uncommitted changes

219

users = tx.query("SELECT User { name }")

220

print(f"Users in transaction: {len(users)}")

221

222

# Transaction automatically commits when exiting the block

223

224

print("Transaction committed successfully")

225

```

226

227

### Async Transactions

228

229

```python

230

import asyncio

231

import edgedb

232

233

async def main():

234

client = edgedb.create_async_client()

235

236

async with client.transaction() as tx:

237

await tx.execute("INSERT User { name := 'Alice', email := 'alice@example.com' }")

238

await tx.execute("INSERT User { name := 'Bob', email := 'bob@example.com' }")

239

240

users = await tx.query("SELECT User { name }")

241

print(f"Users in transaction: {len(users)}")

242

243

print("Async transaction committed successfully")

244

await client.aclose()

245

246

asyncio.run(main())

247

```

248

249

### Transaction Options

250

251

```python

252

import edgedb

253

from edgedb import TransactionOptions, IsolationLevel

254

255

client = edgedb.create_client()

256

257

# Read-only transaction

258

options = TransactionOptions(readonly=True)

259

with client.transaction(options=options) as tx:

260

# Can only perform read operations

261

users = tx.query("SELECT User { name, email }")

262

# tx.execute("INSERT User { name := 'Charlie' }") # Would raise error

263

264

# Deferrable transaction

265

options = TransactionOptions(deferrable=True)

266

with client.transaction(options=options) as tx:

267

# Transaction can be deferred by the database

268

report = tx.query("SELECT generate_monthly_report()")

269

```

270

271

### Retry Configuration

272

273

```python

274

import edgedb

275

from edgedb import RetryOptions, RetryCondition, default_backoff

276

277

client = edgedb.create_client()

278

279

# Custom retry options

280

retry_options = RetryOptions(

281

attempts=5,

282

backoff=default_backoff

283

)

284

285

with client.transaction(retry_options=retry_options) as tx:

286

# This transaction will be retried up to 5 times on conflicts

287

tx.execute("""

288

UPDATE User

289

FILTER .email = 'alice@example.com'

290

SET { login_count := .login_count + 1 }

291

""")

292

293

# Retry with specific conditions

294

retry_options = (

295

RetryOptions.defaults()

296

.with_rule(RetryCondition.TransactionConflict, attempts=10)

297

.with_rule(RetryCondition.NetworkError, attempts=3)

298

)

299

300

with client.transaction(retry_options=retry_options) as tx:

301

# Different retry strategies for different error types

302

tx.execute("INSERT User { name := 'Dave', email := 'dave@example.com' }")

303

```

304

305

### Error Handling

306

307

```python

308

import edgedb

309

310

client = edgedb.create_client()

311

312

try:

313

with client.transaction() as tx:

314

tx.execute("INSERT User { name := 'Alice', email := 'alice@example.com' }")

315

tx.execute("INSERT User { name := 'Alice', email := 'alice@example.com' }") # Duplicate

316

# Transaction is automatically rolled back on error

317

except edgedb.ConstraintViolationError:

318

print("Constraint violation - transaction rolled back")

319

except edgedb.TransactionError as e:

320

print(f"Transaction error: {e}")

321

322

print("Continuing after transaction failure")

323

```

324

325

### Manual Transaction Control

326

327

```python

328

import edgedb

329

330

client = edgedb.create_client()

331

332

# Get transaction object without context manager

333

tx = client.transaction()

334

335

try:

336

tx.start()

337

tx.execute("INSERT User { name := 'Alice' }")

338

tx.execute("INSERT User { name := 'Bob' }")

339

tx.commit()

340

print("Transaction committed manually")

341

except Exception as e:

342

tx.rollback()

343

print(f"Transaction rolled back: {e}")

344

raise

345

```

346

347

### Nested Operations

348

349

```python

350

import edgedb

351

352

client = edgedb.create_client()

353

354

def create_user_with_profile(tx, name, email, bio):

355

"""Function that takes a transaction and performs multiple operations."""

356

user_id = tx.query_single(

357

"INSERT User { name := $name, email := $email } RETURNING .id",

358

name=name, email=email

359

)

360

361

tx.execute(

362

"INSERT Profile { user := $user_id, bio := $bio }",

363

user_id=user_id, bio=bio

364

)

365

366

return user_id

367

368

# Use function within transaction

369

with client.transaction() as tx:

370

user1_id = create_user_with_profile(

371

tx, "Alice", "alice@example.com", "Software developer"

372

)

373

user2_id = create_user_with_profile(

374

tx, "Bob", "bob@example.com", "Data scientist"

375

)

376

377

# Both users and profiles created atomically

378

print(f"Created users: {user1_id}, {user2_id}")

379

```

380

381

### Transaction State Monitoring

382

383

```python

384

import edgedb

385

386

client = edgedb.create_client()

387

388

# Access transaction state

389

tx = client.transaction()

390

print(f"Initial state: {tx.state}") # TransactionState.NEW

391

392

tx.start()

393

print(f"After start: {tx.state}") # TransactionState.STARTED

394

395

try:

396

tx.execute("INSERT User { name := 'Alice' }")

397

tx.commit()

398

print(f"After commit: {tx.state}") # TransactionState.COMMITTED

399

except Exception:

400

tx.rollback()

401

print(f"After rollback: {tx.state}") # TransactionState.ROLLEDBACK

402

```

403

404

### Complex Transaction Patterns

405

406

```python

407

import edgedb

408

from edgedb import RetryOptions, TransactionOptions

409

410

client = edgedb.create_client()

411

412

def transfer_credits(from_user_id, to_user_id, amount):

413

"""Transfer credits between users with retry logic."""

414

415

retry_options = RetryOptions(

416

attempts=10,

417

backoff=lambda attempt: min(2 ** attempt * 0.1, 1.0)

418

)

419

420

with client.transaction(retry_options=retry_options) as tx:

421

# Check sender balance

422

sender = tx.query_required_single(

423

"SELECT User { credits } FILTER .id = $id",

424

id=from_user_id

425

)

426

427

if sender.credits < amount:

428

raise ValueError("Insufficient credits")

429

430

# Perform transfer

431

tx.execute(

432

"UPDATE User FILTER .id = $id SET { credits := .credits - $amount }",

433

id=from_user_id, amount=amount

434

)

435

436

tx.execute(

437

"UPDATE User FILTER .id = $id SET { credits := .credits + $amount }",

438

id=to_user_id, amount=amount

439

)

440

441

# Log transaction

442

tx.execute("""

443

INSERT Transaction {

444

from_user := $from_user,

445

to_user := $to_user,

446

amount := $amount,

447

timestamp := datetime_current()

448

}

449

""", from_user=from_user_id, to_user=to_user_id, amount=amount)

450

451

# Use the transfer function

452

try:

453

transfer_credits(

454

"123e4567-e89b-12d3-a456-426614174000",

455

"987fcdeb-51d2-43a8-b456-426614174000",

456

100

457

)

458

print("Transfer completed successfully")

459

except ValueError as e:

460

print(f"Transfer failed: {e}")

461

except edgedb.TransactionConflictError:

462

print("Transfer failed due to conflict, but was retried automatically")

463

```