tekartik / sembast.dart

Simple io database
BSD 2-Clause "Simplified" License
780 stars 64 forks source link

ImmutableList seems to produce problems with nested Lists #244

Closed ChristianKleineidam closed 3 years ago

ChristianKleineidam commented 3 years ago

If I put a List<List<List>> object into sembast_db the object that I can read from sembast db can't be cast to List<List<List>>. This is very confusing.

This problem seems to exist because sembast wraps lists with ImmutableList with does not subclass List directly. Given that ImmutableList currently looks like it's just a wrapper for list, I seems questionable to me what value gets provided by returning list objects in that format to the user. The ImmutableList wrapper is more likely to cost performance then increase performance.

If sembast continues to give out ImmutableList, that class should at least have a function that gives me a List<List<List>> if that's what I put into the database. Such a function might be called .toList().

ChristianKleineidam commented 3 years ago

It's also worth noting that ImmutableList makes it impossible to mock Sembast for unittests at the moment because it outputs with ImmutableList a class where the constructor is not exposed outside of the plugin.

alextekartik commented 3 years ago

This issue is not sembast specific. Every list (even a list of string) will be read as a List<Object?> since the content is simply json encoded in the storage.

You can try the following:

  var listOfListOfList = <List<List>>[];
  expect(listOfListOfList, const TypeMatcher<List<List<List>>>());
  var newList = jsonDecode(jsonEncode(listOfListOfList));
  expect(newList, const TypeMatcher<List>());
  // Not anymore
  expect(newList, isNot(const TypeMatcher<List<List<List>>>()));
alextekartik commented 3 years ago

Whether you're using sembast on Flutter or on the web you can easily mock sembast in memory for unit test.

import 'package:sembast/sembast.dart';
import 'package:sembast/sembast_memory.dart';
import 'package:test/test.dart';

void main() {
  test('my_unit_test', () async {
    // In memory factory for unit test
    var factory = newDatabaseFactoryMemory();

    // Define the store
    var store = StoreRef<String, String>.main();
    // Define the record
    var record = store.record('my_key');

    // Open the database
    var db = await factory.openDatabase('test.db');

    // Write a record
    await record.put(db, 'my_value');

    // Verify record content.
    expect(await record.get(db), 'my_value');

    // Close the database
    await db.close();
  });
}