source: Dev/trunk/client/qed/store/CouchStore.js @ 424

Last change on this file since 424 was 418, checked in by hendrikvanantwerpen, 12 years ago

Reflect new naming.

File size: 10.6 KB
Line 
1define([
2    'dojo/_base/array',
3    'dojo/_base/declare',
4    'dojo/_base/Deferred',
5    'dojo/_base/json',
6    'dojo/_base/lang',
7    'dojo/_base/xhr',
8    'dojo/store/util/QueryResults'
9],function(array,declare,Deferred,json,lang,xhr,QueryResults){
10   
11    function getCouchError(err){
12        var reason = err.response &&
13                     err.response.data &&
14                     json.fromJson(err.response.data).reason;
15        return reason || "Unknown error.";
16    }
17
18    var CouchStore = declare(null, {
19        /** dojo Store implementation for CouchDB
20         *
21         * See for details on the REST API, the wiki
22         * at http://wiki.apache.org/couchdb/HTTP_Document_API.
23         */
24        target: "",
25        accepts: "application/json",
26        idProperty: "_id",
27        revProperty: "_rev",
28        _responseIdProperty: "id",
29        _responseRevProperty: "rev",
30        constructor: function(options){
31            declare.safeMixin(this, options);
32        },
33        getIdentity: function(object){
34            return object[this.idProperty];
35        },
36        getRevision: function(object){
37            return object[this.revProperty];
38        },
39        info: function(){
40            var dfd = new Deferred();
41            xhr("GET", {
42                url: this.target,
43                handleAs: "json",
44                headers: {
45                    Accept: this.accepts
46                }
47            }).then(function(result){
48                if ( result.error ) {
49                    dfd.reject(result.reason);
50                } else {
51                    dfd.resolve(result);
52                }
53            }, function(err){
54                dfd.reject(getCouchError(err));
55            });
56            return dfd.promise;
57        },
58        get: function(id){
59            var dfd = new Deferred();
60            xhr("GET", {
61                url: this.target + id,
62                handleAs: "json",
63                headers: {
64                    Accept: this.accepts
65                }
66            }).then(function(result){
67                if ( result.error ) {
68                    dfd.reject(result.reason);
69                } else {
70                    dfd.resolve(result);
71                }
72            }, function(err){
73                dfd.reject(getCouchError(err));
74            });
75            return dfd.promise;
76        },
77        validate: function(object) {
78            return true;
79        },
80        put: function(object, options){
81             // summary:
82             //     put an object in CouchDB
83             // object: Object
84             //     The object to put
85             // options: Object
86             //     Options object as
87             //         id: String
88             //
89
90            if ( !this.validate(object) ) {
91                var dfd = new Deferred();
92                dfd.reject("Invalid document.");
93                return dfd.promise;
94            }
95            return this._putValid(object, options);
96
97        },
98        _putValid: function(object,options) {
99            var dfd = new Deferred();
100            options = options || {};
101            var id = options.id ? options.id : this.getIdentity(object);
102            var hasId = typeof id !== "undefined";
103            xhr(hasId ? "PUT" : "POST", {
104                url: hasId ? this.target + id : this.target,
105                postData: json.toJson(object),
106                handleAs: "json",
107                headers:{
108                    "Content-Type": "application/json",
109                    Accept: this.accepts
110                }
111            }).then(lang.hitch(this,function(result){
112                if ( result.error ) {
113                    dfd.reject(result.reason);
114                } else {
115                    object[this.idProperty] = result[this._responseIdProperty];
116                    object[this.revProperty] = result[this._responseRevProperty];
117                    dfd.resolve(object);
118                }
119            }), function(err){
120                dfd.reject(getCouchError(err));
121            });
122            return dfd.promise;
123        },
124        add: function(object, options){
125            return this.put(object,options);
126        },
127        remove: function(id,rev){
128            var dfd = new Deferred();
129            xhr("DELETE",{
130                url: this.target + id,
131                headers: {
132                    'If-Match': rev
133                }
134            }).then(function(result){
135                if ( result.error ) {
136                    dfd.reject(result.reason);
137                } else {
138                    dfd.resolve();
139                }
140            },function(err){
141                dfd.reject(getCouchError(err));
142            });
143            return dfd.promise;
144        },
145        query: function(query, options){
146            // summary:
147            //    query a couchdb view
148            // query: String
149            //    name of a couchdb view you want to query, relative to the current database
150            // options: Object
151            //     options object as
152            //        start: Number
153            //            Start results at this item
154            //        count: Number
155            //            Number of items to return
156            //        sort: [{attribute:'key',descending:true|false}]
157            //            CouchDB only support sorting by key, so only 'key'
158            //            is allowed as attribute value. Multiple sort items
159            //            are ignored.
160            //        key: String|Array|Object
161            //            Return only values with this key.
162            //            Excludes start/endkey usage.
163            //        startkey: String|Array|Object
164            //            Return values starting from this key.
165            //        endkey: String|Array|Object
166            //            Return values with key lower than this key.
167            //        include_docs: true|false
168            //            Return the full documents instead of the view
169            //            values.
170            //        reduce: true|false
171            //            Execute reduce on the view or not. Default depends
172            //            on if a reduce function is defined on the view.
173            //        group: true|false
174            //            Should values be grouped per key or not? Default
175            //            is false.
176            //        group_level: Number
177            //            When group = true and the key is an array,
178            //            determines which elements starting from the first
179            //            are used for grouping. Default is 0.
180            //        get_keys: true|false
181            //            Instead of returning the values or documents,
182            //            return the array of keys as the result.
183            //            This does not affect the forPairs function.
184            options = options || {};
185
186            var dfd = new Deferred();
187            var queryOpts = {};
188            if ( !query ) {
189                query = '_all_docs';
190            }
191
192            if (!lang.isString(query)) {
193                console.warn("Query must be a view name");
194            }
195
196            // Standard options
197            if (options.start >= 0) {
198                queryOpts.skip = options.start;
199            }
200            if (options.count >= 0) {
201                queryOpts.limit = options.count;
202            }
203            if (options.sort) {
204                if (options.sort[0]) {
205                    if (options.sort[0].attribute && options.sort[0].attribute !== "key") {
206                        console.warn("Can only sort on key");
207                    }
208                    if (options.sort[0].descending) {
209                        queryOpts.descending = true;
210                    }
211                }
212                if (options.sort.length > 1) {
213                    console.warn("multiple sort fields not supported");
214                }
215            }
216
217            // Custom options
218            if (options.key !== undefined) {
219                queryOpts.key = options.key;
220            } else if (options.keys !== undefined) {
221                queryOpts.keys = options.keys;
222            } else if (options.startkey !== undefined || options.endkey !== undefined) {
223                queryOpts.startkey = options.startkey;
224                queryOpts.endkey = options.endkey;
225            }
226            if (options.include_docs !== undefined) {
227                queryOpts.include_docs = options.include_docs;
228            }
229            if (options.reduce !== undefined) {
230                queryOpts.reduce = options.reduce;
231            }
232            if (options.group !== undefined) {
233                queryOpts.group = options.group;
234                if (options.group_level !== undefined) {
235                    queryOpts.group_level = options.group_level;
236                }
237            }
238
239            for (var qp in queryOpts) {
240                queryOpts[qp] = json.toJson(queryOpts[qp]);
241            }
242            query += '?' + xhr.objectToQuery(queryOpts);
243
244            xhr("GET", {
245                url: this.target + query,
246                handleAs: "json",
247                headers: {
248                    Accept: this.accepts
249                }
250            }).then(function(result){
251                if (result.error) {
252                    dfd.reject(result.reason);
253                } else  {
254                    var results;
255                    var values = array.map(result.rows,function(result){
256                        return options.include_docs === true ? result.doc : result.value;
257                    });
258                    var keys = array.map(result.rows,function(result){
259                        return result.key;
260                    });
261                    if (options.get_keys === true) {
262                        results = keys;
263                        results.values = values;
264                    } else {
265                        results = values;
266                        results.keys = keys;
267                    }
268                    dfd.resolve(results);
269                }
270            },function(err){
271                dfd.reject(getCouchError(err));
272            });
273            return CouchResults(dfd.promise);
274        }
275    });
276
277    function CouchResults(results) {
278        results = QueryResults(results);
279        results.forPairs = function(callback,thisObject) {
280            callback = lang.hitch(thisObject,callback);
281            return Deferred.when(results,function(results) {
282                var values = results.values || results;
283                var keys = results.keys || results;
284                return array.forEach(values, function(value,index) {
285                    callback(value,keys[index],index);
286                });
287            });
288        };
289        return results;
290    }
291
292    return CouchStore;
293
294});
Note: See TracBrowser for help on using the repository browser.