source: Dev/trunk/src/client/qed-client/store/CouchStore.js

Last change on this file was 472, checked in by hendrikvanantwerpen, 12 years ago

Fixed deploy script.
Fix for ... in ... complaints by jshint.
Fix a typo.

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