Skip to content

Commit

Permalink
nitrite spatial module
Browse files Browse the repository at this point in the history
  • Loading branch information
anidotnet committed Dec 26, 2023
1 parent 16242c3 commit 5f4a4ea
Show file tree
Hide file tree
Showing 43 changed files with 1,232 additions and 214 deletions.
2 changes: 1 addition & 1 deletion packages/nitrite/lib/src/common/db_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class DBValue implements Comparable<DBValue> {
return -1;
}

return compare(_value!, other._value!);
return compare(_value, other._value);
}

@override
Expand Down
13 changes: 12 additions & 1 deletion packages/nitrite/lib/src/common/mapper/entity_converter.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'package:nitrite/nitrite.dart';

import '../util/object_utils.dart';

/// An abstract class that is used to convert an entity of type [T]
/// into a database [Document] and vice versa.
abstract class EntityConverter<T> {
abstract class EntityConverter<T> extends NitritePlugin {
/// Gets the entity type.
Type get entityType => T;

Expand Down Expand Up @@ -186,4 +188,13 @@ abstract class EntityConverter<T> {
}
return resultMap;
}

bool matchesRuntimeType(dynamic value) => value.runtimeType == T;

bool matchesType(dynamic value) => value is T;

bool matchesByType<R>() => isSubtype<R?, T?>();

@override
Future<void> initialize(NitriteConfig nitriteConfig) async {}
}
57 changes: 38 additions & 19 deletions packages/nitrite/lib/src/common/mapper/simple_nitrite_mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import 'package:nitrite/src/common/util/object_utils.dart';
import 'package:nitrite/src/common/util/validation_utils.dart';

