0
# Cursor Operations
1
2
Efficient database traversal and iteration capabilities for large datasets with positioning and filtering support. Cursors provide low-level access for manual record traversal and bulk operations.
3
4
## Capabilities
5
6
### Cursor Creation and Management
7
8
Create and manage database cursors for efficient traversal.
9
10
```python { .api }
11
def cursor(self):
12
"""Create a cursor for iterating through the database.
13
Returns Cursor object."""
14
...
15
16
class Cursor:
17
def __enter__(self):
18
"""Enter context manager. Resets cursor position."""
19
...
20
21
def __exit__(self, exc_type, exc_val, exc_tb):
22
"""Exit context manager."""
23
...
24
```
25
26
**Usage Example:**
27
28
```python
29
db = unqlite.UnQLite(':mem:')
30
31
# Add test data
32
for i in range(10):
33
db[f'key{i:02d}'] = f'value{i}'
34
35
# Create and use cursor
36
cursor = db.cursor()
37
38
# Use as context manager for automatic cleanup
39
with db.cursor() as cursor:
40
cursor.first()
41
while cursor.is_valid():
42
key = cursor.key()
43
value = cursor.value()
44
print(f"{key}: {value}")
45
try:
46
cursor.next_entry()
47
except StopIteration:
48
break
49
```
50
51
### Cursor Positioning
52
53
Move cursor to specific positions within the database.
54
55
```python { .api }
56
def reset(self):
57
"""Reset the cursor's position."""
58
...
59
60
def seek(self, key, flags=UNQLITE_CURSOR_MATCH_EXACT):
61
"""Seek to the given key using specified matching flags."""
62
...
63
64
def first(self):
65
"""Set cursor to the first record in the database."""
66
...
67
68
def last(self):
69
"""Set cursor to the last record in the database."""
70
...
71
```
72
73
**Usage Example:**
74
75
```python
76
db = unqlite.UnQLite(':mem:')
77
78
# Add sorted test data
79
keys = ['apple', 'banana', 'cherry', 'date', 'elderberry']
80
for key in keys:
81
db[key] = f'fruit:{key}'
82
83
with db.cursor() as cursor:
84
# Move to first record
85
cursor.first()
86
print(f"First: {cursor.key()} = {cursor.value()}")
87
88
# Move to last record
89
cursor.last()
90
print(f"Last: {cursor.key()} = {cursor.value()}")
91
92
# Seek to specific key
93
cursor.seek('cherry')
94
print(f"Found: {cursor.key()} = {cursor.value()}")
95
96
# Seek with different matching modes
97
cursor.seek('c', flags=unqlite.UNQLITE_CURSOR_MATCH_GE) # Greater or equal
98
print(f"First key >= 'c': {cursor.key()}")
99
```
100
101
### Cursor Movement
102
103
Navigate between records sequentially.
104
105
```python { .api }
106
def next_entry(self):
107
"""Move cursor to the next entry. Raises StopIteration at end."""
108
...
109
110
def previous_entry(self):
111
"""Move cursor to the previous entry. Raises StopIteration at beginning."""
112
...
113
114
def is_valid(self):
115
"""Return True if cursor points to a valid record."""
116
...
117
```
118
119
**Usage Example:**
120
121
```python
122
db = unqlite.UnQLite(':mem:')
123
124
# Add test data
125
for i in range(5):
126
db[f'item{i}'] = f'data{i}'
127
128
with db.cursor() as cursor:
129
# Forward iteration
130
cursor.first()
131
print("Forward iteration:")
132
while cursor.is_valid():
133
print(f" {cursor.key()}: {cursor.value()}")
134
try:
135
cursor.next_entry()
136
except StopIteration:
137
break
138
139
# Backward iteration
140
cursor.last()
141
print("Backward iteration:")
142
while cursor.is_valid():
143
print(f" {cursor.key()}: {cursor.value()}")
144
try:
145
cursor.previous_entry()
146
except StopIteration:
147
break
148
```
149
150
### Data Access
151
152
Access key and value data at cursor's current position.
153
154
```python { .api }
155
def key(self):
156
"""Retrieve the key at the cursor's current location."""
157
...
158
159
def value(self):
160
"""Retrieve the value at the cursor's current location."""
161
...
162
163
def delete(self):
164
"""Delete the record at the cursor's current location."""
165
...
166
```
167
168
**Usage Example:**
169
170
```python
171
db = unqlite.UnQLite(':mem:')
172
173
# Add test data with different types
174
db['string_key'] = 'text_value'
175
db['json_key'] = '{"type": "json", "valid": true}'
176
db['binary_key'] = b'\x00\x01\x02\x03'
177
178
with db.cursor() as cursor:
179
cursor.first()
180
while cursor.is_valid():
181
key = cursor.key()
182
value = cursor.value()
183
184
print(f"Key: {key} (type: {type(key)})")
185
print(f"Value: {value} (type: {type(value)})")
186
187
# Delete specific records
188
if key == 'binary_key':
189
cursor.delete()
190
print("Deleted binary record")
191
else:
192
try:
193
cursor.next_entry()
194
except StopIteration:
195
break
196
```
197
198
### Iterator Interface
199
200
Use cursors as Python iterators for convenient traversal.
201
202
```python { .api }
203
def __iter__(self):
204
"""Return iterator for cursor."""
205
...
206
207
def __next__(self):
208
"""Get next key-value pair. Raises StopIteration at end."""
209
...
210
211
def fetch_until(self, stop_key, include_stop_key=True):
212
"""Iterate until specified key is reached."""
213
...
214
```
215
216
**Usage Example:**
217
218
```python
219
db = unqlite.UnQLite(':mem:')
220
221
# Add range of data
222
for i in range(20):
223
db[f'record{i:03d}'] = f'data_{i}'
224
225
# Iterate using cursor as iterator
226
with db.cursor() as cursor:
227
print("All records:")
228
for key, value in cursor:
229
print(f" {key}: {value}")
230
231
# Partial iteration with fetch_until
232
with db.cursor() as cursor:
233
cursor.seek('record005')
234
print("Records from record005 to record010:")
235
for key, value in cursor.fetch_until('record010'):
236
print(f" {key}: {value}")
237
```
238
239
## Database-Level Iteration Methods
240
241
UnQLite provides convenient iteration methods that use cursors internally.
242
243
```python { .api }
244
def keys(self):
245
"""Efficiently iterate through the database's keys."""
246
...
247
248
def values(self):
249
"""Efficiently iterate through the database's values."""
250
...
251
252
def items(self):
253
"""Efficiently iterate through the database's key-value pairs."""
254
...
255
256
def range(self, start_key, end_key, include_end_key=True):
257
"""Iterate over a range of keys."""
258
...
259
260
def __iter__(self):
261
"""Return iterator for database keys."""
262
...
263
```
264
265
**Usage Example:**
266
267
```python
268
db = unqlite.UnQLite(':mem:')
269
270
# Add test data
271
data = {'alpha': '1', 'beta': '2', 'gamma': '3', 'delta': '4'}
272
db.update(data)
273
274
# Iterate over keys only
275
print("Keys:")
276
for key in db.keys():
277
print(f" {key}")
278
279
# Iterate over values only
280
print("Values:")
281
for value in db.values():
282
print(f" {value}")
283
284
# Iterate over key-value pairs
285
print("Items:")
286
for key, value in db.items():
287
print(f" {key}: {value}")
288
289
# Range iteration
290
print("Range from 'beta' to 'gamma':")
291
for key, value in db.range('beta', 'gamma'):
292
print(f" {key}: {value}")
293
294
# Database as iterator (keys only)
295
print("Database iteration:")
296
for key in db:
297
print(f" {key}: {db[key]}")
298
```
299
300
## Cursor Seek Modes
301
302
Control how the cursor positions itself when seeking to keys.
303
304
```python
305
# Exact match (default)
306
unqlite.UNQLITE_CURSOR_MATCH_EXACT
307
308
# Less than or equal to key
309
unqlite.UNQLITE_CURSOR_MATCH_LE
310
311
# Greater than or equal to key
312
unqlite.UNQLITE_CURSOR_MATCH_GE
313
```
314
315
**Usage Example:**
316
317
```python
318
db = unqlite.UnQLite(':mem:')
319
320
# Add sorted data
321
keys = ['aardvark', 'bear', 'cat', 'dog', 'elephant']
322
for key in keys:
323
db[key] = f'animal:{key}'
324
325
with db.cursor() as cursor:
326
# Find exact match
327
try:
328
cursor.seek('cat', unqlite.UNQLITE_CURSOR_MATCH_EXACT)
329
print(f"Exact match: {cursor.key()}")
330
except:
331
print("Exact match not found")
332
333
# Find first key >= 'cow' (will find 'dog')
334
cursor.seek('cow', unqlite.UNQLITE_CURSOR_MATCH_GE)
335
print(f"First key >= 'cow': {cursor.key()}")
336
337
# Find last key <= 'cow' (will find 'cat')
338
cursor.seek('cow', unqlite.UNQLITE_CURSOR_MATCH_LE)
339
print(f"Last key <= 'cow': {cursor.key()}")
340
```
341
342
## Performance Considerations
343
344
Cursors are highly efficient for:
345
- **Large dataset traversal**: O(1) per record vs O(n) for repeated lookups
346
- **Sequential processing**: Optimal disk/memory access patterns
347
- **Range queries**: Efficient key range iteration
348
- **Bulk operations**: Process many records with minimal overhead
349
350
```python
351
db = unqlite.UnQLite('large.db')
352
353
# Efficient: Use cursor for large dataset processing
354
with db.cursor() as cursor:
355
for key, value in cursor:
356
# Process each record efficiently
357
process_record(key, value)
358
359
# Inefficient: Individual key lookups
360
for key in db.keys(): # This internally uses a cursor
361
value = db[key] # This is an additional lookup
362
process_record(key, value)
363
```
364
365
## Error Handling
366
367
Cursor operations handle various error conditions:
368
369
```python
370
db = unqlite.UnQLite(':mem:')
371
372
with db.cursor() as cursor:
373
try:
374
# Movement operations raise StopIteration at boundaries
375
cursor.first()
376
while True:
377
print(cursor.key())
378
cursor.next_entry() # Will eventually raise StopIteration
379
380
except StopIteration:
381
print("Reached end of database")
382
383
try:
384
# Seek operations may raise exceptions for invalid keys
385
cursor.seek('nonexistent_key')
386
387
except unqlite.UnQLiteError as e:
388
print(f"Seek failed: {e}")
389
```