or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdindex.mdmigrations-seeds.mdquery-builder.mdschema-builder.mdtransactions-raw.md
tile.json

transactions-raw.mddocs/

0

# Transactions & Raw Queries

1

2

Transaction management with ACID compliance and raw SQL query execution for complex operations and database-specific functionality that requires precise control over SQL generation.

3

4

## Capabilities

5

6

### Transaction Management

7

8

ACID-compliant transaction support with nested transactions, savepoints, and comprehensive rollback capabilities.

9

10

```typescript { .api }

11

/**

12

* Execute operations within a transaction

13

* @param callback - Function containing transaction operations

14

* @param config - Optional transaction configuration

15

* @returns Promise resolving to callback result

16

*/

17

function transaction<T>(callback: (trx: Knex.Transaction) => Promise<T>, config?: TransactionConfig): Promise<T>;

18

19

/**

20

* Create a transaction provider for reusable transaction configuration

21

* @param config - Transaction configuration

22

* @returns Function that creates transactions with the given config

23

*/

24

function transactionProvider(config?: TransactionConfig): <T>(callback: (trx: Knex.Transaction) => Promise<T>) => Promise<T>;

25

26

interface Transaction extends Knex.QueryBuilder {

27

/**

28

* Commit the transaction

29

* @param value - Optional value to resolve the transaction with

30

* @returns Promise that resolves when transaction is committed

31

*/

32

commit(value?: any): Promise<any>;

33

34

/**

35

* Rollback the transaction

36

* @param error - Optional error to reject the transaction with

37

* @returns Promise that rejects when transaction is rolled back

38

*/

39

rollback(error?: any): Promise<any>;

40

41

/**

42

* Create a savepoint within the transaction

43

* @param callback - Function to execute within the savepoint

44

* @returns Promise resolving to callback result

45

*/

46

savepoint<T>(callback: (trx: Transaction) => Promise<T>): Promise<T>;

47

48

/**

49

* Check if the transaction has been completed

50

* @returns true if transaction has been committed or rolled back

51

*/

52

isCompleted(): boolean;

53

54

/**

55

* Promise that resolves when transaction execution completes

56

*/

57

executionPromise: Promise<any>;

58

59

/**

60

* Reference to parent transaction (for nested transactions)

61

*/

62

parentTransaction?: Transaction;

63

64

/**

65

* Transaction-specific user parameters

66

*/

67

userParams: Record<string, any>;

68

}

69

70

interface TransactionConfig {

71

/**

72

* Transaction isolation level

73

*/

74

isolationLevel?: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable';

75

76

/**

77

* Whether the transaction is read-only

78

*/

79

readOnly?: boolean;

80

81

/**

82

* Custom connection to use for the transaction

83

*/

84

connection?: any;

85

86

/**

87

* Whether to disable acquiring connection from pool

88

*/

89

doNotRejectOnRollback?: boolean;

90

}

91

```

92

93

### Raw Query Execution

94

95

Direct SQL execution with parameter binding and result processing for database-specific operations.

96

97

