From cf0fe66386c56e9b5f13a2009a5963acda6acb76 Mon Sep 17 00:00:00 2001 From: Timm Preetz Date: Sun, 10 Nov 2024 11:16:02 +0100 Subject: [PATCH] Use stricter analysis options --- analysis_options.yaml | 122 ++++++++++++++++++++++++++- lib/src/index_columns.dart | 6 +- lib/src/index_entity_store.dart | 23 ++--- lib/src/indexed_entity_database.dart | 12 +-- lib/src/query.dart | 16 ++-- test/indexed_entity_store_test.dart | 97 ++++++++++++--------- 6 files changed, 207 insertions(+), 69 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index a5744c1..f29eae4 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1,120 @@ -include: package:flutter_lints/flutter.yaml +include: package:flutter_lints/flutter.yaml # https://github.com/flutter/packages/blob/main/packages/flutter_lints/lib/flutter.yaml -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options +analyzer: + language: + strict-casts: true + strict-raw-types: true + + errors: + always_declare_return_types: error + always_put_required_named_parameters_first: error + always_require_non_null_named_parameters: error + # Disabled due to the usage in "hand-rolled" from JSON, will be removed once we can make use of the JSON macro in tests & the example + argument_type_not_assignable: ignore + avoid_bool_literals_in_conditional_expressions: error + avoid_catching_errors: error + avoid_double_and_int_checks: error + avoid_empty_else: error + avoid_equals_and_hash_code_on_mutable_classes: error + avoid_escaping_inner_quotes: error + avoid_field_initializers_in_const_classes: error + avoid_function_literals_in_foreach_calls: error + avoid_init_to_null: error + avoid_js_rounded_ints: error + avoid_null_checks_in_equality_operators: error + avoid_returning_null_for_future: error + avoid_returning_null_for_void: error + avoid_returning_this: error + avoid_setters_without_getters: error + avoid_shadowing_type_parameters: error + avoid_single_cascade_in_expression_statements: error + avoid_slow_async_io: error + avoid_types_as_parameter_names: error + avoid_void_async: error + avoid_web_libraries_in_flutter: error + await_only_futures: error + camel_case_extensions: error + camel_case_types: error + cancel_subscriptions: error + close_sinks: error + control_flow_in_finally: error + curly_braces_in_flow_control_structures: error + do_not_use_environment: error + empty_catches: error + empty_constructor_bodies: error + empty_statements: error + exhaustive_cases: error + file_names: error + flutter_style_todos: error + hash_and_equals: error + implementation_imports: error + invariant_booleans: error + iterable_contains_unrelated_type: error + join_return_with_assignment: error + leading_newlines_in_multiline_strings: error + library_names: error + library_prefixes: error + list_remove_unrelated_type: error + missing_required_param: error + missing_return: error + unused_import: error + +linter: + rules: + - always_declare_return_types + - avoid_bool_literals_in_conditional_expressions + - avoid_catching_errors + - avoid_double_and_int_checks + - avoid_dynamic_calls + - avoid_empty_else + - avoid_equals_and_hash_code_on_mutable_classes + - avoid_escaping_inner_quotes + - avoid_field_initializers_in_const_classes + - avoid_init_to_null + - avoid_js_rounded_ints + - avoid_null_checks_in_equality_operators + - avoid_returning_null_for_void + - avoid_returning_this + - avoid_setters_without_getters + - avoid_shadowing_type_parameters + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_type_to_string + - avoid_types_as_parameter_names + - avoid_void_async + - avoid_web_libraries_in_flutter + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + - close_sinks + - collection_methods_unrelated_type + - control_flow_in_finally + - curly_braces_in_flow_control_structures + - depend_on_referenced_packages + - directives_ordering + - do_not_use_environment + - empty_catches + - empty_constructor_bodies + - empty_statements + - exhaustive_cases + - file_names + - flutter_style_todos + - hash_and_equals + - implementation_imports + - join_return_with_assignment + - leading_newlines_in_multiline_strings + - library_names + - library_prefixes + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + - prefer_iterable_whereType + - prefer_single_quotes + - require_trailing_commas + - sort_constructors_first + - test_types_in_equals + - type_annotate_public_apis + - unawaited_futures + - unrelated_type_equality_checks + - use_super_parameters diff --git a/lib/src/index_columns.dart b/lib/src/index_columns.dart index 5bf321c..c183d60 100644 --- a/lib/src/index_columns.dart +++ b/lib/src/index_columns.dart @@ -3,12 +3,12 @@ part of 'index_entity_store.dart'; /// The collection of indexed columns for a given [IndexedEntityStore] class IndexColumns { IndexColumns._( - Map indexColumns, + Map> indexColumns, ) : _indexColumns = Map.unmodifiable(indexColumns); - final Map _indexColumns; + final Map> _indexColumns; - IndexColumn operator [](String columnName) { + IndexColumn operator [](String columnName) { final col = _indexColumns[columnName]; if (col == null) { diff --git a/lib/src/index_entity_store.dart b/lib/src/index_entity_store.dart index 089fe86..8a693be 100644 --- a/lib/src/index_entity_store.dart +++ b/lib/src/index_entity_store.dart @@ -41,9 +41,9 @@ class IndexedEntityStore { String get _entityKey => _connector.entityKey; - final Map> _singleEntityResults = {}; + final Map>> _singleEntityResults = {}; - final List _entityResults = []; + final List> _entityResults = []; @visibleForTesting int get subscriptionCount { @@ -187,7 +187,7 @@ class IndexedEntityStore { if (whereClause != null) ' AND `entity`.`key` IN ( ${whereClause.$1} ) ', if (orderBy != null) 'AND `index`.`field` = ? ORDER BY `index`.`value` ${orderBy.$2 == SortOrder.asc ? 'ASC' : 'DESC'}', - if (limit != null) ' LIMIT ?' + if (limit != null) ' LIMIT ?', ].join(); final values = [ _entityKey, @@ -294,11 +294,13 @@ class IndexedEntityStore { // TODO(tp): QueryBuilder? where, final bool? all, }) { - assert(entity != null || - entities != null || - key != null || - keys != null || - all != null); + assert( + entity != null || + entities != null || + key != null || + keys != null || + all != null, + ); assert( all == null || (entity == null && entities == null && key == null && keys == null), @@ -325,7 +327,7 @@ class IndexedEntityStore { _handleUpdate( { - for (final row in result) row['key']!, + for (final row in result) row['key']! as K, }, ); } @@ -418,7 +420,8 @@ class IndexedEntityStore { if (newValue.dbValues.length == mapping.$2._value.value.dbValues.length && newValue.dbValues.indexed.every( - (e) => mapping.$2._value.value.dbValues[e.$1] == e.$2)) { + (e) => mapping.$2._value.value.dbValues[e.$1] == e.$2, + )) { continue; // values already match } diff --git a/lib/src/indexed_entity_database.dart b/lib/src/indexed_entity_database.dart index e6d72c9..5bf0059 100644 --- a/lib/src/indexed_entity_database.dart +++ b/lib/src/indexed_entity_database.dart @@ -3,7 +3,9 @@ import 'package:indexed_entity_store/indexed_entity_store.dart'; import 'package:sqlite3/sqlite3.dart'; class IndexedEntityDabase { - final Database _database; + factory IndexedEntityDabase.open(String path) { + return IndexedEntityDabase._(path); + } IndexedEntityDabase._(String path) : _database = sqlite3.open(path) { final res = _database.select( @@ -36,6 +38,8 @@ class IndexedEntityDabase { ); } + final Database _database; + void _initialDBSetup() { _database.execute('PRAGMA foreign_keys = ON'); @@ -95,10 +99,6 @@ class IndexedEntityDabase { ); } - factory IndexedEntityDabase.open(String path) { - return IndexedEntityDabase._(path); - } - IndexedEntityStore entityStore( IndexedEntityConnector connector, ) { @@ -110,7 +110,7 @@ class IndexedEntityDabase { ); } - dispose() { + void dispose() { _database.dispose(); } } diff --git a/lib/src/query.dart b/lib/src/query.dart index 56fd8e7..3dfc099 100644 --- a/lib/src/query.dart +++ b/lib/src/query.dart @@ -21,7 +21,7 @@ class _AndQuery extends Query { final Query second; @override - (String, List) _entityKeysQuery() { + (String, List) _entityKeysQuery() { return ( ' ${first._entityKeysQuery().$1} INTERSECT ${second._entityKeysQuery().$1} ', [...first._entityKeysQuery().$2, ...second._entityKeysQuery().$2], @@ -36,7 +36,7 @@ class _OrQuery extends Query { final Query second; @override - (String, List) _entityKeysQuery() { + (String, List) _entityKeysQuery() { return ( ' ${first._entityKeysQuery().$1} UNION ${second._entityKeysQuery().$1} ', [...first._entityKeysQuery().$2, ...second._entityKeysQuery().$2], @@ -52,7 +52,7 @@ class _EqualQuery extends Query { final dynamic value; @override - (String, List) _entityKeysQuery() { + (String, List) _entityKeysQuery() { if (this.value == null) { return ( 'SELECT `entity` FROM `index` WHERE `type` = ? AND `field` = ? AND `value` IS NULL', @@ -85,7 +85,7 @@ class _GreaterThanQuery extends Query { final dynamic value; @override - (String, List) _entityKeysQuery() { + (String, List) _entityKeysQuery() { final value = this.value is DateTime ? (this.value as DateTime).microsecondsSinceEpoch : this.value; @@ -111,7 +111,7 @@ class _LessThanQuery extends Query { final dynamic value; @override - (String, List) _entityKeysQuery() { + (String, List) _entityKeysQuery() { final value = this.value is DateTime ? (this.value as DateTime).microsecondsSinceEpoch : this.value; @@ -137,10 +137,10 @@ class _ContainsStringQuery extends Query { final bool caseInsensitive; @override - (String, List) _entityKeysQuery() { + (String, List) _entityKeysQuery() { if (caseInsensitive) { return ( - "SELECT `entity` FROM `index` WHERE `type` = ? AND `field` = ? AND `value` LIKE ?", + 'SELECT `entity` FROM `index` WHERE `type` = ? AND `field` = ? AND `value` LIKE ?', [ entity, field, @@ -150,7 +150,7 @@ class _ContainsStringQuery extends Query { } return ( - "SELECT `entity` FROM `index` WHERE `type` = ? AND `field` = ? AND `value` GLOB ?", + 'SELECT `entity` FROM `index` WHERE `type` = ? AND `field` = ? AND `value` GLOB ?', [ entity, field, diff --git a/test/indexed_entity_store_test.dart b/test/indexed_entity_store_test.dart index 0eddc6a..691ff71 100644 --- a/test/indexed_entity_store_test.dart +++ b/test/indexed_entity_store_test.dart @@ -41,50 +41,62 @@ void main() { ); expect( - fooStore.queryOnce(where: (cols) => cols['b'].equals(2)), hasLength(1)); + fooStore.queryOnce(where: (cols) => cols['b'].equals(2)), + hasLength(1), + ); expect( - fooStore.queryOnce(where: (cols) => cols['b'].equals(4)), hasLength(0)); + fooStore.queryOnce(where: (cols) => cols['b'].equals(4)), + hasLength(0), + ); expect( fooStore.queryOnce( - where: (cols) => cols['a'].equals('a') & cols['b'].equals(2)), + where: (cols) => cols['a'].equals('a') & cols['b'].equals(2), + ), hasLength(1), ); expect( fooStore.queryOnce( - where: (cols) => cols['a'].equals('b') & cols['b'].equals(2)), + where: (cols) => cols['a'].equals('b') & cols['b'].equals(2), + ), isEmpty, ); expect( fooStore.queryOnce( - where: (cols) => cols['a'].equals('a') & cols['b'].equals(3)), + where: (cols) => cols['a'].equals('a') & cols['b'].equals(3), + ), isEmpty, ); expect( fooStore.queryOnce( - where: (cols) => cols['a'].equals('b') & cols['b'].equals(3)), + where: (cols) => cols['a'].equals('b') & cols['b'].equals(3), + ), isEmpty, ); expect( fooStore.queryOnce( - where: (cols) => cols['a'].equals('a') | cols['b'].equals(3)), + where: (cols) => cols['a'].equals('a') | cols['b'].equals(3), + ), hasLength(1), ); expect( fooStore.queryOnce( - where: (cols) => cols['a'].equals('b') | cols['b'].equals(2)), + where: (cols) => cols['a'].equals('b') | cols['b'].equals(2), + ), hasLength(1), ); expect( fooStore.queryOnce( - where: (cols) => cols['a'].equals('b') | cols['b'].equals(3)), + where: (cols) => cols['a'].equals('b') | cols['b'].equals(3), + ), isEmpty, ); expect( () => fooStore.queryOnce( - where: (cols) => cols['does_not_exist'].equals('b')), + where: (cols) => cols['does_not_exist'].equals('b'), + ), throwsException, ); @@ -94,8 +106,10 @@ void main() { ); expect(fooStore.queryOnce(), hasLength(2)); - expect(fooStore.queryOnce(where: (cols) => cols['a'].equals('a')), - hasLength(2)); + expect( + fooStore.queryOnce(where: (cols) => cols['a'].equals('a')), + hasLength(2), + ); // delete initial fooStore.delete(key: 99); @@ -107,7 +121,7 @@ void main() { db.dispose(); - File(path).delete(); + File(path).deleteSync(); }); test( @@ -182,7 +196,7 @@ void main() { ); } - File(path).delete(); + File(path).deleteSync(); }, ); @@ -336,7 +350,7 @@ void main() { shortValues, [ [], - [isA<_ValueWrapper>().having((w) => w.value, 'value', 'one')] + [isA<_ValueWrapper>().having((w) => w.value, 'value', 'one')], ], ); } @@ -360,7 +374,7 @@ void main() { [isA<_ValueWrapper>().having((w) => w.value, 'value', 'one')], [ isA<_ValueWrapper>().having((w) => w.value, 'value', 'one'), - isA<_ValueWrapper>().having((w) => w.value, 'value', 'two') + isA<_ValueWrapper>().having((w) => w.value, 'value', 'two'), ], ], ); @@ -385,7 +399,7 @@ void main() { [isA<_ValueWrapper>().having((w) => w.value, 'value', 'one')], [ isA<_ValueWrapper>().having((w) => w.value, 'value', 'one'), - isA<_ValueWrapper>().having((w) => w.value, 'value', 'two') + isA<_ValueWrapper>().having((w) => w.value, 'value', 'two'), ], ], ); @@ -410,7 +424,7 @@ void main() { [isA<_ValueWrapper>().having((w) => w.value, 'value', 'one')], [ isA<_ValueWrapper>().having((w) => w.value, 'value', 'one'), - isA<_ValueWrapper>().having((w) => w.value, 'value', 'two') + isA<_ValueWrapper>().having((w) => w.value, 'value', 'two'), ], ], ); @@ -436,11 +450,11 @@ void main() { [isA<_ValueWrapper>().having((w) => w.value, 'value', 'one')], [ isA<_ValueWrapper>().having((w) => w.value, 'value', 'one'), - isA<_ValueWrapper>().having((w) => w.value, 'value', 'two') + isA<_ValueWrapper>().having((w) => w.value, 'value', 'two'), ], [ isA<_ValueWrapper>().having((w) => w.value, 'value', 'eins'), - isA<_ValueWrapper>().having((w) => w.value, 'value', 'two') + isA<_ValueWrapper>().having((w) => w.value, 'value', 'two'), ], ], ); @@ -795,7 +809,8 @@ void main() { ); expect( store.queryOnce( - where: (cols) => cols['dateTimeOpt'].lessThanOrEqual(now)), + where: (cols) => cols['dateTimeOpt'].lessThanOrEqual(now), + ), isEmpty, ); expect( @@ -804,13 +819,16 @@ void main() { ); expect( store.queryOnce( - where: (cols) => cols['dateTimeOpt'].greaterThanOrEqual(now)), + where: (cols) => cols['dateTimeOpt'].greaterThanOrEqual(now), + ), isEmpty, ); /// Numeric - expect(store.queryOnce(where: (cols) => cols['float'].equals(1000)), - hasLength(1)); + expect( + store.queryOnce(where: (cols) => cols['float'].equals(1000)), + hasLength(1), + ); expect( store.queryOnce(where: (cols) => cols['float'].greaterThan(1000)), isEmpty, @@ -821,7 +839,8 @@ void main() { ); expect( store.queryOnce( - where: (cols) => cols['float'].greaterThanOrEqual(1000.0)), + where: (cols) => cols['float'].greaterThanOrEqual(1000.0), + ), hasLength(1), ); @@ -879,7 +898,7 @@ void main() { final indexedEntityConnector = IndexedEntityConnector( entityKey: 'indexed_entity', - getPrimaryKey: (i) => "$i", + getPrimaryKey: (i) => '$i', getIndices: (index) { index((e) => e, as: 'value'); }, @@ -1264,19 +1283,6 @@ final fooConnectorWithIndexOnBAndC = ); class _AllSupportedIndexTypes { - final String string; - final String? stringOpt; - final num number; - final num? numberOpt; - final int integer; - final int? integerOpt; - final double float; - final double? floatOpt; - final bool boolean; - final bool? booleanOpt; - final DateTime dateTime; - final DateTime? dateTimeOpt; - _AllSupportedIndexTypes({ required this.string, required this.stringOpt, @@ -1322,6 +1328,19 @@ class _AllSupportedIndexTypes { ); } + final String string; + final String? stringOpt; + final num number; + final num? numberOpt; + final int integer; + final int? integerOpt; + final double float; + final double? floatOpt; + final bool boolean; + final bool? booleanOpt; + final DateTime dateTime; + final DateTime? dateTimeOpt; + Map toJSON() { return { 'string': string,