Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/internal/codec/lc_decoder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,8 @@ class _LCDecoder {
});
return acl;
}

static _LCOperation decodeOperation(dynamic data) {
return _LCOperation.decode(data);
}
}
15 changes: 12 additions & 3 deletions lib/internal/codec/lc_encoder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,18 @@ class _LCEncoder {
if (object.updatedAt != null) {
data['updatedAt'] = object.updatedAt.toString();
}
object._estimatedData.forEach((k, v) {
data[k] = _LCEncoder.encode(v, full: full);
});
if (object._data.customPropertyMap.length > 0) {
object._data.customPropertyMap.forEach((k, v) {
data[k] = _LCEncoder.encode(v, full: full);
});
}
if (object._operationMap.length > 0) {
Map opMap = new Map();
object._operationMap.forEach((k, v) {
opMap[k] = encodeOperation(v);
});
data['__operationMap'] = opMap;
}
}
return data;
}
Expand Down
9 changes: 9 additions & 0 deletions lib/internal/object/lc_object_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class _LCObjectData {

late Map<String, dynamic> customPropertyMap;

Map<String, _LCOperation>? operationMap;

_LCObjectData() {
customPropertyMap = new Map<String, dynamic>();
}
Expand All @@ -30,6 +32,13 @@ class _LCObjectData {
} else {
if (key == 'ACL' && value is Map) {
result.customPropertyMap[key] = _LCDecoder.decodeACL(value);
} else if (key == '__operationMap' && value is Map) {
// 操作记录
Map<String, _LCOperation> opMap = new Map();
value.forEach((k, v) {
opMap[k] = _LCDecoder.decodeOperation(v);
});
result.operationMap = opMap;
} else {
// 自定义属性
result.customPropertyMap[key] = _LCDecoder.decode(value);
Expand Down
4 changes: 3 additions & 1 deletion lib/internal/operation/lc_add_operation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
part of leancloud_storage;

class _LCAddOperation extends _LCOperation {
static const String OP = 'Add';

late List valueList;

_LCAddOperation(Iterable values) {
Expand All @@ -16,7 +18,7 @@ class _LCAddOperation extends _LCOperation {

@override
encode() {
return {'__op': 'Add', 'objects': _LCEncoder.encodeList(valueList)};
return {'__op': OP, 'objects': _LCEncoder.encodeList(valueList)};
}

@override
Expand Down
4 changes: 3 additions & 1 deletion lib/internal/operation/lc_add_relation_operation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
part of leancloud_storage;

class _LCAddRelationOperation extends _LCOperation {
static const String OP = 'AddRelation';

late List<LCObject> valueList;

_LCAddRelationOperation(dynamic value) {
Expand All @@ -16,7 +18,7 @@ class _LCAddRelationOperation extends _LCOperation {

@override
encode() {
return {'__op': 'AddRelation', 'objects': _LCEncoder.encodeList(valueList)};
return {'__op': OP, 'objects': _LCEncoder.encodeList(valueList)};
}

@override
Expand Down
7 changes: 3 additions & 4 deletions lib/internal/operation/lc_add_unique_operation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
part of leancloud_storage;

class _LCAddUniqueOperation extends _LCOperation {
static const String OP = 'AddUnique';

late Set values;

_LCAddUniqueOperation(Iterable values) {
Expand All @@ -16,10 +18,7 @@ class _LCAddUniqueOperation extends _LCOperation {

@override
encode() {
return {
'__op': 'AddUnique',
'objects': _LCEncoder.encodeList(values.toList())
};
return {'__op': OP, 'objects': _LCEncoder.encodeList(values.toList())};
}

@override
Expand Down
4 changes: 3 additions & 1 deletion lib/internal/operation/lc_decrement_operation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
part of leancloud_storage;

class _LCDecrementOperation extends _LCOperation {
static const String OP = 'Decrement';

num value;

_LCDecrementOperation(this.value);
Expand All @@ -15,7 +17,7 @@ class _LCDecrementOperation extends _LCOperation {

@override
encode() {
return {'__op': 'Decrement', 'amount': value};
return {'__op': OP, 'amount': value};
}

@override
Expand Down
4 changes: 3 additions & 1 deletion lib/internal/operation/lc_delete_operation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ part of leancloud_storage;

/// Deletion
class _LCDeleteOperation extends _LCOperation {
static const String OP = 'Delete';

@override
_LCOperation mergeWithPrevious(_LCOperation previousOp) {
return this;
}

@override
encode() {
return {'__op': 'Delete'};
return {'__op': OP};
}

@override
Expand Down
4 changes: 3 additions & 1 deletion lib/internal/operation/lc_increment_operation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
part of leancloud_storage;

class _LCIncrementOperation extends _LCOperation {
static const String OP = 'Increment';

num value;

_LCIncrementOperation(this.value);
Expand All @@ -15,7 +17,7 @@ class _LCIncrementOperation extends _LCOperation {

@override
encode() {
return {'__op': 'Increment', 'amount': value};
return {'__op': OP, 'amount': value};
}

@override
Expand Down
28 changes: 28 additions & 0 deletions lib/internal/operation/lc_operation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,32 @@ abstract class _LCOperation {

// 得到增加的对象
List? getNewObjectList();

static _LCOperation decode(dynamic data) {
if (!(data is Map) || !data.containsKey('__op')) {
// set
return new _LCSetOperation(_LCDecoder.decode(data));
}
String op = data['__op'];
switch (op) {
case _LCAddOperation.OP:
return new _LCAddOperation(_LCDecoder.decode(data['objects']));
case _LCAddRelationOperation.OP:
return new _LCAddRelationOperation(_LCDecoder.decode(data['objects']));
case _LCAddUniqueOperation.OP:
return new _LCAddUniqueOperation(_LCDecoder.decode(data['objects']));
case _LCDecrementOperation.OP:
return new _LCDecrementOperation(data['amount']);
case _LCDeleteOperation.OP:
return new _LCDeleteOperation();
case _LCIncrementOperation.OP:
return new _LCIncrementOperation(data['amount']);
case _LCRemoveOperation.OP:
return new _LCRemoveOperation(_LCDecoder.decode(data['objects']));
case _LCRemoveRelationOperation.OP:
return new _LCRemoveRelationOperation(data['objects']);
default:
throw ('Error operation: ${jsonEncode(data)}');
}
}
}
4 changes: 3 additions & 1 deletion lib/internal/operation/lc_remove_operation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
part of leancloud_storage;

class _LCRemoveOperation extends _LCOperation {
static const String OP = 'Remove';

late List valueList;

_LCRemoveOperation(Iterable values) {
Expand All @@ -18,7 +20,7 @@ class _LCRemoveOperation extends _LCOperation {

@override
encode() {
return {'__op': 'Remove', 'objects': _LCEncoder.encodeList(valueList)};
return {'__op': OP, 'objects': _LCEncoder.encodeList(valueList)};
}

@override
Expand Down
7 changes: 3 additions & 4 deletions lib/internal/operation/lc_remove_relation_operation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
part of leancloud_storage;

class _LCRemoveRelationOperation extends _LCOperation {
static const String OP = 'RemoveRelation';

late List<LCObject> valueList;

_LCRemoveRelationOperation(dynamic value) {
Expand All @@ -16,10 +18,7 @@ class _LCRemoveRelationOperation extends _LCOperation {

@override
encode() {
return {
'__op': 'RemoveRelation',
'objects': _LCEncoder.encodeList(valueList.toList())
};
return {'__op': OP, 'objects': _LCEncoder.encodeList(valueList.toList())};
}

@override
Expand Down
22 changes: 17 additions & 5 deletions lib/lc_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -247,21 +247,33 @@ class LCObject {
if (data == null) {
return;
}

_data.className = data.className ?? _data.className;
_data.objectId = data.objectId ?? _data.objectId;
_data.createdAt = data.createdAt ?? _data.createdAt;
_data.updatedAt = data.updatedAt ?? _data.updatedAt;

// 先将本地的预估数据直接替换
_data.customPropertyMap = _estimatedData;

// 再将服务端的数据覆盖
data.customPropertyMap.forEach((String key, dynamic value) {
_data.customPropertyMap[key] = value;
});
// 最后重新生成预估数据,用于后续访问和操作
_rebuildEstimatedData();
// 清空操作
_operationMap.clear();
_isDirty = false;

// 最后根据 data 情况确定如何合并
if (data.operationMap != null && data.operationMap!.length > 0) {
// 如果有保存操作
data.operationMap!.forEach((k, v) {
_applyOperation(k, v);
});
} else {
// 清空操作
_operationMap.clear();
// 最后重新生成预估数据,用于后续访问和操作
_rebuildEstimatedData();
_isDirty = false;
}
}

/// Fetches the object from the cloud.
Expand Down
14 changes: 10 additions & 4 deletions test/object_test.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import 'package:flutter_test/flutter_test.dart';

import 'package:leancloud_storage/leancloud.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'utils.dart';

void main() {
SharedPreferences.setMockInitialValues({});

group('object', () {
setUp(() => initNorthChina());

Expand Down Expand Up @@ -162,11 +165,11 @@ void main() {

test('serialization', () async {
LCObject object = new LCObject('Hello');
object['intValue'] = 123;
object.increment('intValue', 12);
object['boolValue'] = true;
object['stringValue'] = 'hello, world';
object['time'] = DateTime.now();
object['intList'] = [1, 1, 2, 3, 5, 8];
object.addAll('intList', [1, 1, 2, 3, 5, 8]);
object['stringMap'] = {'k1': 111, 'k2': true, 'k3': 'haha'};
LCObject nestedObj = new LCObject('World');
nestedObj['content'] = '7788';
Expand All @@ -175,16 +178,19 @@ void main() {
World world = new World();
world.content = 'hello, world';
object['pointerList'] = [world, new LCObject('World')];
await object.save();
//

String json = object.toString();
LCLogger.debug(json);
LCObject newObj = LCObject.parseObject(json);

newObj = await object.save();

assert(newObj.objectId != null);
assert(newObj.className != null);
assert(newObj.createdAt != null);
assert(newObj.updatedAt != null);
assert(newObj['intValue'] == 123);
assert(newObj['intValue'] == 12);
assert(newObj['boolValue'] == true);
assert(newObj['stringValue'] == 'hello, world');
assert(newObj['objectValue']['content'] == '7788');
Expand Down