or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bitmap-operations.mdcore-clients.mdgeneric-operations.mdgeospatial-operations.mdhash-operations.mdindex.mdlist-operations.mdlua-scripting.mdpubsub-operations.mdserver-management.mdserver-operations.mdset-operations.mdsorted-set-operations.mdstack-extensions.mdstream-operations.mdstring-operations.mdtransaction-operations.mdvalkey-support.md

generic-operations.mddocs/

0

# Generic Operations

1

2

Redis generic key operations providing functionality that works across all data types. These operations include key management, expiration handling, pattern matching, and utility functions for working with Redis keys regardless of their underlying data type.

3

4

## Capabilities

5

6

### Key Existence and Management

7

8

Core functions for testing key existence, deletion, and basic key information.

9

10

```python { .api }

11

def exists(self, *names: KeyT) -> ResponseT: ...

12

13

def delete(self, *names: KeyT) -> ResponseT: ...

14

# Note: delete() is the method name, but del_() is also available for Python keyword compatibility

15

16

def del_(self, *names: KeyT) -> ResponseT: ...

17

18

def unlink(self, *names: KeyT) -> ResponseT: ...

19

20

def type(self, name: KeyT) -> ResponseT: ...

21

22

def touch(self, *names: KeyT) -> ResponseT: ...

23

24

def randomkey(self) -> Optional[bytes]: ...

25

26

def dbsize(self) -> ResponseT: ...

27

```

28

29

### Key Expiration

30

31

Functions for setting, checking, and managing key expiration times.

32

33

```python { .api }

34

def expire(self, name: KeyT, time: ExpiryT) -> ResponseT: ...

35

36

def expireat(self, name: KeyT, when: AbsExpiryT) -> ResponseT: ...

37

38

def pexpire(self, name: KeyT, time: ExpiryT) -> ResponseT: ...

39

40

def pexpireat(self, name: KeyT, when: AbsExpiryT) -> ResponseT: ...

41

42

def ttl(self, name: KeyT) -> ResponseT: ...

43

44

def pttl(self, name: KeyT) -> ResponseT: ...

45

46

def persist(self, name: KeyT) -> ResponseT: ...

47

```

48

49

### Key Movement and Renaming

50

51

Functions for moving keys between databases and renaming operations.

52

53

```python { .api }

54

def move(self, name: KeyT, db: int) -> ResponseT: ...

55

56

def rename(self, src: KeyT, dst: KeyT) -> ResponseT: ...

57

58

def renamenx(self, src: KeyT, dst: KeyT) -> ResponseT: ...

59

60

def copy(

61

self,

62

source: KeyT,

63

destination: KeyT,

64

destination_db: Optional[int] = None,

65

replace: bool = False

66

) -> ResponseT: ...

67

```

68

69

### Pattern Matching and Scanning

70

71

Functions for finding keys by patterns and iterating through keyspaces.

72

73

```python { .api }

74

def keys(self, pattern: PatternT = "*") -> List[bytes]: ...

75

76

def scan(

77

self,

78

cursor: int = 0,

79

match: Optional[PatternT] = None,

80

count: Optional[int] = None,

81

_type: Optional[str] = None

82

) -> ResponseT: ...

83

84

def scan_iter(

85

self,

86

match: Optional[PatternT] = None,

87

count: Optional[int] = None,

88

_type: Optional[str] = None

89

) -> Iterator[bytes]: ...

90

```

91

92

### Sorting and Object Information

93

94

Functions for sorting data and inspecting object properties.

95

96

```python { .api }

97

def sort(

98

self,

99

name: KeyT,

100

start: Optional[int] = None,

101

num: Optional[int] = None,

102

by: Optional[str] = None,

103

get: Optional[Union[KeyT, List[KeyT]]] = None,

104

desc: bool = False,

105

alpha: bool = False,

106

store: Optional[KeyT] = None,

107

groups: bool = False

108

) -> Union[List[bytes], int]: ...

109

110

def object(self, infotype: str, key: KeyT) -> ResponseT: ...

111

112

def memory_usage(self, key: KeyT, samples: Optional[int] = None) -> Optional[int]: ...

113

```

114

115

### Serialization

116

117

Functions for dumping and restoring key data.

118

119

