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