```typescript { .api }

98

/**

99

* Create a raw SQL query

100

* @param sql - Raw SQL string with optional parameter placeholders

101

* @param bindings - Values to bind to SQL parameters

102

* @returns Raw query instance

103

*/

104

function raw(sql: string, bindings?: readonly RawBinding[] | ValueDict): Knex.Raw;

105

106

/**

107

* Create a column reference

108

* @param columnName - Name of the column to reference

109

* @returns Reference object for use in queries

110

*/

111

function ref<TMapping extends Record<string, string>>(columnName: string): Knex.Ref<string, TMapping>;

112

113

interface Raw<TResult = any> extends Promise<TResult> {

114

/**

115

* Wrap the raw query with prefix and suffix strings

116

* @param before - String to prepend

117

* @param after - String to append

118

* @returns New Raw instance with wrapped SQL

119

*/

120

wrap<TResult2 = TResult>(before: string, after: string): Raw<TResult2>;

121

122

/**

123

* Set timeout for the raw query

124

* @param ms - Timeout in milliseconds

125

* @param options - Timeout options

126

* @returns Raw query with timeout

127

*/

128

timeout(ms: number, options?: { cancel?: boolean }): Raw<TResult>;

129

130

/**

131

* Get SQL representation of the raw query

132

* @returns SQL object with query string and bindings

133

*/

134

toSQL(): Sql;

135

136

/**

137

* Convert raw query to string representation

138

* @returns SQL string

139

*/

140

toString(): string;

141

142

/**

143

* Set or get query context

144

* @param context - Context object to set

145

* @returns Raw query with context or current context

146

*/

147

queryContext(context?: any): Raw<TResult>;

148

149

/**

150

* Convert to callback-style interface

151

* @param callback - Node.js style callback

152

* @returns void

153

*/

154

asCallback(callback: (err: any, result: TResult) => void): void;

155

156

/**

157

* Return results as readable stream

158

* @param options - Stream options

159

* @returns Readable stream of results

160

*/

161

stream(options?: Readonly<{ objectMode?: boolean; highWaterMark?: number }>): NodeJS.ReadableStream;

162

163

/**

164

* Pipe results to writable stream

165

* @param writable - Destination stream

166

* @param options - Pipe options

167

* @returns Destination stream

168

*/

169

pipe<T extends NodeJS.WritableStream>(writable: T, options?: { end?: boolean }): T;

170

}

171

172

interface Ref<TSrc extends string, TMapping extends Record<string, any>> {

173

/**

174

* Create an aliased reference

175

* @param alias - Alias name for the reference

176

* @returns Aliased reference

177

*/

178

as<TAlias extends string>(alias: TAlias): Ref<TSrc, { [K in TAlias]: any }>;

179

180

/**

181

* Use the reference with a specific schema

182

* @param schema - Schema name

183

* @returns Reference with schema context

184

*/

185

withSchema(schema: string): Ref<TSrc, TMapping>;

186

187

/**

188

* Convert reference to SQL representation

189

* @returns SQL object

190

*/

191

toSQL(): Sql;

192

193

/**

194

* Convert reference to string

195

* @returns SQL string representation

196

*/

197

toString(): string;

198

}

199

```

200

201

### Batch Operations

202

203

Efficient bulk operations for inserting large datasets with automatic chunking.

204

205

```typescript { .api }

206

/**

207

* Insert data in batches to handle large datasets efficiently

208

* @param tableName - Target table name

209

* @param data - Array of records to insert

210

* @param chunkSize - Number of records per batch (default: 1000)

211

* @returns Promise that resolves when all batches are inserted

212

*/

213

function batchInsert(tableName: string, data: readonly any[], chunkSize?: number): Promise<any>;

214

215

/**

216

* Batch insert with custom options

217

* @param tableName - Target table name

218

* @param data - Array of records to insert

219

* @param chunkSize - Number of records per batch

220

* @param options - Batch insert options

221

* @returns Promise that resolves when all batches are inserted

222

*/

223

function batchInsert(tableName: string, data: readonly any[], chunkSize: number, options: BatchInsertOptions): Promise<any>;

224

225

interface BatchInsertOptions {

226

/**

227

* Whether to use transactions for each batch

228

*/

229

useTransaction?: boolean;

230

231

/**

232

* Custom transaction to use for all batches

233

*/

234

transaction?: Transaction;

235

236

/**

237

* Columns to return after insert

238

*/

239

returning?: string | readonly string[];

240

}

241

```

242

243

### Connection Management

244

245

Direct connection management for advanced use cases requiring connection pooling control.

246

247

```typescript { .api }

248

/**

249

* Initialize the connection pool

250

* @param config - Optional initialization configuration

251

* @returns Promise that resolves when pool is initialized

252

*/

253

function initialize(config?: any): Promise<void>;

254

255

/**

256

* Destroy the connection pool and close all connections

257

* @param callback - Optional callback for completion

258

* @returns Promise that resolves when pool is destroyed

259

*/

260

function destroy(callback?: (err?: any) => void): Promise<void>;

261

262

/**

263

* Get a connection from the pool

264

* @returns Promise resolving to database connection

265

*/

266

function acquireConnection(): Promise<any>;

267

268

/**

269

* Release a connection back to the pool

270

* @param connection - Connection to release

271

* @returns Promise that resolves when connection is released

272

*/

273

function releaseConnection(connection: any): Promise<void>;

274

275

/**

276

* Create a new knex instance with user parameters

277

* @param params - User parameters to attach

278

* @returns New knex instance with parameters

279

*/

280

function withUserParams(params: Record<string, any>): Knex;

281

```

282

283

### Function Helpers

284

285

Database function helpers for common operations that vary across database systems.

286

287