```python { .api }

120

def dump(self, name: KeyT) -> Optional[bytes]: ...

121

122

def restore(

123

self,

124

name: KeyT,

125

ttl: int,

126

value: bytes,

127

replace: bool = False,

128

absttl: bool = False,

129

idletime: Optional[int] = None,

130

frequency: Optional[int] = None

131

) -> ResponseT: ...

132

```

133

134

## Usage Examples

135

136

### Basic Key Operations

137

138

```python

139

import fakeredis

140

141

client = fakeredis.FakeRedis()

142

143

# Set some test data

144

client.set('user:1', 'alice')

145

client.hset('profile:1', 'name', 'Alice')

146

client.lpush('messages:1', 'hello', 'world')

147

148

# Check if keys exist

149

exists_count = client.exists('user:1', 'user:2', 'profile:1')

150

print(f"Existing keys: {exists_count}") # 2

151

152

# Check individual key existence

153

if client.exists('user:1'):

154

print("User 1 exists")

155

156

# Get key types

157

user_type = client.type('user:1')

158

profile_type = client.type('profile:1')

159

messages_type = client.type('messages:1')

160

print(f"Types: {user_type.decode()}, {profile_type.decode()}, {messages_type.decode()}")

161

162

# Delete keys

163

deleted_count = client.delete('user:1', 'nonexistent_key')

164

print(f"Deleted keys: {deleted_count}") # 1

165

166

# Get database size

167

size = client.dbsize()

168

print(f"Database size: {size} keys")

169

170

# Get random key

171

random_key = client.randomkey()

172

if random_key:

173

print(f"Random key: {random_key.decode()}")

174

```

175

176

### Key Expiration Management

177

178

```python

179

import fakeredis

180

import time

181

182

client = fakeredis.FakeRedis()

183

184

# Set key with expiration

185

client.set('session:abc123', 'user_data')

186

client.expire('session:abc123', 30) # Expires in 30 seconds

187

188

# Check time to live

189

ttl_seconds = client.ttl('session:abc123')

190

print(f"TTL: {ttl_seconds} seconds")

191

192

# Set expiration with millisecond precision

193

client.set('temp:data', 'temporary')

194

client.pexpire('temp:data', 5000) # Expires in 5000 milliseconds (5 seconds)

195

196

ttl_ms = client.pttl('temp:data')

197

print(f"TTL: {ttl_ms} milliseconds")

198

199

# Set absolute expiration time

200

future_timestamp = int(time.time()) + 60 # 1 minute from now

201

client.set('scheduled:task', 'task_data')

202

client.expireat('scheduled:task', future_timestamp)

203

204

# Remove expiration (make key persistent)

205

client.persist('scheduled:task')

206

new_ttl = client.ttl('scheduled:task')

207

print(f"TTL after persist: {new_ttl}") # -1 means no expiration

208

209

# Touch keys to update last access time

210

client.set('key1', 'value1')

211

client.set('key2', 'value2')

212

touched = client.touch('key1', 'key2', 'nonexistent')

213

print(f"Touched keys: {touched}") # 2

214

```

215

216

### Pattern Matching and Key Discovery

217

218

```python

219

import fakeredis

220

221

client = fakeredis.FakeRedis()

222

223

# Setup test data with patterns

224

test_data = {

225

'user:1:name': 'alice',

226

'user:1:email': 'alice@example.com',

227

'user:2:name': 'bob',

228

'user:2:email': 'bob@example.com',

229

'session:abc': 'session_data_1',

230

'session:xyz': 'session_data_2',

231

'config:app:debug': 'true',

232

'config:db:host': 'localhost'

233

}

234

235

for key, value in test_data.items():

236

client.set(key, value)

237

238

# Find all user keys

239

user_keys = client.keys('user:*')

240

print("User keys:", [key.decode() for key in user_keys])

241

242

# Find user names specifically

243

user_names = client.keys('user:*:name')

244

print("User name keys:", [key.decode() for key in user_names])

245

246

# Find session keys

247

session_keys = client.keys('session:*')

248

print("Session keys:", [key.decode() for key in session_keys])

249

250

# Use character classes in patterns

251

config_keys = client.keys('config:*:*')

252

print("Config keys:", [key.decode() for key in config_keys])

253

254

# Find keys with single character wildcards

255

user_1_keys = client.keys('user:1:*')

256

print("User 1 keys:", [key.decode() for key in user_1_keys])

257

```

