remove tests
This commit is contained in:
@@ -1,188 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'dart:indexed_db';
|
|
||||||
import 'dart:js';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:js/js.dart';
|
|
||||||
import 'package:js/js_util.dart';
|
|
||||||
|
|
||||||
@JS('JSON.stringify')
|
|
||||||
external String stringify(dynamic value);
|
|
||||||
|
|
||||||
@JS('indexedDB.cmp')
|
|
||||||
external int idbCmp(dynamic value1, dynamic value2);
|
|
||||||
|
|
||||||
@JS('Object.keys')
|
|
||||||
external List<String> objectKeys(dynamic obj);
|
|
||||||
|
|
||||||
Map<String, dynamic> jsMapToDart(Object obj) {
|
|
||||||
final keys = objectKeys(obj);
|
|
||||||
final map = <String, dynamic>{};
|
|
||||||
for (final key in keys) {
|
|
||||||
map[key] = getProperty<dynamic>(obj, key);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('Promise')
|
|
||||||
class Promise {}
|
|
||||||
|
|
||||||
extension PromiseX on Promise {
|
|
||||||
Future<T> wait<T>() => promiseToFuture(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('openIsar')
|
|
||||||
external Promise openIsarJs(
|
|
||||||
String name,
|
|
||||||
List<dynamic> schemas,
|
|
||||||
bool relaxedDurability,
|
|
||||||
);
|
|
||||||
|
|
||||||
@JS('IsarTxn')
|
|
||||||
class IsarTxnJs {
|
|
||||||
external Promise commit();
|
|
||||||
|
|
||||||
external void abort();
|
|
||||||
|
|
||||||
external bool get write;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('IsarInstance')
|
|
||||||
class IsarInstanceJs {
|
|
||||||
external IsarTxnJs beginTxn(bool write);
|
|
||||||
|
|
||||||
external IsarCollectionJs getCollection(String name);
|
|
||||||
|
|
||||||
external Promise close(bool deleteFromDisk);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef ChangeCallbackJs = void Function();
|
|
||||||
|
|
||||||
typedef ObjectChangeCallbackJs = void Function(Object? object);
|
|
||||||
|
|
||||||
typedef QueryChangeCallbackJs = void Function(List<dynamic> results);
|
|
||||||
|
|
||||||
typedef StopWatchingJs = JsFunction;
|
|
||||||
|
|
||||||
@JS('IsarCollection')
|
|
||||||
class IsarCollectionJs {
|
|
||||||
external IsarLinkJs getLink(String name);
|
|
||||||
|
|
||||||
external Promise getAll(IsarTxnJs txn, List<Id> ids);
|
|
||||||
|
|
||||||
external Promise getAllByIndex(
|
|
||||||
IsarTxnJs txn,
|
|
||||||
String indexName,
|
|
||||||
List<List<dynamic>> values,
|
|
||||||
);
|
|
||||||
|
|
||||||
external Promise putAll(IsarTxnJs txn, List<dynamic> objects);
|
|
||||||
|
|
||||||
external Promise deleteAll(IsarTxnJs txn, List<Id> ids);
|
|
||||||
|
|
||||||
external Promise deleteAllByIndex(
|
|
||||||
IsarTxnJs txn,
|
|
||||||
String indexName,
|
|
||||||
List<dynamic> keys,
|
|
||||||
);
|
|
||||||
|
|
||||||
external Promise clear(IsarTxnJs txn);
|
|
||||||
|
|
||||||
external StopWatchingJs watchLazy(ChangeCallbackJs callback);
|
|
||||||
|
|
||||||
external StopWatchingJs watchObject(Id id, ObjectChangeCallbackJs callback);
|
|
||||||
|
|
||||||
external StopWatchingJs watchQuery(
|
|
||||||
QueryJs query,
|
|
||||||
QueryChangeCallbackJs callback,
|
|
||||||
);
|
|
||||||
|
|
||||||
external StopWatchingJs watchQueryLazy(
|
|
||||||
QueryJs query,
|
|
||||||
ChangeCallbackJs callback,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('IsarLink')
|
|
||||||
class IsarLinkJs {
|
|
||||||
external Promise update(
|
|
||||||
IsarTxnJs txn,
|
|
||||||
bool backlink,
|
|
||||||
Id id,
|
|
||||||
List<Id> addedTargets,
|
|
||||||
List<Id> deletedTargets,
|
|
||||||
);
|
|
||||||
|
|
||||||
external Promise clear(IsarTxnJs txn, Id id, bool backlink);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('IdWhereClause')
|
|
||||||
@anonymous
|
|
||||||
class IdWhereClauseJs {
|
|
||||||
external KeyRange? range;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('IndexWhereClause')
|
|
||||||
@anonymous
|
|
||||||
class IndexWhereClauseJs {
|
|
||||||
external String indexName;
|
|
||||||
external KeyRange? range;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('LinkWhereClause')
|
|
||||||
@anonymous
|
|
||||||
class LinkWhereClauseJs {
|
|
||||||
external String linkCollection;
|
|
||||||
external String linkName;
|
|
||||||
external bool backlink;
|
|
||||||
external Id id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('Function')
|
|
||||||
class FilterJs {
|
|
||||||
external FilterJs(String id, String obj, String method);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('Function')
|
|
||||||
class SortCmpJs {
|
|
||||||
external SortCmpJs(String a, String b, String method);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('Function')
|
|
||||||
class DistinctValueJs {
|
|
||||||
external DistinctValueJs(String obj, String method);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JS('IsarQuery')
|
|
||||||
class QueryJs {
|
|
||||||
external QueryJs(
|
|
||||||
IsarCollectionJs collection,
|
|
||||||
List<dynamic> whereClauses,
|
|
||||||
bool whereDistinct,
|
|
||||||
bool whereAscending,
|
|
||||||
FilterJs? filter,
|
|
||||||
SortCmpJs? sortCmp,
|
|
||||||
DistinctValueJs? distinctValue,
|
|
||||||
int? offset,
|
|
||||||
int? limit,
|
|
||||||
);
|
|
||||||
|
|
||||||
external Promise findFirst(IsarTxnJs txn);
|
|
||||||
|
|
||||||
external Promise findAll(IsarTxnJs txn);
|
|
||||||
|
|
||||||
external Promise deleteFirst(IsarTxnJs txn);
|
|
||||||
|
|
||||||
external Promise deleteAll(IsarTxnJs txn);
|
|
||||||
|
|
||||||
external Promise min(IsarTxnJs txn, String propertyName);
|
|
||||||
|
|
||||||
external Promise max(IsarTxnJs txn, String propertyName);
|
|
||||||
|
|
||||||
external Promise sum(IsarTxnJs txn, String propertyName);
|
|
||||||
|
|
||||||
external Promise average(IsarTxnJs txn, String propertyName);
|
|
||||||
|
|
||||||
external Promise count(IsarTxnJs txn);
|
|
||||||
}
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs, invalid_use_of_protected_member
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:js';
|
|
||||||
import 'dart:js_util';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:isar/src/web/bindings.dart';
|
|
||||||
import 'package:isar/src/web/isar_impl.dart';
|
|
||||||
import 'package:isar/src/web/isar_reader_impl.dart';
|
|
||||||
import 'package:isar/src/web/isar_web.dart';
|
|
||||||
import 'package:isar/src/web/isar_writer_impl.dart';
|
|
||||||
import 'package:isar/src/web/query_build.dart';
|
|
||||||
import 'package:meta/dart2js.dart';
|
|
||||||
|
|
||||||
class IsarCollectionImpl<OBJ> extends IsarCollection<OBJ> {
|
|
||||||
IsarCollectionImpl({
|
|
||||||
required this.isar,
|
|
||||||
required this.native,
|
|
||||||
required this.schema,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
final IsarImpl isar;
|
|
||||||
final IsarCollectionJs native;
|
|
||||||
|
|
||||||
@override
|
|
||||||
final CollectionSchema<OBJ> schema;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => schema.name;
|
|
||||||
|
|
||||||
late final _offsets = isar.offsets[OBJ]!;
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
OBJ deserializeObject(Object object) {
|
|
||||||
final id = getProperty<int>(object, idName);
|
|
||||||
final reader = IsarReaderImpl(object);
|
|
||||||
return schema.deserialize(id, reader, _offsets, isar.offsets);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
List<OBJ?> deserializeObjects(dynamic objects) {
|
|
||||||
final list = objects as List;
|
|
||||||
final results = <OBJ?>[];
|
|
||||||
for (final object in list) {
|
|
||||||
results.add(object is Object ? deserializeObject(object) : null);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<OBJ?>> getAll(List<Id> ids) {
|
|
||||||
return isar.getTxn(false, (IsarTxnJs txn) async {
|
|
||||||
final objects = await native.getAll(txn, ids).wait<List<Object?>>();
|
|
||||||
return deserializeObjects(objects);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<OBJ?>> getAllByIndex(String indexName, List<IndexKey> keys) {
|
|
||||||
return isar.getTxn(false, (IsarTxnJs txn) async {
|
|
||||||
final objects = await native
|
|
||||||
.getAllByIndex(txn, indexName, keys)
|
|
||||||
.wait<List<Object?>>();
|
|
||||||
return deserializeObjects(objects);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<OBJ?> getAllSync(List<Id> ids) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<OBJ?> getAllByIndexSync(String indexName, List<IndexKey> keys) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<Id>> putAll(List<OBJ> objects) {
|
|
||||||
return putAllByIndex(null, objects);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<int> putAllSync(List<OBJ> objects, {bool saveLinks = true}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<Id>> putAllByIndex(String? indexName, List<OBJ> objects) {
|
|
||||||
return isar.getTxn(true, (IsarTxnJs txn) async {
|
|
||||||
final serialized = <Object>[];
|
|
||||||
for (final object in objects) {
|
|
||||||
final jsObj = newObject<Object>();
|
|
||||||
final writer = IsarWriterImpl(jsObj);
|
|
||||||
schema.serialize(object, writer, _offsets, isar.offsets);
|
|
||||||
setProperty(jsObj, idName, schema.getId(object));
|
|
||||||
serialized.add(jsObj);
|
|
||||||
}
|
|
||||||
final ids = await native.putAll(txn, serialized).wait<List<dynamic>>();
|
|
||||||
for (var i = 0; i < objects.length; i++) {
|
|
||||||
final object = objects[i];
|
|
||||||
final id = ids[i] as Id;
|
|
||||||
schema.attach(this, id, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids.cast<Id>().toList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Id> putAllByIndexSync(
|
|
||||||
String indexName,
|
|
||||||
List<OBJ> objects, {
|
|
||||||
bool saveLinks = true,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<int> deleteAll(List<Id> ids) async {
|
|
||||||
await isar.getTxn(true, (IsarTxnJs txn) {
|
|
||||||
return native.deleteAll(txn, ids).wait<void>();
|
|
||||||
});
|
|
||||||
return ids.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<int> deleteAllByIndex(String indexName, List<IndexKey> keys) {
|
|
||||||
return isar.getTxn(true, (IsarTxnJs txn) {
|
|
||||||
return native.deleteAllByIndex(txn, indexName, keys).wait();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int deleteAllSync(List<Id> ids) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
int deleteAllByIndexSync(String indexName, List<IndexKey> keys) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> clear() {
|
|
||||||
return isar.getTxn(true, (IsarTxnJs txn) {
|
|
||||||
return native.clear(txn).wait();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void clearSync() => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> importJson(List<Map<String, dynamic>> json) {
|
|
||||||
return isar.getTxn(true, (IsarTxnJs txn) async {
|
|
||||||
await native.putAll(txn, json.map(jsify).toList()).wait<dynamic>();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> importJsonRaw(Uint8List jsonBytes) {
|
|
||||||
final json = jsonDecode(const Utf8Decoder().convert(jsonBytes)) as List;
|
|
||||||
return importJson(json.cast());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void importJsonSync(List<Map<String, dynamic>> json) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void importJsonRawSync(Uint8List jsonBytes) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<int> count() => where().count();
|
|
||||||
|
|
||||||
@override
|
|
||||||
int countSync() => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<int> getSize({
|
|
||||||
bool includeIndexes = false,
|
|
||||||
bool includeLinks = false,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getSizeSync({
|
|
||||||
bool includeIndexes = false,
|
|
||||||
bool includeLinks = false,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<void> watchLazy({bool fireImmediately = false}) {
|
|
||||||
JsFunction? stop;
|
|
||||||
final controller = StreamController<void>(
|
|
||||||
onCancel: () {
|
|
||||||
stop?.apply([]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
final void Function() callback = allowInterop(() => controller.add(null));
|
|
||||||
stop = native.watchLazy(callback);
|
|
||||||
|
|
||||||
return controller.stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<OBJ?> watchObject(
|
|
||||||
Id id, {
|
|
||||||
bool fireImmediately = false,
|
|
||||||
bool deserialize = true,
|
|
||||||
}) {
|
|
||||||
JsFunction? stop;
|
|
||||||
final controller = StreamController<OBJ?>(
|
|
||||||
onCancel: () {
|
|
||||||
stop?.apply([]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
final Null Function(Object? obj) callback = allowInterop((Object? obj) {
|
|
||||||
final object = deserialize && obj != null ? deserializeObject(obj) : null;
|
|
||||||
controller.add(object);
|
|
||||||
});
|
|
||||||
stop = native.watchObject(id, callback);
|
|
||||||
|
|
||||||
return controller.stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<void> watchObjectLazy(Id id, {bool fireImmediately = false}) =>
|
|
||||||
watchObject(id, deserialize: false);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Query<T> buildQuery<T>({
|
|
||||||
List<WhereClause> whereClauses = const [],
|
|
||||||
bool whereDistinct = false,
|
|
||||||
Sort whereSort = Sort.asc,
|
|
||||||
FilterOperation? filter,
|
|
||||||
List<SortProperty> sortBy = const [],
|
|
||||||
List<DistinctProperty> distinctBy = const [],
|
|
||||||
int? offset,
|
|
||||||
int? limit,
|
|
||||||
String? property,
|
|
||||||
}) {
|
|
||||||
return buildWebQuery(
|
|
||||||
this,
|
|
||||||
whereClauses,
|
|
||||||
whereDistinct,
|
|
||||||
whereSort,
|
|
||||||
filter,
|
|
||||||
sortBy,
|
|
||||||
distinctBy,
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
property,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> verify(List<OBJ> objects) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> verifyLink(
|
|
||||||
String linkName,
|
|
||||||
List<int> sourceIds,
|
|
||||||
List<int> targetIds,
|
|
||||||
) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:html';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
|
|
||||||
import 'package:isar/src/web/bindings.dart';
|
|
||||||
import 'package:isar/src/web/isar_web.dart';
|
|
||||||
|
|
||||||
const Symbol _zoneTxn = #zoneTxn;
|
|
||||||
|
|
||||||
class IsarImpl extends Isar {
|
|
||||||
IsarImpl(super.name, this.instance);
|
|
||||||
|
|
||||||
final IsarInstanceJs instance;
|
|
||||||
final offsets = <Type, List<int>>{};
|
|
||||||
final List<Future<void>> _activeAsyncTxns = [];
|
|
||||||
|
|
||||||
@override
|
|
||||||
final String? directory = null;
|
|
||||||
|
|
||||||
void requireNotInTxn() {
|
|
||||||
if (Zone.current[_zoneTxn] != null) {
|
|
||||||
throw IsarError(
|
|
||||||
'Cannot perform this operation from within an active transaction.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<T> _txn<T>(
|
|
||||||
bool write,
|
|
||||||
bool silent,
|
|
||||||
Future<T> Function() callback,
|
|
||||||
) async {
|
|
||||||
requireOpen();
|
|
||||||
requireNotInTxn();
|
|
||||||
|
|
||||||
final completer = Completer<void>();
|
|
||||||
_activeAsyncTxns.add(completer.future);
|
|
||||||
|
|
||||||
final txn = instance.beginTxn(write);
|
|
||||||
|
|
||||||
final zone = Zone.current.fork(
|
|
||||||
zoneValues: {_zoneTxn: txn},
|
|
||||||
);
|
|
||||||
|
|
||||||
T result;
|
|
||||||
try {
|
|
||||||
result = await zone.run(callback);
|
|
||||||
await txn.commit().wait<dynamic>();
|
|
||||||
} catch (e) {
|
|
||||||
txn.abort();
|
|
||||||
if (e is DomException) {
|
|
||||||
if (e.name == DomException.CONSTRAINT) {
|
|
||||||
throw IsarUniqueViolationError();
|
|
||||||
} else {
|
|
||||||
throw IsarError('${e.name}: ${e.message}');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
completer.complete();
|
|
||||||
_activeAsyncTxns.remove(completer.future);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> txn<T>(Future<T> Function() callback) {
|
|
||||||
return _txn(false, false, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> writeTxn<T>(Future<T> Function() callback, {bool silent = false}) {
|
|
||||||
return _txn(true, silent, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T txnSync<T>(T Function() callback) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
T writeTxnSync<T>(T Function() callback, {bool silent = false}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
Future<T> getTxn<T>(bool write, Future<T> Function(IsarTxnJs txn) callback) {
|
|
||||||
final currentTxn = Zone.current[_zoneTxn] as IsarTxnJs?;
|
|
||||||
if (currentTxn != null) {
|
|
||||||
if (write && !currentTxn.write) {
|
|
||||||
throw IsarError(
|
|
||||||
'Operation cannot be performed within a read transaction.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return callback(currentTxn);
|
|
||||||
} else if (!write) {
|
|
||||||
return _txn(false, false, () {
|
|
||||||
return callback(Zone.current[_zoneTxn] as IsarTxnJs);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw IsarError('Write operations require an explicit transaction.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<int> getSize({
|
|
||||||
bool includeIndexes = false,
|
|
||||||
bool includeLinks = false,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getSizeSync({
|
|
||||||
bool includeIndexes = false,
|
|
||||||
bool includeLinks = false,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> copyToFile(String targetPath) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> close({bool deleteFromDisk = false}) async {
|
|
||||||
requireOpen();
|
|
||||||
requireNotInTxn();
|
|
||||||
await Future.wait(_activeAsyncTxns);
|
|
||||||
await super.close();
|
|
||||||
await instance.close(deleteFromDisk).wait<dynamic>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> verify() => unsupportedOnWeb();
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:isar/src/common/isar_link_base_impl.dart';
|
|
||||||
import 'package:isar/src/common/isar_link_common.dart';
|
|
||||||
import 'package:isar/src/common/isar_links_common.dart';
|
|
||||||
import 'package:isar/src/web/bindings.dart';
|
|
||||||
import 'package:isar/src/web/isar_collection_impl.dart';
|
|
||||||
import 'package:isar/src/web/isar_web.dart';
|
|
||||||
|
|
||||||
mixin IsarLinkBaseMixin<OBJ> on IsarLinkBaseImpl<OBJ> {
|
|
||||||
@override
|
|
||||||
IsarCollectionImpl<dynamic> get sourceCollection =>
|
|
||||||
super.sourceCollection as IsarCollectionImpl;
|
|
||||||
|
|
||||||
@override
|
|
||||||
IsarCollectionImpl<OBJ> get targetCollection =>
|
|
||||||
super.targetCollection as IsarCollectionImpl<OBJ>;
|
|
||||||
|
|
||||||
@override
|
|
||||||
late final Id Function(OBJ) getId = targetCollection.schema.getId;
|
|
||||||
|
|
||||||
late final String? backlinkLinkName =
|
|
||||||
sourceCollection.schema.link(linkName).linkName;
|
|
||||||
|
|
||||||
late final IsarLinkJs jsLink = backlinkLinkName != null
|
|
||||||
? targetCollection.native.getLink(backlinkLinkName!)
|
|
||||||
: sourceCollection.native.getLink(linkName);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> update({
|
|
||||||
Iterable<OBJ> link = const [],
|
|
||||||
Iterable<OBJ> unlink = const [],
|
|
||||||
bool reset = false,
|
|
||||||
}) {
|
|
||||||
final linkList = link.toList();
|
|
||||||
final unlinkList = unlink.toList();
|
|
||||||
|
|
||||||
final containingId = requireAttached();
|
|
||||||
final backlink = backlinkLinkName != null;
|
|
||||||
|
|
||||||
final linkIds = List<Id>.filled(linkList.length, 0);
|
|
||||||
for (var i = 0; i < linkList.length; i++) {
|
|
||||||
linkIds[i] = requireGetId(linkList[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
final unlinkIds = List<Id>.filled(unlinkList.length, 0);
|
|
||||||
for (var i = 0; i < unlinkList.length; i++) {
|
|
||||||
unlinkIds[i] = requireGetId(unlinkList[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetCollection.isar.getTxn(true, (IsarTxnJs txn) async {
|
|
||||||
if (reset) {
|
|
||||||
await jsLink.clear(txn, containingId, backlink).wait<dynamic>();
|
|
||||||
}
|
|
||||||
return jsLink
|
|
||||||
.update(txn, backlink, containingId, linkIds, unlinkIds)
|
|
||||||
.wait();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void updateSync({
|
|
||||||
Iterable<OBJ> link = const [],
|
|
||||||
Iterable<OBJ> unlink = const [],
|
|
||||||
bool reset = false,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
}
|
|
||||||
|
|
||||||
class IsarLinkImpl<OBJ> extends IsarLinkCommon<OBJ>
|
|
||||||
with IsarLinkBaseMixin<OBJ> {}
|
|
||||||
|
|
||||||
class IsarLinksImpl<OBJ> extends IsarLinksCommon<OBJ>
|
|
||||||
with IsarLinkBaseMixin<OBJ> {}
|
|
||||||
@@ -1,347 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:js/js_util.dart';
|
|
||||||
import 'package:meta/dart2js.dart';
|
|
||||||
|
|
||||||
const nullNumber = double.negativeInfinity;
|
|
||||||
const idName = '_id';
|
|
||||||
final nullDate = DateTime.fromMillisecondsSinceEpoch(0);
|
|
||||||
|
|
||||||
class IsarReaderImpl implements IsarReader {
|
|
||||||
IsarReaderImpl(this.object);
|
|
||||||
|
|
||||||
final Object object;
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
bool readBool(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
bool? readBoolOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value == 0
|
|
||||||
? false
|
|
||||||
: value == 1
|
|
||||||
? true
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
int readByte(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int ? value : nullNumber as int;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
int? readByteOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int && value != nullNumber ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
int readInt(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int ? value : nullNumber as int;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
int? readIntOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int && value != nullNumber ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
double readFloat(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is double ? value : nullNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
double? readFloatOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is double && value != nullNumber ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
int readLong(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int ? value : nullNumber as int;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
int? readLongOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int && value != nullNumber ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
double readDouble(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is double && value != nullNumber ? value : nullNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
double? readDoubleOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is double && value != nullNumber ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
DateTime readDateTime(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int && value != nullNumber
|
|
||||||
? DateTime.fromMillisecondsSinceEpoch(value, isUtc: true).toLocal()
|
|
||||||
: nullDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
DateTime? readDateTimeOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is int && value != nullNumber
|
|
||||||
? DateTime.fromMillisecondsSinceEpoch(value, isUtc: true).toLocal()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
String readString(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is String ? value : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
String? readStringOrNull(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is String ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
T? readObjectOrNull<T>(
|
|
||||||
int offset,
|
|
||||||
Deserialize<T> deserialize,
|
|
||||||
Map<Type, List<int>> allOffsets,
|
|
||||||
) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
if (value is Object) {
|
|
||||||
final reader = IsarReaderImpl(value);
|
|
||||||
return deserialize(0, reader, allOffsets[T]!, allOffsets);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<bool>? readBoolList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List ? value.map((e) => e == 1).toList() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<bool?>? readBoolOrNullList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value
|
|
||||||
.map(
|
|
||||||
(e) => e == 0
|
|
||||||
? false
|
|
||||||
: e == 1
|
|
||||||
? true
|
|
||||||
: null,
|
|
||||||
)
|
|
||||||
.toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<int>? readByteList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is int ? e : nullNumber as int).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<int>? readIntList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is int ? e : nullNumber as int).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<int?>? readIntOrNullList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is int && e != nullNumber ? e : null).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<double>? readFloatList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is double ? e : nullNumber).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<double?>? readFloatOrNullList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is double && e != nullNumber ? e : null).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<int>? readLongList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is int ? e : nullNumber as int).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<int?>? readLongOrNullList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is int && e != nullNumber ? e : null).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<double>? readDoubleList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is double ? e : nullNumber).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<double?>? readDoubleOrNullList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is double && e != nullNumber ? e : null).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<DateTime>? readDateTimeList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value
|
|
||||||
.map(
|
|
||||||
(e) => e is int && e != nullNumber
|
|
||||||
? DateTime.fromMillisecondsSinceEpoch(e, isUtc: true)
|
|
||||||
.toLocal()
|
|
||||||
: nullDate,
|
|
||||||
)
|
|
||||||
.toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<DateTime?>? readDateTimeOrNullList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value
|
|
||||||
.map(
|
|
||||||
(e) => e is int && e != nullNumber
|
|
||||||
? DateTime.fromMillisecondsSinceEpoch(e, isUtc: true)
|
|
||||||
.toLocal()
|
|
||||||
: null,
|
|
||||||
)
|
|
||||||
.toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<String>? readStringList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is String ? e : '').toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<String?>? readStringOrNullList(int offset) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) => e is String ? e : null).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<T>? readObjectList<T>(
|
|
||||||
int offset,
|
|
||||||
Deserialize<T> deserialize,
|
|
||||||
Map<Type, List<int>> allOffsets,
|
|
||||||
T defaultValue,
|
|
||||||
) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) {
|
|
||||||
if (e is Object) {
|
|
||||||
final reader = IsarReaderImpl(e);
|
|
||||||
return deserialize(0, reader, allOffsets[T]!, allOffsets);
|
|
||||||
} else {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
List<T?>? readObjectOrNullList<T>(
|
|
||||||
int offset,
|
|
||||||
Deserialize<T> deserialize,
|
|
||||||
Map<Type, List<int>> allOffsets,
|
|
||||||
) {
|
|
||||||
final value = getProperty<dynamic>(object, offset);
|
|
||||||
return value is List
|
|
||||||
? value.map((e) {
|
|
||||||
if (e is Object) {
|
|
||||||
final reader = IsarReaderImpl(e);
|
|
||||||
return deserialize(0, reader, allOffsets[T]!, allOffsets);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).toList()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// ignore_for_file: unused_field, public_member_api_docs
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@protected
|
|
||||||
const Id isarMinId = -9007199254740990;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@protected
|
|
||||||
const Id isarMaxId = 9007199254740991;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@protected
|
|
||||||
const Id isarAutoIncrementId = -9007199254740991;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
Never unsupportedOnWeb() {
|
|
||||||
throw UnsupportedError('This operation is not supported for Isar web');
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebAbi {
|
|
||||||
static const androidArm = null as dynamic;
|
|
||||||
static const androidArm64 = null as dynamic;
|
|
||||||
static const androidIA32 = null as dynamic;
|
|
||||||
static const androidX64 = null as dynamic;
|
|
||||||
static const iosArm64 = null as dynamic;
|
|
||||||
static const iosX64 = null as dynamic;
|
|
||||||
static const linuxArm64 = null as dynamic;
|
|
||||||
static const linuxX64 = null as dynamic;
|
|
||||||
static const macosArm64 = null as dynamic;
|
|
||||||
static const macosX64 = null as dynamic;
|
|
||||||
static const windowsArm64 = null as dynamic;
|
|
||||||
static const windowsX64 = null as dynamic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@protected
|
|
||||||
typedef IsarAbi = _WebAbi;
|
|
||||||
|
|
||||||
FutureOr<void> initializeCoreBinary({
|
|
||||||
Map<IsarAbi, String> libraries = const {},
|
|
||||||
bool download = false,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:isar/src/web/isar_reader_impl.dart';
|
|
||||||
import 'package:js/js_util.dart';
|
|
||||||
import 'package:meta/dart2js.dart';
|
|
||||||
|
|
||||||
class IsarWriterImpl implements IsarWriter {
|
|
||||||
IsarWriterImpl(this.object);
|
|
||||||
|
|
||||||
final Object object;
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeBool(int offset, bool? value) {
|
|
||||||
final number = value == true
|
|
||||||
? 1
|
|
||||||
: value == false
|
|
||||||
? 0
|
|
||||||
: nullNumber;
|
|
||||||
setProperty(object, offset, number);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeByte(int offset, int value) {
|
|
||||||
setProperty(object, offset, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeInt(int offset, int? value) {
|
|
||||||
setProperty(object, offset, value ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeFloat(int offset, double? value) {
|
|
||||||
setProperty(object, offset, value ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeLong(int offset, int? value) {
|
|
||||||
setProperty(object, offset, value ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeDouble(int offset, double? value) {
|
|
||||||
setProperty(object, offset, value ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeDateTime(int offset, DateTime? value) {
|
|
||||||
setProperty(
|
|
||||||
object,
|
|
||||||
offset,
|
|
||||||
value?.toUtc().millisecondsSinceEpoch ?? nullNumber,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeString(int offset, String? value) {
|
|
||||||
setProperty(object, offset, value ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeObject<T>(
|
|
||||||
int offset,
|
|
||||||
Map<Type, List<int>> allOffsets,
|
|
||||||
Serialize<T> serialize,
|
|
||||||
T? value,
|
|
||||||
) {
|
|
||||||
if (value != null) {
|
|
||||||
final object = newObject<Object>();
|
|
||||||
final writer = IsarWriterImpl(object);
|
|
||||||
serialize(value, writer, allOffsets[T]!, allOffsets);
|
|
||||||
setProperty(this.object, offset, object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeByteList(int offset, List<int>? values) {
|
|
||||||
setProperty(object, offset, values ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeBoolList(int offset, List<bool?>? values) {
|
|
||||||
final list = values
|
|
||||||
?.map(
|
|
||||||
(e) => e == false
|
|
||||||
? 0
|
|
||||||
: e == true
|
|
||||||
? 1
|
|
||||||
: nullNumber,
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
setProperty(object, offset, list ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeIntList(int offset, List<int?>? values) {
|
|
||||||
final list = values?.map((e) => e ?? nullNumber).toList();
|
|
||||||
setProperty(object, offset, list ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeFloatList(int offset, List<double?>? values) {
|
|
||||||
final list = values?.map((e) => e ?? nullNumber).toList();
|
|
||||||
setProperty(object, offset, list ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeLongList(int offset, List<int?>? values) {
|
|
||||||
final list = values?.map((e) => e ?? nullNumber).toList();
|
|
||||||
setProperty(object, offset, list ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeDoubleList(int offset, List<double?>? values) {
|
|
||||||
final list = values?.map((e) => e ?? nullNumber).toList();
|
|
||||||
setProperty(object, offset, list ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeDateTimeList(int offset, List<DateTime?>? values) {
|
|
||||||
final list = values
|
|
||||||
?.map((e) => e?.toUtc().millisecondsSinceEpoch ?? nullNumber)
|
|
||||||
.toList();
|
|
||||||
setProperty(object, offset, list ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeStringList(int offset, List<String?>? values) {
|
|
||||||
final list = values?.map((e) => e ?? nullNumber).toList();
|
|
||||||
setProperty(object, offset, list ?? nullNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tryInline
|
|
||||||
@override
|
|
||||||
void writeObjectList<T>(
|
|
||||||
int offset,
|
|
||||||
Map<Type, List<int>> allOffsets,
|
|
||||||
Serialize<T> serialize,
|
|
||||||
List<T?>? values,
|
|
||||||
) {
|
|
||||||
if (values != null) {
|
|
||||||
final list = values.map((e) {
|
|
||||||
if (e != null) {
|
|
||||||
final object = newObject<Object>();
|
|
||||||
final writer = IsarWriterImpl(object);
|
|
||||||
serialize(e, writer, allOffsets[T]!, allOffsets);
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
}).toList();
|
|
||||||
setProperty(object, offset, list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs, invalid_use_of_protected_member
|
|
||||||
|
|
||||||
import 'dart:html';
|
|
||||||
//import 'dart:js_util';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
/*import 'package:isar/src/common/schemas.dart';
|
|
||||||
|
|
||||||
import 'package:isar/src/web/bindings.dart';
|
|
||||||
import 'package:isar/src/web/isar_collection_impl.dart';
|
|
||||||
import 'package:isar/src/web/isar_impl.dart';*/
|
|
||||||
import 'package:isar/src/web/isar_web.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
bool _loaded = false;
|
|
||||||
Future<void> initializeIsarWeb([String? jsUrl]) async {
|
|
||||||
if (_loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_loaded = true;
|
|
||||||
|
|
||||||
final script = ScriptElement();
|
|
||||||
script.type = 'text/javascript';
|
|
||||||
// ignore: unsafe_html
|
|
||||||
script.src = 'https://unpkg.com/isar@${Isar.version}/dist/index.js';
|
|
||||||
script.async = true;
|
|
||||||
document.head!.append(script);
|
|
||||||
await script.onLoad.first.timeout(
|
|
||||||
const Duration(seconds: 30),
|
|
||||||
onTimeout: () {
|
|
||||||
throw IsarError('Failed to load Isar');
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@visibleForTesting
|
|
||||||
void doNotInitializeIsarWeb() {
|
|
||||||
_loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Isar> openIsar({
|
|
||||||
required List<CollectionSchema<dynamic>> schemas,
|
|
||||||
String? directory,
|
|
||||||
required String name,
|
|
||||||
required int maxSizeMiB,
|
|
||||||
required bool relaxedDurability,
|
|
||||||
CompactCondition? compactOnLaunch,
|
|
||||||
}) async {
|
|
||||||
throw IsarError('Please use Isar 2.5.0 if you need web support. '
|
|
||||||
'A 3.x version with web support will be released soon.');
|
|
||||||
/*await initializeIsarWeb();
|
|
||||||
final schemasJson = getSchemas(schemas).map((e) => e.toJson());
|
|
||||||
final schemasJs = jsify(schemasJson.toList()) as List<dynamic>;
|
|
||||||
final instance = await openIsarJs(name, schemasJs, relaxedDurability)
|
|
||||||
.wait<IsarInstanceJs>();
|
|
||||||
final isar = IsarImpl(name, instance);
|
|
||||||
final cols = <Type, IsarCollection<dynamic>>{};
|
|
||||||
for (final schema in schemas) {
|
|
||||||
final col = instance.getCollection(schema.name);
|
|
||||||
schema.toCollection(<OBJ>() {
|
|
||||||
schema as CollectionSchema<OBJ>;
|
|
||||||
cols[OBJ] = IsarCollectionImpl<OBJ>(
|
|
||||||
isar: isar,
|
|
||||||
native: col,
|
|
||||||
schema: schema,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
isar.attachCollections(cols);
|
|
||||||
return isar;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
Isar openIsarSync({
|
|
||||||
required List<CollectionSchema<dynamic>> schemas,
|
|
||||||
String? directory,
|
|
||||||
required String name,
|
|
||||||
required int maxSizeMiB,
|
|
||||||
required bool relaxedDurability,
|
|
||||||
CompactCondition? compactOnLaunch,
|
|
||||||
}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
@@ -1,375 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs, invalid_use_of_protected_member
|
|
||||||
|
|
||||||
import 'dart:indexed_db';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
|
|
||||||
import 'package:isar/src/web/bindings.dart';
|
|
||||||
import 'package:isar/src/web/isar_collection_impl.dart';
|
|
||||||
import 'package:isar/src/web/isar_web.dart';
|
|
||||||
import 'package:isar/src/web/query_impl.dart';
|
|
||||||
|
|
||||||
Query<T> buildWebQuery<T, OBJ>(
|
|
||||||
IsarCollectionImpl<OBJ> col,
|
|
||||||
List<WhereClause> whereClauses,
|
|
||||||
bool whereDistinct,
|
|
||||||
Sort whereSort,
|
|
||||||
FilterOperation? filter,
|
|
||||||
List<SortProperty> sortBy,
|
|
||||||
List<DistinctProperty> distinctBy,
|
|
||||||
int? offset,
|
|
||||||
int? limit,
|
|
||||||
String? property,
|
|
||||||
) {
|
|
||||||
final whereClausesJs = whereClauses.map((wc) {
|
|
||||||
if (wc is IdWhereClause) {
|
|
||||||
return _buildIdWhereClause(wc);
|
|
||||||
} else if (wc is IndexWhereClause) {
|
|
||||||
return _buildIndexWhereClause(col.schema, wc);
|
|
||||||
} else {
|
|
||||||
return _buildLinkWhereClause(col, wc as LinkWhereClause);
|
|
||||||
}
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
final filterJs = filter != null ? _buildFilter(col.schema, filter) : null;
|
|
||||||
final sortJs = sortBy.isNotEmpty ? _buildSort(sortBy) : null;
|
|
||||||
final distinctJs = distinctBy.isNotEmpty ? _buildDistinct(distinctBy) : null;
|
|
||||||
|
|
||||||
final queryJs = QueryJs(
|
|
||||||
col.native,
|
|
||||||
whereClausesJs,
|
|
||||||
whereDistinct,
|
|
||||||
whereSort == Sort.asc,
|
|
||||||
filterJs,
|
|
||||||
sortJs,
|
|
||||||
distinctJs,
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
);
|
|
||||||
|
|
||||||
QueryDeserialize<T> deserialize;
|
|
||||||
//if (property == null) {
|
|
||||||
deserialize = col.deserializeObject as T Function(Object);
|
|
||||||
/*} else {
|
|
||||||
deserialize = (jsObj) => col.schema.deserializeProp(jsObj, property) as T;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return QueryImpl<T>(col, queryJs, deserialize, property);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _valueToJs(dynamic value) {
|
|
||||||
if (value == null) {
|
|
||||||
return double.negativeInfinity;
|
|
||||||
} else if (value == true) {
|
|
||||||
return 1;
|
|
||||||
} else if (value == false) {
|
|
||||||
return 0;
|
|
||||||
} else if (value is DateTime) {
|
|
||||||
return value.toUtc().millisecondsSinceEpoch;
|
|
||||||
} else if (value is List) {
|
|
||||||
return value.map(_valueToJs).toList();
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IdWhereClauseJs _buildIdWhereClause(IdWhereClause wc) {
|
|
||||||
return IdWhereClauseJs()
|
|
||||||
..range = _buildKeyRange(
|
|
||||||
wc.lower,
|
|
||||||
wc.upper,
|
|
||||||
wc.includeLower,
|
|
||||||
wc.includeUpper,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
IndexWhereClauseJs _buildIndexWhereClause(
|
|
||||||
CollectionSchema<dynamic> schema,
|
|
||||||
IndexWhereClause wc,
|
|
||||||
) {
|
|
||||||
final index = schema.index(wc.indexName);
|
|
||||||
|
|
||||||
final lower = wc.lower?.toList();
|
|
||||||
final upper = wc.upper?.toList();
|
|
||||||
if (upper != null) {
|
|
||||||
while (index.properties.length > upper.length) {
|
|
||||||
upper.add([]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic lowerUnwrapped = wc.lower;
|
|
||||||
if (index.properties.length == 1 && lower != null) {
|
|
||||||
lowerUnwrapped = lower.isNotEmpty ? lower[0] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic upperUnwrapped = upper;
|
|
||||||
if (index.properties.length == 1 && upper != null) {
|
|
||||||
upperUnwrapped = upper.isNotEmpty ? upper[0] : double.infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IndexWhereClauseJs()
|
|
||||||
..indexName = wc.indexName
|
|
||||||
..range = _buildKeyRange(
|
|
||||||
wc.lower != null ? _valueToJs(lowerUnwrapped) : null,
|
|
||||||
wc.upper != null ? _valueToJs(upperUnwrapped) : null,
|
|
||||||
wc.includeLower,
|
|
||||||
wc.includeUpper,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkWhereClauseJs _buildLinkWhereClause(
|
|
||||||
IsarCollectionImpl<dynamic> col,
|
|
||||||
LinkWhereClause wc,
|
|
||||||
) {
|
|
||||||
// ignore: unused_local_variable
|
|
||||||
final linkCol = col.isar.getCollectionByNameInternal(wc.linkCollection)!
|
|
||||||
as IsarCollectionImpl;
|
|
||||||
//final backlinkLinkName = linkCol.schema.backlinkLinkNames[wc.linkName];
|
|
||||||
return LinkWhereClauseJs()
|
|
||||||
..linkCollection = wc.linkCollection
|
|
||||||
//..linkName = backlinkLinkName ?? wc.linkName
|
|
||||||
//..backlink = backlinkLinkName != null
|
|
||||||
..id = wc.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyRange? _buildKeyRange(
|
|
||||||
dynamic lower,
|
|
||||||
dynamic upper,
|
|
||||||
bool includeLower,
|
|
||||||
bool includeUpper,
|
|
||||||
) {
|
|
||||||
if (lower != null) {
|
|
||||||
if (upper != null) {
|
|
||||||
final boundsEqual = idbCmp(lower, upper) == 0;
|
|
||||||
if (boundsEqual) {
|
|
||||||
if (includeLower && includeUpper) {
|
|
||||||
return KeyRange.only(lower);
|
|
||||||
} else {
|
|
||||||
// empty range
|
|
||||||
return KeyRange.upperBound(double.negativeInfinity, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return KeyRange.bound(
|
|
||||||
lower,
|
|
||||||
upper,
|
|
||||||
!includeLower,
|
|
||||||
!includeUpper,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return KeyRange.lowerBound(lower, !includeLower);
|
|
||||||
}
|
|
||||||
} else if (upper != null) {
|
|
||||||
return KeyRange.upperBound(upper, !includeUpper);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilterJs? _buildFilter(
|
|
||||||
CollectionSchema<dynamic> schema,
|
|
||||||
FilterOperation filter,
|
|
||||||
) {
|
|
||||||
final filterStr = _buildFilterOperation(schema, filter);
|
|
||||||
if (filterStr != null) {
|
|
||||||
return FilterJs('id', 'obj', 'return $filterStr');
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String? _buildFilterOperation(
|
|
||||||
CollectionSchema<dynamic> schema,
|
|
||||||
FilterOperation filter,
|
|
||||||
) {
|
|
||||||
if (filter is FilterGroup) {
|
|
||||||
return _buildFilterGroup(schema, filter);
|
|
||||||
} else if (filter is LinkFilter) {
|
|
||||||
unsupportedOnWeb();
|
|
||||||
} else if (filter is FilterCondition) {
|
|
||||||
return _buildCondition(schema, filter);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String? _buildFilterGroup(CollectionSchema<dynamic> schema, FilterGroup group) {
|
|
||||||
final builtConditions = group.filters
|
|
||||||
.map((op) => _buildFilterOperation(schema, op))
|
|
||||||
.where((e) => e != null)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (builtConditions.isEmpty) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group.type == FilterGroupType.not) {
|
|
||||||
return '!(${builtConditions[0]})';
|
|
||||||
} else if (builtConditions.length == 1) {
|
|
||||||
return builtConditions[0];
|
|
||||||
} else if (group.type == FilterGroupType.xor) {
|
|
||||||
final conditions = builtConditions.join(',');
|
|
||||||
return 'IsarQuery.xor($conditions)';
|
|
||||||
} else {
|
|
||||||
final op = group.type == FilterGroupType.or ? '||' : '&&';
|
|
||||||
final condition = builtConditions.join(op);
|
|
||||||
return '($condition)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _buildCondition(
|
|
||||||
CollectionSchema<dynamic> schema,
|
|
||||||
FilterCondition condition,
|
|
||||||
) {
|
|
||||||
dynamic _prepareFilterValue(dynamic value) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
} else if (value is String) {
|
|
||||||
return stringify(value);
|
|
||||||
} else {
|
|
||||||
return _valueToJs(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final isListOp = condition.type != FilterConditionType.isNull &&
|
|
||||||
condition.type != FilterConditionType.listLength &&
|
|
||||||
schema.property(condition.property).type.isList;
|
|
||||||
final accessor =
|
|
||||||
condition.property == schema.idName ? 'id' : 'obj.${condition.property}';
|
|
||||||
final variable = isListOp ? 'e' : accessor;
|
|
||||||
|
|
||||||
final cond = _buildConditionInternal(
|
|
||||||
conditionType: condition.type,
|
|
||||||
variable: variable,
|
|
||||||
val1: _prepareFilterValue(condition.value1),
|
|
||||||
include1: condition.include1,
|
|
||||||
val2: _prepareFilterValue(condition.value2),
|
|
||||||
include2: condition.include2,
|
|
||||||
caseSensitive: condition.caseSensitive,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isListOp) {
|
|
||||||
return '(Array.isArray($accessor) && $accessor.some(e => $cond))';
|
|
||||||
} else {
|
|
||||||
return cond;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _buildConditionInternal({
|
|
||||||
required FilterConditionType conditionType,
|
|
||||||
required String variable,
|
|
||||||
required Object? val1,
|
|
||||||
required bool include1,
|
|
||||||
required Object? val2,
|
|
||||||
required bool include2,
|
|
||||||
required bool caseSensitive,
|
|
||||||
}) {
|
|
||||||
final isNull = '($variable == null || $variable === -Infinity)';
|
|
||||||
switch (conditionType) {
|
|
||||||
case FilterConditionType.equalTo:
|
|
||||||
if (val1 == null) {
|
|
||||||
return isNull;
|
|
||||||
} else if (val1 is String && !caseSensitive) {
|
|
||||||
return '$variable?.toLowerCase() === ${val1.toLowerCase()}';
|
|
||||||
} else {
|
|
||||||
return '$variable === $val1';
|
|
||||||
}
|
|
||||||
case FilterConditionType.between:
|
|
||||||
final val = val1 ?? val2;
|
|
||||||
final lowerOp = include1 ? '>=' : '>';
|
|
||||||
final upperOp = include2 ? '<=' : '<';
|
|
||||||
if (val == null) {
|
|
||||||
return isNull;
|
|
||||||
} else if ((val1 is String?) && (val2 is String?) && !caseSensitive) {
|
|
||||||
final lower = val1?.toLowerCase() ?? '-Infinity';
|
|
||||||
final upper = val2?.toLowerCase() ?? '-Infinity';
|
|
||||||
final variableLc = '$variable?.toLowerCase() ?? -Infinity';
|
|
||||||
final lowerCond = 'indexedDB.cmp($variableLc, $lower) $lowerOp 0';
|
|
||||||
final upperCond = 'indexedDB.cmp($variableLc, $upper) $upperOp 0';
|
|
||||||
return '($lowerCond && $upperCond)';
|
|
||||||
} else {
|
|
||||||
final lowerCond =
|
|
||||||
'indexedDB.cmp($variable, ${val1 ?? '-Infinity'}) $lowerOp 0';
|
|
||||||
final upperCond =
|
|
||||||
'indexedDB.cmp($variable, ${val2 ?? '-Infinity'}) $upperOp 0';
|
|
||||||
return '($lowerCond && $upperCond)';
|
|
||||||
}
|
|
||||||
case FilterConditionType.lessThan:
|
|
||||||
if (val1 == null) {
|
|
||||||
if (include1) {
|
|
||||||
return isNull;
|
|
||||||
} else {
|
|
||||||
return 'false';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final op = include1 ? '<=' : '<';
|
|
||||||
if (val1 is String && !caseSensitive) {
|
|
||||||
return 'indexedDB.cmp($variable?.toLowerCase() ?? '
|
|
||||||
'-Infinity, ${val1.toLowerCase()}) $op 0';
|
|
||||||
} else {
|
|
||||||
return 'indexedDB.cmp($variable, $val1) $op 0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case FilterConditionType.greaterThan:
|
|
||||||
if (val1 == null) {
|
|
||||||
if (include1) {
|
|
||||||
return 'true';
|
|
||||||
} else {
|
|
||||||
return '!$isNull';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final op = include1 ? '>=' : '>';
|
|
||||||
if (val1 is String && !caseSensitive) {
|
|
||||||
return 'indexedDB.cmp($variable?.toLowerCase() ?? '
|
|
||||||
'-Infinity, ${val1.toLowerCase()}) $op 0';
|
|
||||||
} else {
|
|
||||||
return 'indexedDB.cmp($variable, $val1) $op 0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case FilterConditionType.startsWith:
|
|
||||||
case FilterConditionType.endsWith:
|
|
||||||
case FilterConditionType.contains:
|
|
||||||
final op = conditionType == FilterConditionType.startsWith
|
|
||||||
? 'startsWith'
|
|
||||||
: conditionType == FilterConditionType.endsWith
|
|
||||||
? 'endsWith'
|
|
||||||
: 'includes';
|
|
||||||
if (val1 is String) {
|
|
||||||
final isString = 'typeof $variable == "string"';
|
|
||||||
if (!caseSensitive) {
|
|
||||||
return '($isString && $variable.toLowerCase() '
|
|
||||||
'.$op(${val1.toLowerCase()}))';
|
|
||||||
} else {
|
|
||||||
return '($isString && $variable.$op($val1))';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw IsarError('Unsupported type for condition');
|
|
||||||
}
|
|
||||||
case FilterConditionType.matches:
|
|
||||||
throw UnimplementedError();
|
|
||||||
case FilterConditionType.isNull:
|
|
||||||
return isNull;
|
|
||||||
// ignore: no_default_cases
|
|
||||||
default:
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SortCmpJs _buildSort(List<SortProperty> properties) {
|
|
||||||
final sort = properties.map((e) {
|
|
||||||
final op = e.sort == Sort.asc ? '' : '-';
|
|
||||||
return '${op}indexedDB.cmp(a.${e.property} ?? "-Infinity", b.${e.property} '
|
|
||||||
'?? "-Infinity")';
|
|
||||||
}).join('||');
|
|
||||||
return SortCmpJs('a', 'b', 'return $sort');
|
|
||||||
}
|
|
||||||
|
|
||||||
DistinctValueJs _buildDistinct(List<DistinctProperty> properties) {
|
|
||||||
final distinct = properties.map((e) {
|
|
||||||
if (e.caseSensitive == false) {
|
|
||||||
return 'obj.${e.property}?.toLowerCase() ?? "-Infinity"';
|
|
||||||
} else {
|
|
||||||
return 'obj.${e.property}?.toString() ?? "-Infinity"';
|
|
||||||
}
|
|
||||||
}).join('+');
|
|
||||||
return DistinctValueJs('obj', 'return $distinct');
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:js';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:isar/src/web/bindings.dart';
|
|
||||||
|
|
||||||
import 'package:isar/src/web/isar_collection_impl.dart';
|
|
||||||
import 'package:isar/src/web/isar_web.dart';
|
|
||||||
|
|
||||||
typedef QueryDeserialize<T> = T Function(Object);
|
|
||||||
|
|
||||||
class QueryImpl<T> extends Query<T> {
|
|
||||||
QueryImpl(this.col, this.queryJs, this.deserialize, this.propertyName);
|
|
||||||
final IsarCollectionImpl<dynamic> col;
|
|
||||||
final QueryJs queryJs;
|
|
||||||
final QueryDeserialize<T> deserialize;
|
|
||||||
final String? propertyName;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Isar get isar => col.isar;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T?> findFirst() {
|
|
||||||
return col.isar.getTxn(false, (IsarTxnJs txn) async {
|
|
||||||
final result = await queryJs.findFirst(txn).wait<Object?>();
|
|
||||||
if (result == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return deserialize(result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T? findFirstSync() => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<T>> findAll() {
|
|
||||||
return col.isar.getTxn(false, (IsarTxnJs txn) async {
|
|
||||||
final result = await queryJs.findAll(txn).wait<List<dynamic>>();
|
|
||||||
return result.map((e) => deserialize(e as Object)).toList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<T> findAllSync() => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<R?> aggregate<R>(AggregationOp op) {
|
|
||||||
return col.isar.getTxn(false, (IsarTxnJs txn) async {
|
|
||||||
final property = propertyName ?? col.schema.idName;
|
|
||||||
|
|
||||||
num? result;
|
|
||||||
switch (op) {
|
|
||||||
case AggregationOp.min:
|
|
||||||
result = await queryJs.min(txn, property).wait();
|
|
||||||
break;
|
|
||||||
case AggregationOp.max:
|
|
||||||
result = await queryJs.max(txn, property).wait();
|
|
||||||
break;
|
|
||||||
case AggregationOp.sum:
|
|
||||||
result = await queryJs.sum(txn, property).wait();
|
|
||||||
break;
|
|
||||||
case AggregationOp.average:
|
|
||||||
result = await queryJs.average(txn, property).wait();
|
|
||||||
break;
|
|
||||||
case AggregationOp.count:
|
|
||||||
result = await queryJs.count(txn).wait();
|
|
||||||
break;
|
|
||||||
// ignore: no_default_cases
|
|
||||||
default:
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R == DateTime) {
|
|
||||||
return DateTime.fromMillisecondsSinceEpoch(result.toInt()).toLocal()
|
|
||||||
as R;
|
|
||||||
} else if (R == int) {
|
|
||||||
return result.toInt() as R;
|
|
||||||
} else if (R == double) {
|
|
||||||
return result.toDouble() as R;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
R? aggregateSync<R>(AggregationOp op) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> deleteFirst() {
|
|
||||||
return col.isar.getTxn(true, (IsarTxnJs txn) {
|
|
||||||
return queryJs.deleteFirst(txn).wait();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool deleteFirstSync() => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<int> deleteAll() {
|
|
||||||
return col.isar.getTxn(true, (IsarTxnJs txn) {
|
|
||||||
return queryJs.deleteAll(txn).wait();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int deleteAllSync() => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<List<T>> watch({bool fireImmediately = false}) {
|
|
||||||
JsFunction? stop;
|
|
||||||
final controller = StreamController<List<T>>(
|
|
||||||
onCancel: () {
|
|
||||||
stop?.apply([]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (fireImmediately) {
|
|
||||||
findAll().then(controller.add);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Null Function(List<dynamic> results) callback =
|
|
||||||
allowInterop((List<dynamic> results) {
|
|
||||||
controller.add(results.map((e) => deserialize(e as Object)).toList());
|
|
||||||
});
|
|
||||||
stop = col.native.watchQuery(queryJs, callback);
|
|
||||||
|
|
||||||
return controller.stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<void> watchLazy({bool fireImmediately = false}) {
|
|
||||||
JsFunction? stop;
|
|
||||||
final controller = StreamController<void>(
|
|
||||||
onCancel: () {
|
|
||||||
stop?.apply([]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
final Null Function() callback = allowInterop(() {
|
|
||||||
controller.add(null);
|
|
||||||
});
|
|
||||||
stop = col.native.watchQueryLazy(queryJs, callback);
|
|
||||||
|
|
||||||
return controller.stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<R> exportJsonRaw<R>(R Function(Uint8List) callback) async {
|
|
||||||
return col.isar.getTxn(false, (IsarTxnJs txn) async {
|
|
||||||
final result = await queryJs.findAll(txn).wait<dynamic>();
|
|
||||||
final jsonStr = stringify(result);
|
|
||||||
return callback(const Utf8Encoder().convert(jsonStr));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<Map<String, dynamic>>> exportJson() {
|
|
||||||
return col.isar.getTxn(false, (IsarTxnJs txn) async {
|
|
||||||
final result = await queryJs.findAll(txn).wait<List<dynamic>>();
|
|
||||||
return result.map((e) => jsMapToDart(e as Object)).toList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
R exportJsonRawSync<R>(R Function(Uint8List) callback) => unsupportedOnWeb();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Map<String, dynamic>> exportJsonSync({bool primitiveNull = true}) =>
|
|
||||||
unsupportedOnWeb();
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'package:isar/src/web/isar_web.dart';
|
|
||||||
|
|
||||||
List<String> isarSplitWords(String input) => unsupportedOnWeb();
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
@TestOn('vm')
|
|
||||||
|
|
||||||
// ignore_for_file: constant_identifier_names
|
|
||||||
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:isar/src/native/isar_core.dart';
|
|
||||||
import 'package:isar/src/native/isar_reader_impl.dart';
|
|
||||||
import 'package:isar/src/native/isar_writer_impl.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group('Golden Binary', () {
|
|
||||||
late final json =
|
|
||||||
File('../isar_core/tests/binary_golden.json').readAsStringSync();
|
|
||||||
late final tests = (jsonDecode(json) as List<dynamic>)
|
|
||||||
.map((e) => BinaryTest.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
test('IsarReader', () {
|
|
||||||
var t = 0;
|
|
||||||
for (final test in tests) {
|
|
||||||
final reader = IsarReaderImpl(Uint8List.fromList(test.bytes));
|
|
||||||
var offset = 2;
|
|
||||||
for (var i = 0; i < test.types.length; i++) {
|
|
||||||
final type = test.types[i];
|
|
||||||
final nullableValue = type.read(reader, offset, true);
|
|
||||||
expect(nullableValue, test.values[i], reason: '${test.types} $t');
|
|
||||||
|
|
||||||
final nonNullableValue = type.read(reader, offset, false);
|
|
||||||
_expectIgnoreNull(nonNullableValue, test.values[i], type);
|
|
||||||
offset += type.size;
|
|
||||||
}
|
|
||||||
t++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('IsarWriter', () {
|
|
||||||
for (final test in tests) {
|
|
||||||
final buffer = Uint8List(10000);
|
|
||||||
final size =
|
|
||||||
test.types.fold<int>(0, (sum, type) => sum + type.size) + 2;
|
|
||||||
|
|
||||||
final bufferView = buffer.buffer.asUint8List(0, test.bytes.length);
|
|
||||||
final writer = IsarWriterImpl(bufferView, size);
|
|
||||||
var offset = 2;
|
|
||||||
for (var i = 0; i < test.types.length; i++) {
|
|
||||||
final type = test.types[i];
|
|
||||||
final value = test.values[i];
|
|
||||||
type.write(writer, offset, value);
|
|
||||||
offset += type.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(buffer.sublist(0, test.bytes.length), test.bytes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Type {
|
|
||||||
Bool(1, false, _readBool, _writeBool),
|
|
||||||
Byte(1, 0, _readByte, _writeByte),
|
|
||||||
Int(4, nullInt, _readInt, _writeInt),
|
|
||||||
Float(4, nullFloat, _readFloat, _writeFloat),
|
|
||||||
Long(8, nullLong, _readLong, _writeLong),
|
|
||||||
Double(8, nullDouble, _readDouble, _writeDouble),
|
|
||||||
String(3, '', _readString, _writeString),
|
|
||||||
BoolList(3, false, _readBoolList, _writeBoolList),
|
|
||||||
ByteList(3, 0, _readByteList, _writeByteList),
|
|
||||||
IntList(3, nullInt, _readIntList, _writeIntList),
|
|
||||||
FloatList(3, nullFloat, _readFloatList, _writeFloatList),
|
|
||||||
LongList(3, nullLong, _readLongList, _writeLongList),
|
|
||||||
DoubleList(3, nullDouble, _readDoubleList, _writeDoubleList),
|
|
||||||
StringList(3, '', _readStringList, _writeStringList);
|
|
||||||
|
|
||||||
const Type(this.size, this.nullValue, this.read, this.write);
|
|
||||||
|
|
||||||
final int size;
|
|
||||||
final dynamic nullValue;
|
|
||||||
final dynamic Function(IsarReader reader, int offset, bool nullable) read;
|
|
||||||
final void Function(IsarWriter reader, int offset, dynamic value) write;
|
|
||||||
}
|
|
||||||
|
|
||||||
class BinaryTest {
|
|
||||||
const BinaryTest(this.types, this.values, this.bytes);
|
|
||||||
|
|
||||||
factory BinaryTest.fromJson(Map<String, dynamic> json) {
|
|
||||||
return BinaryTest(
|
|
||||||
(json['types'] as List)
|
|
||||||
.map((type) => Type.values.firstWhere((t) => t.name == type))
|
|
||||||
.toList(),
|
|
||||||
json['values'] as List,
|
|
||||||
(json['bytes'] as List).cast(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Type> types;
|
|
||||||
final List<dynamic> values;
|
|
||||||
final List<int> bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _expectIgnoreNull(
|
|
||||||
dynamic left,
|
|
||||||
dynamic right,
|
|
||||||
Type type, {
|
|
||||||
bool inList = false,
|
|
||||||
}) {
|
|
||||||
if (right == null && (type.index < Type.BoolList.index || inList)) {
|
|
||||||
if (left is double) {
|
|
||||||
expect(left, isNaN);
|
|
||||||
} else {
|
|
||||||
expect(left, type.nullValue);
|
|
||||||
}
|
|
||||||
} else if (right is List) {
|
|
||||||
left as List;
|
|
||||||
for (var i = 0; i < right.length; i++) {
|
|
||||||
_expectIgnoreNull(left[i], right[i], type, inList: true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
expect(left, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool? _readBool(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readBoolOrNull(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readBool(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeBool(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeBool(offset, value as bool?);
|
|
||||||
}
|
|
||||||
|
|
||||||
int? _readByte(IsarReader reader, int offset, bool nullable) {
|
|
||||||
return reader.readByte(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeByte(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeByte(offset, value as int);
|
|
||||||
}
|
|
||||||
|
|
||||||
int? _readInt(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readIntOrNull(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readInt(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeInt(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeInt(offset, value as int?);
|
|
||||||
}
|
|
||||||
|
|
||||||
double? _readFloat(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readFloatOrNull(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readFloat(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeFloat(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeFloat(offset, value as double?);
|
|
||||||
}
|
|
||||||
|
|
||||||
int? _readLong(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readLongOrNull(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readLong(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeLong(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeLong(offset, value as int?);
|
|
||||||
}
|
|
||||||
|
|
||||||
double? _readDouble(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readDoubleOrNull(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readDouble(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeDouble(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeDouble(offset, value as double?);
|
|
||||||
}
|
|
||||||
|
|
||||||
String? _readString(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readStringOrNull(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readString(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeString(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
final bytes = value is String ? utf8.encode(value) as Uint8List : null;
|
|
||||||
writer.writeByteList(offset, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<bool?>? _readBoolList(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readBoolOrNullList(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readBoolList(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeBoolList(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeBoolList(offset, (value as List?)?.cast());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<int>? _readByteList(IsarReader reader, int offset, bool nullable) {
|
|
||||||
return reader.readByteList(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeByteList(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
final bytes = value is List ? Uint8List.fromList(value.cast()) : null;
|
|
||||||
writer.writeByteList(offset, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<int?>? _readIntList(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readIntOrNullList(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readIntList(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeIntList(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeIntList(offset, (value as List?)?.cast());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<double?>? _readFloatList(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readFloatOrNullList(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readFloatList(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeFloatList(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeFloatList(offset, (value as List?)?.cast());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<int?>? _readLongList(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readLongOrNullList(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readLongList(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeLongList(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeLongList(offset, (value as List?)?.cast());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<double?>? _readDoubleList(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readDoubleOrNullList(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readDoubleList(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeDoubleList(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeDoubleList(offset, (value as List?)?.cast());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String?>? _readStringList(IsarReader reader, int offset, bool nullable) {
|
|
||||||
if (nullable) {
|
|
||||||
return reader.readStringOrNullList(offset);
|
|
||||||
} else {
|
|
||||||
return reader.readStringList(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _writeStringList(IsarWriter writer, int offset, dynamic value) {
|
|
||||||
writer.writeStringList(offset, (value as List?)?.cast());
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user