1 module rocksdb.iterator;
2 
3 import std.conv : to;
4 import std.string : fromStringz, toStringz;
5 
6 import rocksdb.slice : Slice;
7 import rocksdb.options : ReadOptions, rocksdb_readoptions_t;
8 import rocksdb.database : Database, rocksdb_t;
9 import rocksdb.columnfamily : ColumnFamily, rocksdb_column_family_handle_t;
10 
11 extern (C) {
12   struct rocksdb_iterator_t {};
13 
14   rocksdb_iterator_t* rocksdb_create_iterator(rocksdb_t*, rocksdb_readoptions_t*);
15   rocksdb_iterator_t* rocksdb_create_iterator_cf(rocksdb_t*, rocksdb_readoptions_t*, rocksdb_column_family_handle_t*);
16 
17   void rocksdb_iter_destroy(rocksdb_iterator_t*);
18   ubyte rocksdb_iter_valid(const rocksdb_iterator_t*);
19   void rocksdb_iter_seek_to_first(rocksdb_iterator_t*);
20   void rocksdb_iter_seek_to_last(rocksdb_iterator_t*);
21   void rocksdb_iter_seek(rocksdb_iterator_t*, const char*, size_t);
22   void rocksdb_iter_seek_for_prev(rocksdb_iterator_t*, const char*, size_t);
23   void rocksdb_iter_next(rocksdb_iterator_t*);
24   void rocksdb_iter_prev(rocksdb_iterator_t*);
25   immutable(char*) rocksdb_iter_key(const rocksdb_iterator_t*, size_t*);
26   immutable(char*) rocksdb_iter_value(const rocksdb_iterator_t*, size_t*);
27   void rocksdb_iter_get_error(const rocksdb_iterator_t*, char**);
28 }
29 
30 
31 class Iterator {
32   rocksdb_iterator_t* iter;
33 
34   this(Database db, ReadOptions opts) {
35     this.iter = rocksdb_create_iterator(db.db, opts.opts);
36     this.seekToFirst();
37   }
38 
39   this(Database db, ColumnFamily family, ReadOptions opts) {
40     this.iter = rocksdb_create_iterator_cf(db.db, opts.opts, family.cf);
41     this.seekToFirst();
42   }
43 
44   ~this() {
45     rocksdb_iter_destroy(this.iter);
46   }
47 
48   void seekToFirst() {
49     rocksdb_iter_seek_to_first(this.iter);
50   }
51 
52   void seekToLast() {
53     rocksdb_iter_seek_to_last(this.iter);
54   }
55 
56   void seek(string key) {
57     this.seek(cast(ubyte[])key);
58   }
59 
60   void seek(in ubyte[] key) {
61     rocksdb_iter_seek(this.iter, cast(char*)key.ptr, key.length);
62   }
63 
64   void seekPrev(string key) {
65     this.seekPrev(cast(ubyte[])key);
66   }
67 
68   void seekPrev(in ubyte[] key) {
69     rocksdb_iter_seek_for_prev(this.iter, cast(char*)key.ptr, key.length);
70   }
71 
72   void next() {
73     rocksdb_iter_next(this.iter);
74   }
75 
76   void prev() {
77     rocksdb_iter_prev(this.iter);
78   }
79 
80   bool valid() {
81     return cast(bool)rocksdb_iter_valid(this.iter);
82   }
83 
84   ubyte[] key() {
85     size_t size;
86     immutable char* ckey = rocksdb_iter_key(this.iter, &size);
87     return cast(ubyte[])ckey[0..size];
88   }
89 
90   Slice keySlice() {
91     size_t size;
92     immutable char* ckey = rocksdb_iter_key(this.iter, &size);
93     return Slice(size, ckey);
94   }
95 
96   ubyte[] value() {
97     size_t size;
98     immutable char* cvalue = rocksdb_iter_value(this.iter, &size);
99     return cast(ubyte[])cvalue[0..size];
100   }
101 
102   Slice valueSlice() {
103     size_t size;
104     immutable char* cvalue = rocksdb_iter_value(this.iter, &size);
105     return Slice(size, cvalue);
106   }
107 
108   /*
109   int opApply(scope int delegate(ref string, ref string) dg) {
110     int result = 0;
111 
112     foreach (key, value; this) {
113       result = dg(cast(string)key, cast(string)value);
114       if (result) break;
115     }
116 
117     return result;
118   }
119   */
120 
121   int opApply(scope int delegate(ubyte[], ubyte[]) dg) {
122     int result = 0;
123 
124     while (this.valid()) {
125       result = dg(this.key(), this.value());
126       if (result) break;
127       this.next();
128     }
129 
130     return result;
131   }
132 
133   void close() {
134     destroy(this);
135   }
136 }