258

259

### Scanning Large Keyspaces

260

261

```python

262

import fakeredis

263

264

client = fakeredis.FakeRedis()

265

266

# Create many keys for demonstration

267

for i in range(1000):

268

client.set(f'key_{i}', f'value_{i}')

269

if i % 100 == 0:

270

client.set(f'special_key_{i}', f'special_value_{i}')

271

272

# Scan all keys efficiently

273

cursor = 0

274

all_keys = []

275

276

while True:

277

cursor, keys = client.scan(cursor=cursor, count=100)

278

all_keys.extend([key.decode() for key in keys])

279

if cursor == 0:

280

break

281

282

print(f"Total keys found: {len(all_keys)}")

283

284

# Scan with pattern matching

285

special_keys = []

286

for key in client.scan_iter(match='special_key_*', count=50):

287

special_keys.append(key.decode())

288

289

print(f"Special keys found: {len(special_keys)}")

290

291

# Scan by type (Redis 6.0+)

292

string_keys = []

293

for key in client.scan_iter(_type='string', count=100):

294

string_keys.append(key.decode())

295

296

print(f"String type keys: {len(string_keys)}")

297

```

298

299

### Key Renaming and Movement

300

301

```python

302

import fakeredis

303

304

client = fakeredis.FakeRedis()

305

306

# Setup test data

307

client.set('old_key', 'important_data')

308

client.set('temp_key', 'temporary_data')

309

310

# Rename key (overwrites destination if exists)

311

client.rename('old_key', 'new_key')

312

313

# Verify rename

314

if not client.exists('old_key') and client.exists('new_key'):

315

print("Key renamed successfully")

316

317

# Conditional rename (only if destination doesn't exist)

318

result = client.renamenx('temp_key', 'new_key') # Will fail because new_key exists

319

print(f"Conditional rename result: {result}") # 0 (failed)

320

321

result = client.renamenx('temp_key', 'unique_key') # Will succeed

322

print(f"Conditional rename result: {result}") # 1 (success)

323

324

# Copy keys (Redis 6.2+)

325

client.set('source', 'data_to_copy')

326

copied = client.copy('source', 'destination')

327

print(f"Copy result: {copied}") # 1 if successful

328

329

# Copy with replace option

330

copied = client.copy('source', 'destination', replace=True)

331

print(f"Copy with replace: {copied}")

332

333

# Move keys between databases (if multiple databases supported)

334

# Note: FakeRedis typically operates on a single database

335

# client.select(0)

336

# client.set('moveable_key', 'data')

337

# moved = client.move('moveable_key', 1) # Move to database 1

338

```

339

340

### Key Sorting

341

342

```python

343

import fakeredis

344

345

client = fakeredis.FakeRedis()

346

347

# Create a list to sort

348

client.lpush('numbers', '30', '10', '50', '20', '40')

349

350

# Sort numerically (default)

351

sorted_numbers = client.sort('numbers')

352

print("Sorted numbers:", [num.decode() for num in sorted_numbers])

353

354

# Sort in descending order

355

sorted_desc = client.sort('numbers', desc=True)

356

print("Descending:", [num.decode() for num in sorted_desc])

357

358

# Sort alphabetically

359

client.lpush('words', 'zebra', 'apple', 'banana', 'cherry')

360

sorted_alpha = client.sort('words', alpha=True)

361

print("Sorted words:", [word.decode() for word in sorted_alpha])

362

363

# Sort with limit

364

limited_sort = client.sort('numbers', start=0, num=3)

365

print("Top 3:", [num.decode() for num in limited_sort])

366

367

# Sort and store result

368

client.sort('numbers', store='sorted_numbers')

369

stored_result = client.lrange('sorted_numbers', 0, -1)

370

print("Stored result:", [num.decode() for num in stored_result])

371

```

372

373

### Advanced Sorting with External Keys

374

375

