forked from creationix/node-leveldb
-
Notifications
You must be signed in to change notification settings - Fork 12
/
iterator.coffee
299 lines (199 loc) · 6.88 KB
/
iterator.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
binding = require '../leveldb.node'
###
An iterator allows sequential and random access to the database.
Usage:
var leveldb = require('leveldb');
leveldb.open('/tmp/test.db', function(err, db) {
db.iterator(function(err, it) {
// iterator is initially invalid
it.first(function(err) {
// get a key
it.get('foobar', function(err, val) {
console.log(val);
});
});
});
});
###
exports.Iterator = class Iterator
toBuffer = (val) ->
new Buffer val unless Buffer.isBuffer val
toValue = (val, options) ->
unless val
null
else unless options?.as_buffer
val.toString 'utf8'
else
val
_wrapSeek: (callback, validate) =>
@_lock()
throw new Error 'Illegal state' if validate and not @_valid
throw new Error 'Missing callback' unless callback
(err, valid, key, val) =>
@_unlock()
@_valid = valid
@_key = key
@_val = val
callback err if callback
_lock: ->
throw new Error 'Concurrent operations not supported' if @_busy
@_busy = true
_unlock: ->
throw new Error 'Not locked' unless @_busy
@_busy = false
_getKey: (options) ->
toValue @_key, options
_getVal: (options) ->
toValue @_val, options
###
Constructor.
@param {Native} self The underlying iterator object.
###
constructor: (@self) ->
@_busy = @_valid = false
@_key = @_val = null
###
Apply a callback over a range.
The iterator will be positioned at the given key or the first key if
not given, then the callback will be applied on each record moving
forward until the iterator is positioned at the limit key or at an
invalid key. Stops on first error.
@param {String|Buffer} [startKey] Optional start key (inclusive) from
which to begin applying the callback. If not given, defaults to the
first key.
@param {String|Buffer} [limitKey] Optional limit key (inclusive) at
which to end applying the callback.
@param {Object} [options] Optional options.
@param {Boolean} [options.as_buffer=false] If true, data will be
returned as a `Buffer`.
@param {Function} callback The callback to apply to the range.
@param {Error} error The error value on error, null otherwise.
@param {String|Buffer} key The key.
@param {String|Buffer} value The value.
@param {Function} finishedCallback An optional callback being called when the limit key has been reached
###
forRange: ->
args = Array.prototype.slice.call arguments
#Optional finished callback
if typeof(args[args.length - 1]) is 'function' and typeof(args[args.length - 2]) is 'function'
finishedCallback = args.pop()
# required callback
callback = args.pop()
throw new Error 'Missing callback' unless callback
# optional options
options = args[args.length - 1]
if typeof options is 'object' and not Buffer.isBuffer options
args.pop()
else
options = {}
# optional keys
[ startKey, limitKey ] = args
# for comparing end key
limit = limitKey.toString 'binary' if limitKey
# loop function
next = (err) =>
return callback err if err
if @_valid
callback null, @_getKey(options), @_getVal(options)
if not limit or limit isnt @_key.toString 'binary'
@next next
else if finishedCallback
finishedCallback()
# start loop
if startKey
@seek startKey, next
else
@first next
###
True if the iterator is positioned at a valid key.
###
valid: -> @_valid
###
Position the iterator at a key.
@param {String} key The key at which to position the iterator.
@param {Function} [callback] Optional callback.
@param {Error} error The error value on error, null otherwise.
###
seek: (key, callback) ->
@self.seek toBuffer(key), @_wrapSeek callback
###
Position the iterator at the first key.
@param {Function} [callback] Optional callback.
@param {Error} error The error value on error, null otherwise.
###
first: (callback) ->
@self.first @_wrapSeek callback
###
Position the iterator at the last key.
@param {Function} [callback] Optional callback.
@param {Error} error The error value on error, null otherwise.
###
last: (callback) ->
@self.last @_wrapSeek callback
###
Advance the iterator to the next key.
@param {Function} [callback] Optional callback.
@param {Error} error The error value on error, null otherwise.
###
next: (callback) ->
@self.next @_wrapSeek callback, true
###
Advance the iterator to the previous key.
@param {Function} [callback] Optional callback.
@param {Error} error The error value on error, null otherwise.
###
prev: (callback) ->
@self.prev @_wrapSeek callback, true
###
Get the key at the current iterator position.
@param {Object} [options] Optional options.
@param {Boolean} [options.as_buffer=false] If true, data will be
returned as a `Buffer`.
@param {Function} callback The callback function.
@param {Error} error The error value on error, null otherwise.
@param {String|Buffer} key The key if successful.
###
key: (options, callback) ->
# optional options
if typeof options is 'function'
callback = options
options = null
key = @_getKey options
callback? null, key
key
###
Get the value at the current iterator position.
@param {Object} [options] Optional options.
@param {Boolean} [options.as_buffer=false] If true, data will be
returned as a `Buffer`.
@param {Function} callback The callback function.
@param {Error} error The error value on error, null otherwise.
@param {String|Buffer} value The value if successful.
###
value: (options, callback) ->
# optional options
if typeof options is 'function'
callback = options
options = null
val = @_getVal options
callback? null, val
val
###
Get the key and value at the current iterator position.
@param {Object} [options] Optional options.
@param {Boolean} [options.as_buffer=false] If true, data will be
returned as a `Buffer`.
@param {Function} callback The callback function.
@param {Error} error The error value on error, null otherwise.
@param {String|Buffer} key The key if successful.
@param {String|Buffer} value The value if successful.
###
current: (options, callback) ->
# optional options
if typeof options is 'function'
callback = options
options = null
key = @_getKey options
val = @_getVal options
callback? null, key, val
[key, val]