Skip to content

Commit 4d52410

Browse files
committed
feat(Object): make toJSON result contains included pointers (#453)
add AV.parseJSON add Object#toFullJSON add File#toFullJSON extend prototypes (rather than replace them) to fix wrong instance constructors
1 parent 6e65f57 commit 4d52410

File tree

12 files changed

+258
-81
lines changed

12 files changed

+258
-81
lines changed

src/av.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -205,34 +205,28 @@ AV._getValue = function(object, prop) {
205205
* is set, then none of the AV Objects that are serialized can be dirty.
206206
* @private
207207
*/
208-
AV._encode = function(value, seenObjects, disallowObjects) {
208+
AV._encode = function(value, seenObjects, disallowObjects, full) {
209209
if (value instanceof AV.Object) {
210210
if (disallowObjects) {
211211
throw new Error("AV.Objects not allowed here");
212212
}
213213
if (!seenObjects || _.include(seenObjects, value) || !value._hasData) {
214214
return value._toPointer();
215215
}
216-
if (!value.dirty()) {
217-
seenObjects = seenObjects.concat(value);
218-
return AV._encode(value._toFullJSON(seenObjects),
219-
seenObjects,
220-
disallowObjects);
221-
}
222-
throw new Error("Tried to save an object with a pointer to a new, unsaved object.");
216+
return value._toFullJSON(seenObjects.concat(value), full);
223217
}
224218
if (value instanceof AV.ACL) {
225219
return value.toJSON();
226220
}
227221
if (_.isDate(value)) {
228-
return { "__type": "Date", "iso": value.toJSON() };
222+
return full ? { "__type": "Date", "iso": value.toJSON() } : value.toJSON();
229223
}
230224
if (value instanceof AV.GeoPoint) {
231225
return value.toJSON();
232226
}
233227
if (_.isArray(value)) {
234228
return _.map(value, function(x) {
235-
return AV._encode(x, seenObjects, disallowObjects);
229+
return AV._encode(x, seenObjects, disallowObjects, full);
236230
});
237231
}
238232
if (_.isRegExp(value)) {
@@ -248,10 +242,10 @@ AV._encode = function(value, seenObjects, disallowObjects) {
248242
if (!value.url() && !value.id) {
249243
throw new Error("Tried to save an object containing an unsaved file.");
250244
}
251-
return value._toFullJSON();
245+
return value._toFullJSON(seenObjects, full);
252246
}
253247
if (_.isObject(value)) {
254-
return _.mapObject(value, (v, k) => AV._encode(v, seenObjects, disallowObjects));
248+
return _.mapObject(value, (v, k) => AV._encode(v, seenObjects, disallowObjects, full));
255249
}
256250
return value;
257251
};
@@ -337,6 +331,14 @@ AV._decode = function(value, key) {
337331
return _.mapObject(value, AV._decode);
338332
};
339333

334+
/**
335+
* The inverse function of {@link AV.Object#toFullJSON}.
336+
* @since 2.0.0
337+
* @param {Object}
338+
* return {AV.Object|AV.File|any}
339+
*/
340+
AV.parseJSON = AV._decode;
341+
340342
AV._encodeObjectOrArray = function(value) {
341343
var encodeAVObject = function(object) {
342344
if (object && object._toFullJSON){

src/file.js

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,13 @@ module.exports = function(AV) {
198198
return file;
199199
};
200200

201-
AV.File.prototype = {
201+
_.extend(AV.File.prototype, /** @lends AV.File.prototype */ {
202202
className: '_File',
203203

204-
_toFullJSON(seenObjects) {
204+
_toFullJSON(seenObjects, full = true) {
205205
var json = _.clone(this.attributes);
206206
AV._objectEach(json, function(val, key) {
207-
json[key] = AV._encode(val, seenObjects);
207+
json[key] = AV._encode(val, seenObjects, undefined, full);
208208
});
209209
AV._objectEach(this._operations, function(val, key) {
210210
json[key] = val;
@@ -219,17 +219,28 @@ module.exports = function(AV) {
219219
json[key] = _.isDate(val) ? val.toJSON() : val;
220220
}
221221
});
222-
json.__type = "File";
222+
if (full) {
223+
json.__type = "File";
224+
}
223225
return json;
224226
},
225227

226-
toJSON() {
227-
const json = this._toFullJSON();
228-
// add id and keep __type for backward compatible
229-
if (_.has(this, 'id')) {
230-
json.id = this.id;
231-
}
232-
return json;
228+
/**
229+
* Returns a JSON version of the file with meta data.
230+
* Inverse to {@link AV.parseJSON}
231+
* @since 2.0.0
232+
* @return {Object}
233+
*/
234+
toFullJSON(seenObjects = []) {
235+
return this._toFullJSON(seenObjects);
236+
},
237+
238+
/**
239+
* Returns a JSON version of the object.
240+
* @return {Object}
241+
*/
242+
toJSON: function(key, holder, seenObjects = [this]) {
243+
return this._toFullJSON(seenObjects, false);
233244
},
234245

235246
/**
@@ -545,5 +556,5 @@ module.exports = function(AV) {
545556
_.extend(this, value);
546557
return this;
547558
}
548-
};
559+
});
549560
};

src/geopoint.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ module.exports = function(AV) {
107107
}, reject);
108108
});
109109

110-
AV.GeoPoint.prototype = {
110+
_.extend(AV.GeoPoint.prototype, /** @lends AV.GeoPoint.prototype */ {
111111
/**
112112
* Returns a JSON representation of the GeoPoint, suitable for AV.
113113
* @return {Object}
@@ -161,5 +161,5 @@ module.exports = function(AV) {
161161
milesTo: function(point) {
162162
return this.radiansTo(point) * 3958.8;
163163
}
164-
};
164+
});
165165
};

src/insight.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ module.exports = function(AV) {
7777
this._limit = 100;
7878
};
7979

80-
AV.Insight.JobQuery.prototype = {
80+
_.extend(AV.Insight.JobQuery.prototype, /** @lends AV.Insight.JobQuery.prototype */ {
8181

8282
/**
8383
* Sets the number of results to skip before returning any results.
@@ -129,6 +129,6 @@ module.exports = function(AV) {
129129
});
130130
}
131131

132-
};
132+
});
133133

134134
};

src/object.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -189,20 +189,30 @@ module.exports = function(AV) {
189189
},
190190

191191
/**
192-
* Returns a JSON version of the object suitable for saving to AV.
192+
* Returns a JSON version of the object.
193193
* @return {Object}
194194
*/
195-
toJSON: function() {
196-
var json = this._toFullJSON();
197-
AV._arrayEach(["__type", "className"],
198-
function(key) { delete json[key]; });
199-
return json;
195+
toJSON: function(key, holder, seenObjects = []) {
196+
return this._toFullJSON(seenObjects, false);
197+
},
198+
199+
/**
200+
* Returns a JSON version of the object with meta data.
201+
* Inverse to {@link AV.parseJSON}
202+
* @since 2.0.0
203+
* @return {Object}
204+
*/
205+
toFullJSON(seenObjects = []) {
206+
return this._toFullJSON(seenObjects);
200207
},
201208

202-
_toFullJSON: function(seenObjects) {
209+
_toFullJSON: function(seenObjects, full = true) {
203210
var json = _.clone(this.attributes);
211+
if (_.isArray(seenObjects)) {
212+
var newSeenObjects = seenObjects.concat(this);
213+
}
204214
AV._objectEach(json, function(val, key) {
205-
json[key] = AV._encode(val, seenObjects);
215+
json[key] = AV._encode(val, newSeenObjects, undefined, full);
206216
});
207217
AV._objectEach(this._operations, function(val, key) {
208218
json[key] = val;
@@ -217,8 +227,11 @@ module.exports = function(AV) {
217227
json[key] = _.isDate(val) ? val.toJSON() : val;
218228
}
219229
});
220-
json.__type = "Object";
221-
json.className = this.className;
230+
if (full) {
231+
json.__type = "Object";
232+
if (_.isArray(seenObjects) && seenObjects.length) json.__type = "Pointer";
233+
json.className = this.className;
234+
}
222235
return json;
223236
},
224237

src/op.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ module.exports = function(AV) {
1919
this._initialize.apply(this, arguments);
2020
};
2121

22-
AV.Op.prototype = {
22+
_.extend(AV.Op.prototype, /** @lends AV.Op.prototype */ {
2323
_initialize: function() {}
24-
};
24+
});
2525

2626
_.extend(AV.Op, {
2727
/**

src/query.js

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ module.exports = function(AV) {
166166

167167
AV.Query._extend = AV._extend;
168168

169-
AV.Query.prototype = {
169+
_.extend(AV.Query.prototype, /** @lends AV.Query.prototype */ {
170170
//hook to iterate result. Added by dennis<[email protected]>.
171171
_processResult: function(obj){
172172
return obj;
@@ -791,21 +791,21 @@ module.exports = function(AV) {
791791
return this;
792792
},
793793

794-
/**
795-
* Also sorts the results in ascending order by the given key. The previous sort keys have
796-
* precedence over this key.
797-
*
798-
* @param {String} key The key to order by
799-
* @return {AV.Query} Returns the query so you can chain this call.
800-
*/
801-
addAscending: function(key){
802-
requires(key, 'undefined is not a valid key');
803-
if(this._order)
804-
this._order += ',' + key;
805-
else
806-
this._order = key;
807-
return this;
808-
},
794+
/**
795+
* Also sorts the results in ascending order by the given key. The previous sort keys have
796+
* precedence over this key.
797+
*
798+
* @param {String} key The key to order by
799+
* @return {AV.Query} Returns the query so you can chain this call.
800+
*/
801+
addAscending: function(key){
802+
requires(key, 'undefined is not a valid key');
803+
if(this._order)
804+
this._order += ',' + key;
805+
else
806+
this._order = key;
807+
return this;
808+
},
809809

810810
/**
811811
* Sorts the results in descending order by the given key.
@@ -819,21 +819,21 @@ module.exports = function(AV) {
819819
return this;
820820
},
821821

822-
/**
823-
* Also sorts the results in descending order by the given key. The previous sort keys have
824-
* precedence over this key.
825-
*
826-
* @param {String} key The key to order by
827-
* @return {AV.Query} Returns the query so you can chain this call.
828-
*/
829-
addDescending: function(key){
830-
requires(key, 'undefined is not a valid key');
831-
if(this._order)
832-
this._order += ',-' + key;
833-
else
834-
this._order = '-' + key;
835-
return this;
836-
},
822+
/**
823+
* Also sorts the results in descending order by the given key. The previous sort keys have
824+
* precedence over this key.
825+
*
826+
* @param {String} key The key to order by
827+
* @return {AV.Query} Returns the query so you can chain this call.
828+
*/
829+
addDescending: function(key){
830+
requires(key, 'undefined is not a valid key');
831+
if(this._order)
832+
this._order += ',-' + key;
833+
else
834+
this._order = '-' + key;
835+
return this;
836+
},
837837

838838
/**
839839
* Add a proximity based constraint for finding objects with key point
@@ -996,7 +996,7 @@ module.exports = function(AV) {
996996
});
997997
});
998998
}
999-
};
999+
});
10001000

10011001
AV.FriendShipQuery = AV.Query._extend({
10021002
_objectClass: AV.User,

src/relation.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ module.exports = function(AV) {
3838
return query;
3939
};
4040

41-
AV.Relation.prototype = {
41+
_.extend(AV.Relation.prototype, /** @lends AV.Relation.prototype */ {
4242
/**
4343
* Makes sure that this relation has the right parent and key.
4444
* @private
@@ -111,5 +111,5 @@ module.exports = function(AV) {
111111

112112
return query;
113113
}
114-
};
114+
});
115115
};

src/search.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module.exports = function(AV) {
1717
this._sortFields = [];
1818
};
1919

20-
AV.SearchSortBuilder.prototype = {
20+
_.extend(AV.SearchSortBuilder.prototype, /** @lends AV.SearchSortBuilder.prototype */ {
2121
_addField: function(key, order, mode, missing) {
2222
var field = {};
2323
field[key] = {
@@ -92,7 +92,7 @@ module.exports = function(AV) {
9292
build: function() {
9393
return JSON.stringify(AV._encode(this._sortFields));
9494
}
95-
};
95+
});
9696

9797
/**
9898
* App searching query.Use just like AV.Query:

src/status.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module.exports = function(AV) {
2929
return this;
3030
};
3131

32-
AV.Status.prototype = {
32+
_.extend(AV.Status.prototype, /** @lends AV.Status.prototype */ {
3333
/**
3434
* Gets the value of an attribute in status data.
3535
* @param {String} attr The string name of an attribute.
@@ -127,7 +127,7 @@ module.exports = function(AV) {
127127
delete serverData.updatedAt;
128128
this.data = AV._decode(serverData);
129129
}
130-
};
130+
});
131131

132132
/**
133133
* Send a status to current signined user's followers.

0 commit comments

Comments
 (0)