```typescript { .api }

288

/**

289

* Access function helpers for database-specific functions

290

*/

291

fn: Knex.FunctionHelper;

292

293

interface FunctionHelper {

294

/**

295

* Current timestamp function with optional precision

296

* @param precision - Optional precision for timestamp

297

* @returns Raw SQL for current timestamp

298

*/

299

now(precision?: number): Raw;

300

301

/**

302

* Generate UUID using database-specific function

303

* @returns Raw SQL for UUID generation

304

*/

305

uuid(): Raw;

306

307

/**

308

* Convert UUID to binary format (MySQL)

309

* @param uuid - UUID string or column reference

310

* @param ordered - Whether to use ordered binary format

311

* @returns Raw SQL for UUID to binary conversion

312

*/

313

uuidToBin(uuid: string | Raw, ordered?: boolean): Raw;

314

315

/**

316

* Convert binary to UUID format (MySQL)

317

* @param binary - Binary data or column reference

318

* @param ordered - Whether binary is in ordered format

319

* @returns Raw SQL for binary to UUID conversion

320

*/

321

binToUuid(binary: string | Raw, ordered?: boolean): Raw;

322

}

323

```

324

325

### Event System

326

327

Event emission and handling for query lifecycle monitoring and debugging.

328

329

```typescript { .api }

330

/**

331

* Add event listener

332

* @param event - Event name

333

* @param callback - Event handler function

334

* @returns Knex instance for chaining

335

*/

336

on(event: string, callback: Function): Knex;

337

338

/**

339

* Remove event listener

340

* @param event - Event name

341

* @param callback - Event handler function to remove

342

* @returns Knex instance for chaining

343

*/

344

off(event: string, callback: Function): Knex;

345

346

/**

347

* Add one-time event listener

348

* @param event - Event name

349

* @param callback - Event handler function

350

* @returns Knex instance for chaining

351

*/

352

once(event: string, callback: Function): Knex;

353

354

/**

355

* Remove all listeners for an event

356

* @param event - Event name

357

* @returns Knex instance for chaining

358

*/

359

removeAllListeners(event?: string): Knex;

360

361

// Event types

362

interface QueryEvent {

363

__knexUid: string;

364

__knexTxId?: string;

365

sql: string;

366

bindings: readonly RawBinding[];

367

options: any;

368

queryContext?: any;

369

}

370

371

interface QueryResponseEvent extends QueryEvent {

372

response: any;

373

duration: [number, number]; // [seconds, nanoseconds]

374

}

375

376

interface QueryErrorEvent extends QueryEvent {

377

error: Error;

378

duration: [number, number]; // [seconds, nanoseconds]

379

}

380

```

381

382

## Types

383

384

```typescript { .api }

385

type RawBinding = Value | QueryBuilder | Raw;

386

type Value = string | number | boolean | Date | Array<string | number | boolean | Date> | null | undefined;

387

type ValueDict = Record<string, RawBinding>;

388

389

interface Sql {

390

method: string;

391

sql: string;

392

bindings: readonly RawBinding[];

393

options: any;

394

toNative(): SqlNative;

395

}

396

397

interface SqlNative {

398

sql: string;

399

bindings: readonly RawBinding[];

400

}

401

402

interface QueryContext {

403

[key: string]: any;

404

}

405

406

interface ConnectionConfig {

407

host?: string;

408

port?: number;

409

user?: string;

410

password?: string;

411

database?: string;

412

ssl?: boolean | object;

413

connection?: {

414

timezone?: string;

415

charset?: string;

416

typeCast?: boolean | ((field: any, next: () => void) => any);

417

};

418

}

419

420

interface PoolConfig {

421

min?: number;

422

max?: number;

423

createTimeoutMillis?: number;

424

acquireTimeoutMillis?: number;

425

idleTimeoutMillis?: number;

426

reapIntervalMillis?: number;

427

createRetryIntervalMillis?: number;

428

propagateCreateError?: boolean;

429

}

430

```

431

432

**Usage Examples:**

433

434