/// A [NitriteMapper] based on [EntityConverter] implementation.
///
/// This mapper is used by default in nitrite. It uses [EntityConverter]
///
/// This mapper is used by default in nitrite. It uses [EntityConverter]
/// to convert an object and vice versa.
class SimpleNitriteMapper extends NitriteMapper {
final Set<String> _valueTypes = {};
Expand Down Expand Up @@ -50,12 +50,6 @@ class SimpleNitriteMapper extends NitriteMapper {
@override
Future<void> initialize(NitriteConfig nitriteConfig) async {}

/// Adds a value type to ignore during mapping.
void addValueType<T>() {
_valueTypes.add("$T");
_valueTypes.add("$T?");
}

/// Registers an [EntityConverter].
void registerEntityConverter(EntityConverter<dynamic> entityConverter) {
entityConverter.notNullOrEmpty("entityConverter cannot be null");
Expand All @@ -80,30 +74,55 @@ class SimpleNitriteMapper extends NitriteMapper {

/// Converts an object of type [Source] to a document.
Document _convertToDocument<Source>(Source source) {
var type = source != null ? source.runtimeType.toString() : "$Source";
if (_converterRegistry.containsKey(type)) {
var serializer = _converterRegistry[type] as EntityConverter<Source>;
var converter = _findEntityConverter(source);
if (converter != null) {
try {
return serializer.toDocument(source, this);
return converter.toDocument(source, this);
} on StackOverflowError {
throw ObjectMappingException('Circular reference detected in $type');
throw ObjectMappingException('Circular reference detected in $source');
}
}

throw ObjectMappingException('Can\'t convert object of type '
'$type to Document, try registering a '
'${source.runtimeType} to Document, try registering a '
'EntityConverter for it.');
}

/// Converts a document to a target object of type [Target].
Target? _convertFromDocument<Target, Source>(Document source) {
var type = "$Target";
if (_converterRegistry.containsKey(type)) {
var serializer = _converterRegistry[type] as EntityConverter<Target>;
return serializer.fromDocument(source, this);
var converter = _findEntityConverterByType<Target>();
if (converter != null) {
return converter.fromDocument(source, this) as Target;
}

throw ObjectMappingException('Can\'t convert Document to type '
'$type, try registering a EntityConverter for it.');
'$Target, try registering a EntityConverter for it.');
}

EntityConverter? _findEntityConverter(dynamic value) {
EntityConverter? match;
for (var converter in _converterRegistry.values) {
if (converter.matchesRuntimeType(value)) {
return converter;
}

if (converter.matchesType(value) && match == null) {
match = converter;
}
}
return match;
}

EntityConverter? _findEntityConverterByType<T>() {
for (var converter in _converterRegistry.values) {
if (converter.matchesByType<T>()) {
return converter;
}

if (converter.matchesByType<T?>()) {
return converter;
}
}
return null;
}
}
21 changes: 21 additions & 0 deletions packages/nitrite/lib/src/common/module/plugin_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:nitrite/src/store/memory/in_memory_store_module.dart';
class PluginManager {
static final Logger _log = Logger('PluginManager');

final List<EntityConverter> _entityConverters = [];
final Map<String, NitriteIndexer> _indexerMap = {};
final NitriteConfig _nitriteConfig;

Expand Down Expand Up @@ -85,6 +86,8 @@ class PluginManager {
await _loadNitriteMapper(plugin);
} else if (plugin is NitriteStore) {
await _loadNitriteStore(plugin);
} else if (plugin is EntityConverter) {
await _loadEntityConverter(plugin);
} else {
await plugin.close();
throw PluginException("Unknown plugin type: ${plugin.runtimeType}");
Expand Down Expand Up @@ -116,6 +119,10 @@ class PluginManager {
_indexerMap[plugin.indexType] = plugin;
}

Future<void> _loadEntityConverter(EntityConverter plugin) async {
_entityConverters.add(plugin);
}

Future<void> _loadInternalPlugins() async {
if (!_indexerMap.containsKey(IndexType.unique)) {
_log.fine("Loading default unique indexer");
Expand All @@ -141,6 +148,20 @@ class PluginManager {
await _loadPlugin(plugin);
}

if (_nitriteMapper != null && _nitriteMapper is SimpleNitriteMapper) {
if (_nitriteConfig.entityConverters.isNotEmpty) {
for (var converter in _nitriteConfig.entityConverters) {
(_nitriteMapper as SimpleNitriteMapper)
.registerEntityConverter(converter);
}
}

for (var converter in _entityConverters) {
(_nitriteMapper as SimpleNitriteMapper)
.registerEntityConverter(converter);
}
}

if (_nitriteStore == null) {
await loadModule(InMemoryStoreModule());
_log.warning('No persistent storage module found, creating an '
Expand Down
4 changes: 3 additions & 1 deletion packages/nitrite/lib/src/common/stream/indexed_stream.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ class IndexedStream extends StreamView<Document> {
NitriteMap<NitriteId, Document> nitriteMap) async* {
await for (var id in stream) {
var doc = await nitriteMap[id];
yield doc!;
if (doc != null) {
yield doc;
}
}
}
}
15 changes: 10 additions & 5 deletions packages/nitrite/lib/src/common/util/spatial_key.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ class SpatialKey {
final int id;
final List<double> minMax;

const SpatialKey(this.id, this.minMax);
SpatialKey(this.id, this.minMax);

double min(int dim) {
return minMax[dim * 2];
return minMax[dim + dim];
}

void setMin(int dim, double value) {
minMax[dim * 2] = value;
minMax[dim + dim] = value;
}

double max(int dim) {
return minMax[dim * 2 + 1];
return minMax[dim + dim + 1];
}

void setMax(int dim, double value) {
minMax[dim * 2 + 1] = value;
minMax[dim + dim + 1] = value;
}

bool isNull() {
Expand All @@ -44,4 +44,9 @@ class SpatialKey {

return ListEquality().equals(minMax, other.minMax);
}

@override
String toString() {
return 'SpatialKey{id: $id, minMax: $minMax}';
}
}
5 changes: 2 additions & 3 deletions packages/nitrite/lib/src/filters/filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dart:collection';
import 'package:nitrite/nitrite.dart';
import 'package:nitrite/src/common/util/object_utils.dart';
import 'package:nitrite/src/common/util/validation_utils.dart';
import 'package:nitrite/src/index/index_map.dart';

part 'filter_impl.dart';

Expand Down Expand Up @@ -288,7 +287,7 @@ abstract class FieldBasedFilter extends NitriteFilter {

/// An abstract class representing a filter that compares fields.
abstract class ComparableFilter extends FieldBasedFilter {
ComparableFilter(String field, dynamic value) : super(field, value);
ComparableFilter(super.field, super.value);

Comparable get comparable {
if (value == null) {
Expand All @@ -303,7 +302,7 @@ abstract class ComparableFilter extends FieldBasedFilter {

/// An abstract class representing a filter for string values.
abstract class StringFilter extends ComparableFilter {
StringFilter(String field, dynamic value) : super(field, value);
StringFilter(super.field, super.value);

String get stringValue => value as String;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/nitrite/lib/src/index/index.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export 'fulltext/index.dart';
export 'nitrite_indexer.dart';
export 'index_map.dart';
export 'nitrite_index.dart';
export 'nitrite_indexer.dart';
export 'types.dart';
44 changes: 22 additions & 22 deletions packages/nitrite/lib/src/index/index_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class IndexMap {
: (comparable == null ? DBNull.instance : DBValue(comparable));

if (_nitriteMap != null) {
return _nitriteMap![dbKey];
return _nitriteMap[dbKey];
} else if (_navigableMap != null) {
return _navigableMap![dbKey];
return _navigableMap[dbKey];
}
return null;
}
Expand All @@ -40,15 +40,15 @@ class IndexMap {

if (!_reverseScan) {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.ceilingKey(dbKey);
dbKey = await _nitriteMap.ceilingKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.ceilingKey(dbKey);
dbKey = _navigableMap.ceilingKey(dbKey);
}
} else {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.floorKey(dbKey);
dbKey = await _nitriteMap.floorKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.floorKey(dbKey);
dbKey = _navigableMap.floorKey(dbKey);
}
}

Expand All @@ -62,15 +62,15 @@ class IndexMap {

if (!_reverseScan) {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.higherKey(dbKey);
dbKey = await _nitriteMap.higherKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.higherKey(dbKey);
dbKey = _navigableMap.higherKey(dbKey);
}
} else {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.lowerKey(dbKey);
dbKey = await _nitriteMap.lowerKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.lowerKey(dbKey);
dbKey = _navigableMap.lowerKey(dbKey);
}
}

Expand All @@ -84,15 +84,15 @@ class IndexMap {

if (!_reverseScan) {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.floorKey(dbKey);
dbKey = await _nitriteMap.floorKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.floorKey(dbKey);
dbKey = _navigableMap.floorKey(dbKey);
}
} else {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.ceilingKey(dbKey);
dbKey = await _nitriteMap.ceilingKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.ceilingKey(dbKey);
dbKey = _navigableMap.ceilingKey(dbKey);
}
}

Expand All @@ -106,15 +106,15 @@ class IndexMap {

if (!_reverseScan) {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.lowerKey(dbKey);
dbKey = await _nitriteMap.lowerKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.lowerKey(dbKey);
dbKey = _navigableMap.lowerKey(dbKey);
}
} else {
if (_nitriteMap != null) {
dbKey = await _nitriteMap!.higherKey(dbKey);
dbKey = await _nitriteMap.higherKey(dbKey);
} else if (_navigableMap != null) {
dbKey = _navigableMap!.higherKey(dbKey);
dbKey = _navigableMap.higherKey(dbKey);
}
}

Expand All @@ -124,7 +124,7 @@ class IndexMap {
Stream<(Comparable?, dynamic)> entries() async* {
if (_nitriteMap != null) {
if (!_reverseScan) {
yield* _nitriteMap!.entries().map((entry) {
yield* _nitriteMap.entries().map((entry) {
var dbKey = entry.$1;
if (dbKey is DBNull) {
return (null, entry.$2);
Expand All @@ -133,7 +133,7 @@ class IndexMap {
}
});
} else {
yield* _nitriteMap!.reversedEntries().map((entry) {
yield* _nitriteMap.reversedEntries().map((entry) {
var dbKey = entry.$1;
if (dbKey is DBNull) {
return (null, entry.$2);
Expand All @@ -144,7 +144,7 @@ class IndexMap {
}
} else if (_navigableMap != null) {
if (!_reverseScan) {
yield* Stream.fromIterable(_navigableMap!.entries.map((entry) {
yield* Stream.fromIterable(_navigableMap.entries.map((entry) {
var dbKey = entry.key;
if (dbKey is DBNull) {
return (null, entry.value);
Expand All @@ -153,7 +153,7 @@ class IndexMap {
}
}));
} else {
yield* Stream.fromIterable(_navigableMap!.reversedEntries.map((entry) {
yield* Stream.fromIterable(_navigableMap.reversedEntries.map((entry) {
var dbKey = entry.key;
if (dbKey is DBNull) {
return (null, entry.value);
Expand Down
Loading

0 comments on commit 5f4a4ea

Please sign in to comment.