Skip to content

Commit f1f9ceb

Browse files
committed
Fix for issue #5 / Parse deserialization of nested objects
1 parent 88e16e3 commit f1f9ceb

File tree

1 file changed

+96
-3
lines changed

1 file changed

+96
-3
lines changed

src/parseExtend.js

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import _ from 'underscore';
66
import extend from 'backbone-es6/src/extend.js';
77
import modelExtend from './modelExtend.js';
88

9+
import Utils from 'typhonjs-core-utils/src/Utils.js';
10+
911
// Add HTTPS image fetch substitution to Parse.Object ---------------------------------------------------------------
1012

1113
/**
@@ -20,8 +22,7 @@ Parse.Object.prototype.getHTTPSUrl = function(key)
2022

2123
if (!_.isUndefined(urlRequest) && urlRequest !== null && !_.isUndefined(urlRequest.url))
2224
{
23-
return urlRequest.url().replace('http://files.parsetfss.com/',
24-
'https://s3.amazonaws.com/files.parsetfss.com/');
25+
return urlRequest.url().replace('http://files.parsetfss.com/', 'https://s3.amazonaws.com/files.parsetfss.com/');
2526
}
2627
};
2728

@@ -56,4 +57,96 @@ export default function parseExtend(Backbone)
5657
'https://s3.amazonaws.com/files.parsetfss.com/');
5758
}
5859
};
59-
}
60+
// Various fixes for Backbone / Parse integration -------------------------------------------------------------------
61+
62+
s_FIX_ISSUE5_DESERIALIZATION(Backbone);
63+
}
64+
65+
/**
66+
* Stores subclass information registered with Parse.Object.
67+
* @type {{}}
68+
*/
69+
const s_PARSE_OBJECT_CLASS_MAP = {};
70+
71+
/**
72+
* Fixes backbone-parse-es6 issue #5 - https://github.com/typhonjs-backbone-parse/backbone-parse-es6/issues/5
73+
*
74+
* It's necessary to override Parse.Object.fromJSON to support proper deserialization.
75+
*
76+
* It should be noted that ParseModel now supports a `subClasses` getter which defines an object hash of an associated
77+
* className with the constructor / class to associate. By adding this to your ParseModel / Backbone.Model classes
78+
* this will automatically register them with `Parse.Object.registerSubclass`.
79+
*
80+
* For a test suite please see:
81+
* https://github.com/typhonjs-demos-test/typhonjs-issues-demos/tree/master/repos/backbone-parse-es6/src/issue5
82+
*
83+
* @param {object} Backbone - Backbone instance
84+
*/
85+
const s_FIX_ISSUE5_DESERIALIZATION = (Backbone) =>
86+
{
87+
/**
88+
* Override `getSubclass` as it is referenced in `fromJSON`.
89+
*
90+
* @param {string} className - Parse.Object className / table ID.
91+
*
92+
* @returns {*}
93+
*/
94+
Parse.Object.getSubclass = (className) =>
95+
{
96+
if (typeof className !== 'string') { throw new TypeError('The first argument must be a valid class name.'); }
97+
98+
return s_PARSE_OBJECT_CLASS_MAP[className];
99+
};
100+
101+
/**
102+
* Override `registerSubclass` as it needs to use `s_PARSE_OBJECT_CLASS_MAP` above.
103+
*
104+
* @param {string} className - Parse.Object className / table ID.
105+
* @param {function} constructor - Class / constructor to register as a subclass.
106+
*/
107+
Parse.Object.registerSubclass = (className, constructor) =>
108+
{
109+
if (typeof className !== 'string') { throw new TypeError('The first argument must be a valid class name.'); }
110+
111+
if (typeof constructor === 'undefined') { throw new TypeError('You must supply a subclass constructor.'); }
112+
113+
if (typeof constructor !== 'function')
114+
{
115+
throw new TypeError(
116+
'You must register the subclass constructor. Did you attempt to register an instance of the subclass?');
117+
}
118+
119+
s_PARSE_OBJECT_CLASS_MAP[className] = constructor;
120+
121+
if (!constructor.className) { constructor.className = className; }
122+
};
123+
124+
/**
125+
* Override `fromJSON` to check constructor. If it is a type of `Backbone.Model` then construct it as a `ParseModel`
126+
* passing in the associated `Parse.Object` otherwise just return the `Parse.Object`.
127+
*
128+
* @param {object} json - JSON object
129+
*
130+
* @returns {*}
131+
*/
132+
Parse.Object.fromJSON = (json) =>
133+
{
134+
if (!json.className) { throw new Error('Cannot create an object without a className'); }
135+
136+
const constructor = Parse.Object.getSubclass(json.className);
137+
const parseObject = new Parse.Object(json.className);
138+
const otherAttributes = {};
139+
140+
for (const attr in json)
141+
{
142+
if (attr !== 'className' && attr !== '__type') { otherAttributes[attr] = json[attr]; }
143+
}
144+
145+
parseObject._finishFetch(otherAttributes);
146+
147+
if (json.objectId) { parseObject._setExisted(true); }
148+
149+
return constructor && Utils.isTypeOf(constructor, Backbone.Model) ? new constructor({}, { parseObject }) :
150+
parseObject;
151+
};
152+
};

0 commit comments

Comments
 (0)