Skip to content

Commit

Permalink
2.0: Hot reload support
Browse files Browse the repository at this point in the history
  • Loading branch information
tp committed Nov 4, 2024
1 parent 110bdaa commit 3a0af15
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 66 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 2.0.0

* 🔥 Hot-reload: The connector interface has been adapted to allow for hot reload (in addition to hot restart)
* This means that instead of a configuration object instead, one now need to implement a class, such that updates to the implementation are accessible on hot reload (which was not possible with the configuration object, which was treated as "state" and thus not refreshed)
* While some patterns on top of the configuration objects (e.g. passing factories) could've allowed for hot-reload, requiring an implementation of the connector class ensures that it works all the time. This requires a one-time migration of all existing code though.
* Update method names
* Most notably `insert` is now `write` to transmit the ambivalence between "insert" and "update"
* `get` is now `read` to be symmetric to write (but instead of entities it takes keys, of course)
Expand Down
37 changes: 25 additions & 12 deletions example/lib/src/stores/todo_connector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,37 @@ import 'package:indexed_entity_store_example/src/stores/entities/todo.dart';

typedef TodoStore = IndexedEntityStore<Todo, int>;

final todoConnector =
IndexedEntityConnector<Todo, int /* key type */, String /* DB type */ >(
entityKey: 'todo',
getPrimaryKey: (t) => t.id,
getIndices: (index) {
class TodoConnector extends IndexedEntityConnector<Todo, int /* key type */,
String /* DB type */ > {
@override
final entityKey = 'todo';

@override
getIndices(index) {
index((t) => t.done, as: 'done');
},
serialize: (t) => jsonEncode(t.toJSON()),
deserialize: (s) => Todo.fromJSON(
jsonDecode(s) as Map<String, dynamic>,
),
);
}

@override
getPrimaryKey(e) {
return e.id;
}

@override
serialize(e) {
return jsonEncode(e.toJSON());
}

@override
deserialize(s) {
return Todo.fromJSON(jsonDecode(s) as Map<String, dynamic>);
}
}

/// Creates a new Todo store, backed by a new, temporary database
///
/// In practice a single database would likely be reused with many stores,
/// and more importantly the same instance would be used instead of a new one created
/// each time as done here for the showcase.
TodoStore getTodoStore() {
return getNewDatabase().entityStore(todoConnector);
return getNewDatabase().entityStore(TodoConnector());
}
53 changes: 1 addition & 52 deletions lib/src/indexed_entity_connector.dart
Original file line number Diff line number Diff line change
@@ -1,65 +1,14 @@
import 'package:indexed_entity_store/indexed_entity_store.dart';

abstract class IndexedEntityConnector<T /* entity */, K /* primary key */,
S /* storage format */ > {
factory IndexedEntityConnector({
required String entityKey,
required K Function(T) getPrimaryKey,
required void Function(IndexCollector<T> index) getIndices,
required S Function(T) serialize,
required T Function(S) deserialize,
}) {
return _IndexedEntityConnector(
entityKey,
getPrimaryKey,
getIndices,
serialize,
deserialize,
);
}

S /* storage format, string or bytes */ > {
String get entityKey;

K getPrimaryKey(T e);

void getIndices(IndexCollector<T> index);

/// String or bytes
S serialize(T e);

T deserialize(S s);
}

class _IndexedEntityConnector<T, K, S>
implements IndexedEntityConnector<T, K, S> {
_IndexedEntityConnector(
this.entityKey,
this._getPrimaryKey,
this._getIndices,
this._serialize,
this._deserialize,
);

@override
final String entityKey;

final K Function(T) _getPrimaryKey;

final void Function(IndexCollector<T> index) _getIndices;

final S Function(T) _serialize;

final T Function(S) _deserialize;

@override
K getPrimaryKey(T e) => _getPrimaryKey(e);

@override
S serialize(T e) => _serialize(e);

@override
T deserialize(S s) => _deserialize(s);

@override
void getIndices(IndexCollector<T> index) => _getIndices(index);
}
14 changes: 12 additions & 2 deletions lib/src/indexed_entity_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,25 @@ class IndexedEntityDabase {
return IndexedEntityDabase._(path);
}

final _stores = <String, IndexedEntityStore>{};

IndexedEntityStore<T, K> entityStore<T, K, S>(
IndexedEntityConnector<T, K, S> connector,
) {
// TODO(tp): Throw if another connected for `type` is already connect (taking reloads into account)
if (_stores.containsKey(connector.entityKey)) {
throw Exception(
'A store for "${connector.entityKey}" has already been created',
);
}

return IndexedEntityStore<T, K>(
final store = IndexedEntityStore<T, K>(
_database,
connector,
);

_stores[connector.entityKey] = store;

return store;
}

dispose() {
Expand Down

0 comments on commit 3a0af15

Please sign in to comment.