11part of flutter_parse_sdk;
22
33abstract class ParseBase {
4- String className ;
4+ String parseClassName ;
55 Type type;
6-
7- String setClassName (String className) => this .className = className;
8-
9- String getClassName () => className;
6+ bool _dirty = false ; // reserved property
7+ final Map <String , dynamic > _unsavedChanges = Map <String , dynamic >();
8+ final Map <String , dynamic > _savingChanges = Map <String , dynamic >();
109
1110 /// Stores all the values of a class
1211 Map <String , dynamic > _objectData = Map <String , dynamic >();
@@ -16,6 +15,40 @@ abstract class ParseBase {
1615
1716 set objectId (String objectId) => set <String >(keyVarObjectId, objectId);
1817
18+ bool isDirty ({String key}) {
19+ if (key != null ) {
20+ return _unsavedChanges[key] != null ;
21+ }
22+ return _isDirty (true );
23+ }
24+
25+ bool _isDirty (bool considerChildren) {
26+ if (_dirty || _unsavedChanges.isNotEmpty) {
27+ return true ;
28+ }
29+
30+ if (considerChildren) {
31+ return _areChildrenDirty (Set <dynamic >());
32+ }
33+ return false ;
34+ }
35+
36+ bool _areChildrenDirty (Set <dynamic > seenObjects) {
37+ if (seenObjects.contains (this )) {
38+ return false ;
39+ }
40+ seenObjects.add (this );
41+ if (_dirty || _unsavedChanges.isNotEmpty) {
42+ return true ;
43+ }
44+ _getObjectData ().forEach ((String key, dynamic value) {
45+ if (value is ParseObject && value._areChildrenDirty (seenObjects)) {
46+ return true ;
47+ }
48+ });
49+ return false ;
50+ }
51+
1952 /// Returns [DateTime] createdAt
2053 DateTime get createdAt {
2154 if (get <dynamic >(keyVarCreatedAt) is String ) {
@@ -40,7 +73,7 @@ abstract class ParseBase {
4073 @protected
4174 Map <String , dynamic > toJson ({bool full, bool forApiRQ = false }) {
4275 final Map <String , dynamic > map = < String , dynamic > {
43- keyVarClassName: className ,
76+ keyVarClassName: parseClassName ,
4477 };
4578
4679 if (objectId != null ) {
@@ -55,7 +88,8 @@ abstract class ParseBase {
5588 map[keyVarUpdatedAt] = _parseDateFormat.format (updatedAt);
5689 }
5790
58- getObjectData ().forEach ((String key, dynamic value) {
91+ final Map <String , dynamic > target = forApiRQ ? _unsavedChanges : _getObjectData ();
92+ target.forEach ((String key, dynamic value) {
5993 if (! map.containsKey (key)) {
6094 map[key] = parseEncode (value, full: full);
6195 }
@@ -81,7 +115,7 @@ abstract class ParseBase {
81115 }
82116
83117 objectData.forEach ((String key, dynamic value) {
84- if (key == className || key == '__type' ) {
118+ if (key == parseClassName || key == '__type' ) {
85119 // NO OP
86120 } else if (key == keyVarObjectId) {
87121 objectId = value;
@@ -98,9 +132,9 @@ abstract class ParseBase {
98132 set <DateTime >(keyVarUpdatedAt, value);
99133 }
100134 } else if (key == keyVarAcl) {
101- getObjectData () [keyVarAcl] = ParseACL ().fromJson (value);
135+ this [keyVarAcl] = ParseACL ().fromJson (value);
102136 } else {
103- getObjectData () [key] = parseDecode (value);
137+ this [key] = parseDecode (value);
104138 }
105139 });
106140
@@ -113,17 +147,32 @@ abstract class ParseBase {
113147
114148 /// Sets all the objects variables
115149 @protected
116- void setObjectData (Map <String , dynamic > objectData) =>
150+ void _setObjectData (Map <String , dynamic > objectData) =>
117151 _objectData = objectData;
118152
119153 /// Returns the objects variables
120154 @protected
121- Map <String , dynamic > getObjectData () => _objectData ?? Map <String , dynamic >();
155+ Map <String , dynamic > _getObjectData () => _objectData ?? Map <String , dynamic >();
156+
157+ bool containsValue (Object value) {
158+ return _getObjectData ().containsValue (value);
159+ }
122160
161+ bool containsKey (Object key) {
162+ return _getObjectData ().containsKey (key);
163+ }
164+
165+ dynamic operator [](Object key) {
166+ get <dynamic >(key);
167+ }
168+
169+ void operator []= (String key, dynamic value) {
170+ set <dynamic >(key, value);
171+ }
123172 /// Saves in storage
124173 Future <void > saveInStorage (String key) async {
125174 final String objectJson = json.encode (toJson (full: true ));
126- await ParseCoreData ().getStore ()
175+ ParseCoreData ().getStore ()
127176 ..setString (key, objectJson);
128177 }
129178
@@ -134,25 +183,29 @@ abstract class ParseBase {
134183 /// needed or not, set to false
135184 void set <T >(String key, T value, {bool forceUpdate = true }) {
136185 if (value != null ) {
137- if (getObjectData ().containsKey (key)) {
186+ if (_getObjectData ().containsKey (key)) {
187+ if (_getObjectData ()[key] == value) {
188+ return ;
189+ }
138190 if (forceUpdate) {
139- getObjectData ()[key] = value;
191+ _getObjectData ()[key] = value;
140192 }
141193 } else {
142- getObjectData ()[key] = value;
194+ _getObjectData ()[key] = value;
143195 }
196+ _unsavedChanges[key] = value;
144197 }
145198 }
146199
147200 ///Set the [ParseACL] governing this object.
148201 void setACL <ParseACL >(ParseACL acl) {
149- getObjectData ()[keyVarAcl] = acl;
202+ _getObjectData ()[keyVarAcl] = acl;
150203 }
151204
152205 ///Access the [ParseACL] governing this object.
153206 ParseACL getACL () {
154- if (getObjectData ().containsKey (keyVarAcl)) {
155- return getObjectData ()[keyVarAcl];
207+ if (_getObjectData ().containsKey (keyVarAcl)) {
208+ return _getObjectData ()[keyVarAcl];
156209 } else {
157210 return ParseACL ();
158211 }
@@ -164,12 +217,12 @@ abstract class ParseBase {
164217 /// getType<int> and an int will be returned, null, or a defaultValue if
165218 /// provided
166219 dynamic get <T >(String key, {T defaultValue}) {
167- if (getObjectData ().containsKey (key)) {
168- if (T != null && getObjectData ()[key] is T ) {
169- final T data = getObjectData ()[key];
220+ if (_getObjectData ().containsKey (key)) {
221+ if (T != null && _getObjectData ()[key] is T ) {
222+ final T data = _getObjectData ()[key];
170223 return data;
171224 } else {
172- return getObjectData ()[key];
225+ return _getObjectData ()[key];
173226 }
174227 } else {
175228 return defaultValue;
@@ -184,7 +237,7 @@ abstract class ParseBase {
184237 await unpin ();
185238 final Map <String , dynamic > objectMap = parseEncode (this , full: true );
186239 final String json = jsonEncode (objectMap);
187- await ParseCoreData ().getStore ()
240+ ParseCoreData ().getStore ()
188241 ..setString (objectId, json);
189242 return true ;
190243 } else {
@@ -197,7 +250,7 @@ abstract class ParseBase {
197250 /// Replicates Android SDK pin process and saves object to storage
198251 Future <bool > unpin ({String key}) async {
199252 if (objectId != null ) {
200- await ParseCoreData ().getStore ()
253+ ParseCoreData ().getStore ()
201254 ..remove (key ?? objectId);
202255 return true ;
203256 }
@@ -210,7 +263,7 @@ abstract class ParseBase {
210263 /// Replicates Android SDK pin process and saves object to storage
211264 dynamic fromPin (String objectId) async {
212265 if (objectId != null ) {
213- final CoreStore coreStore = await ParseCoreData ().getStore ();
266+ final CoreStore coreStore = ParseCoreData ().getStore ();
214267 final String itemFromStore = await coreStore.getString (objectId);
215268
216269 if (itemFromStore != null ) {
@@ -220,5 +273,19 @@ abstract class ParseBase {
220273 return null ;
221274 }
222275
223- Map <String , dynamic > toPointer () => encodeObject (className, objectId);
276+ Map <String , dynamic > toPointer () => encodeObject (parseClassName, objectId);
277+
278+ /// Deprecated
279+ @Deprecated ('Prefer to use parseClassName' )
280+ String className;
281+ @Deprecated ('Prefer to use parseClassName' )
282+ String getClassName () => parseClassName;
283+ @Deprecated ('Prefer to use parseClassName' )
284+ String setClassName (String className) => parseClassName = className;
285+ @protected @Deprecated ('Prefer to use _getObjectData method, or operator [] for certain key.' )
286+ Map <String , dynamic > getObjectData () => _getObjectData ();
287+
288+ @protected @Deprecated ('Prefer to use _setObjectData method, or operator [] for certain key.' )
289+ void setObjectData (Map <String , dynamic > objectData) =>
290+ _setObjectData (objectData);
224291}
0 commit comments