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

Last change on this file since 427 was 426, checked in by hendrikvanantwerpen, 12 years ago

Added grunt tasks and code cleanup.

Added grunt for less and jshint procesing.
Cleanup of code to pass jshint (one bug found :).

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    var queryResults = QueryResults;
278
279    function couchResults(results) {
280        results = queryResults(results);
281        results.forPairs = function(callback,thisObject) {
282            callback = lang.hitch(thisObject,callback);
283            return Deferred.when(results,function(results) {
284                var values = results.values || results;
285                var keys = results.keys || results;
286                return array.forEach(values, function(value,index) {
287                    callback(value,keys[index],index);
288                });
289            });
290        };
291        return results;
292    }
293
294    return CouchStore;
295
296});
Note: See TracBrowser for help on using the repository browser.