Skip to content

Commit

Permalink
Finished initial uber-basic implementation of ObjectBoxBackend
Browse files Browse the repository at this point in the history
Changed exporting/visibility to avoid exporting internals
  • Loading branch information
JaffaKetchup committed Nov 4, 2023
1 parent 4ee03e7 commit 7d15976
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 93 deletions.
2 changes: 2 additions & 0 deletions lib/flutter_map_tile_caching.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:stream_transform/stream_transform.dart';
import 'package:watcher/watcher.dart';

import 'src/backend/export_std.dart';
import 'src/bulk_download/instance.dart';
import 'src/bulk_download/rate_limited_stream.dart';
import 'src/bulk_download/tile_loops/shared.dart';
Expand All @@ -51,6 +52,7 @@ import 'src/misc/obscure_query_params.dart';
import 'src/misc/typedefs.dart';
import 'src/providers/image_provider.dart';

export 'src/backend/export_std.dart';
export 'src/errors/browsing.dart';
export 'src/errors/damaged_store.dart';
export 'src/errors/initialisation.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/fmtc_module_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
/// **Do not use in normal applications. I may be unable to offer support.**
library fmtc_module_api;

export 'src/backend/export_plus.dart';
export 'src/db/defs/metadata.dart';
export 'src/db/defs/store_descriptor.dart';
export 'src/db/defs/tile.dart';
Expand Down
2 changes: 2 additions & 0 deletions lib/src/backend/export_plus.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'export_std.dart';
export 'interfaces/models.dart';
3 changes: 3 additions & 0 deletions lib/src/backend/export_std.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export 'errors.dart';
export 'impls/objectbox/backend.dart';
export 'interfaces/backend.dart';
160 changes: 100 additions & 60 deletions lib/src/backend/impls/objectbox/backend.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:path_provider/path_provider.dart';

import '../../../misc/exts.dart';
Expand All @@ -12,35 +12,31 @@ import 'models/generated/objectbox.g.dart';
import 'models/models.dart';

