Skip to content

Commit da854fb

Browse files
committed
proxy identify object using playback queue
1 parent 3c170cf commit da854fb

File tree

12 files changed

+146
-217
lines changed

12 files changed

+146
-217
lines changed

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ Amplitude-Javascript
88
2. On every page that uses analytics, paste the following Javascript code between the `<head>` and `</head>` tags:
99

1010
<script type="text/javascript">
11-
(function(e,t){var n=e.amplitude||{};var s=t.createElement("script");s.type="text/javascript";
12-
s.async=true;s.src="https://d24n15hnbwhuhn.cloudfront.net/libs/amplitude-2.4.1-min.gz.js";
13-
var i=t.getElementsByTagName("script")[0];i.parentNode.insertBefore(s,i);var r={add:["a",false],
14-
set:["s",false],setOnce:["so",false],unset:["u",true]};n.Identify=function(){this.p={};
15-
Object.keys(r).forEach(function(e){this.p[r[e][0]]={}}.bind(this))};function a(e,t,s){
16-
n.Identify.prototype[e]=function(e,n){this.p[t][e]=s?"-":n;return this}}Object.keys(r).forEach(function(e){
17-
a(e,r[e][0],r[e][1])});n._q=[];function o(e){n[e]=function(){n._q.push([e].concat(Array.prototype.slice.call(arguments,0)));
18-
}}var c=["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties","identify"];
19-
for(var u=0;u<c.length;u++){o(c[u])}e.amplitude=n})(window,document);
11+
(function(t,e){var n=t.amplitude||{};var r=e.createElement("script");r.type="text/javascript";
12+
r.async=true;r.src="https://d24n15hnbwhuhn.cloudfront.net/libs/amplitude-2.4.1-min.gz.js";
13+
var s=e.getElementsByTagName("script")[0];s.parentNode.insertBefore(r,s);var i=function(){
14+
this._q=[];return this};function a(t){i.prototype[t]=function(){this._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
15+
return this}}var o=["add","set","setOnce","unset"];for(var c=0;c<o.length;c++){a(o[c]);
16+
}n.Identify=i;n._q=[];function u(t){n[t]=function(){n._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
17+
}}var p=["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties","identify"];
18+
for(var l=0;l<p.length;l++){u(p[l])}t.amplitude=n})(window,document);
2019

2120
amplitude.init("YOUR_API_KEY_HERE");
2221
</script>

amplitude-segment-snippet.min.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
(function(t,e){var n=t.amplitude||{};n.Identify=function(){this.p={};Object.keys(identifyFuncs).forEach(function(t){
2-
this.p[identifyFuncs[t][0]]={}}.bind(this))};function i(t,e,i){n.Identify.prototype[t]=function(t,n){
3-
this.p[e][t]=i?"-":n;return this}}Object.keys(identifyFuncs).forEach(function(t){
4-
i(t,identifyFuncs[t][0],identifyFuncs[t][1])});n._q=[];function s(t){n[t]=function(){
5-
n._q.push([t].concat(Array.prototype.slice.call(arguments,0)))}}var o=["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties","identify"];
6-
for(var c=0;c<o.length;c++){s(o[c])}t.amplitude=n})(window,document);
1+
(function(t,e){var n=t.amplitude||{};var r=function(){this._q=[];return this};function s(t){
2+
r.prototype[t]=function(){this._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
3+
return this}}var i=["add","set","setOnce","unset"];for(var o=0;o<i.length;o++){s(i[o]);
4+
}n.Identify=r;n._q=[];function a(t){n[t]=function(){n._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
5+
}}var u=["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties","identify"];
6+
for(var c=0;c<u.length;c++){a(u[c])}t.amplitude=n})(window,document);