```javascript

435

const knex = require('knex')({ client: 'postgresql', connection: process.env.DATABASE_URL });

436

437

// Basic transaction

438

await knex.transaction(async trx => {

439

const user = await trx('users').insert({

440

email: 'john@example.com',

441

name: 'John Doe'

442

}).returning('*');

443

444

await trx('user_profiles').insert({

445

user_id: user[0].id,

446

bio: 'Software developer'

447

});

448

449

// Transaction will automatically commit if no errors

450

});

451

452

// Transaction with explicit commit/rollback control

453

const trx = await knex.transaction();

454

try {

455

const result = await trx('users').insert(userData).returning('*');

456

await trx('logs').insert({ action: 'user_created', user_id: result[0].id });

457

458

await trx.commit();

459

console.log('Transaction committed');

460

} catch (error) {

461

await trx.rollback();

462

console.error('Transaction rolled back:', error);

463

}

464

465

// Savepoints for nested transactions

466

await knex.transaction(async trx => {

467

await trx('users').insert({ name: 'User 1' });

468

469

await trx.savepoint(async sp => {

470

await sp('users').insert({ name: 'User 2' });

471

// This will rollback to the savepoint if it fails

472

throw new Error('Rollback to savepoint');

473

});

474

475

// This insert will still happen

476

await trx('users').insert({ name: 'User 3' });

477

});

478

479

// Raw queries with parameter binding

480

const users = await knex.raw('SELECT * FROM users WHERE age > ? AND city = ?', [18, 'New York']);

481

482

// Raw query with named parameters

483

const result = await knex.raw('SELECT * FROM users WHERE name = :name', { name: 'John' });

484

485

// Complex raw query with joins

486

const stats = await knex.raw(`

487

SELECT

488

u.id,

489

u.name,

490

COUNT(p.id) as post_count,

491

AVG(p.view_count) as avg_views

492

FROM users u

493

LEFT JOIN posts p ON u.id = p.user_id

494

WHERE u.created_at > ?

495

GROUP BY u.id, u.name

496

HAVING COUNT(p.id) > ?

497

ORDER BY post_count DESC

498

`, [new Date('2023-01-01'), 5]);

499

500

// Raw query with transaction

501

await knex.transaction(async trx => {

502

await trx.raw('LOCK TABLE users IN EXCLUSIVE MODE');

503

504

const maxId = await trx.raw('SELECT MAX(id) as max_id FROM users');

505

const nextId = maxId.rows[0].max_id + 1;

506

507

await trx.raw('INSERT INTO users (id, name) VALUES (?, ?)', [nextId, 'New User']);

508

});

509

510

// Column references

511

const query = knex('posts')

512

.select('title', knex.ref('users.name').as('author_name'))

513

.join('users', 'posts.user_id', 'users.id')

514

.where(knex.ref('posts.published_at'), '>', knex.fn.now());

515

516

// Function helpers

517

await knex('events').insert({

518

name: 'User signup',

519

event_id: knex.fn.uuid(),

520

created_at: knex.fn.now()

521

});

522

523

// MySQL UUID functions

524

await knex('sessions').insert({

525

id: knex.fn.uuidToBin(knex.fn.uuid(), true),

526

user_id: userId,

527

expires_at: knex.fn.now()

528

});

529

530

// Batch insert for large datasets

531

const users = [];

532

for (let i = 0; i < 10000; i++) {

533

users.push({

534

name: `User ${i}`,

535

email: `user${i}@example.com`,

536

created_at: new Date()

537

});

538

}

539

540

await knex.batchInsert('users', users, 500); // Insert in chunks of 500

541

542

// Event listeners for monitoring

543

knex.on('query', (query) => {

544

console.log('Executing:', query.sql);

545

console.log('Bindings:', query.bindings);

546

});

547

548

knex.on('query-response', (response, query) => {

549

console.log('Query completed in', response.duration, 'ms');

550

});

551

552

knex.on('query-error', (error, query) => {

553

console.error('Query failed:', error.message);

554

console.error('SQL:', query.sql);

555

});

556

557

// Connection management

558

await knex.initialize(); // Initialize connection pool

559

560

// Custom connection for specific operations

561

const connection = await knex.acquireConnection();

562

try {

563

await knex.raw('SELECT pg_advisory_lock(12345)').connection(connection);

564

// Perform operations with locked resource

565

await knex('critical_table').insert(data).connection(connection);

566

} finally {

567

await knex.raw('SELECT pg_advisory_unlock(12345)').connection(connection);

568

await knex.releaseConnection(connection);

569

}

570

571

// Graceful shutdown

572

process.on('SIGINT', async () => {

573

await knex.destroy();

574

process.exit(0);

575

});

576

577

// Database-specific raw operations

578

// PostgreSQL array operations

579

await knex.raw("UPDATE users SET tags = tags || ? WHERE id = ?", [['new-tag'], userId]);

580

581

// MySQL JSON operations

582

await knex.raw("UPDATE users SET preferences = JSON_SET(preferences, '$.theme', ?) WHERE id = ?", ['dark', userId]);

583

584

// SQLite pragma settings

585

await knex.raw("PRAGMA foreign_keys = ON");

586

587

// Transaction isolation levels

588

await knex.transaction(async trx => {

589

await trx.raw('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');

590

// Perform serializable operations

591

}, { isolationLevel: 'serializable' });

592

```