Release 2.0.0-dev.0

This commit is contained in:
Simon Leier
2022-01-14 01:28:36 +01:00
parent 60910d8dfb
commit bcb09c999f
23 changed files with 124 additions and 82 deletions
+1 -1
View File
@@ -1 +1 @@
tags/1.1.0
tags/1.1.1
+5 -1
View File
@@ -1,4 +1,4 @@
## Unreleased
## 2.0.0-dev.0
### Breaking
- The id for non-final objects is now assigned automatically after `.put()` and `.putSync()`
@@ -6,6 +6,7 @@
- `List<double>` indexes can no longer be hashed
- `.greaterThan()`, `.lessThan()` and `.between()` filters and are now excluding for `double` values (`>=` -> `>`)
- Changed the default index type for lists to `IndexType.value`
- `IsarLink` and `IsarLinks` will no longer initialized by Isar and must not be `nullable` or `late`.
### Enhancements
- Added `isar.clear()`, `isar.clearSync()`, `col.clear()` and `col.clearSync()`
@@ -24,6 +25,9 @@
- Fixed multi-entry index queries returning items multiple times in some cases
- Fixed `.anyLessThan()` and `.anyGreaterThan()` issues
- Fixed issues with backlinks
- Fixed issue where query only returned the first `99999` results
- Fixed issue with id where clauses
- `IsarLink` and `IsarLinks` can now be final
## 1.0.5
+3
View File
@@ -0,0 +1,3 @@
## The fastest way to get started is by following the [Quickstart Guide](https://isar.dev/quickstart.html)!
Have fun using Isar!
+4 -4
View File
@@ -23,13 +23,13 @@ abstract class IsarCollection<OBJ> {
@protected
Future<List<OBJ?>> getAllByIndex(
String indexName,
List<List<dynamic>> values,
List<List<Object?>> values,
);
/// Get a list of objects by the [indexName] index or `null` if an object
/// does not exist. Don't use this method directly.
@protected
List<OBJ?> getAllByIndexSync(String indexName, List<List<dynamic>> values);
List<OBJ?> getAllByIndexSync(String indexName, List<List<Object?>> values);
/// Insert or update an [object] and returns the assigned id.
Future<int> put(OBJ object, {bool replaceOnConflict = false}) {
@@ -72,12 +72,12 @@ abstract class IsarCollection<OBJ> {
/// Delete a list of objecs by the [indexName] index. Returns the number
/// of objects that have been deleted. Don't use this method directly.
@protected
Future<int> deleteAllByIndex(String indexName, List<List<dynamic>> values);
Future<int> deleteAllByIndex(String indexName, List<List<Object?>> values);
/// Delete a list of objecs by the [indexName] index. Returns the number
/// of objects that have been deleted. Don't use this method directly.
@protected
int deleteAllByIndexSync(String indexName, List<List<dynamic>> values);
int deleteAllByIndexSync(String indexName, List<List<Object?>> values);
/// Remove all data in this collection.
Future<void> clear();
+1 -1
View File
@@ -13,7 +13,7 @@ abstract class IsarLinkBase<OBJ> {
void saveSync();
void attach(IsarCollection col, IsarCollection<OBJ> targetCol,
dynamic containingObject, String linkName, bool backlink);
Object containingObject, String linkName, bool backlink);
}
abstract class IsarLink<OBJ> extends IsarLinkBase<OBJ> {
+4 -4
View File
@@ -7,7 +7,7 @@ import 'native_query_builder.dart';
final _keyPtrPtr = malloc<Pointer>();
Pointer<NativeType> buildIndexKey(
IsarCollectionImpl col, String indexName, List<dynamic> values) {
IsarCollectionImpl col, String indexName, List<Object?> values) {
final types = col.indexTypes[indexName]!;
if (values.length > types.length) {
throw 'Invalid values for index $indexName';
@@ -37,7 +37,7 @@ Pointer<NativeType> buildUpperUnboundedIndexKey(IsarCollectionImpl col) {
}
void _addKeyValue(
Pointer<NativeType> keyPtr, dynamic value, NativeIndexType type) {
Pointer<NativeType> keyPtr, Object? value, NativeIndexType type) {
switch (type) {
case NativeIndexType.bool:
if (value is bool?) {
@@ -71,13 +71,13 @@ void _addKeyValue(
break;
case NativeIndexType.string:
case NativeIndexType.stringCIS:
final strPtr = _strToNative(value);
final strPtr = _strToNative(value as String?);
IC.isar_key_add_string(keyPtr, strPtr, type == NativeIndexType.string);
_freeStr(strPtr);
break;
case NativeIndexType.stringHash:
case NativeIndexType.stringHashCIS:
final strPtr = _strToNative(value);
final strPtr = _strToNative(value as String?);
IC.isar_key_add_string_hash(
keyPtr, strPtr, type == NativeIndexType.stringHash);
_freeStr(strPtr);
@@ -96,7 +96,7 @@ class IsarCollectionImpl<OBJ> extends IsarCollection<OBJ> {
@pragma('vm:prefer-inline')
Pointer<Pointer<NativeType>> _getKeysPtr(
String indexName, List<List<dynamic>> values) {
String indexName, List<List<Object?>> values) {
final keysPtrPtr = malloc<Pointer>(values.length);
for (var i = 0; i < values.length; i++) {
keysPtrPtr[i] = buildIndexKey(this, indexName, values[i]);
@@ -337,6 +337,13 @@ class IsarLinksImpl<OBJ> extends IsarLinkBaseImpl<OBJ>
return false;
}
@override
void clear() {
_objects.clear();
_addedObjects.clear();
_removedObjects.clear();
}
@override
Set<OBJ> toSet() => _objects.toSet();
}
@@ -148,8 +148,8 @@ class NativeQuery<T> extends Query<T> {
final bytesPtrPtr = malloc<Pointer<Uint8>>();
final lengthPtr = malloc<Uint32>();
final idNamePtr = col.idName.toNativeUtf8();
IC.isar_q_export_json(queryPtr, col.ptr, txnPtr, idNamePtr.cast(),
primitiveNull, bytesPtrPtr, lengthPtr);
nCall(IC.isar_q_export_json(queryPtr, col.ptr, txnPtr, idNamePtr.cast(),
primitiveNull, bytesPtrPtr, lengthPtr));
try {
await stream.first;
@@ -47,7 +47,10 @@ Query<T> buildNativeQuery<T>(
}
}
IC.isar_qb_set_offset_limit(qbPtr, offset ?? 0, limit ?? 99999);
if (offset != null || limit != null) {
IC.isar_qb_set_offset_limit(qbPtr, offset ?? -1, limit ?? -1);
}
for (var distinctByProperty in distinctBy) {
final propertyId = col.propertyIds[distinctByProperty.property];
if (propertyId != null) {
@@ -83,10 +86,10 @@ Query<T> buildNativeQuery<T>(
void _addWhereClause(IsarCollectionImpl col, Pointer qbPtr, WhereClause wc,
bool? distinct, Sort? sort) {
if (wc.indexName == null) {
if (wc.lower != null && wc.lower!.length != 1 || wc.lower![0] is! int?) {
if (wc.lower != null && wc.lower!.length != 1 || wc.lower?[0] is! int?) {
throw 'Invalid WhereClause';
}
if (wc.upper != null && wc.upper!.length != 1 || wc.upper![0] is! int?) {
if (wc.upper != null && wc.upper!.length != 1 || wc.upper?[0] is! int?) {
throw 'Invalid WhereClause';
}
nCall(IC.isar_qb_add_id_where_clause(
@@ -253,9 +256,9 @@ Pointer<NativeType> _buildConditionInternal({
required IsarCollectionImpl col,
required ConditionType conditionType,
required int propertyId,
required dynamic val1,
required Object? val1,
required bool include1,
required dynamic val2,
required Object? val2,
required bool include2,
required bool caseSensitive,
}) {
@@ -286,11 +289,21 @@ Pointer<NativeType> _buildConditionInternal({
if (val == null) {
nCall(IC.isar_filter_null(col.ptr, filterPtrPtr, propertyId, true));
} else if (val is int) {
nCall(IC.isar_filter_long(col.ptr, filterPtrPtr, val1 ?? nullLong,
include1, val2 ?? maxLong, include2, propertyId));
nCall(IC.isar_filter_long(
col.ptr,
filterPtrPtr,
val1 as int? ?? nullLong,
include1,
val2 as int? ?? maxLong,
include2,
propertyId));
} else if (val is double) {
nCall(IC.isar_filter_double(col.ptr, filterPtrPtr, val1 ?? nullDouble,
val2 ?? maxDouble, propertyId));
nCall(IC.isar_filter_double(
col.ptr,
filterPtrPtr,
val1 as double? ?? nullDouble,
val2 as double? ?? maxDouble,
propertyId));
} else if (val is String) {
late Pointer<Int8> lowerPtr;
late Pointer<Int8> upperPtr;
+1 -1
View File
@@ -1,6 +1,6 @@
name: isar
description: Fast Cross Platform Database for Flutter & Web Apps. Supports indexes, FTS, queries etc.
version: 1.0.5
version: 2.0.0-dev.0
repository: https://github.com/isar/isar
homepage: https://isar.dev
+2 -2
View File
@@ -1,6 +1,6 @@
name: isar_connect
description: Use this package to connect your app to the Isar Inspector.
version: 1.0.5
version: 2.0.0-dev.0
repository: https://github.com/isar/isar
homepage: https://isar.dev
@@ -8,7 +8,7 @@ environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
isar: ">=1.0.0 <1.1.0"
isar: 2.0.0-dev.0
dev_dependencies:
lints: ^1.0.1
+2 -2
View File
@@ -1,6 +1,6 @@
name: isar_flutter_libs
description: Flutter binaries for the Isar Database. Needs to be included for Flutter apps.
version: 1.0.5
version: 2.0.0-dev.0
repository: https://github.com/isar/isar
homepage: https://isar.dev
@@ -11,7 +11,7 @@ environment:
dependencies:
flutter:
sdk: flutter
isar: ">=1.0.5 <1.1.0"
isar: 2.0.0-dev.0
flutter:
plugin:
@@ -1,3 +1,4 @@
import 'package:dartx/dartx.dart';
import 'package:isar_generator/src/object_info.dart';
String generateByIndexExtension(ObjectInfo oi) {
@@ -16,6 +17,12 @@ String generateByIndexExtension(ObjectInfo oi) {
}''';
}
extension on ObjectIndex {
String get dartName {
return properties.map((e) => e.property.dartName.capitalize()).join();
}
}
String generateSingleByIndex(ObjectInfo oi, ObjectIndex index) {
final params = index.properties
.map((i) => '${i.property.dartType} ${i.property.dartName}')
@@ -24,22 +31,22 @@ String generateSingleByIndex(ObjectInfo oi, ObjectIndex index) {
final getDeleteAllParams =
"'${index.properties.first.property.dartName}', [[$paramsList]]";
return '''
Future<${oi.dartName}?> getBy${index.name}($params) {
Future<${oi.dartName}?> getBy${index.dartName}($params) {
// ignore: invalid_use_of_protected_member
return getAllByIndex($getDeleteAllParams).then((e) => e[0]);
}
${oi.dartName}? getBy${index.name}Sync($params) {
${oi.dartName}? getBy${index.dartName}Sync($params) {
// ignore: invalid_use_of_protected_member
return getAllByIndexSync($getDeleteAllParams)[0];
}
Future<bool> deleteBy${index.name}($params) {
Future<bool> deleteBy${index.dartName}($params) {
// ignore: invalid_use_of_protected_member
return deleteAllByIndex($getDeleteAllParams).then((e) => e == 1);
}
bool deleteBy${index.name}Sync($params) {
bool deleteBy${index.dartName}Sync($params) {
// ignore: invalid_use_of_protected_member
return getAllByIndexSync($getDeleteAllParams) == 1;
}
@@ -48,22 +55,22 @@ String generateSingleByIndex(ObjectInfo oi, ObjectIndex index) {
String generateAllByIndex(ObjectInfo oi, ObjectIndex index) {
return '''
Future<List<${oi.dartName}?>> getAllBy${index.name}(List<List<dynamic>> values) {
Future<List<${oi.dartName}?>> getAllBy${index.dartName}(List<List<Object?>> values) {
// ignore: invalid_use_of_protected_member
return getAllByIndex('${index.name}', values);
}
List<${oi.dartName}?> getAllBy${index.name}Sync(List<List<dynamic>> values) {
List<${oi.dartName}?> getAllBy${index.dartName}Sync(List<List<Object?>> values) {
// ignore: invalid_use_of_protected_member
return getAllByIndexSync('${index.name}', values);
}
Future<int> deleteAllBy${index.name}(List<List<dynamic>> values) {
Future<int> deleteAllBy${index.dartName}(List<List<Object?>> values) {
// ignore: invalid_use_of_protected_member
return deleteAllByIndex('${index.name}', values);
}
int deleteAllBy${index.name}Sync(List<List<dynamic>> values) {
int deleteAllBy${index.dartName}Sync(List<List<Object?>> values) {
// ignore: invalid_use_of_protected_member
return deleteAllByIndexSync('${index.name}', values);
}
@@ -10,13 +10,11 @@ String generateCollectionSchema(ObjectInfo object) {
final propertyIds = object.objectProperties
.mapIndexed((index, p) => "'${p.dartName}': $index")
.join(',');
final indexIds = object.indexes
.mapIndexed(
(index, i) => "'${i.properties.first.property.dartName}': $index")
.join(',');
final indexIds =
object.indexes.mapIndexed((index, i) => "'${i.name}': $index").join(',');
final indexTypes = object.indexes
.map((i) =>
"'${i.properties.first.property.dartName}': [${i.properties.map((e) => e.indexTypeEnum).join(',')},]")
"'${i.name}': [${i.properties.map((e) => e.indexTypeEnum).join(',')},]")
.join(',');
final linkIds = object.links
.where((l) => !l.backlink)
@@ -11,24 +11,19 @@ class WhereGenerator {
WhereGenerator(this.object) : objName = object.dartName;
String generate() {
final primaryIndex = ObjectIndex(
name: '_id',
unique: true,
properties: [
ObjectIndexProperty(
property: object.idProperty,
type: IndexType.hash,
caseSensitive: false,
),
],
);
final indexes = [primaryIndex, ...object.indexes];
var code =
'extension ${objName}QueryWhereSort on QueryBuilder<$objName, $objName, QWhere> {';
for (var index in indexes) {
final idIndexProps = [
ObjectIndexProperty(
property: object.idProperty,
type: IndexType.value,
caseSensitive: false,
)
];
code += generateAny(null, idIndexProps);
for (var index in object.indexes) {
code += generateAny(index.name, index.properties);
}
@@ -38,7 +33,13 @@ class WhereGenerator {
extension ${objName}QueryWhere on QueryBuilder<$objName, $objName, QWhereClause> {
''';
for (var index in indexes) {
code += generateWhereEqualTo(null, idIndexProps);
code += generateWhereNotEqualTo(null, idIndexProps);
code += generateWhereGreaterThan(null, idIndexProps);
code += generateWhereLessThan(null, idIndexProps);
code += generateWhereBetween(null, idIndexProps);
for (var index in object.indexes) {
for (var n = 0; n < index.properties.length; n++) {
var properties = index.properties.sublist(0, n + 1);
@@ -129,12 +130,16 @@ class WhereGenerator {
}).join(', ');
}
String generateAny(String indexName, List<ObjectIndexProperty> properties) {
String generateAny(String? indexName, List<ObjectIndexProperty> properties) {
final name = 'any' + joinToName(properties, false).capitalize();
if (!existing.add(name)) return '';
return '''
QueryBuilder<$objName, $objName, QAfterWhere> $name() {
return addWhereClause(WhereClause(indexName: '$indexName'));
return addWhereClause(
WhereClause(
indexName: ${indexName == null ? null : "'$indexName'"}
)
);
}
''';
}
@@ -142,7 +147,7 @@ class WhereGenerator {
String get mPrefix => 'QueryBuilder<$objName, $objName, QAfterWhereClause>';
String generateWhereEqualTo(
String indexName, List<ObjectIndexProperty> properties) {
String? indexName, List<ObjectIndexProperty> properties) {
final name = joinToName(properties, false) + 'EqualTo';
if (!existing.add(name)) return '';
@@ -151,7 +156,7 @@ class WhereGenerator {
return '''
$mPrefix $name($params) {
return addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
lower: [$values],
includeLower: true,
upper: [$values],
@@ -162,7 +167,7 @@ class WhereGenerator {
}
String generateWhereNotEqualTo(
String indexName, List<ObjectIndexProperty> properties) {
String? indexName, List<ObjectIndexProperty> properties) {
final name = joinToName(properties, false) + 'NotEqualTo';
if (!existing.add(name)) return '';
@@ -172,21 +177,21 @@ class WhereGenerator {
$mPrefix $name($params) {
if (whereSortInternal == Sort.asc) {
return addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
upper: [$values],
includeUpper: false,
)).addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
lower: [$values],
includeLower: false,
));
} else {
return addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
lower: [$values],
includeLower: false,
)).addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
upper: [$values],
includeUpper: false,
));
@@ -196,7 +201,7 @@ class WhereGenerator {
}
String generateWhereGreaterThan(
String indexName, List<ObjectIndexProperty> properties) {
String? indexName, List<ObjectIndexProperty> properties) {
final name = joinToName(properties, true) + 'GreaterThan';
if (!existing.add(name)) return '';
@@ -205,7 +210,7 @@ class WhereGenerator {
return '''
$mPrefix $name(${joinToParams(properties)} $include) {
return addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
lower: [${joinToValues(properties)}],
includeLower: ${!properties.containsFloat ? 'include' : 'false'},
));
@@ -214,7 +219,7 @@ class WhereGenerator {
}
String generateWhereLessThan(
String indexName, List<ObjectIndexProperty> properties) {
String? indexName, List<ObjectIndexProperty> properties) {
final name = joinToName(properties, true) + 'LessThan';
if (!existing.add(name)) return '';
@@ -223,7 +228,7 @@ class WhereGenerator {
return '''
$mPrefix $name(${joinToParams(properties)} $include) {
return addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
upper: [${joinToValues(properties)}],
includeUpper: ${!properties.containsFloat ? 'include' : 'false'},
));
@@ -232,7 +237,7 @@ class WhereGenerator {
}
String generateWhereBetween(
String indexName, List<ObjectIndexProperty> properties) {
String? indexName, List<ObjectIndexProperty> properties) {
final firstPs = properties.sublist(0, properties.length - 1);
final lastP = properties.last;
final name = joinToName(properties, true) + 'Between';
@@ -258,7 +263,7 @@ class WhereGenerator {
return '''
$mPrefix $name($params $include) {
return addWhereClause(WhereClause(
indexName: '$indexName',
indexName: ${indexName == null ? null : "'$indexName'"},
lower: [$values $lowerName],
includeLower: ${!properties.containsFloat ? 'includeLower' : 'false'},
upper: [$values $upperName],
@@ -5,7 +5,6 @@ import 'package:isar_generator/src/code_gen/collection_schema_generator.dart';
import 'package:isar_generator/src/isar_analyzer.dart';
import 'package:source_gen/source_gen.dart';
import 'package:isar/isar.dart';
import 'package:dartx/dartx.dart';
import 'code_gen/by_index_generator.dart';
import 'code_gen/object_adapter_generator.dart';
@@ -172,6 +172,12 @@ class IsarAnalyzer {
if (!isLink && !isLinks) return null;
if (property.type.nullabilitySuffix != NullabilitySuffix.none) {
err('Link properties must not be nullable.', property);
} else if (property.isLate) {
err('Link properties must not be late.', property);
}
final type = property.type as ParameterizedType;
if (type.typeArguments.length != 1) {
err('Illegal type arguments for link.', property);
@@ -215,7 +221,7 @@ class IsarAnalyzer {
List<ObjectProperty> properties, PropertyInducingElement element) sync* {
final property =
properties.firstOrNullWhere((it) => it.dartName == element.name);
if (property == null) return;
if (property == null || property.isId) return;
for (var index in element.indexAnnotations) {
final indexProperties = <ObjectIndexProperty>[];
@@ -235,6 +241,8 @@ class IsarAnalyzer {
properties.firstOrNullWhere((it) => it.dartName == c.property);
if (compositeProperty == null) {
err('Property does not exist: "${c.property}".', element);
} else if (compositeProperty.isId) {
err('The Id property cannot be part of composite indexes.', element);
} else {
indexProperties.add(ObjectIndexProperty(
property: compositeProperty,
@@ -1,5 +1,3 @@
import 'dart:typed_data';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:isar/isar.dart';
+2 -2
View File
@@ -1,6 +1,6 @@
name: isar_generator
description: Code generator for the Isar Database. Finds classes annotated with @IsarCollection.
version: 1.0.5
version: 2.0.0-dev.0
repository: https://github.com/isar/isar
homepage: https://isar.dev
@@ -8,7 +8,7 @@ environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
isar: ">=1.0.0 <1.1.0"
isar: 2.0.0-dev.0
build: ^2.1.0
source_gen: ^1.0.5
analyzer: ^3.0.0
+2 -2
View File
@@ -83,8 +83,8 @@ class AppState extends ChangeNotifier {
int _subscriptionHandle = 0;
List<Map<String, dynamic>>? _objects;
List<Map<String, dynamic>>? get objects => _objects;
List<Map<String, Object>>? _objects;
List<Map<String, Object>>? get objects => _objects;
FilterOperation _filter = const FilterGroup.or([]);
FilterOperation get filter => _filter;
@@ -178,7 +178,7 @@ class _CollectionTableState extends State<CollectionTable> {
}
Widget _buildRow(ThemeData theme, Collection collection,
Map<String, dynamic> object, int index) {
Map<String, Object> object, int index) {
return IsarCard(
color: index % 2 == 0 ? Colors.transparent : null,
radius: BorderRadius.circular(15),
+1 -1
View File
@@ -53,7 +53,7 @@ class Service {
return (instances as List).cast();
}
Future<List<Map<String, dynamic>>> executeQuery(
Future<List<Map<String, Object>>> executeQuery(
String instance,
String collection,
FilterOperation filter,