or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconfiguration.mddata-types.mddrivers.mdindex.mdsessions.mdtransactions-results.md

transactions-results.mddocs/

0

# Transactions & Results

1

2

Transaction management and result handling supporting auto-commit transactions, explicit transactions with full ACID properties, and flexible result consumption patterns. The system provides both streaming and eager result consumption with comprehensive metadata access.

3

4

## Capabilities

5

6

### Transaction Classes

7

8

Explicit transaction management providing full control over transaction lifecycle with commit and rollback capabilities.

9

10

```python { .api }

11

class Transaction:

12

def run(

13

self,

14

query: str,

15

parameters: dict = None,

16

**kwparameters

17

) -> Result:

18

"""

19

Run a Cypher query within the transaction.

20

21

Parameters:

22

- query: Cypher query string

23

- parameters: Query parameters dictionary

24

- **kwparameters: Additional parameters as keyword arguments

25

26

Returns:

27

Result stream for the query execution

28

"""

29

30

def commit(self) -> None:

31

"""

32

Commit the transaction, making all changes permanent.

33

After commit, the transaction cannot be used further.

34

"""

35

36

def rollback(self) -> None:

37

"""

38

Roll back the transaction, discarding all changes.

39

After rollback, the transaction cannot be used further.

40

"""

41

42

def close(self) -> None:

43

"""

44

Close the transaction.

45

If not committed, changes will be rolled back.

46

"""

47

```

48

49

```python { .api }

50

class AsyncTransaction:

51

async def run(

52

self,

53

query: str,

54

parameters: dict = None,

55

**kwparameters

56

) -> AsyncResult:

57

"""

58

Run a Cypher query within the async transaction.

59

60

Parameters:

61

- query: Cypher query string

62

- parameters: Query parameters dictionary

63

- **kwparameters: Additional parameters as keyword arguments

64

65

Returns:

66

AsyncResult stream for the query execution

67

"""

68

69

async def commit(self) -> None:

70

"""

71

Asynchronously commit the transaction.

72

"""

73

74

async def rollback(self) -> None:

75

"""

76

Asynchronously roll back the transaction.

77

"""

78

79

async def close(self) -> None:

80

"""

81

Asynchronously close the transaction.

82

"""

83

```

84

85

Example transaction usage:

86

87

```python

88

from neo4j import GraphDatabase, basic_auth

89

90

driver = GraphDatabase.driver("bolt://localhost:7687", auth=basic_auth("neo4j", "password"))

91

92

# Manual transaction control

93

with driver.session() as session:

94

tx = session.begin_transaction()

95

try:

96

# Execute multiple operations in transaction

97

tx.run("CREATE (n:Person {name: $name})", name="Alice")

98

tx.run("CREATE (n:Person {name: $name})", name="Bob")

99

100

# Create relationship between them

101

result = tx.run("""

102

MATCH (a:Person {name: $name1}), (b:Person {name: $name2})

103

CREATE (a)-[:KNOWS]->(b)

104

RETURN a.name, b.name

105

""", name1="Alice", name2="Bob")

106

107

# Process results

108

for record in result:

109

print(f"{record['a.name']} knows {record['b.name']}")

110

111

# Commit all changes

112

tx.commit()

113

print("Transaction committed successfully")

114

115

except Exception as e:

116

# Rollback on error

117

tx.rollback()

118

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

119

raise

120

```

121

122

### Result Classes

123

124

Result handling providing flexible consumption patterns for query results with both streaming and eager loading capabilities.

125

126

```python { .api }

127

class Result:

128

def keys(self) -> list[str]:

129

"""

130

Get the column keys/names from the query result.

131

132

Returns:

133

List of column names as strings

134

"""

135

136

def consume(self) -> ResultSummary:

137

"""

138

Consume all remaining records and return execution summary.

139

After calling consume(), no more records can be retrieved.

140

141

Returns:

142

ResultSummary containing execution metadata

143

"""

144

145

def single(self, strict: bool = True) -> Record | None:

146

"""

147

Return the single record from the result.

148

149

Parameters:

150

- strict: If True, raise exception if not exactly one record

151

152

Returns:

153

Single Record if exactly one exists, None if zero (when strict=False)

154

155

Raises:

156

Exception if zero records (when strict=True) or multiple records

157

"""

158

159

def peek(self) -> Record:

160

"""

161

Return the next record without consuming it from the stream.

162

163

Returns:

164

Next Record in the stream (can be retrieved again)

165

166

Raises:

167

StopIteration if no more records available

168

"""

169

170

def data(self, *args) -> list[dict]:

171

"""

172

Return all records as a list of dictionaries.

173

174

Parameters:

175

- *args: Optional column names to include (all if not specified)

176

177

Returns:

178

List of dictionaries representing records

179

"""

180

181

def value(self, item: int | str = 0, default=None):

182

"""

183

Return a single column from a single record.

184

185

Parameters:

186

- item: Column index or name to retrieve

187

- default: Value to return if not found

188

189

Returns:

190

Single value from the specified column

191

"""

192

193

def values(self, *items) -> list:

194

"""

195

Return specified columns from all records as lists.

196

197

Parameters:

198

- *items: Column indices or names to retrieve

199

200

Returns:

201

List of column values for each record

202

"""

203

204

def to_df(self, expand: bool = False) -> pandas.DataFrame:

205

"""

206

Convert result to pandas DataFrame.

207

208

Parameters:

209

- expand: Whether to expand nested structures

210

211

Returns:

212

pandas DataFrame containing all records

213

214

Requires:

215

pandas package to be installed

216

"""

217

218

def to_eager_result(self) -> EagerResult:

219

"""

220

Convert to an EagerResult containing all records in memory.

221

222

Returns:

223

EagerResult with records, summary, and keys

224

"""

225

226

def __iter__(self) -> Iterator[Record]:

227

"""Iterator interface for consuming records one by one."""

228

229

def __next__(self) -> Record:

230

"""Get next record from the stream."""

231

```