amplitude-snippet.min.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
(function(e,t){var n=e.amplitude||{};var s=t.createElement("script");s.type="text/javascript";
2-
s.async=true;s.src="https://d24n15hnbwhuhn.cloudfront.net/libs/amplitude-2.4.1-min.gz.js";
3-
var i=t.getElementsByTagName("script")[0];i.parentNode.insertBefore(s,i);var r={add:["a",false],
4-
set:["s",false],setOnce:["so",false],unset:["u",true]};n.Identify=function(){this.p={};
5-
Object.keys(r).forEach(function(e){this.p[r[e][0]]={}}.bind(this))};function a(e,t,s){
6-
n.Identify.prototype[e]=function(e,n){this.p[t][e]=s?"-":n;return this}}Object.keys(r).forEach(function(e){
7-
a(e,r[e][0],r[e][1])});n._q=[];function o(e){n[e]=function(){n._q.push([e].concat(Array.prototype.slice.call(arguments,0)));
8-
}}var c=["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties","identify"];
9-
for(var u=0;u<c.length;u++){o(c[u])}e.amplitude=n})(window,document);
1+
(function(t,e){var n=t.amplitude||{};var r=e.createElement("script");r.type="text/javascript";
2+
r.async=true;r.src="https://d24n15hnbwhuhn.cloudfront.net/libs/amplitude-2.4.1-min.gz.js";
3+
var s=e.getElementsByTagName("script")[0];s.parentNode.insertBefore(r,s);var i=function(){
4+
this._q=[];return this};function a(t){i.prototype[t]=function(){this._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
5+
return this}}var o=["add","set","setOnce","unset"];for(var c=0;c<o.length;c++){a(o[c]);
6+
}n.Identify=i;n._q=[];function u(t){n[t]=function(){n._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
7+
}}var p=["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties","identify"];
8+
for(var l=0;l<p.length;l++){u(p[l])}t.amplitude=n})(window,document);

amplitude.js

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -464,13 +464,21 @@ Amplitude.prototype.setUserProperties = function(userProperties) {
464464
};
465465

466466
Amplitude.prototype.identify = function(identify) {
467+
468+
if (type(identify) === 'object' && '_q' in identify) {
469+
var instance = new Identify();
470+
// Apply the queued commands
471+
for (var i = 0; i < identify._q.length; i++) {
472+
var fn = instance[identify._q[i][0]];
473+
if (fn && type(fn) === 'function') {
474+
fn.apply(instance, identify._q[i].slice(1));
475+
}
476+
}
477+
identify = instance;
478+
}
479+
467480
if (identify instanceof Identify && Object.keys(identify.userPropertiesOperations).length > 0) {
468481
this._logEvent(IDENTIFY_EVENT, null, null, identify.userPropertiesOperations);
469-
} else if (type(identify) === 'object' && 'p' in identify) {
470-
var identifyObject = new Identify().fromProxyObject(identify);
471-
if (Object.keys(identifyObject.userPropertiesOperations).length > 0) {
472-
this._logEvent(IDENTIFY_EVENT, null, null, identifyObject.userPropertiesOperations);
473-
}
474482
}
475483
};
476484

@@ -3295,14 +3303,10 @@ var type = require('./type');
32953303
* only the first operation will be saved, and the rest will be ignored.
32963304
*/
32973305

3298-
// maps operation to identify string and proxy key
3299-
// order listed also defines order of processing
3300-
var OPERATIONS = {
3301-
'AMP_OP_SET_ONCE': {'opString': '$setOnce', 'proxyKey': 'so'},
3302-
'AMP_OP_UNSET': {'opString': '$unset', 'proxyKey': 'u'},
3303-
'AMP_OP_SET': {'opString': '$set', 'proxyKey': 's'},
3304-
'AMP_OP_ADD': {'opString': '$add', 'proxyKey': 'a'}
3305-
};
3306+
var AMP_OP_ADD = '$add';
3307+
var AMP_OP_SET = '$set';
3308+
var AMP_OP_SET_ONCE = '$setOnce';
3309+
var AMP_OP_UNSET = '$unset';
33063310

