Skip to content

Commit a3f1697

Browse files
committed
Merged port-ignorehook into chore-port-1.5.x
2 parents e65131a + 2c60aeb commit a3f1697

File tree

7 files changed

+253
-24
lines changed

7 files changed

+253
-24
lines changed

src/init.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
const AV = require('./av');
22
const request = require('./request');
33

4-
const initialize = (appId, appKey, masterKey) => {
4+
const initialize = (appId, appKey, masterKey, hookKey) => {
55
if (AV.applicationId && appId !== AV.applicationId && appKey !== AV.applicationKey && masterKey !== AV.masterKey) {
66
console.warn('LeanCloud SDK is already initialized, please do not reinitialize it.');
77
}
88
AV.applicationId = appId;
99
AV.applicationKey = appKey;
1010
AV.masterKey = masterKey;
11+
AV.hookKey = hookKey || (AV._config.isNode && process.env.LEANCLOUD_APP_HOOK_KEY);
1112
AV._useMasterKey = false;
1213
};
1314

@@ -33,7 +34,7 @@ AV.init = (...args) => {
3334
if (!AV._config.isNode && options.masterKey) {
3435
masterKeyWarn();
3536
}
36-
initialize(options.appId, options.appKey, options.masterKey);
37+
initialize(options.appId, options.appKey, options.masterKey, options.hookKey);
3738
request.setServerUrlByRegion(options.region);
3839
AV._config.disableCurrentUser = options.disableCurrentUser;
3940
} else {

src/object.js

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ module.exports = function(AV) {
6262

6363
this._serverData = {}; // The last known data for this object from cloud.
6464
this._opSetQueue = [{}]; // List of sets of changes to the data.
65+
this._flags = {};
6566
this.attributes = {}; // The best estimate of this's current data.
6667

6768
this._hashedJSON = {}; // Hash of values of containers at last save.
@@ -938,6 +939,8 @@ module.exports = function(AV) {
938939
}
939940
}
940941

942+
_.extend(json, model._flags);
943+
941944
var route = "classes";
942945
var className = model.className;
943946
if (model.className === "_User" && !model.id) {
@@ -997,7 +1000,7 @@ module.exports = function(AV) {
9971000
}
9981001

9991002
var request =
1000-
AVRequest('classes', this.className, this.id, 'DELETE', null, options);
1003+
AVRequest('classes', this.className, this.id, 'DELETE', this._flags, options);
10011004
return request.then(function() {
10021005
if (options.wait) {
10031006
triggerDestroy();
@@ -1206,8 +1209,35 @@ module.exports = function(AV) {
12061209
*/
12071210
setACL: function(acl, options) {
12081211
return this.set("ACL", acl, options);
1209-
}
1212+
},
1213+
1214+
disableBeforeHook: function() {
1215+
this.ignoreHook('beforeSave');
1216+
this.ignoreHook('beforeUpdate');
1217+
this.ignoreHook('beforeDelete');
1218+
},
12101219

1220+
disableAfterHook: function() {
1221+
this.ignoreHook('afterSave');
1222+
this.ignoreHook('afterUpdate');
1223+
this.ignoreHook('afterDelete');
1224+
},
1225+
1226+
ignoreHook: function(hookName) {
1227+
if (!_.contains(['beforeSave', 'afterSave', 'beforeUpdate', 'afterUpdate', 'beforeDelete', 'afterDelete'], hookName)) {
1228+
console.trace('Unsupported hookName: ' + hookName);
1229+
}
1230+
1231+
if (!AV.hookKey) {
1232+
console.trace('ignoreHook required hookKey');
1233+
}
1234+
1235+
if (!this._flags.__ignore_hooks) {
1236+
this._flags.__ignore_hooks = [];
1237+
}
1238+
1239+
this._flags.__ignore_hooks.push(hookName);
1240+
}
12111241
});
12121242

12131243
/**
@@ -1224,35 +1254,31 @@ module.exports = function(AV) {
12241254
return result;
12251255
};
12261256
/**
1227-
* Delete objects in batch.The objects className must be the same.
1257+
* Delete objects in batch.
12281258
* @param {AV.Object[]} objects The <code>AV.Object</code> array to be deleted.
12291259
* @param {AuthOptions} options
12301260
* @return {Promise} A promise that is fulfilled when the save
12311261
* completes.
12321262
*/
1233-
AV.Object.destroyAll = function(objects, options){
1234-
options = options || {};
1263+
AV.Object.destroyAll = function(objects, options = {}){
12351264
if (!objects || objects.length === 0){
12361265
return AV.Promise.resolve();
12371266
}
1238-
var className = objects[0].className;
1239-
var id = "";
1240-
var wasFirst = true;
1241-
objects.forEach(function(obj){
1242-
if(obj.className != className)
1243-
throw "AV.Object.destroyAll requires the argument object array's classNames must be the same";
1244-
if(!obj.id)
1245-
throw "Could not delete unsaved object";
1246-
if(wasFirst){
1247-
id = obj.id;
1248-
wasFirst = false;
1249-
}else{
1250-
id = id + ',' + obj.id;
1267+
const objectsByClassNameAndFlags = _.groupBy(objects, object => JSON.stringify({
1268+
className: object.className,
1269+
flags: object._flags
1270+
}));
1271+
const body = {
1272+
requests: _.map(objectsByClassNameAndFlags, objects => {
1273+
const ids = _.map(objects, 'id').join(',');
1274+
return {
1275+
method: 'DELETE',
1276+
path: `/1.1/classes/${objects[0].className}/${ids}`,
1277+
body: objects[0]._flags
12511278
}
1252-
});
1253-
var request =
1254-
AVRequest('classes', className, id, 'DELETE', null, options);
1255-
return request;
1279+
})
1280+
};
1281+
return AVRequest('batch', null, null, 'POST', body, options);
12561282
};
12571283

12581284
/**
@@ -1520,6 +1546,7 @@ module.exports = function(AV) {
15201546
AVRequest("batch", null, null, "POST", {
15211547
requests: _.map(batch, function(object) {
15221548
var json = object._getSaveJSON();
1549+
_.extend(json, object._flags);
15231550
var method = "POST";
15241551

15251552
var path = "/1.1/classes/" + object.className;

src/request.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ const setHeaders = (authOptions = {}, signKey) => {
133133
} else {
134134
setAppId(headers, signKey);
135135
}
136+
if (AV.hookKey) {
137+
headers['X-LC-Hook-Key'] = AV.hookKey;
138+
}
136139
if (AV._config.applicationProduction !== null) {
137140
headers['X-LC-Prod'] = String(AV._config.applicationProduction);
138141
}

test/hooks.js

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
var IgnoreHookTest = AV.Object.extend('IgnoreHookTest');
2+
3+
describe('hooks', function() {
4+
it('Object#save (new object)', function() {
5+
var object = new IgnoreHookTest();
6+
object.set('title', 'test');
7+
return object.save().then(function() {
8+
return object.fetch(function(object) {
9+
expect(object.get('byBeforeSave')).to.be.ok();
10+
expect(object.get('byAfterSave')).to.be.ok();
11+
});
12+
});
13+
});
14+
15+
it('Object#save (new object) disableBeforeHook', function() {
16+
var object = new IgnoreHookTest();
17+
object.set('title', 'test');
18+
object.disableBeforeHook();
19+
return object.save().then(function() {
20+
return object.fetch(function(object) {
21+
expect(object.get('byBeforeSave')).to.not.be.ok();
22+
expect(object.get('byAfterSave')).to.be.ok();
23+
});
24+
});
25+
});
26+
27+
it('Object#save (new object) ignore afterSave', function() {
28+
var object = new IgnoreHookTest();
29+
object.set('title', 'test');
30+
object.ignoreHook('afterSave');
31+
return object.save().then(function() {
32+
return object.fetch(function(object) {
33+
expect(object.get('byBeforeSave')).to.be.ok();
34+
expect(object.get('byAfterSave')).to.not.be.ok();
35+
});
36+
});
37+
});
38+
39+
it('Object#save (update object)', function() {
40+
var object = new IgnoreHookTest();
41+
object.set('title', 'test');
42+
return object.save().then(function() {
43+
object.set('title', 'something')
44+
return object.save().then(function() {
45+
return object.fetch(function(object) {
46+
expect(object.get('byBeforeSave')).to.be.ok();
47+
expect(object.get('byAfterSave')).to.be.ok();
48+
expect(object.get('byBeforeUpdate')).to.be.ok();
49+
expect(object.get('byAfterUpdate')).to.be.ok();
50+
});
51+
});
52+
});
53+
});
54+
55+
it('Object#save (update object) disableAfterHook', function() {
56+
var object = new IgnoreHookTest();
57+
object.set('title', 'test');
58+
return object.save().then(function() {
59+
object.set('title', 'something');
60+
object.disableAfterHook();
61+
return object.save().then(function() {
62+
return object.fetch(function(object) {
63+
expect(object.get('byBeforeSave')).to.be.ok();
64+
expect(object.get('byAfterSave')).to.be.ok();
65+
expect(object.get('byBeforeUpdate')).to.be.ok();
66+
expect(object.get('byAfterUpdate')).to.not.be.ok();
67+
});
68+
});
69+
});
70+
});
71+
72+
it('Object#save (modify children)', function() {
73+
var object = new IgnoreHookTest();
74+
var child1 = new IgnoreHookTest();
75+
var child2 = new IgnoreHookTest();
76+
child1.set('title', 'test');
77+
child1.disableBeforeHook();
78+
object.set('child1', child1);
79+
object.disableAfterHook();
80+
return object.save().then(function() {
81+
return object.fetch(function(object) {
82+
expect(object.get('byBeforeSave')).to.be.ok();
83+
expect(object.get('byAfterSave')).to.not.be.ok();
84+
}).then(function() {
85+
return child1.fetch(function(child1) {
86+
expect(child1.get('byBeforeSave')).to.not.be.ok();
87+
expect(child1.get('byAfterSave')).to.be.ok();
88+
});
89+
}).then(function() {
90+
child1.set('title', 'something');
91+
object.set('child1', child1);
92+
child2.set('title', 'test');
93+
child2.disableAfterHook();
94+
object.set('child2', child2);
95+
return object.save().then(function() {
96+
object.fetch(function(object) {
97+
expect(object.get('byBeforeUpdate')).to.be.ok();
98+
expect(object.get('byAfterUpdate')).to.not.be.ok();
99+
});
100+
});
101+
}).then(function() {
102+
child1.fetch().then(function(child1) {
103+
expect(child1.get('byBeforeUpdate')).to.not.be.ok();
104+
expect(child1.get('byAfterUpdate')).to.be.ok();
105+
});
106+
}).then(function() {
107+
child2.fetch().then(function(child2) {
108+
expect(child2.get('byBeforeSave')).to.be.ok();
109+
expect(child2.get('byAfterSave')).to.not.be.ok();
110+
});
111+
});
112+
});
113+
});
114+
115+
it('Object.saveAll', function() {
116+
var object = new IgnoreHookTest();
117+
var objectIgnoreBefore = new IgnoreHookTest();
118+
var objectIgnoreAfter = new IgnoreHookTest();
119+
var newObject = new IgnoreHookTest();
120+
var newObjectIgnoreAll = new IgnoreHookTest();
121+
122+
return Promise.all([object, objectIgnoreBefore, objectIgnoreAfter].map(function(object) {
123+
object.set('title', 'test');
124+
return object.save();
125+
})).then(function() {
126+
newObjectIgnoreAll.disableBeforeHook();
127+
newObjectIgnoreAll.disableAfterHook();
128+
129+
objectIgnoreBefore.disableBeforeHook();
130+
objectIgnoreAfter.disableAfterHook();
131+
132+
var objects = [object, objectIgnoreBefore, objectIgnoreAfter, newObject, newObjectIgnoreAll];
133+
134+
objects.forEach(function(object) {
135+
object.set('title', 'something');
136+
});
137+
138+
return AV.Object.saveAll(objects).then(function(objects) {
139+
return Promise.all(objects.map(function(object) {
140+
return object.fetch();
141+
})).then(function() {
142+
expect(object.get('byBeforeSave')).to.be.ok();
143+
expect(object.get('byAfterSave')).to.be.ok();
144+
expect(object.get('byBeforeUpdate')).to.be.ok();
145+
expect(object.get('byAfterUpdate')).to.be.ok();
146+
147+
expect(objectIgnoreBefore.get('byBeforeSave')).to.be.ok();
148+
expect(objectIgnoreBefore.get('byAfterSave')).to.be.ok();
149+
expect(objectIgnoreBefore.get('byBeforeUpdate')).to.not.be.ok();
150+
expect(objectIgnoreBefore.get('byAfterUpdate')).to.be.ok();
151+
152+
expect(objectIgnoreAfter.get('byBeforeSave')).to.be.ok();
153+
expect(objectIgnoreAfter.get('byAfterSave')).to.be.ok();
154+
expect(objectIgnoreAfter.get('byBeforeUpdate')).to.be.ok();
155+
expect(objectIgnoreAfter.get('byAfterUpdate')).to.not.be.ok();
156+
157+
expect(newObject.get('byBeforeSave')).to.be.ok();
158+
expect(newObject.get('byAfterSave')).to.be.ok();
159+
expect(newObject.get('byBeforeUpdate')).to.not.be.ok();
160+
expect(newObject.get('byAfterUpdate')).to.not.be.ok();
161+
162+
expect(newObjectIgnoreAll.get('byBeforeSave')).to.not.be.ok();
163+
expect(newObjectIgnoreAll.get('byAfterSave')).to.not.be.ok();
164+
expect(newObjectIgnoreAll.get('byBeforeUpdate')).to.not.be.ok();
165+
expect(newObjectIgnoreAll.get('byAfterUpdate')).to.not.be.ok();
166+
});
167+
});
168+
});
169+
});
170+
171+
it('Object#destroy', function() {
172+
var object = new IgnoreHookTest();
173+
object.set('title', 'test');
174+
return object.save().then(function() {
175+
object.set('title', 'something');
176+
object.disableBeforeHook();
177+
return object.destroy();
178+
});
179+
});
180+
181+
it('Object#destroyAll', function() {
182+
var object = new IgnoreHookTest();
183+
var objectIgnoreBefore = new IgnoreHookTest();
184+
objectIgnoreBefore.disableBeforeHook();
185+
186+
return Promise.all([object, objectIgnoreBefore].map(function(object) {
187+
return object.save();
188+
})).then(function() {
189+
return AV.Object.destroyAll([object, objectIgnoreBefore]);
190+
}).then(function(result) {
191+
expect(result[0].error).to.be.ok();
192+
expect(result[1].error).to.not.be.ok();
193+
});
194+
});
195+
});

test/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ require('./role.js');
1212
require('./status.js');
1313
require('./sms.js');
1414
require('./search.js');
15+
require('./hooks.js');

test/test.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<script src="sms.js"></script>
3838
<script src="search.js"></script>
3939
<script src="cloud.js"></script>
40+
<script src="hooks.js"></script>
4041
<script>
4142
onload = function(){
4243
mocha.checkLeaks();

test/test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ AV.init({
1616
appId: '95TNUaOSUd8IpKNW0RSqSEOm-9Nh9j0Va',
1717
appKey: 'gNAE1iHowdQvV7cqpfCMGaGN',
1818
masterKey: 'ue9M9nqwD4MQNXD3oiN5rAOv',
19+
hookKey: '2iCbUZDgEF0siKxmCn2kVQXV'
1920
});
2021
AV.setProduction(true);

0 commit comments

Comments
 (0)