```python

376

import fakeredis

377

378

client = fakeredis.FakeRedis()

379

380

# Setup data for advanced sorting

381

users = ['user:1', 'user:2', 'user:3']

382

client.lpush('users', *users)

383

384

# Set up external sort keys (scores)

385

client.set('score:user:1', '85')

386

client.set('score:user:2', '92')

387

client.set('score:user:3', '78')

388

389

# Set up data to retrieve

390

client.set('name:user:1', 'Alice')

391

client.set('name:user:2', 'Bob')

392

client.set('name:user:3', 'Charlie')

393

394

# Sort users by their scores

395

sorted_by_score = client.sort('users', by='score:*')

396

print("Users sorted by score:", [user.decode() for user in sorted_by_score])

397

398

# Sort and get additional data

399

sorted_with_names = client.sort('users', by='score:*', get=['name:*', 'score:*'])

400

print("Sorted with names and scores:")

401

for i in range(0, len(sorted_with_names), 2):

402

name = sorted_with_names[i].decode()

403

score = sorted_with_names[i + 1].decode()

404

print(f" {name}: {score}")

405

```

406

407

### Object Information and Memory Usage

408

409

```python

410

import fakeredis

411

412

client = fakeredis.FakeRedis()

413

414

# Create various data structures

415

client.set('simple_string', 'hello world')

416

client.hset('user_hash', 'name', 'Alice', 'age', '30', 'email', 'alice@example.com')

417

client.lpush('number_list', *[str(i) for i in range(100)])

418

419

# Get object information (encoding, idle time, etc.)

420

try:

421

encoding = client.object('encoding', 'simple_string')

422

print(f"String encoding: {encoding}")

423

except:

424

print("Object command not fully supported in this Redis version")

425

426

# Get memory usage (Redis 4.0+)

427

try:

428

string_memory = client.memory_usage('simple_string')

429

hash_memory = client.memory_usage('user_hash')

430

list_memory = client.memory_usage('number_list')

431

432

print(f"Memory usage:")

433

print(f" String: {string_memory} bytes")

434

print(f" Hash: {hash_memory} bytes")

435

print(f" List: {list_memory} bytes")

436

except:

437

print("Memory usage command not available")

438

```

439

440

### Serialization and Backup

441

442

```python

443

import fakeredis

444

445

client = fakeredis.FakeRedis()

446

447

# Create some data

448

client.set('backup_test', 'important_data')

449

client.hset('user_profile', 'name', 'Alice', 'age', '30')

450

client.lpush('activity_log', 'login', 'view_page', 'logout')

451

452

# Dump key data for backup

453

string_dump = client.dump('backup_test')

454

hash_dump = client.dump('user_profile')

455

list_dump = client.dump('activity_log')

456

457

print(f"Dump sizes: string={len(string_dump)}, hash={len(hash_dump)}, list={len(list_dump)}")

458

459

# Delete original keys

460

client.delete('backup_test', 'user_profile', 'activity_log')

461

462

# Restore from dumps

463

if string_dump:

464

client.restore('backup_test_restored', 0, string_dump)

465

if hash_dump:

466

client.restore('user_profile_restored', 0, hash_dump)

467

if list_dump:

468

client.restore('activity_log_restored', 0, list_dump)

469

470

# Verify restoration

471

restored_string = client.get('backup_test_restored')

472

restored_hash = client.hgetall('user_profile_restored')

473

restored_list = client.lrange('activity_log_restored', 0, -1)

474

475

print(f"Restored string: {restored_string.decode()}")

476

print(f"Restored hash: {restored_hash}")

477

print(f"Restored list: {[item.decode() for item in restored_list]}")

478

```

479

480

### Pattern: Key Expiration Manager

481

482

