Skip to content

Commit

Permalink
fix: Reading nested JSON throws TypeError issue #45
Browse files Browse the repository at this point in the history
  • Loading branch information
ivoleitao committed Apr 29, 2023
1 parent 69d348e commit e93ff90
Show file tree
Hide file tree
Showing 37 changed files with 733 additions and 510 deletions.
3 changes: 2 additions & 1 deletion packages/stash/lib/src/api/codec/bytes_reader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ abstract class BytesReader {
/// Reads a [Map] from the backing buffer
///
/// * [length]: The number of bytes
Map readMap(int length) {
Map readStandardMap(int length) {
final res = {};
while (length > 0) {
res[read()] = read();
Expand All @@ -146,5 +146,6 @@ abstract class BytesReader {
return res;
}

/// Reads the buffer contents
dynamic read();
}
31 changes: 31 additions & 0 deletions packages/stash/lib/src/api/store.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:typed_data';

import 'package:meta/meta.dart';

import '../msgpack/codec.dart';
Expand Down Expand Up @@ -118,6 +120,34 @@ abstract class PersistenceStore<I extends Info, E extends Entry<I>>
return _fromEncodables[name];
}

/// Encodes a value into a list of bytes
///
/// * [value]: The value to encode
///
/// Returns the value encoded as a list of bytes
@protected
Uint8List valueEncoder(dynamic value) {
final writer = codec.encoder();

writer.write(value);

return writer.takeBytes();
}

/// Returns a value decoded from the provided list of bytes
///
/// * [bytes]: The list of bytes
/// * [fromEncodable]: An function that converts between the Map representation and the object
///
/// Returns the decoded value from the list of bytes
@protected
dynamic valueDecoder(
Uint8List bytes, dynamic Function(Map<String, dynamic>)? fromEncodable) {
final reader = codec.decoder(bytes, fromEncodable: fromEncodable);

return reader.read();
}

/// Decodes a value
///
/// * [value]: The value to decode
Expand All @@ -126,6 +156,7 @@ abstract class PersistenceStore<I extends Info, E extends Entry<I>>
/// * [defaultFn]: A optional function that obtains the value to use in
/// case there is no `fromEncodable` function for the partition
@protected
@Deprecated('Use valueEncoder and valueDecoder')
dynamic decodeValue(
dynamic value, dynamic Function(Map<String, dynamic>)? fromEncodable,
{dynamic Function(dynamic)? mapFn, dynamic Function()? defaultFn}) {
Expand Down
66 changes: 37 additions & 29 deletions packages/stash/lib/src/msgpack/reader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import 'package:stash/src/api/codec/bytes_reader.dart';
import 'package:stash/src/msgpack/extension.dart';
import 'package:stash/src/msgpack/types.dart' as types;

/// The reader mode
enum MsgPackReaderMode {
/// Normal mode
standard,

/// Enforces Json compatible datatypes
json
}

/// Error thrown by MessagePack serialization if an object cannot be deserialized.
///
/// The [unsupportedType] field holds that object that failed to be deserialized.
Expand Down Expand Up @@ -41,7 +50,10 @@ class MsgPackUnsupportedTypeError extends Error {
/// dart package or similar. Note that what is deserialized is the [Map] representation of the object,
/// therefore this method should be provided in some form.
class MsgPackReader extends BytesReader {
// Implementation of the default decoder returns the Map<String, dynamic> without trying to convert it to a proper object
/// The reader mode
final MsgPackReaderMode mode;

/// Implementation of the default decoder returns the Map<String, dynamic> without trying to convert it to a proper object
static dynamic _defaultFromEncodable(Map<String, dynamic> encodable) =>
encodable;

Expand All @@ -57,16 +69,17 @@ class MsgPackReader extends BytesReader {
/// * [fromEncodable]: A custom function the converts the deserialized `Map<String, dynamic>` representation of the object into the object
/// * [extensions]: A optional list of extensions to use
MsgPackReader(Uint8List list,
{dynamic Function(Map<String, dynamic>)? fromEncodable,
{this.mode = MsgPackReaderMode.standard,
dynamic Function(Map<String, dynamic>)? fromEncodable,
List<MsgPackExtension>? extensions})
: _fromEncodable = fromEncodable ?? _defaultFromEncodable,
_extensions = [const DateTimeExtension(), ...?extensions],
super(list);

/// Reads the [String] key of the encodable [Map] representation of the object
/// Reads a [String]
///
/// Returns the key
String _readEncodableKey() {
/// Returns the string
String _readString() {
final u = readUInt8();

if ((u & 0xE0) == 0xA0) {
Expand All @@ -85,32 +98,15 @@ class MsgPackReader extends BytesReader {
/// * [length]: The length of the encodable representation
///
/// Returns the Map<String, dynamic> representation of the encoded object
Map<String, dynamic> _readEncodable(int length) {
Map<String, dynamic> readJsonMap(int length) {
final res = <String, dynamic>{};
while (length > 0) {
res[_readEncodableKey()] = read();
res[_readString()] = read();
length--;
}
return res;
}

/// Reads the encodable representation of the object
///
/// Returns the Map<String, dynamic> representation of the encoded object
Map<String, dynamic> readEncodable() {
final u = readUInt8();

if ((u & 0xF0) == 0x80) {
return _readEncodable(u & 0xF);
} else if (u == types.map16) {
return _readEncodable(readUInt16());
} else if (u == types.map32) {
return _readEncodable(readUInt32());
}

throw MsgPackUnsupportedTypeError(u);
}

/// Reads a extension object from the byte buffer
///
/// * [length]: The length of the extension object
Expand All @@ -121,8 +117,8 @@ class MsgPackReader extends BytesReader {
final bytes = readBuffer(length);

if (type == 0) {
var reader = MsgPackReader(bytes);
return _fromEncodable(reader.readEncodable());
var reader = MsgPackReader(bytes, mode: MsgPackReaderMode.json);
return _fromEncodable(reader.read());
}

for (var ext in _extensions) {
Expand All @@ -135,6 +131,18 @@ class MsgPackReader extends BytesReader {
return null;
}

/// Reads a [Map] from the backing buffer
///
/// * [length]: The number of bytes
dynamic _readMap(int length) {
switch (mode) {
case MsgPackReaderMode.json:
return readJsonMap(length);
default:
return readStandardMap(length);
}
}

@override
dynamic read() {
final u = readUInt8();
Expand All @@ -148,7 +156,7 @@ class MsgPackReader extends BytesReader {
} else if ((u & 0xF0) == 0x90) {
return readArray(u & 0xF);
} else if ((u & 0xF0) == 0x80) {
return readMap(u & 0xF);
return _readMap(u & 0xF);
}
switch (u) {
case types.nil:
Expand Down Expand Up @@ -210,9 +218,9 @@ class MsgPackReader extends BytesReader {
case types.array32:
return readArray(readUInt32());
case types.map16:
return readMap(readUInt16());
return _readMap(readUInt16());
case types.map32:
return readMap(readUInt32());
return _readMap(readUInt32());
default:
throw MsgPackUnsupportedTypeError(u);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/stash_cbl/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ dependencies:
# Flutter shared dependencies
path: ^1.8.3
# Other dependencies
cbl: ^2.1.6
cbl: ^2.1.8
stash: ^4.5.2
dev_dependencies:
# Flutter shared dependencies
test: ^1.21.4
# Other dependencies
lints: ^2.0.1
stash_test: ^4.5.2
cbl_dart: ^2.1.7
cbl_dart: ^2.1.9
2 changes: 1 addition & 1 deletion packages/stash_dio/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies:
equatable: ^2.0.5
http_parser: ^4.0.2
crypto: ^3.0.2
dio: ^5.0.3
dio: ^5.1.1
stash: ^4.5.2
dev_dependencies:
# Flutter shared dependencies
Expand Down
3 changes: 2 additions & 1 deletion packages/stash_file/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ dev_dependencies:
test: ^1.21.4
# Other dependencies
lints: ^2.0.1
stash_test: ^4.5.2
stash_test: ^4.5.2
build_runner: ^2.3.3
14 changes: 7 additions & 7 deletions packages/stash_hive/lib/src/hive/hive_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ abstract class HiveAdapter<T extends BoxBase<Map>> {

/// Returns the box value by key
///
/// * [box]: The Hive box
/// * [partition]: The Hive box
/// * [key]: The store key
///
/// Returns the [Map] stored in the box
Future<Map?> boxValue(T box, String key);
Future<Map?> partitionValue(T partition, String key);

/// Returns the partition box identified by [name]
///
/// * [name]: The partition name
T? box(String name) {
T? partition(String name) {
return _partitions[name];
}

Expand Down Expand Up @@ -119,8 +119,8 @@ class HiveDefaultAdapter extends HiveAdapter<Box<Map>> {
}

@override
Future<Map?> boxValue(Box<Map> box, String key) {
return Future.value(box.get(key));
Future<Map?> partitionValue(Box<Map> partition, String key) {
return Future.value(partition.get(key));
}
}

Expand Down Expand Up @@ -154,7 +154,7 @@ class HiveLazyAdapter extends HiveAdapter<LazyBox<Map>> {
}

@override
Future<Map?> boxValue(LazyBox<Map> box, String key) {
return box.get(key);
Future<Map?> partitionValue(LazyBox<Map> partition, String key) {
return partition.get(key);
}
}
Loading

0 comments on commit e93ff90

Please sign in to comment.