Skip to content

Commit 59bb483

Browse files
committed
refactored merging and added type library
1 parent de59453 commit 59bb483

File tree

5 files changed

+258
-131
lines changed

5 files changed

+258
-131
lines changed

amplitude.js

Lines changed: 137 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ var UAParser = require('ua-parser-js');
121121
var UUID = require('./uuid');
122122
var version = require('./version');
123123
var Identify = require('./identify');
124+
var type = require('./type');
124125

125126
var log = function(s) {
126127
console.log('[Amplitude] ' + s);
@@ -457,27 +458,25 @@ Amplitude.prototype.setVersionName = function(versionName) {
457458

458459
// truncate string values in event and user properties so that request size does not get too large
459460
Amplitude.prototype._truncate = function(value) {
460-
if (typeof(value) === 'object') {
461-
if (Array.isArray(value)) {
462-
for (var i = 0; i < value.length; i++) {
463-
value[i] = this._truncate(value[i]);
464-
}
465-
} else {
466-
for (var key in value) {
467-
if (value.hasOwnProperty(key)) {
468-
value[key] = this._truncate(value[key]);
469-
}
461+
if (type(value) === 'array') {
462+
for (var i = 0; i < value.length; i++) {
463+
value[i] = this._truncate(value[i]);
464+
}
465+
} else if (type(value) === 'object') {
466+
for (var key in value) {
467+
if (value.hasOwnProperty(key)) {
468+
value[key] = this._truncate(value[key]);
470469
}
471470
}
472-
473-
return value;
471+
} else {
472+
value = _truncateValue(value);
474473
}
475474

476-
return _truncateValue(value);
475+
return value;
477476
};
478477

479478
var _truncateValue = function(value) {
480-
if (typeof(value) === 'string') {
479+
if (type(value) === 'string') {
481480
return value.length > MAX_STRING_LENGTH ? value.substring(0, MAX_STRING_LENGTH) : value;
482481
}
483482
return value;
@@ -612,7 +611,7 @@ Amplitude.prototype.logRevenue = function(price, quantity, product) {
612611
* a true filter in case events get out of order or old events are removed.
613612
*/
614613
Amplitude.prototype.removeEvents = function (maxEventId, maxIdentifyId) {
615-
if (maxEventId) {
614+
if (maxEventId >= 0) {
616615
var filteredEvents = [];
617616
for (var i = 0; i < this._unsentEvents.length; i++) {
618617
if (this._unsentEvents[i].event_id > maxEventId) {
@@ -622,7 +621,7 @@ Amplitude.prototype.removeEvents = function (maxEventId, maxIdentifyId) {
622621
this._unsentEvents = filteredEvents;
623622
}
624623

625-
if (maxIdentifyId) {
624+
if (maxIdentifyId >= 0) {
626625
var filteredIdentifys = [];
627626
for (var j = 0; j < this._unsentIdentifys.length; j++) {
628627
if (this._unsentIdentifys[j].event_id > maxIdentifyId) {
@@ -639,42 +638,12 @@ Amplitude.prototype.sendEvents = function(callback) {
639638
var url = ('https:' === window.location.protocol ? 'https' : 'http') + '://' +
640639
this.options.apiEndpoint + '/';
641640

642-
// Determine how many events to send and track the maximum event id sent in this batch.
641+
// fetch events to send
643642
var numEvents = Math.min(this._unsentCount(), this.options.uploadBatchSize);
644-
645-
// coalesce events from both queues
646-
var eventsToSend = [];
647-
var eventIndex = 0;
648-
var identifyIndex = 0;
649-
650-
while (eventsToSend.length < numEvents) {
651-
var event;
652-
653-
// case 1: no identifys - grab from events
654-
if (identifyIndex >= this._unsentIdentifys.length) {
655-
event = this._unsentEvents[eventIndex++];
656-
657-
// case 2: no events - grab from identifys
658-
} else if (eventIndex >= this._unsentEvents.length) {
659-
event = this._unsentIdentifys[identifyIndex++];
660-
661-
// case 3: need to compare timestamps
662-
} else {
663-
if (this._unsentIdentifys[identifyIndex].timestamp <= this._unsentEvents[eventIndex].timestamp) {
664-
event = this._unsentIdentifys[identifyIndex++];
665-
} else {
666-
event = this._unsentEvents[eventIndex++];
667-
}
668-
}
669-
670-
eventsToSend.push(event);
671-
}
672-
673-
var maxEventId = eventIndex > 0 && this._unsentEvents.length > 0 ?
674-
this._unsentEvents[eventIndex - 1].event_id : null;
675-
var maxIdentifyId = identifyIndex > 0 && this._unsentIdentifys.length > 0 ?
676-
this._unsentIdentifys[identifyIndex - 1].event_id : null;
677-
var events = JSON.stringify(eventsToSend);
643+
var mergedEvents = this._mergeEventsAndIdentifys(numEvents);
644+
var maxEventId = mergedEvents.maxEventId;
645+
var maxIdentifyId = mergedEvents.maxIdentifyId;
646+
var events = JSON.stringify(mergedEvents.eventsToSend);
678647

679648
var uploadTime = new Date().getTime();
680649
var data = {
@@ -728,6 +697,48 @@ Amplitude.prototype.sendEvents = function(callback) {
728697
}
729698
};
730699

700+
Amplitude.prototype._mergeEventsAndIdentifys = function(numEvents) {
701+
// coalesce events from both queues
702+
var eventsToSend = [];
703+
var eventIndex = 0;
704+
var maxEventId = -1;
705+
var identifyIndex = 0;
706+
var maxIdentifyId = -1;
707+
708+
while (eventsToSend.length < numEvents) {
709+
var event;
710+
711+
// case 1: no identifys - grab from events
712+
if (identifyIndex >= this._unsentIdentifys.length) {
713+
event = this._unsentEvents[eventIndex++];
714+
maxEventId = event.event_id;
715+
716+
// case 2: no events - grab from identifys
717+
} else if (eventIndex >= this._unsentEvents.length) {
718+
event = this._unsentIdentifys[identifyIndex++];
719+
maxIdentifyId = event.event_id;
720+
721+
// case 3: need to compare timestamps
722+
} else {
723+
if (this._unsentIdentifys[identifyIndex].timestamp <= this._unsentEvents[eventIndex].timestamp) {
724+
event = this._unsentIdentifys[identifyIndex++];
725+
maxIdentifyId = event.event_id;
726+
} else {
727+
event = this._unsentEvents[eventIndex++];
728+
maxEventId = event.event_id;
729+
}
730+
}
731+
732+
eventsToSend.push(event);
733+
}
734+
735+
return {
736+
eventsToSend: eventsToSend,
737+
maxEventId: maxEventId,
738+
maxIdentifyId: maxIdentifyId
739+
};
740+
};
741+
731742
/**
732743
* @deprecated
733744
*/
@@ -737,7 +748,7 @@ Amplitude.prototype.__VERSION__ = version;
737748

738749
module.exports = Amplitude;
739750

740-
}, {"./cookie":3,"json":4,"./language":5,"./localstorage":6,"JavaScript-MD5":7,"object":8,"./xhr":9,"ua-parser-js":10,"./uuid":11,"./version":12,"./identify":13}],
751+
}, {"./cookie":3,"json":4,"./language":5,"./localstorage":6,"JavaScript-MD5":7,"object":8,"./xhr":9,"ua-parser-js":10,"./uuid":11,"./version":12,"./identify":13,"./type":14}],
741752
3: [function(require, module, exports) {
742753
/*
743754
* Cookie data
@@ -864,8 +875,8 @@ module.exports = {
864875

865876
};
866877

867-
}, {"./base64":14,"json":4,"top-domain":15}],
868-
14: [function(require, module, exports) {
878+
}, {"./base64":15,"json":4,"top-domain":16}],
879+
15: [function(require, module, exports) {
869880
/* jshint bitwise: false */
870881
/* global escape, unescape */
871882

@@ -964,8 +975,8 @@ var Base64 = {
964975

965976
module.exports = Base64;
966977

967-
}, {"./utf8":16}],
968-
16: [function(require, module, exports) {
978+
}, {"./utf8":17}],
979+
17: [function(require, module, exports) {
969980
/* jshint bitwise: false */
970981

971982
/*
@@ -1035,8 +1046,8 @@ module.exports = parse && stringify
10351046
? JSON
10361047
: require('json-fallback');
10371048

1038-
}, {"json-fallback":17}],
1039-
17: [function(require, module, exports) {
1049+
}, {"json-fallback":18}],
1050+
18: [function(require, module, exports) {
10401051
/*
10411052
json2.js
10421053
2014-02-04
@@ -1526,7 +1537,7 @@ module.exports = parse && stringify
15261537
}());
15271538

15281539
}, {}],
1529-
15: [function(require, module, exports) {
1540+
16: [function(require, module, exports) {
15301541

15311542
/**
15321543
* Module dependencies.
@@ -1574,8 +1585,8 @@ function domain(url){
15741585
return match ? match[0] : '';
15751586
};
15761587

1577-
}, {"url":18}],
1578-
18: [function(require, module, exports) {
1588+
}, {"url":19}],
1589+
19: [function(require, module, exports) {
15791590

15801591
/**
15811592
* Parse the given `url`.
@@ -2170,8 +2181,8 @@ Request.prototype.send = function(callback) {
21702181

21712182
module.exports = Request;
21722183

2173-
}, {"querystring":19}],
2174-
19: [function(require, module, exports) {
2184+
}, {"querystring":20}],
2185+
20: [function(require, module, exports) {
21752186

21762187
/**
21772188
* Module dependencies.
@@ -2246,8 +2257,8 @@ exports.stringify = function(obj){
22462257
return pairs.join('&');
22472258
};
22482259

2249-
}, {"trim":20,"type":21}],
2250-
20: [function(require, module, exports) {
2260+
}, {"trim":21,"type":22}],
2261+
21: [function(require, module, exports) {
22512262

22522263
exports = module.exports = trim;
22532264

@@ -2267,7 +2278,7 @@ exports.right = function(str){
22672278
};
22682279

22692280
}, {}],
2270-
21: [function(require, module, exports) {
2281+
22: [function(require, module, exports) {
22712282
/**
22722283
* toString ref.
22732284
*/
@@ -3226,28 +3237,34 @@ module.exports = '2.4.0';
32263237

32273238
}, {}],
32283239
13: [function(require, module, exports) {
3240+
var type = require('./type');
3241+
32293242
/*
3230-
* Wrapper for a user properties JSON object that supports operations
3243+
* Wrapper for a user properties JSON object that supports operations.
3244+
* Note: if a user property is used in multiple operations on the same Identify object,
3245+
* only the first operation will be saved, and the rest will be ignored.
32313246
*/
32323247

32333248
var AMP_OP_ADD = '$add';
32343249
var AMP_OP_SET = '$set';
32353250
var AMP_OP_SET_ONCE = '$setOnce';
32363251
var AMP_OP_UNSET = '$unset';
32373252

3253+
var log = function(s) {
3254+
console.log('[Amplitude] ' + s);
3255+
};
3256+
32383257

32393258
var Identify = function() {
32403259
this.userPropertiesOperations = {};
32413260
this.properties = []; // keep track of keys that have been added
32423261
};
32433262

3244-
var isNumeric = function(n) {
3245-
return !isNaN(parseFloat(n)) && isFinite(n);
3246-
};
3247-
32483263
Identify.prototype.add = function(property, value) {
3249-
if (isNumeric(value) || typeof(value) === 'string' || value instanceof String) {
3264+
if (type(value) === 'number' || type(value) === 'string') {
32503265
this._addOperation(AMP_OP_ADD, property, value);
3266+
} else {
3267+
log('Unsupported type for value: ' + type(value) + ', expecting number or string');
32513268
}
32523269
return this;
32533270
};
@@ -3282,5 +3299,53 @@ Identify.prototype._addOperation = function(operation, property, value) {
32823299

32833300
module.exports = Identify;
32843301

3302+
}, {"./type":14}],
3303+
14: [function(require, module, exports) {
3304+
/* Taken from: https://github.com/component/type */
3305+
3306+
/**
3307+
* toString ref.
3308+
*/
3309+
3310+
var toString = Object.prototype.toString;
3311+
3312+
/**
3313+
* Return the type of `val`.
3314+
*
3315+
* @param {Mixed} val
3316+
* @return {String}
3317+
* @api public
3318+
*/
3319+
3320+
module.exports = function(val){
3321+
switch (toString.call(val)) {
3322+
case '[object Date]': return 'date';
3323+
case '[object RegExp]': return 'regexp';
3324+
case '[object Arguments]': return 'arguments';
3325+
case '[object Array]': return 'array';
3326+
case '[object Error]': return 'error';
3327+
}
3328+
3329+
if (val === null) {
3330+
return 'null';
3331+
}
3332+
if (val === undefined) {
3333+
return 'undefined';
3334+
}
3335+
if (val !== val) {
3336+
return 'nan';
3337+
}
3338+
if (val && val.nodeType === 1) {
3339+
return 'element';
3340+
}
3341+
3342+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(val)) {
3343+
return 'buffer';
3344+
}
3345+
3346+
val = val.valueOf ? val.valueOf() : Object.prototype.valueOf.apply(val);
3347+
return typeof val;
3348+
};
3349+
32853350
}, {}]}, {}, {"1":""})
32863351
);

amplitude.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)