@@ -121,6 +121,7 @@ var UAParser = require('ua-parser-js');
121121var UUID = require ( './uuid' ) ;
122122var version = require ( './version' ) ;
123123var Identify = require ( './identify' ) ;
124+ var type = require ( './type' ) ;
124125
125126var 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
459460Amplitude . 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
479478var _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 */
614613Amplitude . 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
738749module . 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 } ] ,
7417523 : [ 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
965976module . 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
21712182module . 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
22522263exports = 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} , { } ] ,
3228323913 : [ 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
32333248var AMP_OP_ADD = '$add' ;
32343249var AMP_OP_SET = '$set' ;
32353250var AMP_OP_SET_ONCE = '$setOnce' ;
32363251var AMP_OP_UNSET = '$unset' ;
32373252
3253+ var log = function ( s ) {
3254+ console . log ( '[Amplitude] ' + s ) ;
3255+ } ;
3256+
32383257
32393258var 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-
32483263Identify . 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
32833300module . 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) ;
0 commit comments