or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

blob-granules.mdc-api.mdgo-api.mdindex.mdjava-api.mdkey-encoding.mdmulti-tenancy.mdpython-api.mdruby-api.md

ruby-api.mddocs/

0

# Ruby API Reference

1

2

The FoundationDB Ruby API provides a Ruby-native interface to the database with block-based transaction handling, enumerable range iteration, and Ruby idioms for database operations. The API follows Ruby conventions and integrates well with Ruby applications.

3

4

## Installation

5

6

```bash

7

gem install fdb

8

```

9

10

## Core Requires

11

12

```ruby

13

require 'fdb'

14

require 'fdb/tuple'

15

require 'fdb/subspace'

16

require 'fdb/directory'

17

```

18

19

## Capabilities

20

21

### Initialization and Database Connection

22

23

```ruby { .api }

24

module FDB

25

# Set API version (must be called first)

26

def self.api_version(version)

27

28

# Open database connection

29

def self.open(cluster_file = nil)

30

31

# Execute block with automatic transaction retry

32

def self.transactional(db_or_tr = nil, &block)

33

end

34

```

35

36

**Usage Example:**

37

38

```ruby

39

require 'fdb'

40

41

# Initialize FoundationDB

42

FDB.api_version(740)

43

44

# Open database

45

db = FDB.open # Uses default cluster file

46

# or specify cluster file path

47

db = FDB.open('/etc/foundationdb/fdb.cluster')

48

```

49

50

### Database Operations

51

52

```ruby { .api }

53

class FDB::Database

54

# Create new transaction

55

def create_transaction

56

57

# Execute block with automatic retry

58

def transact(&block)

59

60

# Open tenant for multi-tenancy

61

def open_tenant(tenant_name)

62

end

63

```

64

65

### Transaction Operations

66

67

```ruby { .api }

68

class FDB::Transaction

69

# Read single key

70

def get(key, snapshot: false)

71

72

# Read key range (returns Enumerator)

73

def get_range(begin_key, end_key, options = {})

74

75

# Write key-value pair

76

def set(key, value)

77

78

# Alias for set (Ruby idiom)

79

def []=(key, value)

80

81

# Read single key (Ruby idiom)

82

def [](key, snapshot: false)

83

84

# Delete single key

85

def clear(key)

86

87

# Delete key range

88

def clear_range(begin_key, end_key)

89

90

# Commit transaction

91

def commit

92

93

# Handle errors and retries

94

def on_error(error)

95

96

# Get/set read version

97

def get_read_version

98

def set_read_version(version)

99

100

# Get committed version (after commit)

101

def get_committed_version

102

103

# Get versionstamp (after commit)

104

def get_versionstamp

105

end

106

```

107

108

**Usage Example:**

109

110

```ruby

111

# Functional transaction handling

112

result = FDB.transactional do |tr|

113

value = tr.get('my_key')

114

if value.nil?

115

tr.set('my_key', 'initial_value')

116

'created'

117

else

118

value

119

end

120

end

121

122

# Manual transaction handling with Ruby idioms

123

db.transact do |tr|

124

tr['counter'] = '1' # Same as tr.set('counter', '1')

125

value = tr['counter'] # Same as tr.get('counter')

126

end

127

```

128

129

### Range Operations and Iteration

130

131

```ruby { .api }

132

# Range iteration with Ruby blocks

133

tr.get_range('begin_key', 'end_key').each do |kv|

134

puts "#{kv.key}: #{kv.value}"

135

end

136

137

# Range options

138

options = {

139

limit: 100,

140

reverse: false,

141

streaming_mode: FDB::StreamingMode::ITERATOR

142

}

143

144

# Enumerable methods work on ranges

145

user_data = tr.get_range(user_begin, user_end)

146

.select { |kv| kv.key.include?('active') }

147

.map { |kv| JSON.parse(kv.value) }

148

```

149

150

### Key Selectors

151

152

```ruby { .api }

153

class FDB::KeySelector

154

def initialize(key, or_equal, offset)

155

156

def self.last_less_than(key)

157

def self.last_less_or_equal(key)

158

def self.first_greater_than(key)

159

def self.first_greater_or_equal(key)

160

161

attr_reader :key, :or_equal, :offset

162

end

163

164

class FDB::KeyValue

165

attr_reader :key, :value

166

end

167

```

168

169

### Future Operations

170

171

```ruby { .api }

172

class FDB::Future

173

# Block until result is ready

174

def wait

175

176

# Check if ready without blocking

177

def ready?

178

179

# Set callback for completion

180

def on_ready(&block)

181

end

182

```

183

184

### Tenant Operations

185

186