232

233

```python { .api }

234

class AsyncResult:

235

async def keys(self) -> list[str]:

236

"""Get the column keys asynchronously."""

237

238

async def consume(self) -> ResultSummary:

239

"""

240

Asynchronously consume all records and return summary.

241

242

Returns:

243

ResultSummary containing execution metadata

244

"""

245

246

async def single(self, strict: bool = True) -> Record | None:

247

"""

248

Return the single record asynchronously.

249

250

Parameters:

251

- strict: If True, raise exception if not exactly one record

252

253

Returns:

254

Single Record or None

255

"""

256

257

async def peek(self) -> Record:

258

"""

259

Peek at next record asynchronously.

260

261

Returns:

262

Next Record without consuming it

263

"""

264

265

async def data(self, *args) -> list[dict]:

266

"""

267

Return all records as dictionaries asynchronously.

268

269

Returns:

270

List of dictionaries representing records

271

"""

272

273

async def to_eager_result(self) -> EagerResult:

274

"""

275

Convert to EagerResult asynchronously.

276

277

Returns:

278

EagerResult with all data loaded

279

"""

280

281

def __aiter__(self) -> AsyncIterator[Record]:

282

"""Async iterator interface."""

283

284

async def __anext__(self) -> Record:

285

"""Get next record asynchronously."""

286

```

287

288

Example result usage:

289

290

```python

291

# Streaming consumption

292

with driver.session() as session:

293

result = session.run("MATCH (n:Person) RETURN n.name AS name, n.age AS age")

294

295

# Iterate over results one by one

296

for record in result:

297

print(f"Name: {record['name']}, Age: {record['age']}")

298

299

# Alternative: consume all at once as dictionaries

300

result = session.run("MATCH (n:Person) RETURN n.name AS name")

301

data = result.data()

302

print(data) # [{'name': 'Alice'}, {'name': 'Bob'}]

303

304

# Get single result

305

result = session.run("MATCH (n:Person {name: $name}) RETURN n", name="Alice")

306

record = result.single()

307

print(record["n"]["name"])

308

309

# Get single value

310

result = session.run("MATCH (n:Person) RETURN count(n)")

311

count = result.value()

312

print(f"Total persons: {count}")

313

```

314

315

### EagerResult

316

317

In-memory result container providing immediate access to all query results and metadata.

318

319

```python { .api }

320

class EagerResult:

321

"""

322

NamedTuple containing complete query results in memory.

323

"""

324

records: list[Record]

325

"""List of all records returned by the query."""

326

327

summary: ResultSummary

328

"""Query execution summary and metadata."""

329

330

keys: list[str]

331

"""List of column names/keys."""

332

```

333

334

Example usage:

335

336

```python

337

with driver.session() as session:

338

result = session.run("MATCH (n:Person) RETURN n.name AS name")

339

eager = result.to_eager_result()

340

341

# Access all records

342

for record in eager.records:

343

print(record["name"])

344

345

# Access summary information

346

print(f"Query completed in {eager.summary.result_consumed_after}ms")

347

348

# Access column keys

349

print(f"Columns: {eager.keys}")

350

```

351

352

### ResultSummary

353

354

Comprehensive metadata about query execution including performance statistics, database changes, and server information.

355

356

