Comparing version 1.4.2 to 1.4.3
@@ -63,2 +63,16 @@ module.exports = Cloudant; | ||
var bulk_get = function(options, callback) { | ||
return nano.request( { path: encodeURIComponent(db) + "/_bulk_get", | ||
method: "post", | ||
body: options }, callback) | ||
}; | ||
// https://docs.cloudant.com/geo.html | ||
var geo = function(docName, indexName, query, callback) { | ||
var path = encodeURIComponent(db) + "/_design/" + | ||
encodeURIComponent(docName) + "/_geo/" + | ||
encodeURIComponent(indexName); | ||
return nano.request({path:path, qs:query}, callback); | ||
}; | ||
// https://docs.cloudant.com/api.html#viewing-permissions | ||
@@ -118,2 +132,4 @@ var get_security = function(callback) { | ||
var obj = nano._use(db); | ||
obj.geo = geo; | ||
obj.bulk_get = bulk_get; | ||
obj.get_security = get_security; | ||
@@ -120,0 +136,0 @@ obj.set_security = set_security; |
@@ -46,3 +46,3 @@ // reconfigure deals with the various ways the credentials can be passed in | ||
config.account.match && | ||
config.account.match(/(\w+)\.cloudant\.com/); | ||
config.account.match(/([^.]+)\.cloudant\.com/); | ||
if (match) | ||
@@ -49,0 +49,0 @@ config.account = match[1]; |
@@ -7,3 +7,3 @@ { | ||
"repository": "git://github.com/cloudant/nodejs-cloudant", | ||
"version": "1.4.2", | ||
"version": "1.4.3", | ||
"author": "Jason Smith <jason@cloudant.com>", | ||
@@ -10,0 +10,0 @@ "contributors": [ |
@@ -228,2 +228,3 @@ # Cloudant Node.js Client | ||
- [Cloudant Search](#cloudant-search) | ||
- [Cloudant Geospatial](#cloudant-geospatial) | ||
- [Cookie Authentication](#cookie-authentication) | ||
@@ -491,3 +492,2 @@ - [Advanced Features](#advanced-features) | ||
To see all the indexes in a database, call the database `.index()` method with a callback function. | ||
, {_id: '_design/library', indexes:{books:{analyzer:{name:'standard'}, index:index}}} | ||
@@ -539,2 +539,90 @@ ~~~ js | ||
## Cloudant Geospatial | ||
This feature interfaces with Cloudant's geospatial features. See the [Cloudant Geospatial documentation][Cloudant Geospatial] for details. | ||
Begin with a database, and insert documents in [GeoJSON format][geojson]. Documents should have `"type"` set to `"Feature"` and also `"geometry"` with a valid GeoJSON value. For example: | ||
~~~ js | ||
var db = cloudant.db.use('my_db') | ||
var cities = [ | ||
{ "_id":"Boston", | ||
"type":"Feature", | ||
"geometry": { | ||
"type":"Point","coordinates": [-71.063611, 42.358056] | ||
} | ||
}, | ||
{ "_id":"Houston", | ||
"type":"Feature", | ||
"geometry": { | ||
"type":"Point","coordinates": [-95.383056, 29.762778] | ||
} | ||
}, | ||
{ "_id":"Ruston", | ||
"type":"Feature", | ||
"geometry": { | ||
"type":"Point","coordinates": [-92.640556, 32.529722] | ||
} | ||
} | ||
]; | ||
db.bulk({docs:cities}, function(er) { | ||
if (er) { | ||
throw er; | ||
} | ||
console.log('Inserted all cities'); | ||
}); | ||
~~~ | ||
To make a spatial index of these documents, create a design document with `"st_indexes"` populated with a JavaScript indexing function. | ||
~~~ js | ||
// Note, you can make a normal JavaScript function. It is not necessary | ||
// for you to convert it to a string as with other languages and tools. | ||
var city_indexer = function(doc) { | ||
if (doc.geometry && doc.geometry.coordinates) { | ||
st_index(doc.geometry); | ||
} | ||
}; | ||
var ddoc = { | ||
_id: '_design/city', | ||
st_indexes: { | ||
city_points: { | ||
index: city_indexer | ||
} | ||
} | ||
}; | ||
db.insert(ddoc, function (er, result) { | ||
if (er) { | ||
throw er; | ||
} | ||
console.log('Created design document with city index'); | ||
}); | ||
~~~ | ||
To query this index, use the database `.geo()` method. The first argument is the design document name, followed by the index name, and finally an object with your search parameters. | ||
~~~ js | ||
// Find the city within 25km (15 miles) of Lexington, MA. | ||
var query = { | ||
lat:42.447222, lon:-71.225, | ||
radius:25000, | ||
include_docs:true | ||
}; | ||
db.geo('city', 'city_points', query, function(er, result) { | ||
if (er) { | ||
throw er; | ||
} | ||
console.log('Cities found: %d', result.rows.length); // "Cities found: 1" | ||
console.log(result.rows[0].doc._id); // "Boston" | ||
}); | ||
~~~ | ||
## Cookie Authentication | ||
@@ -848,4 +936,6 @@ | ||
[Cloudant Search]: https://docs.cloudant.com/search.html | ||
[Cloudant Geospatial]: https://docs.cloudant.com/geo.html | ||
[Authentication]: https://docs.cloudant.com/authentication.html | ||
[Authorization]: https://docs.cloudant.com/authorization.html | ||
[geojson]: http://geojson.org/ | ||
[CORS]: https://docs.cloudant.com/cors.html | ||
@@ -852,0 +942,0 @@ [Issues]: https://github.com/cloudant/nodejs-cloudant/issues |
107
tests/api.js
@@ -228,2 +228,107 @@ /** | ||
describe('Cloudant-Specific APIs', function() { | ||
before(function(done) { | ||
var mocks = nock(SERVER) | ||
.put('/' + MYDB).reply(200, { "ok": true }); | ||
cc = Cloudant({account:ME, password:PASSWORD}); | ||
cc.db.create(MYDB, function(er, d) { | ||
should(er).equal(null); | ||
d.should.be.an.Object; | ||
d.should.have.a.property("ok"); | ||
d.ok.should.be.equal(true); | ||
mydb = cc.db.use("mydb"); | ||
ddoc = viewname = null; | ||
mocks.done(); | ||
done(); | ||
}); | ||
}); | ||
it('create query dummy data', function(done) { | ||
var mocks = nock(SERVER) | ||
.post('/' + MYDB + '/_bulk_docs') | ||
.reply(200, [{"id":"doc1","rev":"1-967a00dff5e02add41819138abb3284d"},{"id":"doc2","rev":"1-967a00dff5e02add41819138abb3284d"}, | ||
{"id":"geodoc", "rev":"1-11da8390b0a7401efda16f63c06b420b"},{"id":"_design/geodd","rev":"1-ff1c0ac66b134edad082d2b7a7d98c9c"}]); | ||
var geoDoc = {"_id":"geodoc", "type":"Feature", "geometry":{"type":"Point","coordinates":[-71.13687953,42.34690635]}}; | ||
var geoDD = {"_id":"_design/geodd", "st_indexes": { "points": { | ||
"index": "function(doc) { if (doc.geometry && doc.geometry.coordinates) { st_index(doc.geometry); } }" | ||
} } }; | ||
mydb.bulk({docs: [ {_id:'doc1'},{_id:'doc2'}, geoDoc, geoDD ]}, function(er, d) { | ||
should(er).equal(null); | ||
d.should.be.an.Array; | ||
for (var i in d) { | ||
d[i].should.be.an.Object; | ||
d[i].should.have.a.property("id"); | ||
d[i].should.have.a.property("rev"); | ||
} | ||
mocks.done(); | ||
done(); | ||
}); | ||
}); | ||
it('Has _bulk_get', function(done) { | ||
var mocks = nock(SERVER) | ||
.post('/' + MYDB + '/_bulk_get') | ||
.reply(200, {results:[{id:'doc1',docs:[{ok:{_id:'doc1',_rev:'1-967a00dff5e02add41819138abb3284d'}}]},{id:'non_id',docs:[{error:{id:'non_id',rev:'undefined',error:'not_found',reason:'missing'}}]},{id:'doc2',docs:[{ok:{_id:'doc2',_rev:'1-967a00dff5e02add41819138abb3284d'}}]}]}) | ||
mydb.bulk_get({docs:[{id:'doc1'}, {id:'non_id'}, {id:'doc2'}]}, function(er, body) { | ||
should(er).equal(null); | ||
body.should.have.a.property('results').which.is.instanceOf(Array); | ||
body.results.should.have.a.length(3); | ||
body.results[0].should.be.an.Object.and.have.a.property('id').and.match(/^doc1$/); | ||
body.results[0].docs[0].ok.should.be.an.Object | ||
.and.have.a.property('_rev').and.match(/^1-967a00dff5e02add41819138abb3284d/); | ||
body.results[1].should.be.an.Object.and.have.a.property('id').and.match(/^non_id/); | ||
body.results[1].docs[0].error.should.be.an.Object | ||
.and.have.a.property('error').and.match(/^not_found$/); | ||
body.results[2].should.be.an.Object.and.have.a.property('id').and.match(/^doc2$/); | ||
body.results[2].docs[0].ok.should.be.an.Object | ||
.and.have.a.property('_rev').and.match(/^1-967a00dff5e02add41819138abb3284d/); | ||
mocks.done(); | ||
done(); | ||
}); | ||
}) | ||
it('Has geo querying', function(done) { | ||
var mocks = nock(SERVER) | ||
.get('/' + MYDB + '/_design/geodd/_geo/points?lat=42.347&lon=-71.137&radius=100&include_docs=true') | ||
.reply(200, {"rows":[{"id":"geodoc","geometry":{"type":"Point","coordinates":[-71.13687953,42.34690635]},"doc":{"_id":"geodoc","_rev":"1-11da8390b0a7401efda16f63c06b420b","type":"Feature","geometry":{"type":"Point","coordinates":[-71.13687953,42.34690635]}}}]}); | ||
mydb.geo('geodd', 'points', {lat:42.347, lon:-71.137, radius:100, include_docs:true}, function(er, body) { | ||
should(er).equal(null); | ||
body.rows.should.be.instanceOf(Array).and.have.lengthOf(1); | ||
body.rows[0].should.be.an.Object; | ||
body.rows[0].should.have.a.property('geometry').which.is.an.Object; | ||
body.rows[0].geometry.coordinates.should.be.instanceOf(Array).and.have.lengthOf(2); | ||
body.rows[0].geometry.coordinates[0].should.equal(-71.13687953); | ||
body.rows[0].geometry.coordinates[1].should.equal(42.34690635); | ||
body.rows[0].doc.should.be.an.Object.and.have.a.property('_id').equal('geodoc'); | ||
done(); | ||
}); | ||
}); | ||
after(function(done) { | ||
var mocks = nock(SERVER) | ||
.delete('/' + MYDB).reply(200, { "ok": true }); | ||
cc.db.destroy(MYDB, function(er, d) { | ||
should(er).equal(null); | ||
d.should.be.an.Object; | ||
d.should.have.a.property("ok"); | ||
d.ok.should.be.equal(true); | ||
mydb = null; | ||
cc = null; | ||
ddoc = viewname = null; | ||
mocks.done(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
describe('Changes query', function() { | ||
@@ -798,3 +903,3 @@ before(function(done) { | ||
data["accept-encoding"].should.be.a.String; | ||
data["accept-encoding"].should.equal("gzip"); | ||
data["accept-encoding"].should.match(/gzip/); | ||
done(); | ||
@@ -801,0 +906,0 @@ }); |
@@ -7,3 +7,3 @@ var should = require('should'); | ||
it('is a function', function(done) { | ||
reconfigure.should.be.a.function; | ||
reconfigure.should.be.a.Function; | ||
done(); | ||
@@ -97,3 +97,12 @@ }); | ||
}); | ||
}); | ||
// Issue cloudant/nodejs-cloudant#141 | ||
it('Allows account names with dashes', function(done) { | ||
var credentials = { account: "this-account-has-dashes.cloudant.com", password: "bacon" }; | ||
var url = reconfigure(credentials); | ||
url.should.be.a.String; | ||
url.should.equal("https://this-account-has-dashes:bacon@this-account-has-dashes.cloudant.com"); | ||
done(); | ||
}); | ||
}); |
122973
1957
941