```ruby { .api }

187

class FDB::Tenant

188

# Create transaction within tenant keyspace

189

def create_transaction

190

191

# Execute block with automatic retry

192

def transact(&block)

193

194

# Get tenant name

195

def name

196

end

197

```

198

199

### Error Handling

200

201

```ruby { .api }

202

class FDB::Error < StandardError

203

attr_reader :code

204

205

def initialize(code)

206

@code = code

207

super(FDB.get_error(code))

208

end

209

210

# Error predicate methods

211

def retryable?

212

def maybe_committed?

213

def retryable_not_committed?

214

end

215

```

216

217

### Tuple Encoding

218

219

```ruby { .api }

220

module FDB::Tuple

221

# Encode tuple to bytes

222

def self.pack(items)

223

224

# Decode bytes to tuple

225

def self.unpack(data)

226

227

# Create range for tuple prefix

228

def self.range(prefix)

229

end

230

```

231

232

**Usage Example:**

233

234

```ruby

235

require 'fdb/tuple'

236

237

# Encode structured keys

238

user_key = FDB::Tuple.pack(['users', user_id, 'profile'])

239

score_key = FDB::Tuple.pack(['scores', game_id, timestamp, player_id])

240

241

# Create ranges for prefix queries

242

user_range = FDB::Tuple.range(['users', user_id])

243

begin_key, end_key = user_range

244

245

# Use in transactions

246

FDB.transactional do |tr|

247

tr.get_range(begin_key, end_key).each do |kv|

248

key_parts = FDB::Tuple.unpack(kv.key)

249

# Process user data

250

end

251

end

252

```

253

254

### Subspace Operations

255

256

```ruby { .api }

257

class FDB::Subspace

258

def initialize(prefix_tuple = [], raw_prefix = '')

259

260

# Pack tuple with subspace prefix

261

def pack(tuple = [])

262

263

# Unpack key and remove prefix

264

def unpack(key)

265

266

# Create range within subspace

267

def range(tuple = [])

268

269

# Check if key belongs to subspace

270

def contains?(key)

271

272

# Create child subspace

273

def subspace(tuple)

274

275

# Get raw prefix

276

def key

277

end

278

```

279

280

### Directory Layer

281

282

```ruby { .api }

283

module FDB::Directory

284

# Create main directory layer

285

def self.new

286

287

class DirectoryLayer

288

# Create or open directory

289

def create_or_open(tr, path, layer = '')

290

291

# Open existing directory

292

def open(tr, path, layer = '')

293

294

# Create new directory

295

def create(tr, path, layer = '', prefix = nil)

296

297

# List subdirectories

298

def list(tr, path = [])

299

300

# Remove directory

301

def remove(tr, path)

302

303

# Move directory

304

def move(tr, old_path, new_path)

305

306

# Check if directory exists

307

def exists?(tr, path)

308

end

309

310

class Directory < FDB::Subspace

311

# Get layer identifier

312

def layer

313

314

# Get directory path

315

def path

316

end

317

end

318

319

# Default directory layer

320

FDB.directory = FDB::Directory.new

321

```

322

323

### Locality Information

324

325

```ruby { .api }

326

module FDB::Locality

327

# Get shard boundary keys

328

def self.get_boundary_keys(tr, begin_key, end_key)

329

330

# Get replica addresses for key

331

def self.get_addresses_for_key(tr, key)

332

end

333

```

334

335

## Configuration Options

336

337

### Transaction Options

338

339

```ruby { .api }

340

module FDB::TransactionOption

341

CAUSAL_READ_RISKY = 20

342

READ_YOUR_WRITES_DISABLE = 22

343

PRIORITY_SYSTEM_IMMEDIATE = 200

344

PRIORITY_BATCH = 201

345

TIMEOUT = 500

346

RETRY_LIMIT = 501

347

SIZE_LIMIT = 503

348

end

349

350

# Set transaction options

351

tr.options.set_timeout(5000) # 5 seconds

352

tr.options.set_retry_limit(100)

353

```

354

355

### Streaming Modes

356

357

```ruby { .api }

358

module FDB::StreamingMode

359

WANT_ALL = -2

360

ITERATOR = -1 # Default

361

EXACT = 0

362

SMALL = 1

363

MEDIUM = 2

364

LARGE = 3

365

SERIAL = 4

366

end

367

```

368

369

## Complete Usage Example

370

371

```ruby

372

require 'fdb'

373

require 'fdb/tuple'

374

require 'fdb/subspace'

375

require 'fdb/directory'

376

require 'json'

377

require 'time'

378

379

# Initialize FoundationDB

380

FDB.api_version(740)

381

db = FDB.open

382

383

# Set up directory structure

384

users_dir = nil

385

sessions_dir = nil

386

387

FDB.transactional do |tr|

388

root = FDB.directory.create_or_open(tr, ['myapp'])

389

users_dir = root.create_or_open(tr, ['users'])

390

sessions_dir = root.create_or_open(tr, ['sessions'])

391

end

392

393

class UserManager

394

def initialize(db, users_directory)

395

@db = db

396

@users_dir = users_directory

397

end

398

399

def create_user(user_id, email, name)

400

FDB.transactional do |tr|

401

user_space = @users_dir.subspace([user_id])

402

403

# Store user profile using Ruby idioms

404

tr[user_space.pack(['email'])] = email

405

tr[user_space.pack(['name'])] = name

406

tr[user_space.pack(['created'])] = Time.now.to_f.to_s

407

408

# Add to email index using tuple encoding

409

email_key = FDB::Tuple.pack(['email_index', email, user_id])

410

tr[email_key] = ''

411

412

user_id

413

end

414

end

415

416

def get_user_profile(user_id)

417

@db.transact do |tr|

418

user_space = @users_dir.subspace([user_id])

419

begin_key, end_key = user_space.range

420

421

profile = {}

422

tr.get_range(begin_key, end_key).each do |kv|

423

field = user_space.unpack(kv.key)[0]

424

profile[field] = kv.value

425

end

426

427

profile

428

end

429

end

430

431

def find_user_by_email(email)

432

@db.transact do |tr|

433

begin_key, end_key = FDB::Tuple.range(['email_index', email])

434

435

tr.get_range(begin_key, end_key, limit: 1).first&.then do |kv|

436

# Extract user_id from key

437

FDB::Tuple.unpack(kv.key)[2]

438

end

439

end

440

end

441

442

def get_all_users

443

@db.transact do |tr|

444

begin_key, end_key = @users_dir.range

445

446

users = {}

447

tr.get_range(begin_key, end_key).each do |kv|

448

key_parts = @users_dir.unpack(kv.key)

449

user_id, field = key_parts

450

451

users[user_id] ||= {}

452

users[user_id][field] = kv.value

453

end

454

455

users

456

end

457

end

458

459

def update_user_field(user_id, field, value)

460

FDB.transactional do |tr|

461

user_space = @users_dir.subspace([user_id])

462

463

# Check if user exists

464

existing = tr[user_space.pack(['email'])]

465

raise "User not found" if existing.nil?

466

467

# Update field

468

tr[user_space.pack([field])] = value

469

470

# Update modification time

471

tr[user_space.pack(['modified'])] = Time.now.to_f.to_s

472

473

value

474

end

475

end

476

477

def delete_user(user_id)

478

FDB.transactional do |tr|

479

user_space = @users_dir.subspace([user_id])

480

481

# Get email for index cleanup

482

email = tr[user_space.pack(['email'])]

483

return false if email.nil?

484

485

# Remove from email index

486

email_key = FDB::Tuple.pack(['email_index', email, user_id])

487

tr.clear(email_key)

488

489

# Remove all user data

490

begin_key, end_key = user_space.range

491

tr.clear_range(begin_key, end_key)

492

493

true

494

end

495

end

496

end

497

498

# Usage example

499

user_manager = UserManager.new(db, users_dir)

500

501

begin

502

# Create user

503

user_id = user_manager.create_user('user123', 'alice@example.com', 'Alice Smith')

504

puts "Created user: #{user_id}"

505

506

# Get user profile

507

profile = user_manager.get_user_profile(user_id)

508

puts "User profile: #{profile}"

509

510

# Update user

511

user_manager.update_user_field(user_id, 'last_login', Time.now.to_f.to_s)

512

puts "Updated user last_login"

513

514

# Find user by email

515

found_user = user_manager.find_user_by_email('alice@example.com')

516

puts "Found user by email: #{found_user}"

517

518

# Get all users

519

all_users = user_manager.get_all_users

520

puts "All users: #{all_users.keys}"

521

522

# Advanced range query with Ruby enumerable methods

523

recent_users = FDB.transactional do |tr|

524

begin_key, end_key = users_dir.range

525

526

cutoff_time = (Time.now - 86400).to_f # 24 hours ago

527

528

tr.get_range(begin_key, end_key)

529

.select { |kv| users_dir.unpack(kv.key)[1] == 'created' }

530

.select { |kv| kv.value.to_f > cutoff_time }

531

.map { |kv| users_dir.unpack(kv.key)[0] }

532

.uniq

533

end

534

535

puts "Recent users: #{recent_users}"

536

537

rescue FDB::Error => e

538

puts "FoundationDB error #{e.code}: #{e.message}"

539

puts "Retryable: #{e.retryable?}"

540

puts "Maybe committed: #{e.maybe_committed?}"

541

ensure

542

# FoundationDB handles cleanup automatically

543

end

544

```