Migrate to `package:lints`

This commit is contained in:
Simon Binder 2022-08-13 23:33:05 +02:00
parent 72fb1fa60c
commit 8f6878292a
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
65 changed files with 161 additions and 517 deletions

View File

@ -1,174 +0,0 @@
analyzer:
strong-mode:
implicit-casts: false
errors:
unused_element: error
unused_import: error
unused_local_variable: error
dead_code: error
public_member_api_docs: ignore # turned on by user-facing subpackages
deprecated_member_use_from_same_package: ignore
exclude:
- "**/*.g.dart"
# Will be analyzed anyway, nobody knows why ¯\_(ツ)_/¯. We're only analyzing lib/ and test/ as a workaround
- ".dart_tool/build/entrypoint/build.dart"
- "**/*.mocks.dart"
# this should always include all rules. Those we don't use are commented out
linter:
rules:
# ERROR RULES
- avoid_empty_else
# - avoid_print (all our prints can be turned off)
- avoid_relative_lib_imports
- avoid_returning_null_for_future
# - avoid_slow_async_io
- avoid_types_as_parameter_names
- cancel_subscriptions
- close_sinks
- comment_references
- control_flow_in_finally
# - diagnostic_describe_all_properties (Flutter-specific, not relevant for us)
- empty_statements
- hash_and_equals
# - invariant_booleans (turned off because the lint rule is buggy)
- iterable_contains_unrelated_type
- list_remove_unrelated_type
- literal_only_boolean_expressions
- no_adjacent_strings_in_list
- no_duplicate_case_values
# - prefer_relative_imports (clashes with avoid_relative_lib_imports)
# - prefer_void_to_null (we do use Null as a type for alwaysThrows functions)
- test_types_in_equals
- throw_in_finally
- unnecessary_statements
- unrelated_type_equality_checks
- unsafe_html
- valid_regexps
# STYLE RULES
- always_declare_return_types
# - always_put_control_body_on_new_line (we don't do this if it fits on the same line)
# - always_put_required_named_parameters_first (we just don't do this)
# - always_require_non_null_named_parameters (we don't use assert foo != null for parameters)
# - always_specify_types (we prefer to omit the type parameter when possible)
- annotate_overrides
# - avoid_annotating_with_dynamic (we prefer to make dynamic explicit)
# - avoid_as (we prefer to make explicit casts explicit!)
- avoid_bool_literals_in_conditional_expressions
# - avoid_catches_without_on_clauses (we have a lot of generic catches)
- avoid_catching_errors
- avoid_classes_with_only_static_members
- avoid_double_and_int_checks
# - avoid_equals_and_hash_code_on_mutable_classes (lint is to generic for transient fields)
- avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls
# - avoid_implementing_value_types (maybe we can consider turning this on?)
- avoid_init_to_null
- avoid_js_rounded_ints
- avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters (there pretty useful when there's only one boolean param)
# - avoid_private_typedef_functions (they're still useful)
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_void
- avoid_returning_this
- avoid_setters_without_getters
- avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements
# - avoid_types_on_closure_parameters (the interference isn't THAT good)
# - avoid_unnecessary_containers (Flutter-specific, not relevant here)
- avoid_unused_constructor_parameters
- avoid_void_async
- await_only_futures
- camel_case_extensions
- camel_case_types
# - cascade_invocations (sometimes the explicit notation is more readable)
- constant_identifier_names
- curly_braces_in_flow_control_structures
- directives_ordering
- empty_catches
- empty_constructor_bodies
- file_names
# - flutter_style_todos (Flutter-development specific, not relevant here)
- implementation_imports
- join_return_with_assignment
- library_names
- library_prefixes
- lines_longer_than_80_chars
- non_constant_identifier_names
- null_closures
- omit_local_variable_types
# - one_member_abstracts (there are cases where a one-member abstract class makes sense, see moor's Insertable)
- only_throw_errors
- overridden_fields
- package_api_docs
# - package_prefixed_library_names (this isn't java)
# - parameter_assignments (we regularly use this to set default values)
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
# - prefer_asserts_with_message (it's annoying to write messages for internal invariants)
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
# - prefer_double_quotes (we prefer single quotes)
- prefer_equal_for_default_values
# - prefer_expression_function_bodies (for multiline expressions, this is ugly to format)
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- prefer_for_elements_to_map_fromIterable
- prefer_foreach
- prefer_function_declarations_over_variables
- prefer_generic_function_type_aliases
- prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators
- prefer_initializing_formals
- prefer_inlined_adds
- prefer_int_literals
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_iterable_whereType
# - prefer_mixin (todo we could consider enabling this)
- prefer_null_aware_operators
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- provide_deprecation_message
- public_member_api_docs
- recursive_getters
- slash_for_doc_comments
# - sort_child_properties_last (Flutter specific)
# - sort_constructors_first (we don't do this)
# - sort_unnamed_constructors_first
- type_annotate_public_apis
- type_init_formals
- unawaited_futures
- unnecessary_brace_in_string_interps
- unnecessary_const
# - unnecessary_final (we prefer final here)
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_this
# - use_full_hex_values_for_flutter_colors (Flutter specific)
- use_function_type_syntax_for_parameters
- use_rethrow_when_possible
- use_setters_to_change_properties
- use_string_buffers
# - use_to_and_as_if_applicable (false positive on operators)
- void_checks
# PUB RULES
- package_names
# - sort_pub_dependencies (we prefer to group them by what they do)

View File

@ -0,0 +1,7 @@
include: package:lints/recommended.yaml
analyzer:
strong-mode:
implicit-casts: false
exclude:
- "**/*.g.dart"

View File

@ -15,10 +15,22 @@ dependencies:
code_snippets:
hosted: https://simonbinder.eu
version: ^0.0.8
# used in snippets
http: ^0.13.5
sqlite3: ^1.7.2
# Fake path_provider for snippets
path_provider:
path: assets/path_provider
# Used in examples
rxdart: ^0.27.3
yaml: ^3.1.1
drift_dev: any
dev_dependencies:
lints: ^2.0.0
build: ^2.1.0
build_runner: ^2.0.5
build_runner_core: ^7.2.3
build_web_compilers: ^3.2.0
built_site:
hosted: https://simonbinder.eu
@ -27,15 +39,9 @@ dev_dependencies:
json_serializable: ^6.1.6
shelf: ^1.2.0
shelf_static: ^1.1.0
# Fake path_provider for snippets
path_provider:
path: assets/path_provider
# Used in examples
rxdart: ^0.27.3
source_span: ^1.9.1
sqlparser:
drift_dev:
dependency_overrides:
moor_generator:

View File

@ -28,7 +28,7 @@ Future<void> main() async {
'', ['github.com', 'pub.dev', 'api.dart.dev', 'fonts.gstatic.com']),
false,
false,
const Stream<Null /*Never*/ >.empty(),
const Stream<void /*Never*/ >.empty(),
stdout,
);
} finally {

View File

@ -1,10 +1,7 @@
include: ../analysis_options.yaml
include: package:lints/recommended.yaml
analyzer:
errors:
public_member_api_docs: warning
deprecated_member_use_from_same_package: ignore
strong-mode:
implicit-casts: false
exclude:
- "example_web/**"
- "**/*.g.dart"
- "**/*.mocks.dart"

View File

@ -103,9 +103,7 @@ class DriftIsolate {
/// Creates a new [DriftIsolate] on a background thread.
///
/// The [opener] function will be used to open the [DatabaseConnection] used
/// by the isolate. Most implementations are likely to use
/// [DatabaseConnection.fromExecutor] instead of providing stream queries and
/// the type system manually.
/// by the isolate.
///
/// Because [opener] will be called on another isolate with its own memory,
/// it must either be a top-level member or a static class method.

View File

@ -264,6 +264,7 @@ extension BuildColumn<T extends Object> on ColumnBuilder<T> {
}
/// Column builders available for both virtual and non-virtual columns.
// ignore: library_private_types_in_public_api
extension BuildGeneralColumn<T extends Object> on _BaseColumnBuilder<T> {
/// By default, the field name will be used as the column name, e.g.
/// `IntColumn get id = integer()` will have "id" as its associated name.

View File

@ -5,8 +5,6 @@ const _zoneRootUserKey = #DatabaseConnectionUser;
typedef _CustomWriter<T> = Future<T> Function(
QueryExecutor e, String sql, List<dynamic> vars);
typedef _BatchRunner = FutureOr<void> Function(Batch batch);
/// Manages a [DatabaseConnection] to send queries to the database.
abstract class DatabaseConnectionUser {
/// The database connection used by this [DatabaseConnectionUser].
@ -158,21 +156,6 @@ abstract class DatabaseConnectionUser {
return executor.ensureOpen(attachedDatabase).then((_) => fn(executor));
}
/// Captures a [table] or view for easier subsequent operations.
///
/// The [TableOrViewOperations] class (or the [TableOperations] extension
/// for tables) provides convenience methods that make common operations
/// easier to write than using the methods from this class directly.
///
/// This method is deprecated. For an even easier access, the methods that
/// were made available here are now available on the [table] or view instance
/// directly.
@Deprecated('Experiment ended - use the methods on the [table] directly')
TableOrViewOperations<T, D> from<T extends HasResultSet, D>(
ResultSetImplementation<T, D> table) {
return TableOrViewOperations._(this, table);
}
/// Starts an [InsertStatement] for a given table. You can use that statement
/// to write data into the [table] by using [InsertStatement.insert].
InsertStatement<T, D> into<T extends Table, D>(TableInfo<T, D> table) {
@ -519,7 +502,7 @@ abstract class DatabaseConnectionUser {
/// );
/// });
/// ```
Future<void> batch(_BatchRunner runInBatch) {
Future<void> batch(FutureOr<void> Function(Batch batch) runInBatch) {
final engine = resolvedEngine;
final batch = Batch._(engine, engine is! Transaction);
@ -586,125 +569,6 @@ abstract class DatabaseConnectionUser {
}
}
/// A capture of a table and a generated database.
///
/// Table operations can be captured with [DatabaseConnectionUser.from], which
/// may make some common operations easier to write:
///
/// - Use `from(table).select()` or `from(table).selectOnly()` instead of
/// `select(table)` or `selectOnly(table)`, respectively.
/// - Use `from(table).insert()` instead of `insert(table)`. You can also use
/// `from(table).insertOne`, or [TableOperations.insertOnConflictUpdate] to
/// insert rows directly.
/// - Use `from(table).update()` instead of `update(table)`. You can also use
/// `from(table).replace()` to replace an existing row.
/// - Use `from(table).delete()`, `from(table).deleteOne()` or
/// `from(table).deleteWhere` to delete rows easily.
@sealed
class TableOrViewOperations<Tbl extends HasResultSet, Row> {
final DatabaseConnectionUser _user;
final ResultSetImplementation<Tbl, Row> _sourceSet;
TableOrViewOperations._(this._user, this._sourceSet);
/// Composes a `SELECT` statement on the captured table or view.
///
/// This is equivalent to calling [DatabaseConnectionUser.select].
SimpleSelectStatement<Tbl, Row> select({bool distinct = false}) {
return _user.select(_sourceSet, distinct: distinct);
}
/// Composes a `SELECT` statement only selecting a subset of columns.
///
/// This is equivalent to calling [DatabaseConnectionUser.selectOnly].
JoinedSelectStatement<Tbl, Row> selectOnly({bool distinct = false}) {
return _user.selectOnly(_sourceSet, distinct: distinct);
}
}
/// Additional methods for a [TableOrViewOperations] that are only available on
/// tables.
extension TableOperations<Tbl extends Table, Row>
on TableOrViewOperations<Tbl, Row> {
TableInfo<Tbl, Row> get _table => _sourceSet as TableInfo<Tbl, Row>;
/// Creates an insert statment to be used to compose an insert on the captured
/// table.
///
/// This is equivalent to calling [DatabaseConnectionUser.into] on the
/// captured table. See that method for more information.
InsertStatement<Tbl, Row> insert() => _user.into(_table);
/// Inserts one row into the captured table.
///
/// This is equivalent to calling [InsertStatement.insert] - see that method
/// for more information.
Future<int> insertOne(
Insertable<Row> row, {
InsertMode? mode,
UpsertClause<Tbl, Row>? onConflict,
}) {
return insert().insert(row, mode: mode, onConflict: onConflict);
}
/// Inserts one row into the captured table, replacing an existing row if it
/// exists already.
///
/// Please note that this method is only available on recent sqlite3 versions.
/// See also [InsertStatement.insertOnConflictUpdate].
Future<int> insertOnConflictUpdate(Insertable<Row> row) {
return insert().insertOnConflictUpdate(row);
}
/// Inserts one row into the captured table and returns it, along with auto-
/// generated fields.
///
/// Please note that this method is only available on recent sqlite3 versions.
/// See also [InsertStatement.insertReturning].
Future<Row> insertReturning(
Insertable<Row> row, {
InsertMode? mode,
UpsertClause<Tbl, Row>? onConflict,
}) {
return insert().insertReturning(
row,
mode: mode,
onConflict: onConflict,
);
}
/// Creates a statement to compose an `UPDATE` into the database.
///
/// This is equivalent to calling [DatabaseConnectionUser.update] with the
/// captured table.
UpdateStatement<Tbl, Row> update() => _user.update(_table);
/// Replaces a single row with an update statement.
///
/// See also [UpdateStatement.replace].
Future<void> replace(Insertable<Row> row) {
return update().replace(row);
}
/// Creates a statement to compose a `DELETE` from the database.
///
/// This is equivalent to calling [DatabaseConnectionUser.delete] with the
/// captured table.
DeleteStatement<Tbl, Row> delete() => _user.delete(_table);
/// Deletes the [row] from the captured table.
Future<bool> deleteOne(Insertable<Row> row) async {
return await (delete()..whereSamePrimaryKey(row)).go() != 0;
}
/// Deletes all rows matching the [filter] from the table.
///
/// See also [SingleTableQueryMixin.where].
Future<int> deleteWhere(Expression<bool> Function(Tbl tbl) filter) {
return (delete()..where(filter)).go();
}
}
extension on TransactionExecutor {
Future<void> rollbackAfterException(
Object exception, StackTrace trace) async {

View File

@ -217,9 +217,9 @@ class _DefaultValueSerializer extends ValueSerializer {
return null as T;
}
final _typeList = <T>[];
final typeList = <T>[];
if (_typeList is List<DateTime?>) {
if (typeList is List<DateTime?>) {
if (json is int) {
return DateTime.fromMillisecondsSinceEpoch(json) as T;
} else {
@ -227,13 +227,13 @@ class _DefaultValueSerializer extends ValueSerializer {
}
}
if (_typeList is List<double?> && json is int) {
if (typeList is List<double?> && json is int) {
return json.toDouble() as T;
}
// blobs are encoded as a regular json array, so we manually convert that to
// a Uint8List
if (_typeList is List<Uint8List?> && json is! Uint8List) {
if (typeList is List<Uint8List?> && json is! Uint8List) {
final asList = (json as List).cast<int>();
return Uint8List.fromList(asList) as T;
}

View File

@ -171,6 +171,7 @@ class _StatementBasedTransactionExecutor extends _TransactionExecutor {
final String _commitCommand;
final String _rollbackCommand;
// ignore: no_leading_underscores_for_local_identifiers
_StatementBasedTransactionExecutor(super._db, this._delegate)
: _startCommand = _delegate.start,
_commitCommand = _delegate.commit,

View File

@ -90,7 +90,7 @@ class StreamQueryStore {
if (key != null) {
final cached = _activeKeyStreams[key];
if (cached != null) {
return cached.stream;
return cached._stream;
}
}
@ -103,7 +103,7 @@ class StreamQueryStore {
// weak reference with an Expando could help.
markAsOpened(stream);
return stream.stream;
return stream._stream;
}
Stream<Set<TableUpdate>> updatesForSync(TableUpdateQuery query) {
@ -189,7 +189,7 @@ class QueryStream {
// We're using a Stream.multi to implement a broadcast-ish stream with per-
// subscription pauses.
late final Stream<_Row> stream = Stream.multi(
late final Stream<_Row> _stream = Stream.multi(
(listener) {
final queryListener = _QueryStreamListener(listener);

View File

@ -24,7 +24,7 @@ const Map<_JoinType, String> _joinKeywords = {
/// [Join] instance.
class Join<T extends HasResultSet, D> extends Component {
/// The [_JoinType] of this join.
final _JoinType type;
final _JoinType _type;
/// The [TableInfo] that will be added to the query
final Table table;
@ -43,7 +43,7 @@ class Join<T extends HasResultSet, D> extends Component {
/// Constructs a [Join] by providing the relevant fields. [on] is optional for
/// [_JoinType.cross].
Join._(this.type, this.table, this.on, {this.includeInResult}) {
Join._(this._type, this.table, this.on, {this.includeInResult}) {
if (table is! ResultSetImplementation<T, D>) {
throw ArgumentError(
'Invalid table parameter. You must provide the table reference from '
@ -54,14 +54,14 @@ class Join<T extends HasResultSet, D> extends Component {
@override
void writeInto(GenerationContext context) {
context.buffer.write(_joinKeywords[type]);
context.buffer.write(_joinKeywords[_type]);
context.buffer.write(' JOIN ');
final resultSet = table as ResultSetImplementation<T, D>;
context.buffer.write(resultSet.tableWithAlias);
context.watchedTables.add(resultSet);
if (type != _JoinType.cross) {
if (_type != _JoinType.cross) {
context.buffer.write(' ON ');
on!.writeInto(context);
}

View File

@ -145,7 +145,7 @@ class Migrator {
Future<void> alterTable(TableMigration migration) async {
final foreignKeysEnabled =
(await _db.customSelect('PRAGMA foreign_keys').getSingle())
.readBool('foreign_keys');
.read<bool>('foreign_keys');
if (foreignKeysEnabled) {
await _db.customStatement('PRAGMA foreign_keys = OFF;');
@ -168,9 +168,9 @@ class Migrator {
final createAffected = <String>[];
for (final row in schemaQuery) {
final type = row.readString('type');
final type = row.read<String>('type');
final sql = row.readNullable<String>('sql');
final name = row.readString('name');
final name = row.read<String>('name');
if (sql == null) {
// These indexes are created by sqlite to enforce different kinds of
@ -253,7 +253,7 @@ class Migrator {
void _writeCreateTable(TableInfo table, GenerationContext context) {
context.buffer.write('CREATE TABLE IF NOT EXISTS '
'${escapeIfNeeded(table.$tableName, context.dialect)} (');
'${escapeIfNeeded(table.aliasedName, context.dialect)} (');
var hasAutoIncrement = false;
for (var i = 0; i < table.$columns.length; i++) {
@ -327,7 +327,7 @@ class Migrator {
void _writeCreateVirtual(VirtualTableInfo table, GenerationContext context) {
context.buffer
..write('CREATE VIRTUAL TABLE IF NOT EXISTS ')
..write(escapeIfNeeded(table.$tableName))
..write(escapeIfNeeded(table.aliasedName))
..write(' USING ')
..write(table.moduleAndArgs)
..write(';');
@ -393,7 +393,7 @@ class Migrator {
final context = _createContext();
context.buffer
.write('ALTER TABLE ${escapeIfNeeded(table.$tableName)} ADD COLUMN ');
.write('ALTER TABLE ${escapeIfNeeded(table.aliasedName)} ADD COLUMN ');
column.writeColumnDefinition(context);
context.buffer.write(';');
@ -421,7 +421,7 @@ class Migrator {
TableInfo table, String oldName, GeneratedColumn column) async {
final context = _createContext();
context.buffer
..write('ALTER TABLE ${escapeIfNeeded(table.$tableName)} ')
..write('ALTER TABLE ${escapeIfNeeded(table.aliasedName)} ')
..write('RENAME COLUMN ${escapeIfNeeded(oldName)} ')
..write('TO ${column.escapedName};');

View File

@ -191,6 +191,7 @@ class GeneratedColumn<T extends Object> extends Column<T> {
if (!nullOk && value == null) {
return _invalidNull;
} else {
// ignore: null_check_on_nullable_type_parameter
return additionalChecks?.call(value!, meta) ??
const VerificationResult.success();
}

View File

@ -36,15 +36,10 @@ mixin TableInfo<TableDsl extends Table, D> on Table
@override
List<Set<GeneratedColumn>> get uniqueKeys => const [];
/// The table name in the sql table. This can be an alias for the actual table
/// name. See [actualTableName] for a table name that is not aliased.
@Deprecated('Use aliasedName instead')
String get $tableName => aliasedName;
@override
String get aliasedName => entityName;
/// The name of the table in the database. Unless [$tableName], this can not
/// The name of the table in the database. Unlike [aliasedName], this can not
/// be aliased.
String get actualTableName;
@ -100,7 +95,8 @@ mixin TableInfo<TableDsl extends Table, D> on Table
bool operator ==(Object other) {
// tables are singleton instances except for aliases
if (other is TableInfo) {
return other.runtimeType == runtimeType && other.$tableName == $tableName;
return other.runtimeType == runtimeType &&
other.aliasedName == aliasedName;
}
return false;
}

View File

@ -156,7 +156,7 @@ class InsertStatement<T extends Table, D> {
..write(_insertKeywords[
ctx.dialect == SqlDialect.postgres ? InsertMode.insert : mode])
..write(' INTO ')
..write(table.$tableName)
..write(table.aliasedName)
..write(' ');
if (map.isEmpty) {
@ -251,7 +251,7 @@ class InsertStatement<T extends Table, D> {
void _validateIntegrity(Insertable<D>? d) {
if (d == null) {
throw InvalidDataException(
'Cannot write null row into ${table.$tableName}');
'Cannot write null row into ${table.entityName}');
}
table.validateIntegrity(d, isInserting: true).throwIfInvalid(d);

View File

@ -91,7 +91,7 @@ class JoinedSelectStatement<FirstT extends HasResultSet, FirstD>
String chosenAlias;
if (column is GeneratedColumn) {
if (ctx.generatingForView == column.tableName) {
chosenAlias = '${column.$name}';
chosenAlias = column.$name;
} else {
chosenAlias = '${column.tableName}.${column.$name}';
}

View File

@ -10,6 +10,7 @@ import 'package:js/js_util.dart';
external Object /*Promise<_SqlJs>*/ _initSqlJs();
@JS('undefined')
// ignore: prefer_void_to_null
external Null get _undefined;
@JS('eval')

View File

@ -27,6 +27,7 @@ dev_dependencies:
drift_docs:
path: ../docs/
http: ^0.13.4
lints: ^2.0.0
uuid: ^3.0.0
path: ^1.8.0
build_runner: ^2.0.0

View File

@ -11,7 +11,7 @@ void main() {
});
test('supports escaping snigle quotes', () {
testStringMapping('what\'s that?', "'what\'\'s that?'");
testStringMapping('what\'s that?', "'what''s that?'");
});
test('other chars are not escaped', () {

View File

@ -59,8 +59,8 @@ void _testWith(TodoDb Function() openDb, {bool dateTimeAsText = false}) {
test('plus and minus', () async {
const nowExpr = currentDateAndTime;
final tomorrow = nowExpr + const Duration(days: 1);
final nowStamp = nowExpr.secondsSinceEpoch;
final tomorrowStamp = tomorrow.secondsSinceEpoch;
final nowStamp = nowExpr.unixepoch;
final tomorrowStamp = tomorrow.unixepoch;
final row = await (db.selectOnly(db.users)
..addColumns([nowStamp, tomorrowStamp]))

View File

@ -9,6 +9,7 @@ void main() {
CustomExpression<int>('name', precedence: Precedence.primary);
test('IS NULL expressions are generated', () {
// ignore: deprecated_member_use_from_same_package
final oldFunction = drift.isNull(innerExpression);
final extension = innerExpression.isNull();
@ -19,6 +20,7 @@ void main() {
});
test('IS NOT NULL expressions are generated', () {
// ignore: deprecated_member_use_from_same_package
final oldFunction = drift.isNotNull(innerExpression);
final extension = innerExpression.isNotNull();

View File

@ -53,11 +53,11 @@ void main() {
final rows = await db.customSelect('').get();
final row = rows.single;
expect(row.readBool('bool'), isTrue);
expect(row.readInt('int'), 3);
expect(row.readDouble('double'), 3.14);
expect(row.readDateTime('dateTime'), time);
expect(row.readBlob('blob'), Uint8List.fromList([1, 2, 3]));
expect(row.read<bool>('bool'), isTrue);
expect(row.read<int>('int'), 3);
expect(row.read<double>('double'), 3.14);
expect(row.read<DateTime>('dateTime'), time);
expect(row.read<Uint8List>('blob'), Uint8List.fromList([1, 2, 3]));
});
test('custom update informs stream queries', () async {

View File

@ -416,58 +416,6 @@ void main() {
));
});
group('with from()', () {
test('insert', () async {
await db
.from(db.categories)
.insert()
.insert(CategoriesCompanion.insert(description: 'description'));
verify(executor.runInsert(
'INSERT INTO categories ("desc") VALUES (?)', ['description']));
});
test('insertOne', () async {
await db.from(db.categories).insertOne(
CategoriesCompanion.insert(description: 'description'),
mode: InsertMode.insertOrReplace);
verify(executor.runInsert(
'INSERT OR REPLACE INTO categories ("desc") VALUES (?)',
['description']));
});
test('insertOnConflictUpdate', () async {
when(executor.runSelect(any, any)).thenAnswer(
(_) => Future.value([
{
'id': 1,
'desc': 'description',
'description_in_upper_case': 'DESCRIPTION',
'priority': 1,
},
]),
);
final row = await db.from(db.categories).insertReturning(
CategoriesCompanion.insert(description: 'description'));
expect(
row,
const Category(
id: 1,
description: 'description',
descriptionInUpperCase: 'DESCRIPTION',
priority: CategoryPriority.medium,
),
);
verify(executor.runSelect(
'INSERT INTO categories ("desc") VALUES (?) RETURNING *',
['description'],
));
});
});
group('on table instances', () {
test('insert', () async {
await db.categories

View File

@ -158,10 +158,10 @@ void main() {
[],
[_dataOfTodoEntry, _dataOfTodoEntry],
];
var _currentRow = 0;
var currentRow = 0;
when(executor.runSelect('SELECT * FROM todos;', any)).thenAnswer((_) {
return Future.value(resultRows[_currentRow++]);
return Future.value(resultRows[currentRow++]);
});
expectLater(
@ -211,17 +211,4 @@ void main() {
await pumpEventQueue();
db.markTablesUpdated([db.categories]);
});
test('can create select statements with from()', () async {
when(executor.runSelect(any, any)).thenAnswer((_) => Future.value([]));
final result = await db.from(db.todosTable).select().get();
expect(result, isEmpty);
final anotherResult = await db.from(db.todosTable).selectOnly().get();
expect(anotherResult, isEmpty);
verify(executor.runSelect('SELECT * FROM todos;', []));
verify(executor.runSelect('SELECT FROM todos;', []));
});
}

View File

@ -162,26 +162,6 @@ void main() {
});
});
group('update with from()', () {
test('update()', () async {
await db
.from(db.users)
.update()
.write(const UsersCompanion(id: Value(3)));
verify(executor.runUpdate('UPDATE users SET id = ?;', [3]));
});
test('replace', () async {
await db.from(db.categories).replace(const CategoriesCompanion(
id: Value(3), description: Value('new name')));
verify(executor.runUpdate(
'UPDATE categories SET "desc" = ?, priority = 0 WHERE id = ?;',
['new name', 3]));
});
});
group('update on table instances', () {
test('update()', () async {
await db.users.update().write(const UsersCompanion(id: Value(3)));

View File

@ -37,7 +37,7 @@ void main() {
'SELECT _mocked_',
readsFrom: {db.users},
)
.map((r) => r.readInt('_mocked_'))
.map((r) => r.read<int>('_mocked_'))
.watchSingleOrNull();
didSetUpStream.complete();

View File

@ -15,7 +15,7 @@ final _file = File(join(Directory.systemTemp.path, fileName));
QueryExecutor _createExecutor() => NativeDatabase(_file);
DatabaseConnection _forBackgroundIsolate() {
return DatabaseConnection.fromExecutor(_createExecutor());
return DatabaseConnection(_createExecutor());
}
void main() {

View File

@ -5,7 +5,7 @@ DatabaseConnection createConnection() {
var counter = 0;
final loggedValues = <int>[];
return DatabaseConnection.fromExecutor(
return DatabaseConnection(
NativeDatabase.memory(
setup: (rawDb) {
rawDb.createFunction(

View File

@ -23,7 +23,7 @@ class DriftNativeExcecutor extends TestExecutor {
@override
DatabaseConnection createConnection() {
return DatabaseConnection.fromExecutor(NativeDatabase(file));
return DatabaseConnection(NativeDatabase(file));
}
@override

View File

@ -19,7 +19,7 @@ class DriftWasmExecutor extends TestExecutor {
@override
DatabaseConnection createConnection() {
return DatabaseConnection.fromExecutor(
return DatabaseConnection(
WasmDatabase(sqlite3: sqlite3(), path: '/drift_test.db'));
}

View File

@ -47,7 +47,7 @@ void main() {
final createStmt = await db
.customSelect("SELECT sql FROM sqlite_master WHERE name = 'todos'")
.map((row) => row.readString('sql'))
.map((row) => row.read<String>('sql'))
.getSingle();
expect(createStmt, contains('category INT'));
@ -58,7 +58,7 @@ void main() {
// We enabled foreign keys, so they should still be enabled now.
final foreignKeysResult =
await db.customSelect('PRAGMA foreign_keys').getSingle();
expect(foreignKeysResult.readBool('foreign_keys'), isTrue);
expect(foreignKeysResult.read<bool>('foreign_keys'), isTrue);
});
test('rename columns', () async {
@ -94,7 +94,7 @@ void main() {
final createStmt = await db
.customSelect("SELECT sql FROM sqlite_master WHERE name = 'todos'")
.map((row) => row.readString('sql'))
.map((row) => row.read<String>('sql'))
.getSingle();
expect(
@ -133,7 +133,7 @@ void main() {
final createStmt = await db
.customSelect("SELECT sql FROM sqlite_master WHERE name = 'todos'")
.map((row) => row.readString('sql'))
.map((row) => row.read<String>('sql'))
.getSingle();
expect(
@ -238,7 +238,7 @@ void main() {
.customSelect("SELECT sql FROM sqlite_master WHERE name = 'no_ids'")
.getSingle();
expect(entry.readString('sql'), contains('WITHOUT ROWID'));
expect(entry.read<String>('sql'), contains('WITHOUT ROWID'));
});
group('exceptions in migrations', () {

View File

@ -13,8 +13,8 @@ class _TestDb extends GeneratedDatabase {
final int schemaVersion = 1;
}
Future<int> _selectOne(_TestDb _db) =>
_db.customSelect('select 1 a').map((row) => row.read<int>('a')).getSingle();
Future<int> _selectOne(_TestDb db) =>
db.customSelect('select 1 a').map((row) => row.read<int>('a')).getSingle();
void main() {
for (final useTransaction in [false, true]) {

View File

@ -25,11 +25,11 @@ void main() {
final a = db
.customSelect("select 'a' as a")
.map(($) => $.readString('a'))
.map(($) => $.read<String>('a'))
.watchSingle();
final b = db
.customSelect("select 'b' as b")
.map(($) => $.readString('b'))
.map(($) => $.read<String>('b'))
.watchSingle();
final c = a.switchMap((_) => b);
expect(await a.first, 'a');

View File

@ -117,8 +117,8 @@ void main() {
test('shutting down will close the underlying executor', () async {
final mockExecutor = MockExecutor();
final isolate = DriftIsolate.inCurrent(
() => DatabaseConnection.fromExecutor(mockExecutor));
final isolate =
DriftIsolate.inCurrent(() => DatabaseConnection(mockExecutor));
await isolate.shutdownAll();
verify(mockExecutor.close());
@ -296,7 +296,7 @@ void _runTests(FutureOr<DriftIsolate> Function() spawner, bool terminateIsolate,
}
DatabaseConnection _backgroundConnection() {
return DatabaseConnection.fromExecutor(NativeDatabase.memory());
return DatabaseConnection(NativeDatabase.memory());
}
Future<void> _writeTodoEntryInBackground(_BackgroundEntryMessage msg) async {
@ -318,7 +318,7 @@ class _BackgroundEntryMessage {
void _createBackground(SendPort send) {
final drift = DriftIsolate.inCurrent(
() => DatabaseConnection.fromExecutor(NativeDatabase.memory()),
() => DatabaseConnection(NativeDatabase.memory()),
killIsolateWhenDone: true);
send.send(drift);
}

View File

@ -19,7 +19,7 @@ void main() {
final db = TodoDb(executor);
final row = await db.customSelect('SELECT my_function() AS r;').getSingle();
expect(row.readString('r'), 'hello from Dart');
expect(row.read<String>('r'), 'hello from Dart');
await db.close();
});
@ -31,7 +31,7 @@ void main() {
final db = TodoDb(executor);
final row = await db.customSelect('SELECT my_function() AS r;').getSingle();
expect(row.readString('r'), 'hello from Dart');
expect(row.read<String>('r'), 'hello from Dart');
final nativeRow = existing.select('SELECT my_function() AS r;').single;
expect(nativeRow['r'], 'hello from Dart');

View File

@ -73,7 +73,7 @@ void main() {
test('can run protocol without using complex types', () async {
final executor = MockExecutor();
final server = DriftServer(DatabaseConnection.fromExecutor(executor));
final server = DriftServer(DatabaseConnection(executor));
addTearDown(server.shutdown);
final channelController = StreamChannelController();
@ -117,7 +117,7 @@ void main() {
when(outerTransaction.beginTransaction()).thenAnswer(newTransaction);
final server = DriftServer(DatabaseConnection.fromExecutor(executor));
final server = DriftServer(DatabaseConnection(executor));
server.serve(controller.foreign);
addTearDown(server.shutdown);

View File

@ -7,5 +7,5 @@ Version get sqlite3Version {
}
DatabaseConnection testInMemoryDatabase() {
return DatabaseConnection.fromExecutor(NativeDatabase.memory());
return DatabaseConnection(NativeDatabase.memory());
}

View File

@ -22,7 +22,7 @@ Future<WasmSqlite3> get sqlite3 {
}
DatabaseConnection testInMemoryDatabase() {
return DatabaseConnection.fromExecutor(LazyDatabase(() async {
return DatabaseConnection(LazyDatabase(() async {
final sqlite = await sqlite3;
return WasmDatabase.inMemory(sqlite);
}));

View File

@ -30,7 +30,7 @@ class _NullExecutor extends Fake implements QueryExecutor {
SqlDialect get dialect => SqlDialect.sqlite;
}
class CustomTable extends Table with TableInfo<CustomTable, Null> {
class CustomTable extends Table with TableInfo<CustomTable, void> {
@override
final String actualTableName;
@override
@ -53,7 +53,7 @@ class CustomTable extends Table with TableInfo<CustomTable, Null> {
}
@override
Future<Null> map(Map<String, dynamic> data, {String? tablePrefix}) async {
return null;
Future<void> map(Map<String, dynamic> data, {String? tablePrefix}) async {
return;
}
}

View File

@ -1 +1,7 @@
include: ../analysis_options.yaml
include: package:lints/recommended.yaml
analyzer:
strong-mode:
implicit-casts: false
exclude:
- "**/*.g.dart"

View File

@ -29,7 +29,7 @@ abstract class SchemaVerifier {
/// - call [schemaAt] with the starting version you want to test
/// - use the [InitializedSchema.rawDatabase] of the returned
/// [InitializedSchema] to insert data.
/// - connect your database class to the [InitializedSchema.connection]
/// - connect your database class to a [InitializedSchema.newConnection]
/// - call [migrateAndValidate] with the database and your target schema
/// version to run a migration and verify that it yields the desired schema
/// when done.
@ -154,8 +154,8 @@ class SchemaMismatch implements Exception {
/// Contains an initialized schema with all tables, views, triggers and indices.
///
/// You can use the [connection] for your database class and the [rawDatabase]
/// to insert data before the migration.
/// You can use the [newConnection] for your database class and the
/// [rawDatabase] to insert data before the migration.
class InitializedSchema {
/// The raw database from the `sqlite3` package.
///
@ -163,7 +163,7 @@ class InitializedSchema {
/// requested schema. It can be used to insert data before a migration to
/// verify that it's still intact after the migration.
///
/// This database backs the [connection], so it's not necessary to close it
/// This database backs the [newConnection], so it's not necessary to close it
/// if you're attaching a database later.
final Database rawDatabase;

View File

@ -275,7 +275,7 @@ class ViewParser {
}
final column =
columns.firstWhere((col) => col.dartGetterName == parts[0]);
return MapEntry('${column.dartGetterName}', column);
return MapEntry(column.dartGetterName, column);
}).toList();
target = target.parent as MethodInvocation;

View File

@ -129,8 +129,10 @@ class DriftOptions {
required this.storeDateTimeValuesAsText,
this.dialect,
}) {
// ignore: deprecated_member_use_from_same_package
if (sqliteAnalysisOptions != null && modules.isNotEmpty) {
throw ArgumentError.value(
// ignore: deprecated_member_use_from_same_package
modules,
'modules',
'May not be set when sqlite options are present. \n'
@ -156,6 +158,7 @@ class DriftOptions {
/// All enabled sqlite modules from these options.
List<SqlModule> get effectiveModules {
// ignore: deprecated_member_use_from_same_package
return sqliteOptions?.modules ?? modules;
}

View File

@ -1,3 +1,5 @@
// ignore_for_file: library_private_types_in_public_api
import 'package:drift_dev/src/model/model.dart';
import 'package:sqlparser/sqlparser.dart';

View File

@ -45,7 +45,7 @@ class FindSchemaDifferences {
);
}
CompareResult _compareNamed<T>({
CompareResult _compareNamed<T extends Object>({
required List<T> reference,
required List<T> actual,
required String Function(T) name,

View File

@ -690,7 +690,7 @@ class _ExpandedVariableWriter {
final constructor = constructVar(r'$');
_buffer.write('for (var \$ in $name) $constructor');
} else {
_buffer.write('${constructVar(name)}');
_buffer.write(constructVar(name));
}
}

View File

@ -24,12 +24,12 @@ class DataClassWriter {
void write() {
final parentClass = table.customParentClass ?? 'DataClass';
_buffer.write('class ${table.dartTypeName} extends $parentClass ');
_buffer.write('class ${table.dartTypeCode()} extends $parentClass ');
if (isInsertable) {
// The data class is only an insertable if we can actually insert rows
// into the target entity.
_buffer.writeln('implements Insertable<${table.dartTypeName}> {');
_buffer.writeln('implements Insertable<${table.dartTypeCode()}> {');
} else {
_buffer.writeln('{');
}
@ -58,7 +58,7 @@ class DataClassWriter {
_buffer.write('const ');
}
_buffer
..write(table.dartTypeName)
..write(table.dartTypeCode())
..write('({')
..write(columns.map((column) {
final nullableDartType = column.typeConverter != null
@ -91,14 +91,14 @@ class DataClassWriter {
_writeHashCode();
overrideEquals(
columns.map((c) => c.dartGetterName), table.dartTypeName, _buffer);
columns.map((c) => c.dartGetterName), table.dartTypeCode(), _buffer);
// finish class declaration
_buffer.write('}');
}
void _writeFromJson() {
final dataClassName = table.dartTypeName;
final dataClassName = table.dartTypeCode();
_buffer
..write('factory $dataClassName.fromJson('
@ -158,7 +158,7 @@ class DataClassWriter {
final converterField =
typeConverter.tableAndField(forNullableColumn: column.nullable);
value = '$converterField.toJson($value)';
dartType = '${column.innerColumnType(nullable: true)}';
dartType = column.innerColumnType(nullable: true);
}
_buffer.write("'$name': serializer.toJson<$dartType>($value),");
@ -168,7 +168,7 @@ class DataClassWriter {
}
void _writeCopyWith() {
final dataClassName = table.dartTypeName;
final dataClassName = table.dartTypeCode();
final wrapNullableInValue = scope.options.generateValuesInCopyWith;
_buffer.write('$dataClassName copyWith({');
@ -308,7 +308,7 @@ class DataClassWriter {
void _writeToString() {
overrideToString(
table.dartTypeName,
table.dartTypeCode(),
[for (final column in columns) column.dartGetterName],
_buffer,
);

View File

@ -206,7 +206,7 @@ abstract class TableOrViewWriter {
databaseGetter: 'attachedDatabase',
);
buffer.write('return ${tableOrView.dartTypeName}');
buffer.write('return ${tableOrView.dartTypeCode()}');
writer.writeArguments(buffer);
buffer.writeln(';');
}

View File

@ -34,5 +34,5 @@ void overrideToString(
into
..write("..write(')')).toString();")
..write('\}\n');
..writeln('}');
}

View File

@ -44,6 +44,7 @@ dependencies:
source_gen: '>=0.9.4 <2.0.0'
dev_dependencies:
lints: ^2.0.0
checked_yaml: ^2.0.1
test: ^1.16.0
test_descriptor: ^2.0.0

View File

@ -89,7 +89,7 @@ class ProgrammingLanguages extends Table {
final importQuery = database.queries!
.singleWhere((q) => q.name == 'transitiveImportTest') as SqlSelectQuery;
expect(importQuery.resultSet.matchingTable!.table.dartTypeName,
expect(importQuery.resultSet.matchingTable!.table.dartTypeCode(),
'ProgrammingLanguage');
expect(importQuery.declaredInMoorFile, isFalse);
expect(importQuery.hasMultipleTables, isFalse);

View File

@ -1,3 +1,7 @@
include: package:lints/recommended.yaml
analyzer:
exclude:
exclude:
- "test/generated/**"
- "lib/src/generated/**"
- "**/*.g.dart"

View File

@ -9,6 +9,7 @@ dependencies:
drift:
dev_dependencies:
lints: ^2.0.0
drift_dev:
build_runner: ^2.0.0
test: ^1.15.4

View File

@ -0,0 +1,5 @@
include: package:lints/recommended.yaml
analyzer:
strong-mode:
implicit-casts: false

View File

@ -6,10 +6,13 @@ environment:
sdk: '>=2.12.0-0 <3.0.0'
dependencies:
collection: ^1.16.0
drift: ^1.6.0
postgres: ^2.4.3
meta: ^1.8.0
dev_dependencies:
lints: ^2.0.0
test: ^1.18.0
drift_testcases:
path: ../integration_tests/drift_testcases

View File

@ -1,4 +1,4 @@
include: ../analysis_options.yaml
#include: ../analysis_options.yaml
analyzer:
errors:

View File

@ -1 +1 @@
include: ../analysis_options.yaml
#include: ../analysis_options.yaml

View File

@ -1 +1,5 @@
include: ../analysis_options.yaml
include: package:lints/recommended.yaml
analyzer:
strong-mode:
implicit-casts: false

View File

@ -12,9 +12,6 @@ class AnalysisError {
{required this.type, this.message, SyntacticEntity? relevantNode})
: source = relevantNode;
@Deprecated('Use source instead')
AstNode? get relevantNode => source as AstNode?;
factory AnalysisError.fromParser(ParsingError error) {
return AnalysisError._internal(
AnalysisErrorType.synctactic,
@ -34,7 +31,7 @@ class AnalysisError {
if (msgSpan != null) {
return msgSpan.message(message ?? type.toString(), color: true);
} else {
return 'Error: $type: $message at $relevantNode';
return 'Error: $type: $message at $source';
}
}
}

View File

@ -1,7 +1,7 @@
part of '../types.dart';
class TypeGraph {
final _ResolvedVariables variables = _ResolvedVariables();
final _ResolvedVariables _variables = _ResolvedVariables();
final Map<Typeable, ResolvedType> _knownTypes = {};
final Map<Typeable, bool?> _knownNullability = {};
@ -13,7 +13,7 @@ class TypeGraph {
final List<DefaultType> _defaultTypes = [];
ResolvedType? operator [](Typeable t) {
final normalized = variables.normalize(t);
final normalized = _variables.normalize(t);
if (_knownTypes.containsKey(normalized)) {
final type = _knownTypes[normalized];
@ -29,7 +29,7 @@ class TypeGraph {
}
void operator []=(Typeable t, ResolvedType type) {
final normalized = variables.normalize(t);
final normalized = _variables.normalize(t);
_knownTypes[normalized] = type;
if (type.nullable != null && !_knownNullability.containsKey(normalized)) {
@ -38,10 +38,11 @@ class TypeGraph {
}
}
bool knowsType(Typeable t) => _knownTypes.containsKey(variables.normalize(t));
bool knowsType(Typeable t) =>
_knownTypes.containsKey(_variables.normalize(t));
bool knowsNullability(Typeable t) {
final normalized = variables.normalize(t);
final normalized = _variables.normalize(t);
final knownType = _knownTypes[normalized];
return (knownType != null && knownType.nullable != null) ||
@ -53,7 +54,7 @@ class TypeGraph {
}
void markNullability(Typeable t, bool isNullable) {
_knownNullability[variables.normalize(t)] = isNullable;
_knownNullability[_variables.normalize(t)] = isNullable;
}
void performResolve() {

View File

@ -15,6 +15,7 @@ dependencies:
charcode: ^1.2.0
dev_dependencies:
lints: ^2.0.0
test: ^1.17.4
path: ^1.8.0
ffi: ^2.0.0

View File

@ -12,7 +12,7 @@ void main() {
expect(error.type, AnalysisErrorType.synctactic);
final problematicSelect = (analyzed.root as CompoundSelectStatement).base;
final wrongLimit = (problematicSelect as SelectStatement).limit;
expect(error.relevantNode, wrongLimit);
expect(error.source, wrongLimit);
});
test('reports error if ORDER BY is used before last part', () {
@ -30,6 +30,6 @@ void main() {
final problematicSelect =
(analyzed.root as CompoundSelectStatement).additional[0].select;
final wrongOrderBy = (problematicSelect as SelectStatement).orderBy;
expect(error.relevantNode, wrongOrderBy);
expect(error.source, wrongOrderBy);
});
}

View File

@ -13,8 +13,8 @@ void main() {
AnalysisErrorType.valuesSelectCountMismatch)
.having((e) => e.message, 'message',
allOf(contains('1'), contains('2')))
.having((e) => e.relevantNode!.span!.text, 'relevantNode.span.text',
'(3)'),
.having(
(e) => e.source!.span!.text, 'relevantNode.span.text', '(3)'),
),
);
});

View File

@ -6,7 +6,7 @@ import 'utils.dart';
void main() {
test('parses CREATE TABLE statement', () {
testStatement(
'CREATE TABLE \"sample_table\" ('
'CREATE TABLE "sample_table" ('
'id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, sample VARCHAR NULL)',
CreateTableStatement(
tableName: 'sample_table',