/// Implementation of [FMTCBackend] that uses ObjectBox as the storage database
///
/// Only the factory constructor ([ObjectBoxBackend.new]), and
/// [friendlyIdentifier], should be used in end-applications. Other methods are
/// for internal use only.
class ObjectBoxBackend implements FMTCBackend {
abstract interface class ObjectBoxBackend implements FMTCBackend {
/// Implementation of [FMTCBackend] that uses ObjectBox as the storage
/// database
factory ObjectBoxBackend() => _instance;
static final ObjectBoxBackend _instance = ObjectBoxBackend._();
ObjectBoxBackend._();
static final _instance = _ObjectBoxBackendImpl._();
}

class _ObjectBoxBackendImpl implements ObjectBoxBackend {
_ObjectBoxBackendImpl._();

Store? _root; // Must not be closed if not `null`
Store get _expectRoot => _root ?? (throw RootUnavailable());
Store? root; // Must not be closed if not `null`
Store get expectRoot => root ?? (throw RootUnavailable());

Future<ObjectBoxStore> _getStore(String name) async =>
(await _expectRoot
Future<ObjectBoxStore> getStore(String name) async =>
(await expectRoot
.box<ObjectBoxStore>()
.query(ObjectBoxStore_.name.equals(name))
.build()
.findFirstAsync()) ??
.findUniqueAsync()) ??
(throw StoreUnavailable(storeName: name));

@override
String get friendlyIdentifier => 'ObjectBox';

@override
@internal
bool get supportsSharing => false;

@override
@internal
Future<void> initialise({
String? rootDirectory,
}) async {
Expand All @@ -49,50 +45,49 @@ class ObjectBoxBackend implements FMTCBackend {
: Directory(rootDirectory)) >>
'fmtc')
.create(recursive: true);
_root = await openStore(directory: dir.absolute.path);
root = await openStore(directory: dir.absolute.path);
}

@override
@internal
Future<void> destroy({
bool deleteRoot = false,
}) async {
_expectRoot;
expectRoot;

await Directory((_root!..close()).directoryPath).delete(recursive: true);
_root = null;
await Directory((root!..close()).directoryPath).delete(recursive: true);
root = null;
}

@override
@internal
Future<void> createStore({
required String storeName,
}) async {
await _expectRoot
await expectRoot
.box<ObjectBoxStore>()
.putAsync(ObjectBoxStore(name: storeName), mode: PutMode.insert);
}

@override
@internal
Future<void> resetStore({
required String storeName,
}) async {
_expectRoot;
expectRoot;

await _root!.runInTransactionAsync(
await root!.runInTransactionAsync(
TxMode.write,
(store, storeName) {
final tiles = _root!.box<ObjectBoxTile>();
final tiles = root!.box<ObjectBoxTile>();

final removeIds = <int>[];

final tilesBelongingToStore = (tiles.query()
..linkMany(ObjectBoxTile_.stores,
ObjectBoxStore_.name.equals(storeName)))
final query = (tiles.query()
..linkMany(
ObjectBoxTile_.stores,
ObjectBoxStore_.name.equals(storeName),
))
.build();
tiles.putMany(
tilesBelongingToStore
query
.find()
.map((tile) {
tile.stores.removeWhere((store) => store.name == storeName);
Expand All @@ -104,7 +99,7 @@ class ObjectBoxBackend implements FMTCBackend {
.toList(),
mode: PutMode.update,
);
tilesBelongingToStore.close();
query.close();

tiles.query(ObjectBoxTile_.id.oneOf(removeIds)).build()
..remove()
Expand All @@ -115,54 +110,99 @@ class ObjectBoxBackend implements FMTCBackend {
}

@override
@internal
Future<void> renameStore({
required String currentStoreName,
required String newStoreName,
}) async =>
_expectRoot
expectRoot
.box<ObjectBoxStore>()
.putAsync((await _getStore(currentStoreName))..name = newStoreName);
.putAsync((await getStore(currentStoreName))..name = newStoreName);

@override
@internal
Future<void> deleteStore({
required String storeName,
}) async {
//await resetStore(storeName: storeName);
await _expectRoot
// await resetStore(storeName: storeName);
// might need to reset relations?

final query = expectRoot
.box<ObjectBoxStore>()
.query(ObjectBoxStore_.name.equals(storeName))
.build()
.removeAsync();
.build();
await query.removeAsync();
query.close();
}

@override
@internal
Future<List<ObjectBoxTile>> readTile({required String url}) async {
final query = _expectRoot
Future<ObjectBoxTile?> readTile({
required String url,
}) async {
final query = expectRoot
.box<ObjectBoxTile>()
.query(ObjectBoxTile_.url.equals(url))
.build();
final tiles = await query.findAsync();
final tile = await query.findUniqueAsync();
query.close();
return tiles;
return tile;
}

@override
@internal
FutureOr<void> createTile() {}
@override
@internal
FutureOr<void> updateTile() {}
@override
@internal
FutureOr<void> deleteTile() {}
Future<void> createTile({
required String url,
required Uint8List bytes,
required String storeName,
}) async {
expectRoot;

await root!.runInTransactionAsync(
TxMode.write,
(store, args) {
final tiles = root!.box<ObjectBoxTile>();

final query = tiles.query(ObjectBoxTile_.url.equals(args.url)).build();

tiles.put(
(query.findUnique() ??
ObjectBoxTile(
url: args.url,
lastModified: DateTime.now(),
bytes: args.bytes,
))
..stores.add(ObjectBoxStore(name: args.storeName)),
);

query.close();
},
(url: url, bytes: bytes, storeName: storeName),
);
}

@override
@internal
FutureOr<void> readLatestTile() {}
@override
@internal
FutureOr<void> pruneTilesOlderThan({required DateTime expiry}) {}
Future<bool?> deleteTile({
required String url,
required String storeName,
}) async {
final tiles = expectRoot.box<ObjectBoxTile>();

final query = (tiles.query(ObjectBoxTile_.url.equals(url))
..linkMany(
ObjectBoxTile_.stores,
ObjectBoxStore_.name.equals(storeName),
))
.build();
final tile = query.findUnique();
if (tile == null) return null;

tile.stores.removeWhere((store) => store.name == storeName);

if (tile.stores.isEmpty) {
await query.removeAsync();
query.close();
return true;
}

await tiles.putAsync(tile, mode: PutMode.update);
query.close();
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"id": "2:5839091915824466165",
"name": "name",
"type": 9,
"flags": 2048,
"flags": 2080,
"indexId": "4:4070553972642232057"
}
],
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions lib/src/backend/impls/objectbox/models/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import 'package:objectbox/objectbox.dart';
import '../../../interfaces/models.dart';

@Entity()
class ObjectBoxStore implements BackendStore {
base class ObjectBoxStore extends BackendStore {
@Id()
int id = 0;

@override
@Index()
@Unique()
String name;

@Index()
Expand All @@ -21,7 +22,7 @@ class ObjectBoxStore implements BackendStore {
}

@Entity()
class ObjectBoxTile implements BackendTile {
base class ObjectBoxTile extends BackendTile {
@Id()
int id = 0;

Expand Down
Loading

0 comments on commit 7d15976

Please sign in to comment.