Skip to content

Instantly share code, notes, and snippets.

@jarrodhroberson
Created April 26, 2010 03:54
Show Gist options
  • Save jarrodhroberson/378958 to your computer and use it in GitHub Desktop.
Save jarrodhroberson/378958 to your computer and use it in GitHub Desktop.
jquery.couch.js patched to allow list function queries with both GET and POST
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
(function($) {
$.couch = $.couch || {};
function encodeDocId(docID) {
var parts = docID.split("/");
if (parts[0] == "_design") {
parts.shift();
return "_design/" + encodeURIComponent(parts.join('/'));
}
return encodeURIComponent(docID);
};
function prepareUserDoc(user_doc, new_password) {
if (typeof hex_sha1 == "undefined") {
alert("creating a user doc requires sha1.js to be loaded in the page");
return;
}
var user_prefix = "org.couchdb.user:";
user_doc._id = user_doc._id || user_prefix + user_doc.name;
if (new_password) {
// handle the password crypto
user_doc.salt = $.couch.newUUID();
user_doc.password_sha = hex_sha1(new_password + user_doc.salt);
}
user_doc.type = "user";
if (!user_doc.roles) {
user_doc.roles = []
}
return user_doc;
};
var uuidCache = [];
$.extend($.couch, {
urlPrefix: '',
activeTasks: function(options) {
ajax(
{url: this.urlPrefix + "/_active_tasks"},
options,
"Active task status could not be retrieved"
);
},
allDbs: function(options) {
ajax(
{url: this.urlPrefix + "/_all_dbs"},
options,
"An error occurred retrieving the list of all databases"
);
},
config: function(options, section, option, value) {
var req = {url: this.urlPrefix + "/_config/"};
if (section) {
req.url += encodeURIComponent(section) + "/";
if (option) {
req.url += encodeURIComponent(option);
}
}
if (value === null) {
req.type = "DELETE";
} else if (value !== undefined) {
req.type = "PUT";
req.data = toJSON(value);
req.contentType = "application/json";
req.processData = false
}
ajax(req, options,
"An error occurred retrieving/updating the server configuration"
);
},
session: function(options) {
options = options || {};
$.ajax({
type: "GET", url: this.urlPrefix + "/_session",
complete: function(req) {
var resp = $.httpData(req, "json");
if (req.status == 200) {
if (options.success) options.success(resp);
} else if (options.error) {
options.error(req.status, resp.error, resp.reason);
} else {
alert("An error occurred getting session info: " + resp.reason);
}
}
});
},
userDb : function(callback) {
$.couch.session({
success : function(resp) {
var userDb = $.couch.db(resp.info.authentication_db);
callback(userDb);
}
});
},
signup: function(user_doc, password, options) {
options = options || {};
// prepare user doc based on name and password
user_doc = prepareUserDoc(user_doc, password);
$.couch.userDb(function(db) {
db.saveDoc(user_doc, options);
})
},
login: function(options) {
options = options || {};
$.ajax({
type: "POST", url: this.urlPrefix + "/_session", dataType: "json",
data: {name: options.name, password: options.password},
complete: function(req) {
var resp = $.httpData(req, "json");
if (req.status == 200) {
if (options.success) options.success(resp);
} else if (options.error) {
options.error(req.status, resp.error, resp.reason);
} else {
alert("An error occurred logging in: " + resp.reason);
}
}
});
},
logout: function(options) {
options = options || {};
$.ajax({
type: "DELETE", url: this.urlPrefix + "/_session", dataType: "json",
username : "_", password : "_",
complete: function(req) {
var resp = $.httpData(req, "json");
if (req.status == 200) {
if (options.success) options.success(resp);
} else if (options.error) {
options.error(req.status, resp.error, resp.reason);
} else {
alert("An error occurred logging out: " + resp.reason);
}
}
});
},
db: function(name) {
return {
name: name,
uri: this.urlPrefix + "/" + encodeURIComponent(name) + "/",
compact: function(options) {
$.extend(options, {successStatus: 202});
ajax({
type: "POST", url: this.uri + "_compact",
data: "", processData: false
},
options,
"The database could not be compacted"
);
},
viewCleanup: function(options) {
$.extend(options, {successStatus: 202});
ajax({
type: "POST", url: this.uri + "_view_cleanup",
data: "", processData: false
},
options,
"The views could not be cleaned up"
);
},
compactView: function(groupname, options) {
$.extend(options, {successStatus: 202});
ajax({
type: "POST", url: this.uri + "_compact/" + groupname,
data: "", processData: false
},
options,
"The view could not be compacted"
);
},
create: function(options) {
$.extend(options, {successStatus: 201});
ajax({
type: "PUT", url: this.uri, contentType: "application/json",
data: "", processData: false
},
options,
"The database could not be created"
);
},
drop: function(options) {
ajax(
{type: "DELETE", url: this.uri},
options,
"The database could not be deleted"
);
},
info: function(options) {
ajax(
{url: this.uri},
options,
"Database information could not be retrieved"
);
},
allDocs: function(options) {
ajax(
{url: this.uri + "_all_docs" + encodeOptions(options)},
options,
"An error occurred retrieving a list of all documents"
);
},
allDesignDocs: function(options) {
this.allDocs($.extend({startkey:"_design", endkey:"_design0"}, options));
},
allApps: function(options) {
options = options || {};
var self = this;
if (options.eachApp) {
this.allDesignDocs({
success: function(resp) {
$.each(resp.rows, function() {
self.openDoc(this.id, {
success: function(ddoc) {
var index, appPath, appName = ddoc._id.split('/');
appName.shift();
appName = appName.join('/');
index = ddoc.couchapp && ddoc.couchapp.index;
if (index) {
appPath = ['', name, ddoc._id, index].join('/');
} else if (ddoc._attachments && ddoc._attachments["index.html"]) {
appPath = ['', name, ddoc._id, "index.html"].join('/');
}
if (appPath) options.eachApp(appName, appPath, ddoc);
}
});
});
}
});
} else {
alert("please provide an eachApp function for allApps()");
}
},
openDoc: function(docId, options, ajaxOptions) {
ajax({url: this.uri + encodeDocId(docId) + encodeOptions(options)},
options,
"The document could not be retrieved",
ajaxOptions
);
},
saveDoc: function(doc, options) {
options = options || {};
if (doc._id === undefined) {
var method = "POST";
var uri = this.uri;
} else {
var method = "PUT";
var uri = this.uri + encodeDocId(doc._id);
}
$.ajax({
type: method, url: uri + encodeOptions(options),
contentType: "application/json",
dataType: "json", data: toJSON(doc),
complete: function(req) {
var resp = $.httpData(req, "json");
if (req.status == 201) {
doc._id = resp.id;
doc._rev = resp.rev;
if (options.success) options.success(resp);
} else if (options.error) {
options.error(req.status, resp.error, resp.reason);
} else {
alert("The document could not be saved: " + resp.reason);
}
}
});
},
bulkSave: function(docs, options) {
$.extend(options, {successStatus: 201});
ajax({
type: "POST",
url: this.uri + "_bulk_docs" + encodeOptions(options),
data: toJSON(docs)
},
options,
"The documents could not be saved"
);
},
removeDoc: function(doc, options) {
ajax({
type: "DELETE",
url: this.uri +
encodeDocId(doc._id) +
encodeOptions({rev: doc._rev})
},
options,
"The document could not be deleted"
);
},
copyDoc: function(doc, options, ajaxOptions) {
ajaxOptions = $.extend(ajaxOptions, {
complete: function(req) {
var resp = $.httpData(req, "json");
if (req.status == 201) {
doc._id = resp.id;
doc._rev = resp.rev;
if (options.success) options.success(resp);
} else if (options.error) {
options.error(req.status, resp.error, resp.reason);
} else {
alert("The document could not be copied: " + resp.reason);
}
}
});
ajax({
type: "COPY",
url: this.uri +
encodeDocId(doc._id) +
encodeOptions({rev: doc._rev})
},
options,
"The document could not be copied",
ajaxOptions
);
},
query: function(mapFun, reduceFun, language, options) {
language = language || "javascript";
if (typeof(mapFun) !== "string") {
mapFun = mapFun.toSource ? mapFun.toSource() : "(" + mapFun.toString() + ")";
}
var body = {language: language, map: mapFun};
if (reduceFun != null) {
if (typeof(reduceFun) !== "string")
reduceFun = reduceFun.toSource ? reduceFun.toSource() : "(" + reduceFun.toString() + ")";
body.reduce = reduceFun;
}
ajax({
type: "POST",
url: this.uri + "_temp_view" + encodeOptions(options),
contentType: "application/json", data: toJSON(body)
},
options,
"An error occurred querying the database"
);
},
list: function(list, view, options) {
var list = list.split('/');
var options = options || {};
var type = 'GET';
var data = null;
if (options['keys']) {
type = 'POST';
var keys = options['keys'];
delete options['keys'];
data = toJSON({'keys': keys });
}
ajax({
type: type,
data: data,
url: this.uri + '_design/' + list[0] +
'/_list/' + list[1] + '/' + view + encodeOptions(options)
},
options, 'An error occured accessing the list'
);
},
view: function(name, options) {
var name = name.split('/');
var options = options || {};
var type = "GET";
var data= null;
if (options["keys"]) {
type = "POST";
var keys = options["keys"];
delete options["keys"];
data = toJSON({ "keys": keys });
}
ajax({
type: type,
data: data,
url: this.uri + "_design/" + name[0] +
"/_view/" + name[1] + encodeOptions(options)
},
options, "An error occurred accessing the view"
);
},
getDbProperty: function(propName, options, ajaxOptions) {
ajax({url: this.uri + propName + encodeOptions(options)},
options,
"The property could not be retrieved",
ajaxOptions
);
},
setDbProperty: function(propName, propValue, options, ajaxOptions) {
ajax({
type: "PUT",
url: this.uri + propName + encodeOptions(options),
data : JSON.stringify(propValue)
},
options,
"The property could not be updated",
ajaxOptions
);
}
};
},
encodeDocId: encodeDocId,
info: function(options) {
ajax(
{url: this.urlPrefix + "/"},
options,
"Server information could not be retrieved"
);
},
replicate: function(source, target, options) {
ajax({
type: "POST", url: this.urlPrefix + "/_replicate",
data: JSON.stringify({source: source, target: target}),
contentType: "application/json"
},
options,
"Replication failed"
);
},
newUUID: function(cacheNum) {
if (cacheNum === undefined) {
cacheNum = 1;
}
if (!uuidCache.length) {
ajax({url: this.urlPrefix + "/_uuids", data: {count: cacheNum}, async: false}, {
success: function(resp) {
uuidCache = resp.uuids
}
},
"Failed to retrieve UUID batch."
);
}
return uuidCache.shift();
}
});
function ajax(obj, options, errorMessage, ajaxOptions) {
options = $.extend({successStatus: 200}, options);
errorMessage = errorMessage || "Unknown error";
$.ajax($.extend($.extend({
type: "GET", dataType: "json",
complete: function(req) {
var resp = $.httpData(req, "json");
if (req.status == options.successStatus) {
if (options.success) options.success(resp);
} else if (options.error) {
options.error(req.status, resp.error, resp.reason);
} else {
alert(errorMessage + ": " + resp.reason);
}
}
}, obj), ajaxOptions));
}
// Convert a options object to an url query string.
// ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"'
function encodeOptions(options) {
var buf = [];
if (typeof(options) === "object" && options !== null) {
for (var name in options) {
if ($.inArray(name, ["error", "success"]) >= 0)
continue;
var value = options[name];
if ($.inArray(name, ["key", "startkey", "endkey"]) >= 0) {
value = toJSON(value);
}
buf.push(encodeURIComponent(name) + "=" + encodeURIComponent(value));
}
}
return buf.length ? "?" + buf.join("&") : "";
}
function toJSON(obj) {
return obj !== null ? JSON.stringify(obj) : null;
}
})(jQuery);
@jarrodhroberson
Copy link
Author

This is patched to allow list querying with both GET and POST ( for multikey view requests )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment