You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

keen.io

Package Overview
Dependencies
Maintainers
3
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

keen.io - npm Package Compare versions

Comparing version

to
0.1.1

lib/query.js

40

index.js

@@ -6,2 +6,5 @@ var rest = require('superagent');

var KeenRequests = require('./lib/requests');
var KeenQuery = require('./lib/query');
function KeenApi(config) {

@@ -24,8 +27,9 @@ if (!config) {

var apiVersion = this.apiVersion;
var self = this;
var request = {
get: function(apiKey, path, callback) {
get: function(apiKey, path, data, callback) {
rest
.get(baseUrl + apiVersion + path)
.set('Authorization', apiKey)
.send(data || {})
.end(function(err, res) {

@@ -75,6 +79,6 @@ processResponse(err, res, callback);

list: function(callback) {
request.get(this.masterKey, '/projects', callback);
request.get(self.masterKey, '/projects', null, callback);
},
view: function(projectId, callback) {
request.get(this.masterKey, '/projects/' + projectId, callback);
request.get(self.masterKey, '/projects/' + projectId, callback);
}

@@ -85,3 +89,3 @@ };

list: function(projectId, callback) {
request.get(this.masterKey, '/projects/' + projectId + '/events', callback);
request.get(self.masterKey, '/projects/' + projectId + '/events', callback);
},

@@ -102,3 +106,3 @@ insert: function(projectId, events, callback) {

});
request.post(this.writeKey, '/projects/' + projectId + '/events', data, callback);
request.post(self.writeKey, '/projects/' + projectId + '/events', data, callback);
}

@@ -109,6 +113,6 @@ };

view: function(projectId, collection, property, callback) {
request.get(this.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
request.get(self.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
},
remove: function(projectId, collection, property, callback) {
request.del(this.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
request.del(self.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
}

@@ -119,6 +123,6 @@ };

view: function(projectId, collection, callback) {
request.get(this.masterKey, '/projects/' + projectId + '/events/' + collection, callback);
request.get(self.masterKey, '/projects/' + projectId + '/events/' + collection, null, callback);
},
remove: function(projectId, collection, callback) {
request.del(this.masterKey, '/projects/' + projectId + '/events/' + collection, callback);
request.del(self.masterKey, '/projects/' + projectId + '/events/' + collection, callback);
}

@@ -169,4 +173,4 @@ };

if(method === 'post') {
return request.post(this[keyType], path, params, callback);
if(method === 'post' || method === 'get') {
return request[method](this[keyType], path, params, callback);
}

@@ -191,2 +195,11 @@

};
this.queries = {
extraction: function(projectId, collection, params, callback){
var path = '/projects/' + projectId + '/queries/extraction?event_collection=' + collection;
request.get(self.readKey, path, params, callback);
}
};
this.run = KeenQuery.client.run;
}

@@ -223,3 +236,4 @@

encryptScopedKey: encryptScopedKey,
decryptScopedKey: decryptScopedKey
decryptScopedKey: decryptScopedKey,
Query: KeenQuery.Query
};
{
"name": "keen.io",
"version": "0.0.4",
"version": "0.1.1",
"description": "Keen IO NodeJS module. Keen IO is a hosted API to collect, analyze, and visualize your data.",

@@ -23,2 +23,17 @@ "homepage": "https://github.com/keenlabs/KeenClient-Node",

"url": "http://keen.io"
},
{
"name": "Dustin Larimer",
"email": "dustin@keen.io",
"url": "https://github.com/dustinlarimer"
},
{
"name": "Bogdan Cirlig",
"email": "",
"url": "https://github.com/bibanul"
},
{
"name": "Jah Raphael",
"email": "jahraphael@yahoo.com",
"url": "https://github.com/jahraphael"
}

@@ -25,0 +40,0 @@ ],

# Keen IO - NodeJS
[![Build Status](https://travis-ci.org/keenlabs/KeenClient-Node.png)](https://travis-ci.org/keenlabs/KeenClient-Node)
[![Build Status](https://travis-ci.org/keenlabs/KeenClient-Node.png?branch=master)](https://travis-ci.org/keenlabs/KeenClient-Node)

@@ -20,6 +20,6 @@ Keen IO is an online service to collect, analyze, and visualize your data.

```javascript
var keen = require('keen.io');
var Keen = require('keen.io');
// Configure instance. Only projectId and writeKey are required to send data.
var keen = keen.configure({
var keen = Keen.configure({
projectId: "<project_id>",

@@ -35,7 +35,7 @@ writeKey: "<write_key>",

```javascript
var keen = require('keen.io');
var Keen = require('keen.io');
// Configure instance with API Key
var keen1 = keen.configure({...});
var keen2 = keen.configure({...});
var keen1 = Keen.configure({...});
var keen2 = Keen.configure({...});
```

@@ -46,6 +46,6 @@

```javascript
var keen = require('keen.io');
var Keen = require('keen.io');
// Configure instance with API Key and options
var keen = keen.configure({
var keen = Keen.configure({
projectId: "<project_id>",

@@ -59,4 +59,4 @@ batchEventInserts: 30

```javascript
var keen = require("keen.io");
var keen = keen.configure({
var Keen = require("keen.io");
var keen = Keen.configure({
projectId: "<project_id>",

@@ -89,6 +89,7 @@ writeKey: "<write_key>"

### Generate Scoped Key
```javascript
var keen = require("keen.io");
var Keen = require("keen.io");
var apiKey = "YOUR_API_KEY";
var scopedKey = keen.encryptScopedKey(apiKey, {
var scopedKey = Keen.encryptScopedKey(apiKey, {
"allowed_operations": ["read"],

@@ -101,3 +102,3 @@ "filters": [{

});
var keen = keen.configure({
var keen = Keen.configure({
projectId: "<project_id>";

@@ -108,5 +109,126 @@ readKey: scopedKey

## Queries
Analyses are first-class citizens, complete with parameter getters and setters.
The `<Client>.run` method is available on each configured client instance to run one or many analyses on a given project. Read more about running multiple analyses below.
**Format:**
```
var your_analysis = new Keen.Query(analysisType, params);
```
### Example Usage
```
var Keen = require('keen.io');
var keen = Keen.configure({
projectId: "your_project_id",
readKey: "your_read_key"
});
var count = new Keen.Query("count", {
event_collection: "pageviews",
group_by: "property",
timeframe: "this_7_days"
});
// Send query
keen.run(count, function(err, response){
if (err) return console.log(err);
// response.result
});
```
### Query Analysis Types
All of the following analyses require an `event_collection` parameter. Some analyses have additional requirements, which are noted below.
`count`
`count_unique`
`sum` requires a `target_property` parameter, where value is an integer
`average` requires a `target_property` parameter, where value is an integer
`maximum` requires a `target_property` parameter, where value is an integer
`minimum` requires a `target_property` parameter, where value is an integer
`select_unique` requires a `target_property` parameter
`extraction`
**A note about extractions:** supply an optional `email` attribute to be notified when your extraction is ready for download. If email is not specified, your extraction will be processed synchronously and your data will be returned as JSON.
`Keen.Funnel` requires a `steps` attribute
**A note about funnels:** funnels require a `steps` as an array of objects. Each step requires an `event_collection` and `actor_property` parameter.
```
var funfunfunnel = new Keen.Query('funnel', {
steps: [
{
event_collection: "view_landing_page",
actor_property: "user.id"
},
{
event_collection: "signed_up",
actor_property: "user.id"
},
],
timeframe: "this_6_months"
});
```
Learn more about funnels in the [API reference](https://keen.io/docs/data-analysis/funnels/#steps)
### Run multiple analyses at once
The `<Client>.run` method accepts an individual analysis or array of analyses. In the latter scenario, the callback is fired once all requests have completed without error. Query results are then returned in a correctly sequenced array.
Query results are also attached to the query object itself, and can be referenced as `this.data`.
```
var avg_revenue = new Keen.Query("average", {
event_collection: "purchase",
target_property: "price",
group_by: "geo.country"
});
var max_revenue = new Keen.Query("maximum", {
event_collection: "purchase",
target_property: "price",
group_by: "geo.country"
});
var mashup = keen.run([avg_revenue, max_revenue], function(err, res){
if (err) return console.log(err);
// res[0].result or this.data[0] (avg_revenue)
// res[1].result or this.data[1] (max_revenue)
});
```
### Get/Set Parameters and Refresh Queries
```
// Based on previous example
// Update parameters
avg_revenue.set({ timeframe: "this_21_days" });
max_revenue.set({ timeframe: "this_21_days" });
// Re-run the query
mashup.refresh();
```
## Future Updates
Future module updates are planned to introduce the remaining API calls. You can see some of the spec for that in [examples/queries.js](https://github.com/keenlabs/KeenClient-Node/blob/master/examples/queries.js). Also, as mentioned above, specifying options when creating an instance to configure the behaviour of the instance (ie, batching event submissions).
Future module updates are planned to introduce the remaining API calls. You can see some sketches for these in the [examples directory](https://github.com/keenlabs/KeenClient-Node/blob/master/examples/). Also, as mentioned above, specifying options when creating an instance to configure the behaviour of the instance (ie, batching event submissions).

@@ -113,0 +235,0 @@ ## Contributing

/* jshint quotmark:false,indent:4,maxlen:600 */
var should = require("should");
var _ = require('underscore');
var buildQueryString = function(params){
var query = [];
for (var key in params) {
if (params[key]) {
var value = params[key];
if (Object.prototype.toString.call(value) !== '[object String]') {
value = JSON.stringify(value);
}
value = encodeURIComponent(value);
query.push(key + '=' + value);
}
}
return "?" + query.join('&');
};
describe("keen", function() {
var keen;
var Keen = require("../");
var projectId = "fakeProjectId";
var writeKey = "fakeWriteKey";
var readKey = "fakeReadKey";
var nock = require("nock");

@@ -20,2 +38,6 @@

afterEach(function() {
nock.cleanAll();
});
it("configure should set up client correctly", function() {

@@ -218,3 +240,3 @@ keen = require("../");

it('should send the request', function() {
mockGetRequest("/3.0/projects/"+projectId+"/queries/count?event_collection=foo", 200, mockResponse);
mockGetRequest("/"+ apiVersion +"/projects/"+ projectId +"/queries/count?event_collection=foo", 200, mockResponse);
keen.request('get', 'read', '/queries/count', {event_collection:'foo'}, function(err, res) {

@@ -227,4 +249,4 @@ (err === null).should.be.true;

it('has optional params', function() {
mockGetRequest("/3.0/projects/"+projectId+"/queries/count?event_collection=bar", 200, mockResponse);
keen.request('get', 'read', '/queries/count?event_collection=bar', function(err, res) {
mockGetRequest("/"+ apiVersion +"/projects/"+projectId+"/queries/count?event_collection=bar", 200, mockResponse);
keen.request('get', 'read', '/queries/count', {event_collection:'bar'}, function(err, res) {
(err === null).should.be.true;

@@ -236,2 +258,288 @@ res.should.eql(mockResponse);

});
describe('Queries', function() {
beforeEach(function() {
nock.cleanAll();
Keen = require("../");
keen = Keen.configure({
projectId: projectId,
readKey: readKey
});
});
describe('<Client>.run method', function(){
it('should be a method', function(){
keen['run'].should.be.a.Function;
});
it('should throw an error when passed an invalid object', function(){
(function(){
keen.run(null);
}).should.throwError();
(function(){
keen.run({});
}).should.throwError();
(function(){
keen.run(0);
}).should.throwError();
// This should be removed when 'saved_query' support is validated
(function(){
keen.run('string');
}).should.throwError();
});
});
describe('Analysis Types', function(){
var analyses = [
'count',
'count_unique',
'sum',
'median',
'percentile',
'average',
'minimum',
'maximum',
'select_unique',
'extraction'
];
_.each(analyses, function(type){
var analysis = new Keen.Query(type, {
eventCollection: 'eventCollection',
timeframe: 'this_7_days'
});
var query_path = "/3.0/projects/" + projectId + "/queries/" + type;
it('should be an instance of Keen.Query', function(){
analysis.should.be.an.instanceOf(Keen.Query);
});
it('should have a correct path propery', function(){
analysis.should.have.property('path');
analysis.path.should.eql('/queries/' + type);
});
it('should have a params property with supplied parameters', function(){
analysis.should.have.property('params');
analysis.params.should.have.property('event_collection', 'eventCollection');
analysis.params.should.have.property('timeframe', 'this_7_days');
});
it('should have a #get method that returns a requested parameter', function(){
analysis.get.should.be.a.Function;
analysis.get('timeframe').should.eql('this_7_days');
});
it('should have a #set method that sets all supplied properties', function(){
analysis.set.should.be.a.Function;
analysis.set({ group_by: 'property', target_property: 'referrer' });
analysis.params.should.have.property('group_by', 'property');
analysis.params.should.have.property('target_property', 'referrer');
});
it('should #set under_score attributes when camelCase attributes are supplied', function(){
analysis.set({ groupBy: 'property' });
analysis.params.should.have.property('group_by', 'property');
});
describe('When handled by <Client>.run method', function(){
beforeEach(function() {
nock.cleanAll();
});
describe('Single analyses', function(){
it('should return a response when successful', function(done){
var mockResponse = { result: 1 };
mockGetRequest(query_path, 200, mockResponse);
analysis.params = {};
var test = keen.run(analysis, function(err, res){
(err === null).should.be.true;
res.should.eql(mockResponse);
done();
});
});
it('should return an error when unsuccessful', function(done){
var mockResponse = { error_code: 'ResourceNotFoundError', message: 'no foo' };
mockGetRequest(query_path, 500, mockResponse);
analysis.params = {};
var test = keen.run(analysis, function(err, res){
err.should.be.an.instanceOf(Error);
err.should.have.property('code', mockResponse.error_code);
done();
});
});
});
describe('Multiple analyses', function(){
it('should return a single response when successful', function(done){
var mockResponse = { result: 1 };
mockGetRequest(query_path, 200, mockResponse);
mockGetRequest(query_path, 200, mockResponse);
mockGetRequest(query_path, 200, mockResponse);
analysis.params = {};
var test = keen.run([analysis, analysis, analysis], function(err, res){
(err === null).should.be.true;
res.should.be.an.Array;
res.should.have.length(3);
res.should.eql([mockResponse, mockResponse, mockResponse]);
done();
});
});
it('should return a single error when unsuccessful', function(done){
var mockResponse = { error_code: 'ResourceNotFoundError', message: 'no foo' };
mockGetRequest(query_path, 500, mockResponse);
analysis.params = {};
var test = keen.run([analysis, analysis, analysis], function(err, res){
err.should.be.an.instanceOf(Error);
err.should.have.property('code', mockResponse.error_code);
done();
});
});
});
});
});
});
describe('Funnels', function(){
var funnel = new Keen.Query('funnel', {
steps: [
{ event_collection: "view_landing_page", actor_property: "user.id" },
{ eventCollection: "sign_up", actorProperty: "user.id" }
],
timeframe: "this_21_days"
});
var funnel_path = "/3.0/projects/" + projectId + "/queries/funnel" + buildQueryString(funnel.params);
it('should be an instance of Keen.Query', function(){
funnel.should.be.an.instanceOf(Keen.Query);
});
it('should have a correct path propery', function(){
funnel.should.have.property('path');
funnel.path.should.eql('/queries/funnel');
});
it('should have a params property with supplied parameters', function(){
funnel.should.have.property('params');
funnel.params.should.have.property('steps');
funnel.params.steps.should.be.an.Array.with.lengthOf(2);
});
it('should have steps with parameters in proper case', function(){
funnel.params.steps[1].should.have.property('event_collection');
funnel.params.steps[1].should.have.property('actor_property');
});
it('should have a #get method that returns a requested parameter', function(){
funnel.get.should.be.a.Function;
funnel.get('steps').should.be.an.Array;
funnel.get('timeframe').should.eql('this_21_days');
});
it('should have a #set method that sets all supplied properties', function(){
funnel.set.should.be.a.Function;
funnel.set({ timeframe: 'this_21_days' });
funnel.params.should.have.property('timeframe', 'this_21_days');
});
it('should #set under_score step attributes when camelCase are supplied ', function(){
funnel.set({ steps: [
{ eventCollection: "view_landing_page", actorProperty: "user.id" },
{ eventCollection: "sign_up", actorProperty: "user.id" }
] });
funnel.params.steps[0].should.have.property('event_collection', 'view_landing_page');
funnel.params.steps[0].should.have.property('actor_property', 'user.id');
funnel.params.steps[1].should.have.property('event_collection', 'sign_up');
funnel.params.steps[1].should.have.property('actor_property', 'user.id');
});
describe('When handled by <Client>.run method', function(){
beforeEach(function() {
nock.cleanAll();
});
describe('Single analyses', function(){
it('should return a response when successful', function(done){
var mockResponse = { result: 1 };
mockGetRequest(funnel_path, 200, mockResponse);
var test = keen.run(funnel, function(err, res){
(err === null).should.be.true;
res.should.eql(mockResponse);
done();
});
});
it('should return an error when unsuccessful', function(done){
var mockResponse = { error_code: 'ResourceNotFoundError', message: 'no foo' };
mockGetRequest(funnel_path, 500, mockResponse);
var test = keen.run(funnel, function(err, res){
err.should.be.an.instanceOf(Error);
err.should.have.property('code', mockResponse.error_code);
done();
});
});
});
describe('Multiple analyses', function(){
it('should return a single response when successful', function(done){
var mockResponse = { result: 1 };
mockGetRequest(funnel_path, 200, mockResponse);
mockGetRequest(funnel_path, 200, mockResponse);
mockGetRequest(funnel_path, 200, mockResponse);
var test = keen.run([funnel, funnel, funnel], function(err, res){
(err === null).should.be.true;
res.should.be.an.Array;
res.should.have.length(3);
res.should.eql([mockResponse, mockResponse, mockResponse]);
done();
});
});
it('should return a single error when unsuccessful', function(done){
var mockResponse = { error_code: 'ResourceNotFoundError', message: 'no foo' };
mockGetRequest(funnel_path, 500, mockResponse);
var test = keen.run([funnel, funnel, funnel], function(err, res){
err.should.be.an.instanceOf(Error);
err.should.have.property('code', mockResponse.error_code);
done();
});
});
});
});
});
});
});