```python

483

import fakeredis

484

import time

485

486

class ExpirationManager:

487

def __init__(self, client):

488

self.client = client

489

490

def set_with_expiry(self, key, value, seconds):

491

"""Set key with expiration"""

492

self.client.set(key, value)

493

return self.client.expire(key, seconds)

494

495

def extend_expiry(self, key, additional_seconds):

496

"""Extend existing expiration"""

497

current_ttl = self.client.ttl(key)

498

if current_ttl > 0:

499

return self.client.expire(key, current_ttl + additional_seconds)

500

return False

501

502

def get_expiring_keys(self, pattern='*', threshold_seconds=60):

503

"""Find keys expiring within threshold"""

504

expiring_keys = []

505

for key in self.client.scan_iter(match=pattern):

506

ttl = self.client.ttl(key.decode())

507

if 0 < ttl <= threshold_seconds:

508

expiring_keys.append((key.decode(), ttl))

509

return expiring_keys

510

511

def refresh_if_expiring(self, key, threshold=60, extension=300):

512

"""Refresh key expiration if it's expiring soon"""

513

ttl = self.client.ttl(key)

514

if 0 < ttl <= threshold:

515

self.client.expire(key, extension)

516

return True

517

return False

518

519

# Usage

520

client = fakeredis.FakeRedis()

521

exp_manager = ExpirationManager(client)

522

523

# Set keys with different expiration times

524

exp_manager.set_with_expiry('session:user1', 'session_data', 30)

525

exp_manager.set_with_expiry('cache:page1', 'cached_content', 300)

526

exp_manager.set_with_expiry('temp:file1', 'temp_data', 10)

527

528

# Find keys expiring soon

529

expiring = exp_manager.get_expiring_keys(threshold_seconds=120)

530

print("Keys expiring within 2 minutes:")

531

for key, ttl in expiring:

532

print(f" {key}: {ttl} seconds")

533

534

# Extend session expiry

535

extended = exp_manager.extend_expiry('session:user1', 300)

536

print(f"Extended session expiry: {extended}")

537

```

538

539

### Pattern: Key Namespace Manager

540

541

```python

542

import fakeredis

543

544

class NamespaceManager:

545

def __init__(self, client, namespace):

546

self.client = client

547

self.namespace = namespace

548

self.separator = ':'

549

550

def _key(self, key):

551

"""Add namespace prefix to key"""

552

return f"{self.namespace}{self.separator}{key}"

553

554

def set(self, key, value, **kwargs):

555

"""Set value in namespace"""

556

return self.client.set(self._key(key), value, **kwargs)

557

558

def get(self, key):

559

"""Get value from namespace"""

560

return self.client.get(self._key(key))

561

562

def delete(self, *keys):

563

"""Delete keys from namespace"""

564

namespaced_keys = [self._key(key) for key in keys]

565

return self.client.delete(*namespaced_keys)

566

567

def exists(self, key):

568

"""Check if key exists in namespace"""

569

return self.client.exists(self._key(key))

570

571

def keys(self, pattern='*'):

572

"""Get all keys in namespace matching pattern"""

573

full_pattern = f"{self.namespace}{self.separator}{pattern}"

574

keys = self.client.keys(full_pattern)

575

# Remove namespace prefix from results

576

prefix_len = len(self.namespace) + len(self.separator)

577

return [key[prefix_len:].decode() for key in keys]

578

579

def clear_namespace(self):

580

"""Delete all keys in this namespace"""

581

pattern = f"{self.namespace}{self.separator}*"

582

keys = self.client.keys(pattern)

583

if keys:

584

return self.client.delete(*keys)

585

return 0

586

587

def scan_iter(self, pattern='*'):

588

"""Iterate over keys in namespace"""

589

full_pattern = f"{self.namespace}{self.separator}{pattern}"

590

prefix_len = len(self.namespace) + len(self.separator)

591

592

for key in self.client.scan_iter(match=full_pattern):

593

yield key[prefix_len:].decode()

594

595

# Usage

596

client = fakeredis.FakeRedis()

597

598

# Create namespace managers for different applications

599

user_cache = NamespaceManager(client, 'user_cache')

600

session_store = NamespaceManager(client, 'sessions')

601

config_store = NamespaceManager(client, 'config')

602

603

# Use namespaced operations

604

user_cache.set('user:123', 'user_data')

605

session_store.set('sess_abc', 'session_data')

606

config_store.set('debug_mode', 'true')

607

608

# Keys are automatically namespaced

609

print("User cache keys:", user_cache.keys())

610

print("Session keys:", session_store.keys())

611

print("Config keys:", config_store.keys())

612

613

# Check actual keys in Redis

614

all_keys = client.keys('*')

615

print("All keys in Redis:", [key.decode() for key in all_keys])

616

617

# Clear specific namespace

618

cleared = user_cache.clear_namespace()

619

print(f"Cleared {cleared} keys from user_cache namespace")

620

```