33073311
var log = function(s) {
33083312
console.log('[Amplitude] ' + s);
@@ -3313,63 +3317,41 @@ var Identify = function() {
33133317
this.properties = []; // keep track of keys that have been added
33143318
};
33153319

3316-
Identify.prototype.fromProxyObject = function(proxyObject) {
3317-
if (!('p' in proxyObject)) {
3318-
return this;
3319-
}
3320-
Object.keys(OPERATIONS).forEach(function(operation) {
3321-
this._addOperationsFromProxyObjectDictionary(operation, proxyObject.p);
3322-
}.bind(this));
3323-
return this;
3324-
};
3325-
3326-
Identify.prototype._addOperationsFromProxyObjectDictionary = function(operation, proxyObjectDict) {
3327-
var proxyKey = OPERATIONS[operation].proxyKey;
3328-
if (!(proxyKey in proxyObjectDict)) {
3329-
return;
3330-
}
3331-
var userPropertiesOperations = proxyObjectDict[proxyKey];
3332-
Object.keys(userPropertiesOperations).forEach(function(key) {
3333-
this._addOperation(operation, key, userPropertiesOperations[key]);
3334-
}.bind(this));
3335-
};
3336-
33373320
Identify.prototype.add = function(property, value) {
33383321
if (type(value) === 'number' || type(value) === 'string') {
3339-
this._addOperation('AMP_OP_ADD', property, value);
3322+
this._addOperation(AMP_OP_ADD, property, value);
33403323
} else {
33413324
log('Unsupported type for value: ' + type(value) + ', expecting number or string');
33423325
}
33433326
return this;
33443327
};
33453328

33463329
Identify.prototype.set = function(property, value) {
3347-
this._addOperation('AMP_OP_SET', property, value);
3330+
this._addOperation(AMP_OP_SET, property, value);
33483331
return this;
33493332
};
33503333

33513334
Identify.prototype.setOnce = function(property, value) {
3352-
this._addOperation('AMP_OP_SET_ONCE', property, value);
3335+
this._addOperation(AMP_OP_SET_ONCE, property, value);
33533336
return this;
33543337
};
33553338

33563339
Identify.prototype.unset = function(property) {
3357-
this._addOperation('AMP_OP_UNSET', property, '-');
3340+
this._addOperation(AMP_OP_UNSET, property, '-');
33583341
return this;
33593342
};
33603343

33613344
Identify.prototype._addOperation = function(operation, property, value) {
3362-
var opString = OPERATIONS[operation].opString;
33633345
// check that property wasn't already used in this Identify
33643346
if (this.properties.indexOf(property) !== -1) {
3365-
log('User property "' + property + '" already used in this identify, skipping operation ' + opString);
3347+
log('User property "' + property + '" already used in this identify, skipping operation ' + operation);
33663348
return;
33673349
}
33683350

3369-
if (!(opString in this.userPropertiesOperations)){
3370-
this.userPropertiesOperations[opString] = {};
3351+
if (!(operation in this.userPropertiesOperations)){
3352+
this.userPropertiesOperations[operation] = {};
33713353
}
3372-
this.userPropertiesOperations[opString][property] = value;
3354+
this.userPropertiesOperations[operation][property] = value;
33733355
this.properties.push(property);
33743356
};
33753357

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.

src/amplitude-snippet.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,28 @@
66
as.src = 'https://d24n15hnbwhuhn.cloudfront.net/libs/amplitude-2.4.1-min.gz.js';
77
var s = document.getElementsByTagName('script')[0];
88
s.parentNode.insertBefore(as, s);
9-
var identifyFuncs = {'add':['a', false], 'set':['s', false], 'setOnce':['so', false], 'unset':['u', true]};
10-
amplitude.Identify = function(){ this.p = {}; Object.keys(identifyFuncs).forEach(function (key) {
11-
this.p[identifyFuncs[key][0]] = {};
12-
}.bind(this));};
13-
function proxyIdentifyFunc(fn, dict, overrideValue) {
14-
amplitude.Identify.prototype[fn] = function(k,v) { this.p[dict][k]=overrideValue?'-':v; return this; };
9+
var Identify = function() { this._q = []; return this; };
10+
function proxyIdentify(fn) {
11+
Identify.prototype[fn] = function() {
12+
this._q.push([fn].concat(Array.prototype.slice.call(arguments, 0))); return this;
13+
};
14+
}
15+
var identifyFuncs = ['add', 'set', 'setOnce', 'unset'];
16+
for (var i = 0; i < identifyFuncs.length; i++) {
17+
proxyIdentify(identifyFuncs[i]);
1518
}
16-
Object.keys(identifyFuncs).forEach(function (key) {
17-
proxyIdentifyFunc(key, identifyFuncs[key][0], identifyFuncs[key][1]);
18-
});
19+
amplitude.Identify = Identify;
1920
amplitude._q = [];
2021
function proxy(fn) {
2122
amplitude[fn] = function() {
2223
amplitude._q.push([fn].concat(Array.prototype.slice.call(arguments, 0)));
2324
};
2425
}
25-
var funcs = ["init", "logEvent", "logRevenue", "setUserId", "setUserProperties",
26-
"setOptOut", "setVersionName", "setDomain", "setDeviceId",
27-
"setGlobalUserProperties", "identify"];
28-
for (var i = 0; i < funcs.length; i++) {
29-
proxy(funcs[i]);
26+
var funcs = ['init', 'logEvent', 'logRevenue', 'setUserId', 'setUserProperties',
27+
'setOptOut', 'setVersionName', 'setDomain', 'setDeviceId',
28+
'setGlobalUserProperties', 'identify'];
29+
for (var j = 0; j < funcs.length; j++) {
30+
proxy(funcs[j]);
3031
}
3132
window.amplitude = amplitude;
3233
})(window, document);

src/amplitude.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,13 +352,21 @@ Amplitude.prototype.setUserProperties = function(userProperties) {
352352
};
353353

354354
Amplitude.prototype.identify = function(identify) {
355+
356+
if (type(identify) === 'object' && '_q' in identify) {
357+
var instance = new Identify();
358+
// Apply the queued commands
359+
for (var i = 0; i < identify._q.length; i++) {
360+
var fn = instance[identify._q[i][0]];
361+
if (fn && type(fn) === 'function') {
362+
fn.apply(instance, identify._q[i].slice(1));
363+
}
364+
}
365+
identify = instance;
366+
}
367+
355368
if (identify instanceof Identify && Object.keys(identify.userPropertiesOperations).length > 0) {
356369
this._logEvent(IDENTIFY_EVENT, null, null, identify.userPropertiesOperations);
357-
} else if (type(identify) === 'object' && 'p' in identify) {
358-
var identifyObject = new Identify().fromProxyObject(identify);
359-
if (Object.keys(identifyObject.userPropertiesOperations).length > 0) {
360-
this._logEvent(IDENTIFY_EVENT, null, null, identifyObject.userPropertiesOperations);
361-
}
362370
}
363371
};
364372

src/identify.js

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,10 @@ var type = require('./type');
66
* only the first operation will be saved, and the rest will be ignored.
77
*/
88

9-
// maps operation to identify string and proxy key
10-
// order listed also defines order of processing
11-
var OPERATIONS = {
12-
'AMP_OP_SET_ONCE': {'opString': '$setOnce', 'proxyKey': 'so'},
13-
'AMP_OP_UNSET': {'opString': '$unset', 'proxyKey': 'u'},
14-
'AMP_OP_SET': {'opString': '$set', 'proxyKey': 's'},
15-
'AMP_OP_ADD': {'opString': '$add', 'proxyKey': 'a'}
16-
};
9+
var AMP_OP_ADD = '$add';
10+
var AMP_OP_SET = '$set';
11+
var AMP_OP_SET_ONCE = '$setOnce';
12+
var AMP_OP_UNSET = '$unset';
1713

1814
var log = function(s) {
1915
console.log('[Amplitude] ' + s);
@@ -24,63 +20,41 @@ var Identify = function() {
2420
this.properties = []; // keep track of keys that have been added
2521
};
2622

27-
Identify.prototype.fromProxyObject = function(proxyObject) {
28-
if (!('p' in proxyObject)) {
29-
return this;
30-
}
31-
Object.keys(OPERATIONS).forEach(function(operation) {
32-
this._addOperationsFromProxyObjectDictionary(operation, proxyObject.p);
33-
}.bind(this));
34-
return this;
35-
};
36-
37-
Identify.prototype._addOperationsFromProxyObjectDictionary = function(operation, proxyObjectDict) {
38-
var proxyKey = OPERATIONS[operation].proxyKey;
39-
if (!(proxyKey in proxyObjectDict)) {
40-
return;
41-
}
42-
var userPropertiesOperations = proxyObjectDict[proxyKey];
43-
Object.keys(userPropertiesOperations).forEach(function(key) {
44-
this._addOperation(operation, key, userPropertiesOperations[key]);
45-
}.bind(this));
46-
};
47-
4823
Identify.prototype.add = function(property, value) {
4924
if (type(value) === 'number' || type(value) === 'string') {
50-
this._addOperation('AMP_OP_ADD', property, value);
25+
this._addOperation(AMP_OP_ADD, property, value);
5126
} else {
5227
log('Unsupported type for value: ' + type(value) + ', expecting number or string');
5328
}
5429
return this;
5530
};
5631

5732
Identify.prototype.set = function(property, value) {
58-
this._addOperation('AMP_OP_SET', property, value);
33+
this._addOperation(AMP_OP_SET, property, value);
5934
return this;
6035
};
6136

6237
Identify.prototype.setOnce = function(property, value) {
63-
this._addOperation('AMP_OP_SET_ONCE', property, value);
38+
this._addOperation(AMP_OP_SET_ONCE, property, value);
6439
return this;
6540
};
6641

6742
Identify.prototype.unset = function(property) {
68-
this._addOperation('AMP_OP_UNSET', property, '-');
43+
this._addOperation(AMP_OP_UNSET, property, '-');
6944
return this;
7045
};
7146

7247
Identify.prototype._addOperation = function(operation, property, value) {
73-
var opString = OPERATIONS[operation].opString;
7448
// check that property wasn't already used in this Identify
7549
if (this.properties.indexOf(property) !== -1) {
76-
log('User property "' + property + '" already used in this identify, skipping operation ' + opString);
50+
log('User property "' + property + '" already used in this identify, skipping operation ' + operation);
7751
return;
7852
}
7953

80-
if (!(opString in this.userPropertiesOperations)){
81-
this.userPropertiesOperations[opString] = {};
54+
if (!(operation in this.userPropertiesOperations)){
55+
this.userPropertiesOperations[operation] = {};
8256
}
83-
this.userPropertiesOperations[opString][property] = value;
57+
this.userPropertiesOperations[operation][property] = value;
8458
this.properties.push(property);
8559
};
8660

test/amplitude.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ describe('Amplitude', function() {
204204
});
205205

206206
it('should ignore empty proxy identify objects', function() {
207-
amplitude.identify({'p': {}});
207+
amplitude.identify({'_q': {}});
208208
assert.lengthOf(amplitude._unsentIdentifys, 0);
209209
assert.lengthOf(server.requests, 0);
210210

@@ -214,12 +214,13 @@ describe('Amplitude', function() {
214214
});
215215

216216
it('should generate an event from a proxy identify object', function() {
217-
var proxyObject = {'p':{
218-
'a':{'key1': 'value1'},
219-
'u':{'key1': 'value2'},
220-
's':{'key2': 'value3', 'key4': 'value5'},
221-
'so':{'key2': 'value4'}
222-
}};
217+
var proxyObject = {'_q':[
218+
['setOnce', 'key2', 'value4'],
219+
['unset', 'key1'],
220+
['add', 'key1', 'value1'],
221+
['set', 'key2', 'value3'],
222+
['set', 'key4', 'value5'],
223+
]};
223224
amplitude.identify(proxyObject);
224225

225226
assert.lengthOf(amplitude._unsentEvents, 0);
@@ -232,7 +233,7 @@ describe('Amplitude', function() {
232233
assert.deepEqual(events[0].event_properties, {});
233234
assert.deepEqual(events[0].user_properties, {
234235
'$setOnce': {'key2': 'value4'},
235-
'$unset': {'key1': 'value2'},
236+
'$unset': {'key1': '-'},
236237
'$set': {'key4': 'value5'}
237238
});
238239
});

0 commit comments

Comments
 (0)