```python { .api }

357

class ResultSummary:

358

@property

359

def query(self) -> str:

360

"""The Cypher query that was executed."""

361

362

@property

363

def parameters(self) -> dict:

364

"""Parameters that were passed to the query."""

365

366

@property

367

def query_type(self) -> str:

368

"""Type of query (r for read, w for write, etc.)."""

369

370

@property

371

def plan(self) -> dict | None:

372

"""Query execution plan (if requested)."""

373

374

@property

375

def profile(self) -> dict | None:

376

"""Query execution profile (if requested)."""

377

378

@property

379

def notifications(self) -> list[SummaryNotification]:

380

"""Server notifications about the query."""

381

382

@property

383

def counters(self) -> SummaryCounters:

384

"""Statistics about database changes made."""

385

386

@property

387

def result_available_after(self) -> int:

388

"""Time in milliseconds until first record was available."""

389

390

@property

391

def result_consumed_after(self) -> int:

392

"""Time in milliseconds to consume all records."""

393

394

@property

395

def server(self) -> Address:

396

"""Address of the server that executed the query."""

397

398

@property

399

def database(self) -> str:

400

"""Name of the database where query was executed."""

401

```

402

403

### SummaryCounters

404

405

Statistics about database modifications made by write operations.

406

407

```python { .api }

408

class SummaryCounters:

409

@property

410

def nodes_created(self) -> int:

411

"""Number of nodes created."""

412

413

@property

414

def nodes_deleted(self) -> int:

415

"""Number of nodes deleted."""

416

417

@property

418

def relationships_created(self) -> int:

419

"""Number of relationships created."""

420

421

@property

422

def relationships_deleted(self) -> int:

423

"""Number of relationships deleted."""

424

425

@property

426

def properties_set(self) -> int:

427

"""Number of properties set."""

428

429

@property

430

def labels_added(self) -> int:

431

"""Number of labels added to nodes."""

432

433

@property

434

def labels_removed(self) -> int:

435

"""Number of labels removed from nodes."""

436

437

@property

438

def indexes_added(self) -> int:

439

"""Number of indexes created."""

440

441

@property

442

def indexes_removed(self) -> int:

443

"""Number of indexes dropped."""

444

445

@property

446

def constraints_added(self) -> int:

447

"""Number of constraints created."""

448

449

@property

450

def constraints_removed(self) -> int:

451

"""Number of constraints dropped."""

452

453

@property

454

def system_updates(self) -> int:

455

"""Number of system updates performed."""

456

```

457

458

### SummaryNotification

459

460

Server notifications providing information about query execution, warnings, and optimization opportunities.

461

462

```python { .api }

463

class SummaryNotification:

464

@property

465

def code(self) -> str:

466

"""Notification code identifier."""

467

468

@property

469

def title(self) -> str:

470

"""Human-readable notification title."""

471

472

@property

473

def description(self) -> str:

474

"""Detailed description of the notification."""

475

476

@property

477

def severity(self) -> str:

478

"""Severity level (WARNING, INFORMATION, etc.)."""

479

480

@property

481

def category(self) -> str:

482

"""Notification category."""

483

484

@property

485

def position(self) -> SummaryInputPosition | None:

486

"""Position in query where notification applies."""

487

488

class SummaryInputPosition:

489

@property

490

def offset(self) -> int:

491

"""Character offset in the query."""

492

493

@property

494

def line(self) -> int:

495

"""Line number in the query."""

496

497

@property

498

def column(self) -> int:

499

"""Column number in the query."""

500

```

501

502

## Usage Examples

503

504

### Async Results

505

506

```python

507

import asyncio

508

from neo4j import AsyncGraphDatabase, basic_auth

509

510

async def async_example():

511

driver = AsyncGraphDatabase.driver("bolt://localhost:7687", auth=basic_auth("neo4j", "password"))

512

513

async with driver.session() as session:

514

result = await session.run("MATCH (n:Person) RETURN n.name AS name")

515

516

# Async iteration

517

async for record in result:

518

print(record["name"])

519

520

# Async single result

521

result = await session.run("MATCH (n:Person {name: $name}) RETURN n", name="Alice")

522

record = await result.single()

523

524

# Async summary

525

result = await session.run("CREATE (n:Person {name: $name})", name="Charlie")

526

summary = await result.consume()

527

print(f"Nodes created: {summary.counters.nodes_created}")

528

529

await driver.close()

530

531

asyncio.run(async_example())

532

```

533

534

### Performance Analysis

535

536

```python

537

with driver.session() as session:

538

result = session.run("EXPLAIN MATCH (n:Person) RETURN n")

539

summary = result.consume()

540

541

if summary.plan:

542

print("Query execution plan:")

543

print(summary.plan)

544

545

print(f"Query type: {summary.query_type}")

546

print(f"Time to first record: {summary.result_available_after}ms")

547

print(f"Total execution time: {summary.result_consumed_after}ms")

548

549

# Check for notifications

550

for notification in summary.notifications:

551

print(f"Notification: {notification.title} - {notification.description}")

552

```