initial checkin of jsutils
[outofuni/jsutils.git] / idb.js
1 /*
2  * idb.js - indexed db interface
3  *
4  * author: hackbard@hackdaworld.org
5  *
6  */
7
8 var idb = {
9         version: '1',
10         name: 'idb',
11         handle: null,
12         stores: {},
13         onupgradeneeded: function(event) {
14                 idb.handle=event.target.result;
15                 idb.handle.onerror=function(event) {
16                         cl("idb: handle error - "+event.target.errorCode);
17                 };
18                 var ov=event.oldVersion;
19                 var nv=event.newVersion;
20                 if(ov<idb.version) {
21                         cl("idb: version upgrade ("+ov+" -> "+nv+')!');
22                         // stores
23                         for(var sn in idb.stores) {
24                                 // key
25                                 var store=idb.stores[sn]
26                                 var key={};
27                                 key[store['keytype']]=store['keyname'];
28                                 cl("idb: creating store '"+sn+"'");
29                                 store.os=idb.handle.createObjectStore(sn,key);
30                                 // indices
31                                 if(store.idx!==undefined) {
32                                         var idx=store.idx[nv];
33                                         if(idx===undefined) {
34                                                 cl('idb: missing version '+nv);
35                                         }
36                                         for(var iname in idx) {
37                                                 cl("idb: creating index '"+
38                                                    iname+"' u: "+
39                                                    idx[iname].unique+
40                                                    " in store "+sn);
41                                                 store.os.createIndex(iname,
42                                                                      iname,
43                                                                      idx[iname]);
44                                         }
45                                 }
46                                 // content
47                                 vc=null;
48                                 if(store.content!==undefined) {
49                                         vc=store.content[nv];
50                                 }
51                                 if(vc===null) continue;
52                                 if(vc!==undefined) {
53                                         cl("idb: put content to store '"+
54                                            sn+"'");
55                                         for(var c in vc) {
56                                                 objdbg(vc[c]);
57                                                 store.os.put(vc[c]);
58                                         }
59                                 }
60                         }
61                 }
62                 cl("idb: upgrade success! ("+ov+"->"+nv+")");
63         },
64         onsuccess: function(event) {
65                 idb.handle=event.target.result;
66                 cl("idb: initialized successfuly ...");
67                 idb.successcb(event);
68         },
69         onerror: function(event) {
70                 cl("idb: error - "+this.error.message);
71         },
72         onblocked: function(event) {
73                 cl("idb: blocked");
74         },
75         init: function(name,successcb,version,stores,upgradecb) {
76                 if(!indexedDB) {
77                         cl("idb: indexed db not supported");
78                         return
79                 }
80                 if(name!==undefined)
81                         idb.name=name;
82                 if(version!==undefined)
83                         idb.version=version;
84                 if(stores!==undefined)
85                         idb.stores=stores;
86                 if(successcb!==undefined)
87                         idb.successcb=successcb;
88                 if(upgradecb!==undefined)
89                         idb.onupgradeneeded=upgradecb;
90                 var req=indexedDB.open(idb.name,idb.version);
91                 req.onsuccess=idb.onsuccess;
92                 req.onupgradeneeded=idb.onupgradeneeded;
93                 req.onerror=idb.onerror;
94                 req.onblocked=idb.onblocked;
95         },
96         add_store_item: function(store,item,callback) {
97                 var tx=idb.handle.transaction(store,'readwrite');
98                 var store=tx.objectStore(store);
99                 var req=store.add(item);
100                 req.onsuccess=function(event) {
101                         callback(event);
102                 };
103                 req.onerror=function(error) {
104                         cl("idb: add item error, "+error);
105                 };
106         },
107         del_store: function(store,callback) {
108                 var tx=db.handle.transaction(store,'readwrite');
109                 var store=tx.objectStore(store);
110                 var req=store.clear();
111                 req.onsuccess=function() {
112                         cl("db: store "+store.name+" deleted");
113                         callback();
114                 };
115         },
116         del_store_item: function(store,num,callback) {
117                 var tx=db.handle.transaction(store,'readwrite');
118                 var store=tx.objectStore(store);
119
120                 var kr=IDBKeyRange.bound(num,num,false,false);
121                 var req=store.openCursor(kr);
122
123                 req.onsuccess=function(event) {
124                         var cursor=event.target.result;
125                         if(cursor) {
126                                 var res=cursor.delete();
127                                 res.onsuccess=function(event) {
128                                         callback(event);
129                                 };
130                                 res.onerror=function(error) {
131                                         cl("db: delete error");
132                                 };
133                                 return;
134                                 //cursor.continue();
135                         }
136                         else {
137                                 cl("db: nothing to delete");
138                         }
139
140                 };
141         },
142         update_store_item: function(store,num,nitem,callback) {
143                 var tx=idb.handle.transaction(store,'readwrite');
144                 var store=tx.objectStore(store);
145
146                 var kr=IDBKeyRange.bound(num,num,false,false);
147                 var req=store.openCursor(kr);
148
149                 req.onsuccess=function(event) {
150                         var cursor=event.target.result;
151                         if(cursor) {
152                                 var oitem=cursor.value;
153                                 var notreq=true;
154                                 for(var k in oitem) {
155                                         if(JSON.stringify(oitem[k])!=
156                                            JSON.stringify(nitem[k])) {
157                                                 oitem[k]=nitem[k];
158                                                 cl("idb: modified "+k);
159                                                 notreq=false;
160                                         }
161                                 }
162                                 if(notreq) {
163                                         return;
164                                 }
165                                 var res=cursor.update(nitem);
166                                 res.onsuccess=function(event) {
167                                         cl("idb: updated cursor");
168                                         callback(event);
169                                 };
170                                 res.onerror=function(error) {
171                                         cl("idb: cursor update error");
172                                 };
173                                 return;
174                                 //cursor.continue();
175                         }
176                         else {
177                                 var addreq=store.add(nitem,num);
178                                 addreq.onsuccess=function(event) {
179                                         cl("idb: added (update mode) key "+num);
180                                         callback(event);
181                                 }
182                                 addreq.onerror=function(error) {
183                                         cl("idb: error add (update mode)");
184                                 };
185                         }
186
187                 };
188         },
189         get_store_items: function(store,callback,low,up) {
190                 // if low and up are undefined, all items are considered
191                 var kr;
192                 var last=false;
193                 var reversed=false;
194                 if((low!==undefined)&&(up!==undefined)) {
195                         if((low===0)&&(up<0)) {
196                                 // get last up items
197                                 last=true;
198                         }
199                         else if((low===0)&&(up===0)) {
200                                 // get all items in reversed order
201                                 // no key range, no stop criteria required!
202                                 reversed=true;
203                         }
204                         else {
205                                 // get items in range
206                                 kr=IDBKeyRange.bound(low,up,true,true);
207                         }
208                 }
209                 else if (low!==undefined) {
210                         // get items from low to current
211                         kr=IDBKeyRange.lowerBound(low,true);
212                 }
213                 else if (up!==undefined) {
214                         // get items from first to up
215                         kr=IDBKeyRange.upperBound(up,true);
216                 }
217
218                 var tx=idb.handle.transaction(store,'readonly');
219                 var store=tx.objectStore(store);
220
221                 var obj={};
222                 obj.cnt_objs=0;
223
224                 if(last||reversed) {
225                         var req=store.openCursor(null,"prev");
226                 }
227                 else {
228                         if(kr!==undefined)
229                                 var req=store.openCursor(kr);
230                         else
231                                 // get all items
232                                 var req=store.openCursor();
233                 }
234
235                 req.onerror=function(error) {
236                         cl("idb: cursor error - "+error);
237                 };
238                 req.onsuccess=function(event) {
239                         var cursor=event.target.result;
240                         if(cursor&&(!(last&&(obj.cnt_objs==-up)))) {
241                                 obj[cursor.key]=cursor.value;
242                                 obj.cnt_objs+=1;
243                                 cursor.continue();
244                         } else {
245                                 delete obj.cnt_objs;
246                                 callback(obj);
247                         }
248                 };
249         },
250         get_item_by_key: function(store,key,callback) {
251                 var tx=idb.handle.transaction(store,'readonly')
252                 var store=tx.objectStore(store);
253                 var req=store.get(key);
254                 req.onerror=function(event) {
255                         cl("idb: get key error - "+event.target.errorCode);
256                 }
257                 req.onsuccess=function(event) {
258                         if(event.target.result!=null) {
259                                 callback(event.target.result);
260                         }
261                 }
262         },
263         get_item_by_index: function(store,index,val,callback) {
264                 var tx=db.handle.transaction(store,'readonly')
265                 var store=tx.objectStore(store);
266                 var idx=store.index(index);
267                 var req=idx.get(val);
268                 req.onerror=function(event) {
269                         cl("db: error! "+event.target.errorCode);
270                 }
271                 req.onsuccess=function(event) {
272                         if(event.target.result!=null) {
273                                 callback(event.target.result);
274                         }
275                 }
276         },
277         del_item_by_key: function(store,key,callback) {
278                 var tx=idb.handle.transaction(store,'readwrite');
279                 var store=tx.objectStore(store);
280
281                 var kr=IDBKeyRange.bound(key,key,false,false);
282                 var req=store.openCursor(kr);
283
284                 req.onsuccess=function(event) {
285                         var cursor=event.target.result;
286                         if(cursor) {
287                                 var res=cursor.delete();
288                                 res.onsuccess=function(event) {
289                                         cl("idb: deleted key "+key);
290                                         callback(event);
291                                 };
292                                 res.onerror=function(error) {
293                                         cl("idb: cursor delete error");
294                                 };
295                         }
296                         else {
297                                 cl('idb: nothing to delete');
298                         }
299
300                 };
301         },
302         del: function() {
303                 var req=indexedDB.deleteDatabase(idb.name);
304                 req.onsuccess=function() {
305                         cl("idb: deleted database '"+idb.name+"'");
306                 };
307                 req.onblocked=function() {
308                         cl("idb: database delete blocked");
309                 };
310                 req.onerror=function() {
311                         cl("idb: delete database error");
312                 };
313         }
314 };
315