Merge pull request #924 from simolus3/nnbd

Migrate core package to null safety
This commit is contained in:
Simon Binder 2020-12-04 20:09:35 +01:00 committed by GitHub
commit 74fc2cea3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
146 changed files with 1889 additions and 1788 deletions

View File

@ -1,20 +0,0 @@
# Run tasks with the dart SDK installed by default
container:
dockerfile: tool/Dockerfile
memory: 12G
cpu: 4
task:
pub_cache:
folder: $HOME/.pub-cache
environment:
CODECOV_TOKEN: ENCRYPTED[6322a159d9b7692b999d13fa2bc7981c8b61ecb1ac18ae076864f1355ee9b65088b2bf9d97d7860196e58bf1db5708af]
dart_version_script: dart --version
pub_get_script: tool/pub_get.sh
analyze_script: tool/analyze.sh
test_moor_script: tool/test_moor.sh
test_sqlparser_script: tool/test_sqlparser.sh
misc_integration_test_script: tool/misc_integration_test.sh
# We just get too many timeouts for moor_generator in the CI runner
# test_moor_generator_script: tool/test_generator.sh
format_coverage_script: tool/upload_coverage.sh

116
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,116 @@
name: CI
on: [push, pull_request]
env:
PUB_ENVIRONMENT: bot.github
jobs:
moor:
name: "moor package"
runs-on: ubuntu-20.04
steps:
# setup
- uses: actions/checkout@v2
- uses: cedx/setup-dart@v2
with:
release-channel: beta
- run: sudo apt-get install -y libsqlite3-dev
name: Install sqlite3 for tests
- run: dart pub upgrade
working-directory: moor
# analysis
- run: dart format -o none --set-exit-if-changed moor/
name: dartfmt
- run: dart analyze --fatal-infos --fatal-warnings
working-directory: moor/
# build, test and upload coverage
- run: dart run build_runner build --delete-conflicting-outputs
working-directory: moor
- run: dart --no-sound-null-safety --null-assertions test #-x background_isolate --coverage=coverage
working-directory: moor
# - uses: actions/upload-artifact@v2
# with:
# name: moor-coverage-data
# path: |
# moor/coverage/
# moor/.dart_tool/package_config.json
# retention-days: 1
moor_generator:
runs-on: ubuntu-20.04
steps:
# setup
- uses: actions/checkout@v2
- uses: cedx/setup-dart@v2
with:
release-channel: beta
- run: dart pub upgrade
working-directory: moor_generator
# analysis
- run: dart format -o none --set-exit-if-changed moor_generator/
name: dartfmt
- run: dart analyze --fatal-infos --fatal-warnings
working-directory: moor_generator/
sqlparser:
runs-on: ubuntu-20.04
steps:
# setup
- uses: actions/checkout@v2
- uses: cedx/setup-dart@v2
- run: sudo apt-get install -y libsqlite3-dev
name: Install sqlite3 for tests
- run: dart pub upgrade
working-directory: sqlparser
# analysis
- run: dart format -o none --set-exit-if-changed sqlparser/
name: dartfmt
- run: dart analyze --fatal-infos --fatal-warnings
working-directory: sqlparser/
# tests and coverage
- run: dart test #--coverage=coverage
working-directory: sqlparser
# - uses: actions/upload-artifact@v2
# with:
# name: sqlparser-coverage-data
# path: |
# sqlparser/coverage/
# sqlparser/.dart_tool/package_config.json
# retention-days: 1
misc_integration_tests:
name: "Integration tests"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: cedx/setup-dart@v2
with:
release-channel: beta
- run: sudo apt-get install -y libsqlite3-dev
name: Install sqlite3 for tests
- run: tool/misc_integration_test.sh
# upload_coverage:
# runs-on: ubuntu-20.04
# needs: [moor, sqlparser]
# steps:
# - uses: actions/checkout@v2
# - uses: cedx/setup-dart@v2
# - run: dart pub upgrade
# name: "Setup coverage processor"
# working-directory: extras/coverage_formatting
# - uses: actions/download-artifact@v2
# with:
# name: moor-coverage-data
# path: moor/
# - uses: actions/download-artifact@v2
# with:
# name: sqlparser-coverage-data
# path: sqlparser/
# - run: dart run extras/coverage_formatting/bin/coverage.dart
# name: "Format coverage from raw data"
# - uses: codecov/codecov-action@v1
# with:
# file: lcov.info

1
.gitignore vendored
View File

@ -8,5 +8,6 @@ pubspec.lock
.dart_tool/
benchmark_results.json
.flutter-plugins
.flutter-plugins-dependencies
flutter_export_environment.sh

View File

@ -13,6 +13,7 @@ analyzer:
# Will be analyzed anyway, nobody knows why ¯\_(ツ)_/¯. We're only analyzing lib/ and test/ as a workaround
- ".dart_tool/build/entrypoint/build.dart"
- "tool/**"
- "**/*.mocks.dart"
# this should always include all rules. Those we don't use are commented out
linter:

View File

@ -1,6 +1,9 @@
name: benchmarks
description: Runs simple and complex benchmarks to measure performance of moor and moor_ffi
environment:
sdk: '>=2.6.0 <3.0.0'
dependencies:
moor:
sqlite3: ^0.1.3

View File

@ -31,7 +31,8 @@ Future runForProject(String projectName) async {
final hitmap = await parseCoverage(files, 1);
final resolver = MoorResolver(
projectRoot: projectName, packagesPath: p.join(projectName, '.packages'));
projectRoot: projectName,
packagesPath: p.join(projectName, '.dart_tool', 'package_config.json'));
final output =
await LcovFormatter(resolver, reportOn: [p.join(projectName, 'lib')])

View File

@ -2,6 +2,9 @@ name: coverage_formatting
publish_to: none
description: Tool used for the CI to format VM coverage jsons to LCOV files
environment:
sdk: '>=2.6.0 <3.0.0'
dependencies:
coverage: '^0.14.0'
path: ^1.6.4

View File

@ -6,7 +6,6 @@ library encrypted_moor;
import 'dart:async';
import 'dart:io';
import 'package:meta/meta.dart';
import 'package:path/path.dart';
import 'package:moor/moor.dart';
import 'package:moor/backends.dart';
@ -19,21 +18,25 @@ typedef DatabaseCreator = FutureOr<void> Function(File file);
class _SqfliteDelegate extends DatabaseDelegate with _SqfliteExecutor {
@override
s.Database db;
late s.Database db;
bool _isOpen = false;
final bool inDbFolder;
final String path;
final String password;
final String? password;
bool singleInstance;
final DatabaseCreator creator;
final DatabaseCreator? creator;
_SqfliteDelegate(this.inDbFolder, this.path,
{this.singleInstance, this.creator, this.password}) {
singleInstance ??= true;
}
_SqfliteDelegate(
this.inDbFolder,
this.path, {
this.singleInstance = true,
this.creator,
this.password,
});
DbVersionDelegate _delegate;
DbVersionDelegate? _delegate;
@override
DbVersionDelegate get versionDelegate {
return _delegate ??= _SqfliteVersionDelegate(db);
@ -44,7 +47,7 @@ class _SqfliteDelegate extends DatabaseDelegate with _SqfliteExecutor {
_SqfliteTransactionDelegate(this);
@override
bool get isOpen => db != null;
bool get isOpen => _isOpen;
@override
Future<void> open(QueryExecutorUser user) async {
@ -57,7 +60,7 @@ class _SqfliteDelegate extends DatabaseDelegate with _SqfliteExecutor {
final file = File(resolvedPath);
if (creator != null && !await file.exists()) {
await creator(file);
await creator!(file);
}
db = await s.openDatabase(
@ -65,6 +68,7 @@ class _SqfliteDelegate extends DatabaseDelegate with _SqfliteExecutor {
password: password,
singleInstance: singleInstance,
);
_isOpen = true;
}
@override
@ -98,7 +102,6 @@ class _SqfliteTransactionDelegate extends SupportedTransactionDelegate {
@override
void startTransaction(Future<void> Function(QueryDelegate) run) {
delegate.db.transaction((transaction) async {
assert(transaction != null);
final executor = _SqfliteTransactionExecutor(transaction);
await run(executor);
}).catchError((_) {
@ -131,23 +134,23 @@ mixin _SqfliteExecutor on QueryDelegate {
}
@override
Future<void> runCustom(String statement, List args) {
Future<void> runCustom(String statement, List<Object?> args) {
return db.execute(statement, args);
}
@override
Future<int> runInsert(String statement, List args) {
Future<int> runInsert(String statement, List<Object?> args) {
return db.rawInsert(statement, args);
}
@override
Future<QueryResult> runSelect(String statement, List args) async {
Future<QueryResult> runSelect(String statement, List<Object?> args) async {
final result = await db.rawQuery(statement, args);
return QueryResult.fromRows(result);
}
@override
Future<int> runUpdate(String statement, List args) {
Future<int> runUpdate(String statement, List<Object?> args) {
return db.rawUpdate(statement, args);
}
}
@ -165,11 +168,11 @@ class EncryptedExecutor extends DelegatedDatabase {
/// [MigrationStrategy.onCreate] callback because it hasn't been created by
/// moor.
EncryptedExecutor(
{@required String path,
@required String password,
bool logStatements,
bool singleInstance,
DatabaseCreator creator})
{required String path,
required String password,
bool? logStatements,
bool singleInstance = true,
DatabaseCreator? creator})
: super(
_SqfliteDelegate(false, path,
singleInstance: singleInstance,
@ -189,11 +192,11 @@ class EncryptedExecutor extends DelegatedDatabase {
/// [MigrationStrategy.onCreate] callback because it hasn't been created by
/// moor.
EncryptedExecutor.inDatabaseFolder(
{@required String path,
@required String password,
bool logStatements,
bool singleInstance,
DatabaseCreator creator})
{required String path,
required String password,
bool? logStatements,
bool singleInstance = true,
DatabaseCreator? creator})
: super(
_SqfliteDelegate(true, path,
singleInstance: singleInstance,
@ -212,8 +215,8 @@ class EncryptedExecutor extends DelegatedDatabase {
///
/// Note that this returns null until the moor database has been opened.
/// A moor database is opened lazily when the first query runs.
s.Database get sqfliteDb {
s.Database? get sqfliteDb {
final sqfliteDelegate = delegate as _SqfliteDelegate;
return sqfliteDelegate.db;
return sqfliteDelegate.isOpen ? sqfliteDelegate.db : null;
}
}

View File

@ -4,11 +4,11 @@ version: 1.0.0
author: Simon Binder <oss@simonbinder.eu>
environment:
sdk: '>=2.4.0 <3.0.0'
sdk: '>=2.12.0-0 <3.0.0'
dependencies:
moor: ^3.0.0
sqflite_sqlcipher: ^1.0.0+6
sqflite_sqlcipher: ^2.0.0-nullsafety
dependency_overrides:
moor:

View File

@ -2,6 +2,8 @@ name: flutter_db
description: Moor integration tests running on sqflite
version: 1.0.0+1
publish_to: none
environment:
sdk: ">=2.1.0 <3.0.0"
flutter: ">=1.12.0"

View File

@ -16,4 +16,4 @@ dev_dependencies:
dependency_overrides:
moor:
path: ../../../moor
path: ../../../moor

View File

@ -23,4 +23,5 @@ dependency_overrides:
path: ../../sqlparser
# todo: Remove after built_value supports analyzer ^0.40
analyzer: 0.40.4
analyzer: 0.40.4
convert: ^3.0.0-nullsafety

View File

@ -1,5 +1,8 @@
## unreleased
## unreleased (breaking - 4.0)
- __Breaking__: Changed the `args` parameter in `QueryExecutor` methods to `List<Object?>`
- __Breaking__: Removed the second type parameter from `TypedResult.read`
- Support null safety
- Changed the sql representation of text types from `VARCHAR` to `TEXT`
- Added extensions for `isNull` and `isNotNull`
- Support creating a `VmDatabase` from a raw sqlite3 `Database` via `VmDatabase.opened`

View File

@ -1,3 +1,4 @@
# Moor
Moor is a reactive persistence library for Flutter and Dart, built ontop of
sqlite.

View File

@ -7,4 +7,5 @@ analyzer:
exclude:
- "example_web/**"
- "example/**"
- "**/*.g.dart"
- "**/*.g.dart"
- "**/*.mocks.dart"

View File

@ -1,5 +1,6 @@
tags:
integration:
background_isolate:
platforms:
- vm

View File

@ -9,15 +9,15 @@ part of 'example.dart';
// ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this
class Category extends DataClass implements Insertable<Category> {
final int id;
final String description;
Category({@required this.id, this.description});
final String? description;
Category({required this.id, this.description});
factory Category.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
{String? prefix}) {
final effectivePrefix = prefix ?? '';
final intType = db.typeSystem.forDartType<int>();
final stringType = db.typeSystem.forDartType<String>();
return Category(
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id'])!,
description: stringType
.mapFromDatabaseResponse(data['${effectivePrefix}description']),
);
@ -25,18 +25,16 @@ class Category extends DataClass implements Insertable<Category> {
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (!nullToAbsent || id != null) {
map['id'] = Variable<int>(id);
}
map['id'] = Variable<int>(id);
if (!nullToAbsent || description != null) {
map['description'] = Variable<String>(description);
map['description'] = Variable<String?>(description);
}
return map;
}
CategoriesCompanion toCompanion(bool nullToAbsent) {
return CategoriesCompanion(
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
id: Value(id),
description: description == null && nullToAbsent
? const Value.absent()
: Value(description),
@ -44,29 +42,29 @@ class Category extends DataClass implements Insertable<Category> {
}
factory Category.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer}) {
{ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return Category(
id: serializer.fromJson<int>(json['id']),
description: serializer.fromJson<String>(json['description']),
description: serializer.fromJson<String?>(json['description']),
);
}
factory Category.fromJsonString(String encodedJson,
{ValueSerializer serializer}) =>
{ValueSerializer? serializer}) =>
Category.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson({ValueSerializer serializer}) {
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<int>(id),
'description': serializer.toJson<String>(description),
'description': serializer.toJson<String?>(description),
};
}
Category copyWith(
{int id, Value<String> description = const Value.absent()}) =>
{int? id, Value<String?> description = const Value.absent()}) =>
Category(
id: id ?? this.id,
description: description.present ? description.value : this.description,
@ -92,7 +90,7 @@ class Category extends DataClass implements Insertable<Category> {
class CategoriesCompanion extends UpdateCompanion<Category> {
final Value<int> id;
final Value<String> description;
final Value<String?> description;
const CategoriesCompanion({
this.id = const Value.absent(),
this.description = const Value.absent(),
@ -102,8 +100,8 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
this.description = const Value.absent(),
});
static Insertable<Category> custom({
Expression<int> id,
Expression<String> description,
Expression<int>? id,
Expression<String?>? description,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
@ -111,7 +109,7 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
});
}
CategoriesCompanion copyWith({Value<int> id, Value<String> description}) {
CategoriesCompanion copyWith({Value<int>? id, Value<String?>? description}) {
return CategoriesCompanion(
id: id ?? this.id,
description: description ?? this.description,
@ -125,7 +123,7 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
map['id'] = Variable<int>(id.value);
}
if (description.present) {
map['description'] = Variable<String>(description.value);
map['description'] = Variable<String?>(description.value);
}
return map;
}
@ -143,12 +141,11 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
class $CategoriesTable extends Categories
with TableInfo<$CategoriesTable, Category> {
final GeneratedDatabase _db;
final String _alias;
final String? _alias;
$CategoriesTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id;
@override
GeneratedIntColumn get id => _id ??= _constructId();
late final GeneratedIntColumn id = _constructId();
GeneratedIntColumn _constructId() {
return GeneratedIntColumn('id', $tableName, false,
hasAutoIncrement: true, declaredAsPrimaryKey: true);
@ -156,10 +153,8 @@ class $CategoriesTable extends Categories
final VerificationMeta _descriptionMeta =
const VerificationMeta('description');
GeneratedTextColumn _description;
@override
GeneratedTextColumn get description =>
_description ??= _constructDescription();
late final GeneratedTextColumn description = _constructDescription();
GeneratedTextColumn _constructDescription() {
return GeneratedTextColumn(
'description',
@ -182,13 +177,13 @@ class $CategoriesTable extends Categories
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta));
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
}
if (data.containsKey('description')) {
context.handle(
_descriptionMeta,
description.isAcceptableOrUnknown(
data['description'], _descriptionMeta));
data['description']!, _descriptionMeta));
}
return context;
}
@ -196,7 +191,7 @@ class $CategoriesTable extends Categories
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
Category map(Map<String, dynamic> data, {String tablePrefix}) {
Category map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return Category.fromData(data, _db, prefix: effectivePrefix);
}
@ -211,23 +206,23 @@ class Recipe extends DataClass implements Insertable<Recipe> {
final int id;
final String title;
final String instructions;
final int category;
final int? category;
Recipe(
{@required this.id,
@required this.title,
@required this.instructions,
{required this.id,
required this.title,
required this.instructions,
this.category});
factory Recipe.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
{String? prefix}) {
final effectivePrefix = prefix ?? '';
final intType = db.typeSystem.forDartType<int>();
final stringType = db.typeSystem.forDartType<String>();
return Recipe(
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id'])!,
title:
stringType.mapFromDatabaseResponse(data['${effectivePrefix}title']),
stringType.mapFromDatabaseResponse(data['${effectivePrefix}title'])!,
instructions: stringType
.mapFromDatabaseResponse(data['${effectivePrefix}instructions']),
.mapFromDatabaseResponse(data['${effectivePrefix}instructions'])!,
category:
intType.mapFromDatabaseResponse(data['${effectivePrefix}category']),
);
@ -235,29 +230,20 @@ class Recipe extends DataClass implements Insertable<Recipe> {
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (!nullToAbsent || id != null) {
map['id'] = Variable<int>(id);
}
if (!nullToAbsent || title != null) {
map['title'] = Variable<String>(title);
}
if (!nullToAbsent || instructions != null) {
map['instructions'] = Variable<String>(instructions);
}
map['id'] = Variable<int>(id);
map['title'] = Variable<String>(title);
map['instructions'] = Variable<String>(instructions);
if (!nullToAbsent || category != null) {
map['category'] = Variable<int>(category);
map['category'] = Variable<int?>(category);
}
return map;
}
RecipesCompanion toCompanion(bool nullToAbsent) {
return RecipesCompanion(
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
title:
title == null && nullToAbsent ? const Value.absent() : Value(title),
instructions: instructions == null && nullToAbsent
? const Value.absent()
: Value(instructions),
id: Value(id),
title: Value(title),
instructions: Value(instructions),
category: category == null && nullToAbsent
? const Value.absent()
: Value(category),
@ -265,35 +251,35 @@ class Recipe extends DataClass implements Insertable<Recipe> {
}
factory Recipe.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer}) {
{ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return Recipe(
id: serializer.fromJson<int>(json['id']),
title: serializer.fromJson<String>(json['title']),
instructions: serializer.fromJson<String>(json['instructions']),
category: serializer.fromJson<int>(json['category']),
category: serializer.fromJson<int?>(json['category']),
);
}
factory Recipe.fromJsonString(String encodedJson,
{ValueSerializer serializer}) =>
{ValueSerializer? serializer}) =>
Recipe.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson({ValueSerializer serializer}) {
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<int>(id),
'title': serializer.toJson<String>(title),
'instructions': serializer.toJson<String>(instructions),
'category': serializer.toJson<int>(category),
'category': serializer.toJson<int?>(category),
};
}
Recipe copyWith(
{int id,
String title,
String instructions,
Value<int> category = const Value.absent()}) =>
{int? id,
String? title,
String? instructions,
Value<int?> category = const Value.absent()}) =>
Recipe(
id: id ?? this.id,
title: title ?? this.title,
@ -328,7 +314,7 @@ class RecipesCompanion extends UpdateCompanion<Recipe> {
final Value<int> id;
final Value<String> title;
final Value<String> instructions;
final Value<int> category;
final Value<int?> category;
const RecipesCompanion({
this.id = const Value.absent(),
this.title = const Value.absent(),
@ -337,16 +323,16 @@ class RecipesCompanion extends UpdateCompanion<Recipe> {
});
RecipesCompanion.insert({
this.id = const Value.absent(),
@required String title,
@required String instructions,
required String title,
required String instructions,
this.category = const Value.absent(),
}) : title = Value(title),
instructions = Value(instructions);
static Insertable<Recipe> custom({
Expression<int> id,
Expression<String> title,
Expression<String> instructions,
Expression<int> category,
Expression<int>? id,
Expression<String>? title,
Expression<String>? instructions,
Expression<int?>? category,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
@ -357,10 +343,10 @@ class RecipesCompanion extends UpdateCompanion<Recipe> {
}
RecipesCompanion copyWith(
{Value<int> id,
Value<String> title,
Value<String> instructions,
Value<int> category}) {
{Value<int>? id,
Value<String>? title,
Value<String>? instructions,
Value<int?>? category}) {
return RecipesCompanion(
id: id ?? this.id,
title: title ?? this.title,
@ -382,7 +368,7 @@ class RecipesCompanion extends UpdateCompanion<Recipe> {
map['instructions'] = Variable<String>(instructions.value);
}
if (category.present) {
map['category'] = Variable<int>(category.value);
map['category'] = Variable<int?>(category.value);
}
return map;
}
@ -401,31 +387,27 @@ class RecipesCompanion extends UpdateCompanion<Recipe> {
class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
final GeneratedDatabase _db;
final String _alias;
final String? _alias;
$RecipesTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id;
@override
GeneratedIntColumn get id => _id ??= _constructId();
late final GeneratedIntColumn id = _constructId();
GeneratedIntColumn _constructId() {
return GeneratedIntColumn('id', $tableName, false,
hasAutoIncrement: true, declaredAsPrimaryKey: true);
}
final VerificationMeta _titleMeta = const VerificationMeta('title');
GeneratedTextColumn _title;
@override
GeneratedTextColumn get title => _title ??= _constructTitle();
late final GeneratedTextColumn title = _constructTitle();
GeneratedTextColumn _constructTitle() {
return GeneratedTextColumn('title', $tableName, false, maxTextLength: 16);
}
final VerificationMeta _instructionsMeta =
const VerificationMeta('instructions');
GeneratedTextColumn _instructions;
@override
GeneratedTextColumn get instructions =>
_instructions ??= _constructInstructions();
late final GeneratedTextColumn instructions = _constructInstructions();
GeneratedTextColumn _constructInstructions() {
return GeneratedTextColumn(
'instructions',
@ -435,9 +417,8 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
}
final VerificationMeta _categoryMeta = const VerificationMeta('category');
GeneratedIntColumn _category;
@override
GeneratedIntColumn get category => _category ??= _constructCategory();
late final GeneratedIntColumn category = _constructCategory();
GeneratedIntColumn _constructCategory() {
return GeneratedIntColumn(
'category',
@ -460,11 +441,11 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta));
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
}
if (data.containsKey('title')) {
context.handle(
_titleMeta, title.isAcceptableOrUnknown(data['title'], _titleMeta));
_titleMeta, title.isAcceptableOrUnknown(data['title']!, _titleMeta));
} else if (isInserting) {
context.missing(_titleMeta);
}
@ -472,13 +453,13 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
context.handle(
_instructionsMeta,
instructions.isAcceptableOrUnknown(
data['instructions'], _instructionsMeta));
data['instructions']!, _instructionsMeta));
} else if (isInserting) {
context.missing(_instructionsMeta);
}
if (data.containsKey('category')) {
context.handle(_categoryMeta,
category.isAcceptableOrUnknown(data['category'], _categoryMeta));
category.isAcceptableOrUnknown(data['category']!, _categoryMeta));
}
return context;
}
@ -486,7 +467,7 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
Recipe map(Map<String, dynamic> data, {String tablePrefix}) {
Recipe map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return Recipe.fromData(data, _db, prefix: effectivePrefix);
}
@ -502,46 +483,38 @@ class Ingredient extends DataClass implements Insertable<Ingredient> {
final String name;
final int caloriesPer100g;
Ingredient(
{@required this.id, @required this.name, @required this.caloriesPer100g});
{required this.id, required this.name, required this.caloriesPer100g});
factory Ingredient.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
{String? prefix}) {
final effectivePrefix = prefix ?? '';
final intType = db.typeSystem.forDartType<int>();
final stringType = db.typeSystem.forDartType<String>();
return Ingredient(
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
name: stringType.mapFromDatabaseResponse(data['${effectivePrefix}name']),
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id'])!,
name: stringType.mapFromDatabaseResponse(data['${effectivePrefix}name'])!,
caloriesPer100g:
intType.mapFromDatabaseResponse(data['${effectivePrefix}calories']),
intType.mapFromDatabaseResponse(data['${effectivePrefix}calories'])!,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (!nullToAbsent || id != null) {
map['id'] = Variable<int>(id);
}
if (!nullToAbsent || name != null) {
map['name'] = Variable<String>(name);
}
if (!nullToAbsent || caloriesPer100g != null) {
map['calories'] = Variable<int>(caloriesPer100g);
}
map['id'] = Variable<int>(id);
map['name'] = Variable<String>(name);
map['calories'] = Variable<int>(caloriesPer100g);
return map;
}
IngredientsCompanion toCompanion(bool nullToAbsent) {
return IngredientsCompanion(
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
name: name == null && nullToAbsent ? const Value.absent() : Value(name),
caloriesPer100g: caloriesPer100g == null && nullToAbsent
? const Value.absent()
: Value(caloriesPer100g),
id: Value(id),
name: Value(name),
caloriesPer100g: Value(caloriesPer100g),
);
}
factory Ingredient.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer}) {
{ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return Ingredient(
id: serializer.fromJson<int>(json['id']),
@ -550,12 +523,12 @@ class Ingredient extends DataClass implements Insertable<Ingredient> {
);
}
factory Ingredient.fromJsonString(String encodedJson,
{ValueSerializer serializer}) =>
{ValueSerializer? serializer}) =>
Ingredient.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson({ValueSerializer serializer}) {
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<int>(id),
@ -564,7 +537,8 @@ class Ingredient extends DataClass implements Insertable<Ingredient> {
};
}
Ingredient copyWith({int id, String name, int caloriesPer100g}) => Ingredient(
Ingredient copyWith({int? id, String? name, int? caloriesPer100g}) =>
Ingredient(
id: id ?? this.id,
name: name ?? this.name,
caloriesPer100g: caloriesPer100g ?? this.caloriesPer100g,
@ -602,14 +576,14 @@ class IngredientsCompanion extends UpdateCompanion<Ingredient> {
});
IngredientsCompanion.insert({
this.id = const Value.absent(),
@required String name,
@required int caloriesPer100g,
}) : name = Value(name),
required String name,
required int caloriesPer100g,
}) : name = Value(name),
caloriesPer100g = Value(caloriesPer100g);
static Insertable<Ingredient> custom({
Expression<int> id,
Expression<String> name,
Expression<int> caloriesPer100g,
Expression<int>? id,
Expression<String>? name,
Expression<int>? caloriesPer100g,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
@ -619,7 +593,7 @@ class IngredientsCompanion extends UpdateCompanion<Ingredient> {
}
IngredientsCompanion copyWith(
{Value<int> id, Value<String> name, Value<int> caloriesPer100g}) {
{Value<int>? id, Value<String>? name, Value<int>? caloriesPer100g}) {
return IngredientsCompanion(
id: id ?? this.id,
name: name ?? this.name,
@ -656,21 +630,19 @@ class IngredientsCompanion extends UpdateCompanion<Ingredient> {
class $IngredientsTable extends Ingredients
with TableInfo<$IngredientsTable, Ingredient> {
final GeneratedDatabase _db;
final String _alias;
final String? _alias;
$IngredientsTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id;
@override
GeneratedIntColumn get id => _id ??= _constructId();
late final GeneratedIntColumn id = _constructId();
GeneratedIntColumn _constructId() {
return GeneratedIntColumn('id', $tableName, false,
hasAutoIncrement: true, declaredAsPrimaryKey: true);
}
final VerificationMeta _nameMeta = const VerificationMeta('name');
GeneratedTextColumn _name;
@override
GeneratedTextColumn get name => _name ??= _constructName();
late final GeneratedTextColumn name = _constructName();
GeneratedTextColumn _constructName() {
return GeneratedTextColumn(
'name',
@ -681,10 +653,8 @@ class $IngredientsTable extends Ingredients
final VerificationMeta _caloriesPer100gMeta =
const VerificationMeta('caloriesPer100g');
GeneratedIntColumn _caloriesPer100g;
@override
GeneratedIntColumn get caloriesPer100g =>
_caloriesPer100g ??= _constructCaloriesPer100g();
late final GeneratedIntColumn caloriesPer100g = _constructCaloriesPer100g();
GeneratedIntColumn _constructCaloriesPer100g() {
return GeneratedIntColumn(
'calories',
@ -707,11 +677,11 @@ class $IngredientsTable extends Ingredients
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta));
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
}
if (data.containsKey('name')) {
context.handle(
_nameMeta, name.isAcceptableOrUnknown(data['name'], _nameMeta));
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
} else if (isInserting) {
context.missing(_nameMeta);
}
@ -719,7 +689,7 @@ class $IngredientsTable extends Ingredients
context.handle(
_caloriesPer100gMeta,
caloriesPer100g.isAcceptableOrUnknown(
data['calories'], _caloriesPer100gMeta));
data['calories']!, _caloriesPer100gMeta));
} else if (isInserting) {
context.missing(_caloriesPer100gMeta);
}
@ -729,7 +699,7 @@ class $IngredientsTable extends Ingredients
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
Ingredient map(Map<String, dynamic> data, {String tablePrefix}) {
Ingredient map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return Ingredient.fromData(data, _db, prefix: effectivePrefix);
}
@ -746,52 +716,42 @@ class IngredientInRecipe extends DataClass
final int ingredient;
final int amountInGrams;
IngredientInRecipe(
{@required this.recipe,
@required this.ingredient,
@required this.amountInGrams});
{required this.recipe,
required this.ingredient,
required this.amountInGrams});
factory IngredientInRecipe.fromData(
Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
{String? prefix}) {
final effectivePrefix = prefix ?? '';
final intType = db.typeSystem.forDartType<int>();
return IngredientInRecipe(
recipe: intType.mapFromDatabaseResponse(data['${effectivePrefix}recipe']),
ingredient:
intType.mapFromDatabaseResponse(data['${effectivePrefix}ingredient']),
recipe:
intType.mapFromDatabaseResponse(data['${effectivePrefix}recipe'])!,
ingredient: intType
.mapFromDatabaseResponse(data['${effectivePrefix}ingredient'])!,
amountInGrams:
intType.mapFromDatabaseResponse(data['${effectivePrefix}amount']),
intType.mapFromDatabaseResponse(data['${effectivePrefix}amount'])!,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (!nullToAbsent || recipe != null) {
map['recipe'] = Variable<int>(recipe);
}
if (!nullToAbsent || ingredient != null) {
map['ingredient'] = Variable<int>(ingredient);
}
if (!nullToAbsent || amountInGrams != null) {
map['amount'] = Variable<int>(amountInGrams);
}
map['recipe'] = Variable<int>(recipe);
map['ingredient'] = Variable<int>(ingredient);
map['amount'] = Variable<int>(amountInGrams);
return map;
}
IngredientInRecipesCompanion toCompanion(bool nullToAbsent) {
return IngredientInRecipesCompanion(
recipe:
recipe == null && nullToAbsent ? const Value.absent() : Value(recipe),
ingredient: ingredient == null && nullToAbsent
? const Value.absent()
: Value(ingredient),
amountInGrams: amountInGrams == null && nullToAbsent
? const Value.absent()
: Value(amountInGrams),
recipe: Value(recipe),
ingredient: Value(ingredient),
amountInGrams: Value(amountInGrams),
);
}
factory IngredientInRecipe.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer}) {
{ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return IngredientInRecipe(
recipe: serializer.fromJson<int>(json['recipe']),
@ -800,12 +760,12 @@ class IngredientInRecipe extends DataClass
);
}
factory IngredientInRecipe.fromJsonString(String encodedJson,
{ValueSerializer serializer}) =>
{ValueSerializer? serializer}) =>
IngredientInRecipe.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson({ValueSerializer serializer}) {
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'recipe': serializer.toJson<int>(recipe),
@ -815,7 +775,7 @@ class IngredientInRecipe extends DataClass
}
IngredientInRecipe copyWith(
{int recipe, int ingredient, int amountInGrams}) =>
{int? recipe, int? ingredient, int? amountInGrams}) =>
IngredientInRecipe(
recipe: recipe ?? this.recipe,
ingredient: ingredient ?? this.ingredient,
@ -853,16 +813,16 @@ class IngredientInRecipesCompanion extends UpdateCompanion<IngredientInRecipe> {
this.amountInGrams = const Value.absent(),
});
IngredientInRecipesCompanion.insert({
@required int recipe,
@required int ingredient,
@required int amountInGrams,
}) : recipe = Value(recipe),
required int recipe,
required int ingredient,
required int amountInGrams,
}) : recipe = Value(recipe),
ingredient = Value(ingredient),
amountInGrams = Value(amountInGrams);
static Insertable<IngredientInRecipe> custom({
Expression<int> recipe,
Expression<int> ingredient,
Expression<int> amountInGrams,
Expression<int>? recipe,
Expression<int>? ingredient,
Expression<int>? amountInGrams,
}) {
return RawValuesInsertable({
if (recipe != null) 'recipe': recipe,
@ -872,7 +832,7 @@ class IngredientInRecipesCompanion extends UpdateCompanion<IngredientInRecipe> {
}
IngredientInRecipesCompanion copyWith(
{Value<int> recipe, Value<int> ingredient, Value<int> amountInGrams}) {
{Value<int>? recipe, Value<int>? ingredient, Value<int>? amountInGrams}) {
return IngredientInRecipesCompanion(
recipe: recipe ?? this.recipe,
ingredient: ingredient ?? this.ingredient,
@ -909,12 +869,11 @@ class IngredientInRecipesCompanion extends UpdateCompanion<IngredientInRecipe> {
class $IngredientInRecipesTable extends IngredientInRecipes
with TableInfo<$IngredientInRecipesTable, IngredientInRecipe> {
final GeneratedDatabase _db;
final String _alias;
final String? _alias;
$IngredientInRecipesTable(this._db, [this._alias]);
final VerificationMeta _recipeMeta = const VerificationMeta('recipe');
GeneratedIntColumn _recipe;
@override
GeneratedIntColumn get recipe => _recipe ??= _constructRecipe();
late final GeneratedIntColumn recipe = _constructRecipe();
GeneratedIntColumn _constructRecipe() {
return GeneratedIntColumn(
'recipe',
@ -924,9 +883,8 @@ class $IngredientInRecipesTable extends IngredientInRecipes
}
final VerificationMeta _ingredientMeta = const VerificationMeta('ingredient');
GeneratedIntColumn _ingredient;
@override
GeneratedIntColumn get ingredient => _ingredient ??= _constructIngredient();
late final GeneratedIntColumn ingredient = _constructIngredient();
GeneratedIntColumn _constructIngredient() {
return GeneratedIntColumn(
'ingredient',
@ -937,10 +895,8 @@ class $IngredientInRecipesTable extends IngredientInRecipes
final VerificationMeta _amountInGramsMeta =
const VerificationMeta('amountInGrams');
GeneratedIntColumn _amountInGrams;
@override
GeneratedIntColumn get amountInGrams =>
_amountInGrams ??= _constructAmountInGrams();
late final GeneratedIntColumn amountInGrams = _constructAmountInGrams();
GeneratedIntColumn _constructAmountInGrams() {
return GeneratedIntColumn(
'amount',
@ -964,7 +920,7 @@ class $IngredientInRecipesTable extends IngredientInRecipes
final data = instance.toColumns(true);
if (data.containsKey('recipe')) {
context.handle(_recipeMeta,
recipe.isAcceptableOrUnknown(data['recipe'], _recipeMeta));
recipe.isAcceptableOrUnknown(data['recipe']!, _recipeMeta));
} else if (isInserting) {
context.missing(_recipeMeta);
}
@ -972,7 +928,7 @@ class $IngredientInRecipesTable extends IngredientInRecipes
context.handle(
_ingredientMeta,
ingredient.isAcceptableOrUnknown(
data['ingredient'], _ingredientMeta));
data['ingredient']!, _ingredientMeta));
} else if (isInserting) {
context.missing(_ingredientMeta);
}
@ -980,7 +936,7 @@ class $IngredientInRecipesTable extends IngredientInRecipes
context.handle(
_amountInGramsMeta,
amountInGrams.isAcceptableOrUnknown(
data['amount'], _amountInGramsMeta));
data['amount']!, _amountInGramsMeta));
} else if (isInserting) {
context.missing(_amountInGramsMeta);
}
@ -990,7 +946,7 @@ class $IngredientInRecipesTable extends IngredientInRecipes
@override
Set<GeneratedColumn> get $primaryKey => {recipe, ingredient};
@override
IngredientInRecipe map(Map<String, dynamic> data, {String tablePrefix}) {
IngredientInRecipe map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return IngredientInRecipe.fromData(data, _db, prefix: effectivePrefix);
}
@ -1004,15 +960,11 @@ class $IngredientInRecipesTable extends IngredientInRecipes
abstract class _$Database extends GeneratedDatabase {
_$Database(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e);
_$Database.connect(DatabaseConnection c) : super.connect(c);
$CategoriesTable _categories;
$CategoriesTable get categories => _categories ??= $CategoriesTable(this);
$RecipesTable _recipes;
$RecipesTable get recipes => _recipes ??= $RecipesTable(this);
$IngredientsTable _ingredients;
$IngredientsTable get ingredients => _ingredients ??= $IngredientsTable(this);
$IngredientInRecipesTable _ingredientInRecipes;
$IngredientInRecipesTable get ingredientInRecipes =>
_ingredientInRecipes ??= $IngredientInRecipesTable(this);
late final $CategoriesTable categories = $CategoriesTable(this);
late final $RecipesTable recipes = $RecipesTable(this);
late final $IngredientsTable ingredients = $IngredientsTable(this);
late final $IngredientInRecipesTable ingredientInRecipes =
$IngredientInRecipesTable(this);
Selectable<TotalWeightResult> totalWeight() {
return customSelect(
'SELECT r.title, SUM(ir.amount) AS total_weight\n FROM recipes r\n INNER JOIN recipe_ingredients ir ON ir.recipe = r.id\n GROUP BY r.id',
@ -1037,9 +989,9 @@ class TotalWeightResult extends CustomResultSet {
final String title;
final int totalWeight;
TotalWeightResult({
@required QueryRow row,
this.title,
this.totalWeight,
required QueryRow row,
required this.title,
required this.totalWeight,
}) : super(row);
@override
int get hashCode => $mrjf($mrjc(title.hashCode, totalWeight.hashCode));

View File

@ -12,7 +12,7 @@ import 'package:meta/meta.dart';
import '../moor.dart';
/// Defines extensions on string expressions to support the json1 api from Dart.
extension JsonExtensions on Expression<String> {
extension JsonExtensions on Expression<String?> {
/// Assuming that this string is a json array, returns the length of this json
/// array.
///
@ -28,7 +28,7 @@ extension JsonExtensions on Expression<String> {
///
/// See also:
/// - the [sqlite documentation for this function](https://www.sqlite.org/json1.html#the_json_array_length_function)
Expression<int> jsonArrayLength([String path]) {
Expression<int> jsonArrayLength([String? path]) {
return FunctionCallExpression('json_array_length', [
this,
if (path != null) Variable.withString(path),

View File

@ -11,7 +11,7 @@ import 'package:moor/moor.dart';
/// instead of `NaN`.
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlPow(Expression<num> base, Expression<num> exponent) {
Expression<num?> sqlPow(Expression<num?> base, Expression<num?> exponent) {
return FunctionCallExpression('pow', [base, exponent]);
}
@ -21,7 +21,7 @@ Expression<num> sqlPow(Expression<num> base, Expression<num> exponent) {
/// of `NaN` for negative values.
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlSqrt(Expression<num> value) {
Expression<num?> sqlSqrt(Expression<num?> value) {
return FunctionCallExpression('sqrt', [value]);
}
@ -30,7 +30,7 @@ Expression<num> sqlSqrt(Expression<num> value) {
/// This function is equivalent to [sin].
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlSin(Expression<num> value) {
Expression<num?> sqlSin(Expression<num?> value) {
return FunctionCallExpression('sin', [value]);
}
@ -39,7 +39,7 @@ Expression<num> sqlSin(Expression<num> value) {
/// This function is equivalent to [sin].
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlCos(Expression<num> value) {
Expression<num?> sqlCos(Expression<num?> value) {
return FunctionCallExpression('cos', [value]);
}
@ -48,7 +48,7 @@ Expression<num> sqlCos(Expression<num> value) {
/// This function is equivalent to [tan].
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlTan(Expression<num> value) {
Expression<num?> sqlTan(Expression<num?> value) {
return FunctionCallExpression('tan', [value]);
}
@ -58,7 +58,7 @@ Expression<num> sqlTan(Expression<num> value) {
/// instead of `NaN`.
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlAsin(Expression<num> value) {
Expression<num?> sqlAsin(Expression<num?> value) {
return FunctionCallExpression('asin', [value]);
}
@ -68,7 +68,7 @@ Expression<num> sqlAsin(Expression<num> value) {
/// instead of `NaN`.
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlAcos(Expression<num> value) {
Expression<num?> sqlAcos(Expression<num?> value) {
return FunctionCallExpression('acos', [value]);
}
@ -78,13 +78,13 @@ Expression<num> sqlAcos(Expression<num> value) {
/// instead of `NaN`.
///
/// This function is only available when using `moor_ffi`.
Expression<num> sqlAtan(Expression<num> value) {
Expression<num?> sqlAtan(Expression<num?> value) {
return FunctionCallExpression('atan', [value]);
}
/// Adds functionality to string expressions that only work when using
/// `moor_ffi`.
extension MoorFfiSpecificStringExtensions on Expression<String> {
extension MoorFfiSpecificStringExtensions on Expression<String?> {
/// Version of `contains` that allows controlling case sensitivity better.
///
/// The default `contains` method uses sqlite's `LIKE`, which is case-
@ -102,7 +102,7 @@ extension MoorFfiSpecificStringExtensions on Expression<String> {
///
/// Note that this is only available when using `moor_ffi` version 0.6.0 or
/// greater.
Expression<bool> containsCase(String substring,
Expression<bool?> containsCase(String substring,
{bool caseSensitive = false}) {
return FunctionCallExpression('moor_contains', [
this,

View File

@ -8,24 +8,24 @@ abstract class Column<T> extends Expression<T> {
}
/// A column that stores int values.
abstract class IntColumn extends Column<int> {}
abstract class IntColumn extends Column<int?> {}
/// A column that stores boolean values. Booleans will be stored as an integer
/// that can either be 0 (false) or 1 (true).
abstract class BoolColumn extends Column<bool> {}
abstract class BoolColumn extends Column<bool?> {}
/// A column that stores text.
abstract class TextColumn extends Column<String> {}
abstract class TextColumn extends Column<String?> {}
/// A column that stores a [DateTime]. Times will be stored as unix timestamp
/// and will thus have a second accuracy.
abstract class DateTimeColumn extends Column<DateTime> {}
abstract class DateTimeColumn extends Column<DateTime?> {}
/// A column that stores arbitrary blobs of data as a [Uint8List].
abstract class BlobColumn extends Column<Uint8List> {}
abstract class BlobColumn extends Column<Uint8List?> {}
/// A column that stores floating point numeric values.
abstract class RealColumn extends Column<double> {}
abstract class RealColumn extends Column<double?> {}
/// A column builder is used to specify which columns should appear in a table.
/// All of the methods defined in this class and its subclasses are not meant to
@ -173,7 +173,8 @@ class ColumnBuilder<Builder, ResultColumn extends Column<ResultDartType>,
/// Tells the generator to build an [IntColumn]. See the docs at [ColumnBuilder]
/// for details.
class IntColumnBuilder extends ColumnBuilder<IntColumnBuilder, IntColumn, int> {
class IntColumnBuilder
extends ColumnBuilder<IntColumnBuilder, IntColumn, int?> {
/// Enables auto-increment for this column, which will also make this column
/// the primary key of the table.
///
@ -185,35 +186,37 @@ class IntColumnBuilder extends ColumnBuilder<IntColumnBuilder, IntColumn, int> {
/// Tells the generator to build an [BoolColumn]. See the docs at
/// [ColumnBuilder] for details.
class BoolColumnBuilder
extends ColumnBuilder<BoolColumnBuilder, BoolColumn, bool> {}
extends ColumnBuilder<BoolColumnBuilder, BoolColumn, bool?> {}
/// Tells the generator to build an [BlobColumn]. See the docs at
/// [ColumnBuilder] for details.
class BlobColumnBuilder
extends ColumnBuilder<BlobColumnBuilder, BlobColumn, Uint8List> {}
extends ColumnBuilder<BlobColumnBuilder, BlobColumn, Uint8List?> {}
/// Tells the generator to build an [RealColumn]. See the docs at
/// [ColumnBuilder] for details.
class RealColumnBuilder
extends ColumnBuilder<RealColumnBuilder, RealColumn, num> {}
extends ColumnBuilder<RealColumnBuilder, RealColumn, num?> {}
/// Tells the generator to build an [TextColumn]. See the docs at
/// [ColumnBuilder] for details.
class TextColumnBuilder
extends ColumnBuilder<TextColumnBuilder, TextColumn, String> {
extends ColumnBuilder<TextColumnBuilder, TextColumn, String?> {
/// Puts a constraint on the minimum and maximum length of text that can be
/// stored in this column (will be validated whenever this column is updated
/// or a value is inserted). If [min] is not null and one tries to write a
/// string so that [String.length] is smaller than [min], the query will throw
/// an exception when executed and no data will be written. The same applies
/// for [max].
TextColumnBuilder withLength({int min, int max}) => _isGenerated();
/// stored in this column.
///
/// Both [min] and [max] are inclusive. This constraint will be validated in
/// Dart, it doesn't have an impact on the database schema. If [min] is not
/// null and one tries to write a string which [String.length] is
/// _strictly less_ than [min], an exception will be thrown. Similarly, you
/// can't insert strings with a length _strictly greater_ than [max].
TextColumnBuilder withLength({int? min, int? max}) => _isGenerated();
}
/// Tells the generator to build an [DateTimeColumn]. See the docs at
/// [ColumnBuilder] for details.
class DateTimeColumnBuilder
extends ColumnBuilder<DateTimeColumnBuilder, DateTimeColumn, DateTime> {}
extends ColumnBuilder<DateTimeColumnBuilder, DateTimeColumn, DateTime?> {}
/// Annotation to use on column getters inside of a [Table] to define the name
/// of the column in the json used by [DataClass.toJson].

View File

@ -30,7 +30,7 @@ part 'table.dart';
/// );
/// }
/// ```
Null /* = Never */ _isGenerated() {
Never _isGenerated() {
throw UnsupportedError(
'This method should not be called at runtime. Are you sure you re-ran the '
'builder after changing your tables or databases?',

View File

@ -15,7 +15,7 @@ abstract class Table {
/// valid, whereas `@override final String tableName = 'my_table';` or
/// `@override String get tableName => createMyTableName();` is not.
@visibleForOverriding
String get tableName => null;
String? get tableName => null;
/// Whether to append a `WITHOUT ROWID` clause in the `CREATE TABLE`
/// statement. This is intended to be used by generated code only.
@ -45,7 +45,7 @@ abstract class Table {
/// As an auto-incremented `IntColumn` is recognized by moor to be the
/// primary key, doing so will result in an exception thrown at runtime.
@visibleForOverriding
Set<Column> get primaryKey => null;
Set<Column>? get primaryKey => null;
/// Custom table constraints that should be added to the table.
///

View File

@ -96,12 +96,12 @@ extension EnableMoorFunctions on Database {
deterministic: true,
directOnly: false,
argumentCount: const AllowedArgumentCount(0),
function: (List<dynamic> args) => DateTime.now().millisecondsSinceEpoch,
function: (List<Object?> args) => DateTime.now().millisecondsSinceEpoch,
);
}
}
num _pow(List<dynamic> args) {
num? _pow(List<Object?> args) {
final first = args[0];
final second = args[1];
@ -109,7 +109,7 @@ num _pow(List<dynamic> args) {
return null;
}
return pow(first as num, second as num);
return pow(first, second);
}
/// Base implementation for a sqlite function that takes one numerical argument
@ -117,8 +117,8 @@ num _pow(List<dynamic> args) {
///
/// When not called with a number, returns will null. Otherwise, returns with
/// [calculation].
num Function(List<dynamic>) _unaryNumFunction(num Function(num) calculation) {
return (List<dynamic> args) {
num? Function(List<Object?>) _unaryNumFunction(num Function(num) calculation) {
return (List<Object?> args) {
// sqlite will ensure that this is only called with one argument
final value = args[0];
if (value is num) {
@ -129,7 +129,7 @@ num Function(List<dynamic>) _unaryNumFunction(num Function(num) calculation) {
};
}
bool _regexpImpl(List<dynamic> args) {
bool? _regexpImpl(List<Object?> args) {
var multiLine = false;
var caseSensitive = true;
var unicode = false;
@ -165,7 +165,7 @@ bool _regexpImpl(List<dynamic> args) {
RegExp regex;
try {
regex = RegExp(
firstParam as String,
firstParam,
multiLine: multiLine,
caseSensitive: caseSensitive,
unicode: unicode,
@ -175,7 +175,7 @@ bool _regexpImpl(List<dynamic> args) {
throw 'Invalid regex';
}
return regex.hasMatch(secondParam as String);
return regex.hasMatch(secondParam);
}
bool _containsImpl(List<dynamic> args) {
@ -193,12 +193,9 @@ bool _containsImpl(List<dynamic> args) {
final caseSensitive = argCount == 3 && args[2] == 1;
final firstAsString = first as String;
final secondAsString = second as String;
final result = caseSensitive
? firstAsString.contains(secondAsString)
: firstAsString.toLowerCase().contains(secondAsString.toLowerCase());
? first.contains(second)
: first.toLowerCase().contains(second.toLowerCase());
return result;
}

View File

@ -32,14 +32,15 @@ class VmDatabase extends DelegatedDatabase {
/// SQLCipher implementations.
/// {@endtemplate}
factory VmDatabase(File file,
{bool logStatements = false, DatabaseSetup setup}) {
{bool logStatements = false, DatabaseSetup? setup}) {
return VmDatabase._(_VmDelegate(file, setup), logStatements);
}
/// Creates an in-memory database won't persist its changes on disk.
///
/// {@macro moor_vm_database_factory}
factory VmDatabase.memory({bool logStatements = false, DatabaseSetup setup}) {
factory VmDatabase.memory(
{bool logStatements = false, DatabaseSetup? setup}) {
return VmDatabase._(_VmDelegate(null, setup), logStatements);
}
@ -51,7 +52,7 @@ class VmDatabase extends DelegatedDatabase {
///
/// {@macro moor_vm_database_factory}
factory VmDatabase.opened(Database database,
{bool logStatements = false, DatabaseSetup setup}) {
{bool logStatements = false, DatabaseSetup? setup}) {
return VmDatabase._(_VmDelegate._opened(database, setup), logStatements);
}
@ -106,11 +107,11 @@ class VmDatabase extends DelegatedDatabase {
}
class _VmDelegate extends DatabaseDelegate {
Database _db;
late Database _db;
bool _isOpen = false;
final File file;
final DatabaseSetup setup;
final File? file;
final DatabaseSetup? setup;
_VmDelegate(this.file, this.setup);
@ -122,14 +123,14 @@ class _VmDelegate extends DatabaseDelegate {
TransactionDelegate get transactionDelegate => const NoTransactionDelegate();
@override
DbVersionDelegate versionDelegate;
late DbVersionDelegate versionDelegate;
@override
Future<bool> get isOpen => Future.value(_isOpen);
@override
Future<void> open(QueryExecutorUser user) async {
if (_db == null) {
if (!_isOpen) {
_createDatabase();
}
_initializeDatabase();
@ -138,7 +139,9 @@ class _VmDelegate extends DatabaseDelegate {
}
void _createDatabase() {
assert(_db == null);
assert(!_isOpen);
final file = this.file;
if (file != null) {
// Create the parent directory if it doesn't exist. sqlite will emit
// confusing misuse warnings otherwise
@ -156,9 +159,7 @@ class _VmDelegate extends DatabaseDelegate {
void _initializeDatabase() {
_db.useMoorVersions();
if (setup != null) {
setup(_db);
}
setup?.call(_db);
versionDelegate = _VmVersionDelegate(_db);
}
@ -181,7 +182,7 @@ class _VmDelegate extends DatabaseDelegate {
return Future.value();
}
Future _runWithArgs(String statement, List<dynamic> args) async {
Future _runWithArgs(String statement, List<Object?> args) async {
if (args.isEmpty) {
_db.execute(statement);
} else {
@ -192,24 +193,24 @@ class _VmDelegate extends DatabaseDelegate {
}
@override
Future<void> runCustom(String statement, List args) async {
Future<void> runCustom(String statement, List<Object?> args) async {
await _runWithArgs(statement, args);
}
@override
Future<int> runInsert(String statement, List args) async {
Future<int> runInsert(String statement, List<Object?> args) async {
await _runWithArgs(statement, args);
return _db.lastInsertRowId;
}
@override
Future<int> runUpdate(String statement, List args) async {
Future<int> runUpdate(String statement, List<Object?> args) async {
await _runWithArgs(statement, args);
return _db.getUpdatedRows();
}
@override
Future<QueryResult> runSelect(String statement, List args) async {
Future<QueryResult> runSelect(String statement, List<Object?> args) async {
final stmt = _db.prepare(statement);
final result = stmt.select(args);
stmt.dispose();

View File

@ -38,7 +38,7 @@ class Batch {
/// - [InsertStatement.insert], which would be used outside a [Batch].
void insert<T extends Table, D extends DataClass>(
TableInfo<T, D> table, Insertable<D> row,
{InsertMode mode, DoUpdate<T, D> onConflict}) {
{InsertMode? mode, DoUpdate<T, D>? onConflict}) {
_addUpdate(table, UpdateKind.insert);
final actualMode = mode ?? InsertMode.insert;
final context = InsertStatement<Table, D>(_engine, table)
@ -60,7 +60,7 @@ class Batch {
/// support it. For details and examples, see [InsertStatement.insert].
void insertAll<T extends Table, D extends DataClass>(
TableInfo<T, D> table, List<Insertable<D>> rows,
{InsertMode mode, DoUpdate<T, D> onConflict}) {
{InsertMode? mode, DoUpdate<T, D>? onConflict}) {
for (final row in rows) {
insert<T, D>(table, row, mode: mode, onConflict: onConflict);
}
@ -82,7 +82,7 @@ class Batch {
/// [UpdateStatement.write] or the [documentation with examples](https://moor.simonbinder.eu/docs/getting-started/writing_queries/#updates-and-deletes)
void update<T extends Table, D extends DataClass>(
TableInfo<T, D> table, Insertable<D> row,
{Expression<bool> Function(T table) where}) {
{Expression<bool> Function(T table)? where}) {
_addUpdate(table, UpdateKind.update);
final stmt = UpdateStatement(_engine, table);
if (where != null) stmt.where(where);
@ -148,8 +148,8 @@ class Batch {
/// See also:
/// - [QueryEngine.customStatement], the equivalent method outside of
/// batches.
void customStatement(String sql, [List<dynamic> args]) {
_addSqlAndArguments(sql, args);
void customStatement(String sql, [List<dynamic>? args]) {
_addSqlAndArguments(sql, args ?? const []);
}
void _addContext(GenerationContext ctx) {
@ -171,17 +171,17 @@ class Batch {
await _engine.executor.ensureOpen(_engine.attachedDatabase);
if (_startTransaction) {
TransactionExecutor transaction;
TransactionExecutor? transaction;
try {
transaction = _engine.executor.beginTransaction();
await transaction.ensureOpen(null);
await transaction.ensureOpen(_engine.attachedDatabase);
await _runWith(transaction);
await transaction.send();
} catch (e) {
await transaction.rollback();
await transaction?.rollback();
rethrow;
}
} else {

View File

@ -52,12 +52,10 @@ class DatabaseConnection {
return connection;
}
final future = connection as Future<DatabaseConnection>;
return DatabaseConnection(
SqlTypeSystem.defaultInstance,
LazyDatabase(() async => (await future).executor),
DelayedStreamQueryStore(future.then((conn) => conn.streamQueries)),
LazyDatabase(() async => (await connection).executor),
DelayedStreamQueryStore(connection.then((conn) => conn.streamQueries)),
);
}
@ -89,16 +87,16 @@ abstract class DatabaseConnectionUser {
/// Constructs a database connection user, which is responsible to store query
/// streams, wrap the underlying executor and perform type mapping.
DatabaseConnectionUser(SqlTypeSystem typeSystem, QueryExecutor executor,
{StreamQueryStore streamQueries})
{StreamQueryStore? streamQueries})
: connection = DatabaseConnection(
typeSystem, executor, streamQueries ?? StreamQueryStore());
/// Creates another [DatabaseConnectionUser] by referencing the implementation
/// from the [other] user.
DatabaseConnectionUser.delegate(DatabaseConnectionUser other,
{SqlTypeSystem typeSystem,
QueryExecutor executor,
StreamQueryStore streamQueries})
{SqlTypeSystem? typeSystem,
QueryExecutor? executor,
StreamQueryStore? streamQueries})
: connection = DatabaseConnection(
typeSystem ?? other.connection.typeSystem,
executor ?? other.connection.executor,

View File

@ -30,7 +30,7 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
/// changes in your schema, you'll need a custom migration strategy to create
/// the new tables or change the columns.
MigrationStrategy get migration => MigrationStrategy();
MigrationStrategy _cachedMigration;
MigrationStrategy? _cachedMigration;
MigrationStrategy get _resolvedMigration => _cachedMigration ??= migration;
/// The collection of update rules contains information on how updates on
@ -58,7 +58,7 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
/// Used by generated code
GeneratedDatabase(SqlTypeSystem types, QueryExecutor executor,
{StreamQueryStore streamStore})
{StreamQueryStore? streamStore})
: super(types, executor, streamQueries: streamStore) {
assert(_handleInstantiated());
}
@ -75,7 +75,9 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
_openedDbCount[runtimeType] = 1;
return true;
}
final count = ++_openedDbCount[runtimeType];
final count =
_openedDbCount[runtimeType] = _openedDbCount[runtimeType]! + 1;
if (count > 1) {
// ignore: avoid_print
print(
@ -117,7 +119,7 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
} else if (details.hadUpgrade) {
final migrator = createMigrator();
await _resolvedMigration.onUpgrade(
migrator, details.versionBefore, details.versionNow);
migrator, details.versionBefore!, details.versionNow);
}
await _resolvedMigration.beforeOpen?.call(details);
@ -131,7 +133,7 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
assert(() {
if (_openedDbCount[runtimeType] != null) {
_openedDbCount[runtimeType]--;
_openedDbCount[runtimeType] = _openedDbCount[runtimeType]! - 1;
}
return true;
}());

View File

@ -47,7 +47,7 @@ mixin QueryEngine on DatabaseConnectionUser {
// if an overridden executor has been specified for this zone (this will
// happen for transactions), use that one.
final resolved = Zone.current[_zoneRootUserKey];
return (resolved as QueryEngine) ?? this;
return (resolved as QueryEngine?) ?? this;
}
}
@ -201,8 +201,8 @@ mixin QueryEngine on DatabaseConnectionUser {
Future<int> customUpdate(
String query, {
List<Variable> variables = const [],
Set<TableInfo> updates,
UpdateKind updateKind,
Set<TableInfo>? updates,
UpdateKind? updateKind,
}) async {
return _customWrite(
query,
@ -221,7 +221,7 @@ mixin QueryEngine on DatabaseConnectionUser {
/// [updates] parameter. Query-streams running on any of these tables will
/// then be re-run.
Future<int> customInsert(String query,
{List<Variable> variables = const [], Set<TableInfo> updates}) {
{List<Variable> variables = const [], Set<TableInfo>? updates}) {
return _customWrite(
query,
variables,
@ -239,8 +239,8 @@ mixin QueryEngine on DatabaseConnectionUser {
Future<T> _customWrite<T>(
String query,
List<Variable> variables,
Set<TableInfo> updates,
UpdateKind updateKind,
Set<TableInfo>? updates,
UpdateKind? updateKind,
_CustomWriter<T> writer,
) async {
final engine = _resolvedEngine;
@ -273,7 +273,6 @@ mixin QueryEngine on DatabaseConnectionUser {
Selectable<QueryRow> customSelect(String query,
{List<Variable> variables = const [],
Set<TableInfo> readsFrom = const {}}) {
readsFrom ??= {};
return CustomSelectStatement(query, variables, readsFrom, _resolvedEngine);
}
@ -294,7 +293,7 @@ mixin QueryEngine on DatabaseConnectionUser {
}
/// Executes the custom sql [statement] on the database.
Future<void> customStatement(String statement, [List<dynamic> args]) {
Future<void> customStatement(String statement, [List<dynamic>? args]) {
final engine = _resolvedEngine;
return engine.doWhenOpened((executor) {
@ -408,7 +407,7 @@ mixin QueryEngine on DatabaseConnectionUser {
/// Will be used by generated code to resolve inline Dart components in sql.
@protected
GenerationContext $write(Component component, {bool hasMultipleTables}) {
GenerationContext $write(Component component, {bool? hasMultipleTables}) {
final context = GenerationContext.fromDb(this);
if (hasMultipleTables != null) {
context.hasMultipleTables = hasMultipleTables;

View File

@ -60,8 +60,7 @@ class WritePropagation extends UpdateRule {
final List<TableUpdate> result;
/// Default constructor. See [WritePropagation] for details.
const WritePropagation({@required this.on, @required this.result})
: super._();
const WritePropagation({required this.on, required this.result}) : super._();
}
/// Classifies a [TableUpdate] by what kind of write happened - an insert, an
@ -83,7 +82,7 @@ class TableUpdate {
/// What kind of update was applied to the [table].
///
/// Can be null, which indicates that the update is not known.
final UpdateKind /*?*/ kind;
final UpdateKind? kind;
/// Name of the table that was updated.
final String table;
@ -93,7 +92,7 @@ class TableUpdate {
/// Creates a [TableUpdate] instance based on a [TableInfo] instead of the raw
/// name.
factory TableUpdate.onTable(TableInfo table, {UpdateKind kind}) {
factory TableUpdate.onTable(TableInfo table, {UpdateKind? kind}) {
return TableUpdate(table.actualTableName, kind: kind);
}
@ -131,14 +130,14 @@ abstract class TableUpdateQuery {
/// The optional [limitUpdateKind] parameter can be used to limit the updates
/// to a certain kind.
const factory TableUpdateQuery.onTableName(String table,
{UpdateKind limitUpdateKind}) = SpecificUpdateQuery;
{UpdateKind? limitUpdateKind}) = SpecificUpdateQuery;
/// A query that listens for all updates on a specific [table].
///
/// The optional [limitUpdateKind] parameter can be used to limit the updates
/// to a certain kind.
factory TableUpdateQuery.onTable(TableInfo table,
{UpdateKind limitUpdateKind}) {
{UpdateKind? limitUpdateKind}) {
return TableUpdateQuery.onTableName(
table.actualTableName,
limitUpdateKind: limitUpdateKind,

View File

@ -32,13 +32,13 @@ abstract class DataClass {
/// [json]. The [serializer] can be used to configure how individual values
/// will be encoded. By default, [MoorRuntimeOptions.defaultSerializer] will
/// be used. See [ValueSerializer.defaults] for details.
Map<String, dynamic> toJson({ValueSerializer serializer});
Map<String, dynamic> toJson({ValueSerializer? serializer});
/// Converts this object into a json representation. The [serializer] can be
/// used to configure how individual values will be encoded. By default,
/// [MoorRuntimeOptions.defaultSerializer] will be used. See
/// [ValueSerializer.defaults] for details.
String toJsonString({ValueSerializer serializer}) {
String toJsonString({ValueSerializer? serializer}) {
return json.encode(toJson(serializer: serializer));
}
@ -73,11 +73,7 @@ abstract class UpdateCompanion<D extends DataClass> implements Insertable<D> {
if (identical(this, other)) return true;
if (other is! UpdateCompanion<D>) return false;
return _mapEquality.equals(
// ignore: test_types_in_equals
(other as UpdateCompanion<D>).toColumns(false),
toColumns(false),
);
return _mapEquality.equals(other.toColumns(false), toColumns(false));
}
}
@ -111,16 +107,20 @@ class Value<T> {
/// inserted or updated.
final bool present;
final T? _value;
/// If this value is [present], contains the value to update or insert.
final T value;
T get value => _value as T;
/// Create a (present) value by wrapping the [value] provided.
const Value(this.value) : present = true;
const Value(T value)
: _value = value,
present = true;
/// Create an absent value that will not be written into the database, the
/// default value or null will be used instead.
const Value.absent()
: value = null,
: _value = null,
present = false;
@override
@ -164,20 +164,22 @@ class _DefaultValueSerializer extends ValueSerializer {
@override
T fromJson<T>(dynamic json) {
if (json == null) {
return null;
return null as T;
}
if (T == DateTime) {
final _typeList = <T>[];
if (_typeList is List<DateTime?>) {
return DateTime.fromMillisecondsSinceEpoch(json as int) as T;
}
if (T == 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 (T == 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

@ -18,7 +18,7 @@ class VerificationResult {
/// If not [success]-ful, contains a human readable description of what went
/// wrong.
final String message;
final String? message;
/// Used internally by moor
const VerificationResult(this.success, this.message);

View File

@ -23,14 +23,14 @@ class MoorWrappedException implements Exception {
final String message;
/// The underlying exception caught by moor
final dynamic cause;
final Object? cause;
/// The original stacktrace when caught by moor
final StackTrace trace;
final StackTrace? trace;
/// Creates a new [MoorWrappedException] to provide additional details about
/// an underlying error from the database.
MoorWrappedException({this.message, this.cause, this.trace});
MoorWrappedException({required this.message, this.cause, this.trace});
@override
String toString() {

View File

@ -1,4 +1,3 @@
import 'package:meta/meta.dart';
import 'package:moor/backends.dart';
import 'package:moor/moor.dart';
@ -10,7 +9,7 @@ abstract class MultiExecutor extends QueryExecutor {
/// with [write]. Select statements outside of a transaction are executed on
/// [read].
factory MultiExecutor(
{@required QueryExecutor read, @required QueryExecutor write}) {
{required QueryExecutor read, required QueryExecutor write}) {
return _MultiExecutorImpl(read, write);
}
@ -44,28 +43,28 @@ class _MultiExecutorImpl extends MultiExecutor {
}
@override
Future<void> runCustom(String statement, [List args]) async {
Future<void> runCustom(String statement, [List<Object?>? args]) async {
await _writes.runCustom(statement, args);
}
@override
Future<int> runDelete(String statement, List args) async {
Future<int> runDelete(String statement, List<Object?> args) async {
return await _writes.runDelete(statement, args);
}
@override
Future<int> runInsert(String statement, List args) async {
Future<int> runInsert(String statement, List<Object?> args) async {
return await _writes.runInsert(statement, args);
}
@override
Future<List<Map<String, dynamic>>> runSelect(
String statement, List args) async {
Future<List<Map<String, Object?>>> runSelect(
String statement, List<Object?> args) async {
return await _reads.runSelect(statement, args);
}
@override
Future<int> runUpdate(String statement, List args) async {
Future<int> runUpdate(String statement, List<Object?> args) async {
return await _writes.runUpdate(statement, args);
}

View File

@ -7,8 +7,8 @@ import 'stream_queries.dart';
/// This class is internal and should not be exposed to moor users. It's used
/// through a delayed database connection.
class DelayedStreamQueryStore implements StreamQueryStore {
Future<StreamQueryStore> _delegate;
StreamQueryStore _resolved;
late Future<StreamQueryStore> _delegate;
StreamQueryStore? _resolved;
/// Creates a [StreamQueryStore] that will work after [delegate] is
/// available.

View File

@ -23,23 +23,23 @@ abstract class QueryExecutor {
/// Runs a select statement with the given variables and returns the raw
/// results.
Future<List<Map<String, dynamic>>> runSelect(
String statement, List<dynamic> args);
Future<List<Map<String, Object?>>> runSelect(
String statement, List<Object?> args);
/// Runs an insert statement with the given variables. Returns the row id or
/// the auto_increment id of the inserted row.
Future<int> runInsert(String statement, List<dynamic> args);
Future<int> runInsert(String statement, List<Object?> args);
/// Runs an update statement with the given variables and returns how many
/// rows where affected.
Future<int> runUpdate(String statement, List<dynamic> args);
Future<int> runUpdate(String statement, List<Object?> args);
/// Runs an delete statement and returns how many rows where affected.
Future<int> runDelete(String statement, List<dynamic> args);
Future<int> runDelete(String statement, List<Object?> args);
/// Runs a custom SQL statement without any variables. The result of that
/// statement will be ignored.
Future<void> runCustom(String statement, [List<dynamic> args]);
Future<void> runCustom(String statement, [List<Object?>? args]);
/// Prepares and runs [statements].
///
@ -119,7 +119,7 @@ class ArgumentsForBatchedStatement {
final int statementIndex;
/// Bound arguments for the referenced statement.
final List<dynamic> arguments;
final List<Object?> arguments;
/// Used internally by moor.
ArgumentsForBatchedStatement(this.statementIndex, this.arguments);

View File

@ -76,7 +76,7 @@ abstract class QueryDelegate {
///
/// If the statement can't be executed, an exception should be thrown. See
/// the class documentation of [DatabaseDelegate] on what types are supported.
Future<QueryResult> runSelect(String statement, List<dynamic> args);
Future<QueryResult> runSelect(String statement, List<Object?> args);
/// Prepares and executes the [statement] with the variables bound to [args].
/// The statement will either be an `UPDATE` or `DELETE` statement.
@ -84,7 +84,7 @@ abstract class QueryDelegate {
/// If the statement completes successfully, the amount of changed rows should
/// be returned, or `0` if no rows where updated. Should throw if the
/// statement can't be executed.
Future<int> runUpdate(String statement, List<dynamic> args);
Future<int> runUpdate(String statement, List<Object?> args);
/// Prepares and executes the [statement] with the variables bound to [args].
/// The statement will be an `INSERT` statement.
@ -92,11 +92,11 @@ abstract class QueryDelegate {
/// If the statement completes successfully, the insert id of the row can be
/// returned. If that information is not available, `null` can be returned.
/// The method should throw if the statement can't be executed.
Future<int> runInsert(String statement, List<dynamic> args);
Future<int> runInsert(String statement, List<Object?> args);
/// Runs a custom [statement] with the given [args]. Ignores all results, but
/// throws when the statement can't be executed.
Future<void> runCustom(String statement, List<dynamic> args);
Future<void> runCustom(String statement, List<Object?> args);
/// Runs multiple [statements] without having to prepare the same statement
/// multiple times.

View File

@ -26,15 +26,15 @@ mixin _ExecutorWithQueryDelegate on QueryExecutor {
}
}
void _log(String sql, List<dynamic> args) {
void _log(String sql, List<Object?> args) {
if (logStatements) {
print('Moor: Sent $sql with args $args');
}
}
@override
Future<List<Map<String, dynamic>>> runSelect(
String statement, List args) async {
Future<List<Map<String, Object?>>> runSelect(
String statement, List<Object?> args) async {
assert(_ensureOpenCalled);
final result = await _synchronized(() {
_log(statement, args);
@ -44,7 +44,7 @@ mixin _ExecutorWithQueryDelegate on QueryExecutor {
}
@override
Future<int> runUpdate(String statement, List args) {
Future<int> runUpdate(String statement, List<Object?> args) {
assert(_ensureOpenCalled);
return _synchronized(() {
_log(statement, args);
@ -53,7 +53,7 @@ mixin _ExecutorWithQueryDelegate on QueryExecutor {
}
@override
Future<int> runDelete(String statement, List args) {
Future<int> runDelete(String statement, List<Object?> args) {
assert(_ensureOpenCalled);
return _synchronized(() {
_log(statement, args);
@ -62,7 +62,7 @@ mixin _ExecutorWithQueryDelegate on QueryExecutor {
}
@override
Future<int> runInsert(String statement, List args) {
Future<int> runInsert(String statement, List<Object?> args) {
assert(_ensureOpenCalled);
return _synchronized(() {
_log(statement, args);
@ -71,7 +71,7 @@ mixin _ExecutorWithQueryDelegate on QueryExecutor {
}
@override
Future<void> runCustom(String statement, [List<dynamic> args]) {
Future<void> runCustom(String statement, [List<Object?>? args]) {
assert(_ensureOpenCalled);
return _synchronized(() {
final resolvedArgs = args ?? const [];
@ -97,7 +97,7 @@ class _TransactionExecutor extends TransactionExecutor
final DelegatedDatabase _db;
@override
QueryDelegate impl;
late QueryDelegate impl;
@override
bool get isSequential => _db.isSequential;
@ -106,10 +106,10 @@ class _TransactionExecutor extends TransactionExecutor
bool get logStatements => _db.logStatements;
final Completer<void> _sendCalled = Completer();
Completer<bool> _openingCompleter;
Completer<bool>? _openingCompleter;
String _sendOnCommit;
String _sendOnRollback;
String? _sendOnCommit;
String? _sendOnRollback;
Future get completed => _sendCalled.future;
bool _sendFakeErrorOnRollback = false;
@ -133,7 +133,7 @@ class _TransactionExecutor extends TransactionExecutor
_ensureOpenCalled = true;
if (_openingCompleter != null) {
return await _openingCompleter.future;
return await _openingCompleter!.future;
}
_openingCompleter = Completer();
@ -178,7 +178,7 @@ class _TransactionExecutor extends TransactionExecutor
}
await transactionStarted.future;
_openingCompleter.complete(true);
_openingCompleter!.complete(true);
return true;
}
@ -188,7 +188,7 @@ class _TransactionExecutor extends TransactionExecutor
if (_openingCompleter == null) return;
if (_sendOnCommit != null) {
await runCustom(_sendOnCommit, const []);
await runCustom(_sendOnCommit!, const []);
_db.delegate.isInTransaction = false;
}
@ -202,7 +202,7 @@ class _TransactionExecutor extends TransactionExecutor
if (_openingCompleter == null) return;
if (_sendOnRollback != null) {
await runCustom(_sendOnRollback, const []);
await runCustom(_sendOnRollback!, const []);
_db.delegate.isInTransaction = false;
}
@ -238,10 +238,8 @@ class DelegatedDatabase extends QueryExecutor with _ExecutorWithQueryDelegate {
/// Constructs a delegated database by providing the [delegate].
DelegatedDatabase(this.delegate,
{this.logStatements, this.isSequential = false}) {
// not using default value because it's commonly set to null
logStatements ??= false;
}
{bool? logStatements, this.isSequential = false})
: logStatements = logStatements ?? false;
@override
Future<bool> ensureOpen(QueryExecutorUser user) {
@ -260,7 +258,7 @@ class DelegatedDatabase extends QueryExecutor with _ExecutorWithQueryDelegate {
Future<void> _runMigrations(QueryExecutorUser user) async {
final versionDelegate = delegate.versionDelegate;
int oldVersion;
int? oldVersion;
final currentVersion = user.schemaVersion;
if (versionDelegate is NoVersionDelegate) {

View File

@ -5,17 +5,17 @@ class QueryResult {
/// The data returned by the select statement. Each list represents a row,
/// which has the data in the same order as [columnNames].
final List<List<dynamic>> rows;
final List<List<Object?>> rows;
Map<String, int> _columnIndexes;
final Map<String, int> _columnIndexes;
/// Constructs a [QueryResult] by specifying the order of column names in
/// [columnNames] and the associated data in [rows].
QueryResult(this.columnNames, this.rows) {
_columnIndexes = {
for (var column in columnNames) column: columnNames.lastIndexOf(column)
};
}
QueryResult(this.columnNames, this.rows)
: _columnIndexes = {
for (var column in columnNames)
column: columnNames.lastIndexOf(column)
};
/// Converts the [rows] into [columnNames] and raw data [QueryResult.rows].
/// We assume that each map in [rows] has the same keys.
@ -38,7 +38,7 @@ class QueryResult {
Iterable<Map<String, dynamic>> get asMap {
return rows.map((row) {
return {
for (var column in columnNames) column: row[_columnIndexes[column]],
for (var column in columnNames) column: row[_columnIndexes[column]!],
};
});
}

View File

@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:collection';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:moor/moor.dart';
import 'package:moor/src/utils/start_with_value_transformer.dart';
import 'package:pedantic/pedantic.dart';
@ -22,13 +21,13 @@ class QueryStreamFetcher<T> {
/// Key that can be used to check whether two fetchers will yield the same
/// result when operating on the same data.
final StreamKey key;
final StreamKey? key;
/// Function that asynchronously fetches the latest set of data.
final Future<T> Function() fetchData;
QueryStreamFetcher(
{@required this.readsFrom, this.key, @required this.fetchData});
{required this.readsFrom, this.key, required this.fetchData});
}
/// Key that uniquely identifies a select statement. If two keys created from
@ -67,7 +66,7 @@ class StreamKey {
/// updates them when needed.
class StreamQueryStore {
final Map<StreamKey, QueryStream> _activeKeyStreams = {};
final HashSet<StreamKey> _keysPendingRemoval = HashSet<StreamKey>();
final HashSet<StreamKey?> _keysPendingRemoval = HashSet<StreamKey?>();
bool _isShuttingDown = false;
// we track pending timers since Flutter throws an exception when timers
@ -185,17 +184,15 @@ class QueryStream<T> {
final QueryStreamFetcher<T> _fetcher;
final StreamQueryStore _store;
StreamController<T> _controller;
StreamSubscription _tablesChangedSubscription;
late final StreamController<T> _controller = StreamController.broadcast(
onListen: _onListen,
onCancel: _onCancel,
);
StreamSubscription? _tablesChangedSubscription;
T _lastData;
T? _lastData;
Stream<T> get stream {
_controller ??= StreamController.broadcast(
onListen: _onListen,
onCancel: _onCancel,
);
return _controller.stream.transform(StartWithValueTransformer(_cachedData));
}
@ -205,7 +202,7 @@ class QueryStream<T> {
/// Called when we have a new listener, makes the stream query behave similar
/// to an `BehaviorSubject` from rxdart.
T _cachedData() => _lastData;
T? _cachedData() => _lastData;
void _onListen() {
_store.markAsOpened(this);
@ -282,7 +279,7 @@ class MultipleUpdateQuery extends TableUpdateQuery {
}
class SpecificUpdateQuery extends TableUpdateQuery {
final UpdateKind limitUpdateKind;
final UpdateKind? limitUpdateKind;
final String table;
const SpecificUpdateQuery(this.table, {this.limitUpdateKind});

View File

@ -3,20 +3,18 @@ part of 'moor_isolate.dart';
class _MoorClient {
final IsolateCommunication _channel;
final SqlTypeSystem typeSystem;
_IsolateStreamQueryStore _streamStore;
DatabaseConnection _connection;
late final _IsolateStreamQueryStore _streamStore =
_IsolateStreamQueryStore(this);
late final DatabaseConnection _connection = DatabaseConnection(
typeSystem,
_IsolateQueryExecutor(this),
_streamStore,
);
QueryExecutorUser _connectedDb;
late QueryExecutorUser _connectedDb;
_MoorClient(this._channel, this.typeSystem) {
_streamStore = _IsolateStreamQueryStore(this);
_connection = DatabaseConnection(
typeSystem,
_IsolateQueryExecutor(this),
_streamStore,
);
_channel.setRequestHandler(_handleRequest);
}
@ -44,7 +42,7 @@ class _MoorClient {
abstract class _BaseExecutor extends QueryExecutor {
final _MoorClient client;
int _executorId;
int? _executorId;
_BaseExecutor(this.client, [this._executorId]);
@ -54,13 +52,14 @@ abstract class _BaseExecutor extends QueryExecutor {
.request(_ExecuteBatchedStatement(statements, _executorId));
}
Future<T> _runRequest<T>(_StatementMethod method, String sql, List args) {
Future<T> _runRequest<T>(
_StatementMethod method, String sql, List<Object?>? args) {
return client._channel
.request<T>(_ExecuteQuery(method, sql, args ?? const [], _executorId));
}
@override
Future<void> runCustom(String statement, [List args]) {
Future<void> runCustom(String statement, [List<Object?>? args]) {
return _runRequest(
_StatementMethod.custom,
statement,
@ -69,31 +68,32 @@ abstract class _BaseExecutor extends QueryExecutor {
}
@override
Future<int> runDelete(String statement, List args) {
Future<int> runDelete(String statement, List<Object?> args) {
return _runRequest(_StatementMethod.deleteOrUpdate, statement, args);
}
@override
Future<int> runUpdate(String statement, List args) {
Future<int> runUpdate(String statement, List<Object?> args) {
return _runRequest(_StatementMethod.deleteOrUpdate, statement, args);
}
@override
Future<int> runInsert(String statement, List args) {
Future<int> runInsert(String statement, List<Object?> args) {
return _runRequest(_StatementMethod.insert, statement, args);
}
@override
Future<List<Map<String, dynamic>>> runSelect(String statement, List args) {
Future<List<Map<String, Object?>>> runSelect(
String statement, List<Object?> args) {
return _runRequest(_StatementMethod.select, statement, args);
}
}
class _IsolateQueryExecutor extends _BaseExecutor {
_IsolateQueryExecutor(_MoorClient client, [int executorId])
_IsolateQueryExecutor(_MoorClient client, [int? executorId])
: super(client, executorId);
Completer<void> _setSchemaVersion;
Completer<void>? _setSchemaVersion;
@override
TransactionExecutor beginTransaction() {
@ -104,7 +104,7 @@ class _IsolateQueryExecutor extends _BaseExecutor {
Future<bool> ensureOpen(QueryExecutorUser user) async {
client._connectedDb = user;
if (_setSchemaVersion != null) {
await _setSchemaVersion.future;
await _setSchemaVersion!.future;
_setSchemaVersion = null;
}
return client._channel
@ -123,17 +123,18 @@ class _IsolateQueryExecutor extends _BaseExecutor {
class _TransactionIsolateExecutor extends _BaseExecutor
implements TransactionExecutor {
final int _outerExecutorId;
final int? _outerExecutorId;
_TransactionIsolateExecutor(_MoorClient client, this._outerExecutorId)
: super(client);
Completer<bool> _pendingOpen;
Completer<bool>? _pendingOpen;
bool _done = false;
// nested transactions aren't supported
@override
TransactionExecutor beginTransaction() => null;
TransactionExecutor beginTransaction() {
throw UnsupportedError('Nested transactions');
}
@override
Future<bool> ensureOpen(_) {
@ -143,8 +144,8 @@ class _TransactionIsolateExecutor extends _BaseExecutor
'somewhere?',
);
_pendingOpen ??= Completer()..complete(_openAtServer());
return _pendingOpen.future;
final completer = _pendingOpen ??= Completer()..complete(_openAtServer());
return completer.future;
}
Future<bool> _openAtServer() async {

View File

@ -19,7 +19,7 @@ class IsolateCommunication {
/// primitive objects.
final MessageCodec messageCodec;
StreamSubscription _inputSubscription;
StreamSubscription? _inputSubscription;
// note that there are two IsolateCommunication instances in each connection,
// and each of them has an independent _currentRequestId field!
@ -102,7 +102,7 @@ class IsolateCommunication {
if (completer != null) {
if (msg is _ErrorResponse) {
final trace = msg.stackTrace != null
? StackTrace.fromString(msg.stackTrace)
? StackTrace.fromString(msg.stackTrace!)
: null;
completer.completeError(msg.error, trace);
@ -146,7 +146,7 @@ class IsolateCommunication {
}
/// Sends an erroneous response for a [Request].
void respondError(Request request, dynamic error, [StackTrace trace]) {
void respondError(Request request, dynamic error, [StackTrace? trace]) {
// sending a message while closed will throw, so don't even try.
if (isClosed) return;
@ -390,9 +390,9 @@ class _Response implements IsolateMessage {
class _ErrorResponse extends _Response {
static const _tag = 6;
final String stackTrace;
final String? stackTrace;
dynamic get error => response;
Object get error => response as Object;
_ErrorResponse(int requestId, dynamic error, [this.stackTrace])
: super(requestId, error);

View File

@ -63,7 +63,7 @@ class _MoorCodec extends MessageCodec {
for (final update in payload.updates)
[
update.table,
update.kind.index,
update.kind?.index,
]
];
} else if (payload is SqlTypeSystem) {
@ -80,7 +80,7 @@ class _MoorCodec extends MessageCodec {
if (encoded == null || encoded is bool) return encoded;
int tag;
List fullMessage;
List? fullMessage;
if (encoded is int) {
tag = encoded;
@ -89,7 +89,8 @@ class _MoorCodec extends MessageCodec {
tag = fullMessage[0] as int;
}
int readInt(int index) => fullMessage[index] as int;
int readInt(int index) => fullMessage![index] as int;
int? readNullableInt(int index) => fullMessage![index] as int?;
switch (tag) {
case _tag_NoArgsRequest_getTypeSystem:
@ -98,12 +99,12 @@ class _MoorCodec extends MessageCodec {
return _NoArgsRequest.terminateAll;
case _tag_ExecuteQuery:
final method = _StatementMethod.values[readInt(1)];
final sql = fullMessage[2] as String;
final sql = fullMessage![2] as String;
final args = (fullMessage[3] as List).map(_decodeDbValue).toList();
final executorId = fullMessage[4] as int /*?*/;
final executorId = readNullableInt(4);
return _ExecuteQuery(method, sql, args, executorId);
case _tag_ExecuteBatchedStatement:
final sql = (fullMessage[1] as List).cast<String>();
final sql = (fullMessage![1] as List).cast<String>();
final args = <ArgumentsForBatchedStatement>[];
for (var i = 2; i < fullMessage.length - 1; i++) {
@ -118,19 +119,19 @@ class _MoorCodec extends MessageCodec {
BatchedStatements(sql, args), executorId);
case _tag_RunTransactionAction:
final control = _TransactionControl.values[readInt(1)];
return _RunTransactionAction(control, readInt(2));
return _RunTransactionAction(control, readNullableInt(2));
case _tag_EnsureOpen:
return _EnsureOpen(readInt(1), readInt(2));
return _EnsureOpen(readInt(1), readNullableInt(2));
case _tag_RunBeforeOpen:
return _RunBeforeOpen(
OpeningDetails(readInt(1), readInt(2)),
OpeningDetails(readNullableInt(1), readInt(2)),
readInt(3),
);
case _tag_DefaultSqlTypeSystem:
return SqlTypeSystem.defaultInstance;
case _tag_NotifyTablesUpdated:
final updates = <TableUpdate>[];
for (var i = 1; i < fullMessage.length; i++) {
for (var i = 1; i < fullMessage!.length; i++) {
final encodedUpdate = fullMessage[i] as List;
updates.add(
TableUpdate(encodedUpdate[0] as String,
@ -186,7 +187,7 @@ class _ExecuteQuery {
final _StatementMethod method;
final String sql;
final List<dynamic> args;
final int executorId;
final int? executorId;
_ExecuteQuery(this.method, this.sql, this.args, [this.executorId]);
@ -202,7 +203,7 @@ class _ExecuteQuery {
/// Sent from the client to run [BatchedStatements]
class _ExecuteBatchedStatement {
final BatchedStatements stmts;
final int executorId;
final int? executorId;
_ExecuteBatchedStatement(this.stmts, [this.executorId]);
}
@ -219,7 +220,7 @@ enum _TransactionControl {
/// Sent from the client to commit or rollback a transaction
class _RunTransactionAction {
final _TransactionControl control;
final int executorId;
final int? executorId;
_RunTransactionAction(this.control, this.executorId);
@ -233,7 +234,7 @@ class _RunTransactionAction {
/// database connection, using the [schemaVersion].
class _EnsureOpen {
final int schemaVersion;
final int executorId;
final int? executorId;
_EnsureOpen(this.schemaVersion, this.executorId);

View File

@ -3,7 +3,7 @@ part of 'moor_isolate.dart';
class _MoorServer {
final Server server;
DatabaseConnection connection;
final DatabaseConnection connection;
final Map<int, QueryExecutor> _managedExecutors = {};
int _currentExecutorId = 0;
@ -19,20 +19,20 @@ class _MoorServer {
final StreamController<void> _backlogUpdated =
StreamController.broadcast(sync: true);
_IsolateDelegatedUser _dbUser;
late final _IsolateDelegatedUser _dbUser = _IsolateDelegatedUser(this);
SendPort get portToOpenConnection => server.portToOpenConnection;
_MoorServer(DatabaseOpener opener) : server = Server(const _MoorCodec()) {
_MoorServer(DatabaseOpener opener)
: connection = opener(),
server = Server(const _MoorCodec()) {
server.openedConnections.listen((connection) {
connection.setRequestHandler(_handleRequest);
});
connection = opener();
_dbUser = _IsolateDelegatedUser(this);
}
/// Returns the first connected client, or null if no client is connected.
IsolateCommunication get firstClient {
IsolateCommunication? get firstClient {
final channels = server.currentChannels;
return channels.isEmpty ? null : channels.first;
}
@ -74,8 +74,8 @@ class _MoorServer {
return await executor.ensureOpen(_dbUser);
}
Future<dynamic> _runQuery(
_StatementMethod method, String sql, List args, int transactionId) async {
Future<dynamic> _runQuery(_StatementMethod method, String sql,
List<Object?> args, int? transactionId) async {
final executor = await _loadExecutor(transactionId);
switch (method) {
@ -88,23 +88,21 @@ class _MoorServer {
case _StatementMethod.select:
return executor.runSelect(sql, args);
}
throw AssertionError("Unknown _StatementMethod, this can't happen.");
}
Future<void> _runBatched(BatchedStatements stmts, int transactionId) async {
Future<void> _runBatched(BatchedStatements stmts, int? transactionId) async {
final executor = await _loadExecutor(transactionId);
await executor.runBatched(stmts);
}
Future<QueryExecutor> _loadExecutor(int transactionId) async {
Future<QueryExecutor> _loadExecutor(int? transactionId) async {
await _waitForTurn(transactionId);
return transactionId != null
? _managedExecutors[transactionId]
? _managedExecutors[transactionId]!
: connection.executor;
}
Future<int> _spawnTransaction(int executor) async {
Future<int> _spawnTransaction(int? executor) async {
final transaction = (await _loadExecutor(executor)).beginTransaction();
final id = _putExecutor(transaction, beforeCurrent: true);
@ -126,7 +124,7 @@ class _MoorServer {
}
Future<dynamic> _transactionControl(
_TransactionControl action, int executorId) async {
_TransactionControl action, int? executorId) async {
if (action == _TransactionControl.begin) {
return await _spawnTransaction(executorId);
}
@ -142,21 +140,19 @@ class _MoorServer {
);
}
final transaction = executor as TransactionExecutor;
try {
switch (action) {
case _TransactionControl.commit:
await transaction.send();
await executor.send();
break;
case _TransactionControl.rollback:
await transaction.rollback();
await executor.rollback();
break;
default:
assert(false, 'Unknown TransactionControl');
}
} finally {
_releaseExecutor(executorId);
_releaseExecutor(executorId!);
}
}
@ -166,7 +162,7 @@ class _MoorServer {
_notifyActiveExecutorUpdated();
}
Future<void> _waitForTurn(int transactionId) {
Future<void> _waitForTurn(int? transactionId) {
bool idIsActive() {
if (transactionId == null) {
return _executorBacklog.isEmpty;
@ -202,7 +198,7 @@ class _IsolateDelegatedUser implements QueryExecutorUser {
QueryExecutor executor, OpeningDetails details) async {
final id = server._putExecutor(executor, beforeCurrent: true);
try {
await server.firstClient.request(_RunBeforeOpen(details, id));
await server.firstClient!.request(_RunBeforeOpen(details, id));
} finally {
server._releaseExecutor(id);
}

View File

@ -6,7 +6,7 @@ class GroupBy extends Component {
final List<Expression> groupBy;
/// Optional, a having clause to exclude some groups.
final Expression<bool> /*?*/ having;
final Expression<bool?>? having;
GroupBy._(this.groupBy, this.having);
@ -17,7 +17,7 @@ class GroupBy extends Component {
if (having != null) {
context.buffer.write(' HAVING ');
having.writeInto(context);
having!.writeInto(context);
}
}
}

View File

@ -31,7 +31,7 @@ class Join<T extends Table, D extends DataClass> extends Component {
/// For joins that aren't [_JoinType.cross], contains an additional predicate
/// that must be matched for the join.
final Expression<bool> on;
final Expression<bool>? on;
/// Whether [table] should appear in the result set (defaults to true).
///
@ -41,7 +41,7 @@ class Join<T extends Table, D extends DataClass> extends Component {
/// Constructs a [Join] by providing the relevant fields. [on] is optional for
/// [_JoinType.cross].
Join._(this.type, this.table, this.on, {bool includeInResult})
Join._(this.type, this.table, this.on, {bool? includeInResult})
: includeInResult = includeInResult ?? true;
@override
@ -53,7 +53,7 @@ class Join<T extends Table, D extends DataClass> extends Component {
if (type != _JoinType.cross) {
context.buffer.write(' ON ');
on.writeInto(context);
on!.writeInto(context);
}
}
}
@ -71,7 +71,7 @@ class Join<T extends Table, D extends DataClass> extends Component {
/// - http://www.sqlitetutorial.net/sqlite-inner-join/
Join innerJoin<T extends Table, D extends DataClass>(
TableInfo<T, D> other, Expression<bool> on,
{bool useColumns}) {
{bool? useColumns}) {
return Join._(_JoinType.inner, other, on, includeInResult: useColumns);
}
@ -85,7 +85,7 @@ Join innerJoin<T extends Table, D extends DataClass>(
/// - http://www.sqlitetutorial.net/sqlite-left-join/
Join leftOuterJoin<T extends Table, D extends DataClass>(
TableInfo<T, D> other, Expression<bool> on,
{bool useColumns}) {
{bool? useColumns}) {
return Join._(_JoinType.leftOuter, other, on, includeInResult: useColumns);
}
@ -97,6 +97,6 @@ Join leftOuterJoin<T extends Table, D extends DataClass>(
/// See also:
/// - https://moor.simonbinder.eu/docs/advanced-features/joins/#joins
/// - http://www.sqlitetutorial.net/sqlite-cross-join/
Join crossJoin<T, D>(TableInfo other, {bool useColumns}) {
Join crossJoin<T, D>(TableInfo other, {bool? useColumns}) {
return Join._(_JoinType.cross, other, null, includeInResult: useColumns);
}

View File

@ -7,7 +7,7 @@ class Limit extends Component {
/// When the offset is non null, the first offset rows will be skipped an not
/// included in the result.
final int offset;
final int? offset;
/// Construct a limit clause from the [amount] of rows to include an a
/// nullable [offset].

View File

@ -25,7 +25,7 @@ class OrderingTerm extends Component {
/// Creates an ordering term by the [expression] and the [mode] (defaults to
/// ascending).
OrderingTerm({@required this.expression, this.mode = OrderingMode.asc});
OrderingTerm({required this.expression, this.mode = OrderingMode.asc});
/// Creates an ordering term that sorts for ascending values of [expression].
factory OrderingTerm.asc(Expression expression) {

View File

@ -4,7 +4,7 @@ part of '../query_builder.dart';
class Where extends Component {
/// The expression that determines whether a given row should be included in
/// the result.
final Expression<bool> predicate;
final Expression<bool?> predicate;
/// Construct a [Where] clause from its [predicate].
Where(this.predicate);

View File

@ -1,8 +1,5 @@
part of '../query_builder.dart';
// todo: We should have a detailed article on group-by clauses and aggregate
// expressions on the website
/// Returns the amount of rows in the current group matching the optional
/// [filter].
///
@ -12,7 +9,7 @@ part of '../query_builder.dart';
///
/// This is equivalent to the `COUNT(*) FILTER (WHERE filter)` sql function. The
/// filter will be omitted if null.
Expression<int> countAll({Expression<bool> filter}) {
Expression<int> countAll({Expression<bool>? filter}) {
return _AggregateExpression('COUNT', const _StarFunctionParameter(),
filter: filter);
}
@ -27,7 +24,7 @@ extension BaseAggregate<DT> on Expression<DT> {
/// counted twice. An optional [filter] can be used to only include values
/// matching the filter. Note that [filter] is only available from sqlite
/// 3.30 and most devices will use an older sqlite version.
Expression<int> count({bool distinct, Expression<bool> filter}) {
Expression<int> count({bool? distinct, Expression<bool>? filter}) {
return _AggregateExpression('COUNT', this,
filter: filter, distinct: distinct);
}
@ -52,19 +49,19 @@ extension BaseAggregate<DT> on Expression<DT> {
}
/// Provides aggregate functions that are available for numeric expressions.
extension ArithmeticAggregates<DT extends num> on Expression<DT> {
extension ArithmeticAggregates<DT extends num> on Expression<DT?> {
/// Return the average of all non-null values in this group.
Expression<double> avg() => _AggregateExpression('AVG', this);
Expression<double?> avg() => _AggregateExpression('AVG', this);
/// Return the maximum of all non-null values in this group.
///
/// If there are no non-null values in the group, returns null.
Expression<DT> max() => _AggregateExpression('MAX', this);
Expression<DT?> max() => _AggregateExpression('MAX', this);
/// Return the minimum of all non-null values in this group.
///
/// If there are no non-null values in the group, returns null.
Expression<DT> min() => _AggregateExpression('MIN', this);
Expression<DT?> min() => _AggregateExpression('MIN', this);
/// Calculate the sum of all non-null values in the group.
///
@ -74,13 +71,13 @@ extension ArithmeticAggregates<DT extends num> on Expression<DT> {
///
/// See also [total], which behaves similarly but returns a floating point
/// value and doesn't throw an overflow exception.
Expression<DT> sum() => _AggregateExpression('SUM', this);
Expression<DT?> sum() => _AggregateExpression('SUM', this);
/// Calculate the sum of all non-null values in the group.
///
/// If all values in the group are null, [total] returns `0.0`. This function
/// uses floating-point values internally.
Expression<double> total() => _AggregateExpression('TOTAL', this);
Expression<double?> total() => _AggregateExpression('TOTAL', this);
}
class _AggregateExpression<D> extends Expression<D> {
@ -88,10 +85,10 @@ class _AggregateExpression<D> extends Expression<D> {
final bool distinct;
final FunctionParameter parameter;
final Where /*?*/ filter;
final Where? filter;
_AggregateExpression(this.functionName, this.parameter,
{Expression<bool> filter, bool distinct})
{Expression<bool>? filter, bool? distinct})
: filter = filter != null ? Where(filter) : null,
distinct = distinct ?? false;
@ -111,7 +108,7 @@ class _AggregateExpression<D> extends Expression<D> {
if (filter != null) {
context.buffer.write(' FILTER (');
filter.writeInto(context);
filter!.writeInto(context);
context.buffer.write(')');
}
}

View File

@ -1,7 +1,7 @@
part of '../query_builder.dart';
/// Defines the `-`, `*` and `/` operators on sql expressions that support it.
extension ArithmeticExpr<DT extends num> on Expression<DT> {
extension ArithmeticExpr<DT extends num?> on Expression<DT> {
/// Performs an addition (`this` + [other]) in sql.
Expression<DT> operator +(Expression<DT> other) {
return _BaseInfixOperator(this, '+', other,

View File

@ -1,24 +1,24 @@
part of '../query_builder.dart';
/// Defines operations on boolean values.
extension BooleanExpressionOperators on Expression<bool> {
extension BooleanExpressionOperators on Expression<bool?> {
/// Negates this boolean expression. The returned expression is true if
/// `this` is false, and vice versa.
Expression<bool> not() => _NotExpression(this);
Expression<bool?> not() => _NotExpression(this);
/// Returns an expression that is true iff both `this` and [other] are true.
Expression<bool> operator &(Expression<bool> other) {
Expression<bool?> operator &(Expression<bool?> other) {
return _BaseInfixOperator(this, 'AND', other, precedence: Precedence.and);
}
/// Returns an expression that is true if `this` or [other] are true.
Expression<bool> operator |(Expression<bool> other) {
Expression<bool?> operator |(Expression<bool?> other) {
return _BaseInfixOperator(this, 'OR', other, precedence: Precedence.or);
}
}
class _NotExpression extends Expression<bool> {
final Expression<bool> inner;
class _NotExpression extends Expression<bool?> {
final Expression<bool?> inner;
_NotExpression(this.inner);

View File

@ -1,7 +1,7 @@
part of '../query_builder.dart';
/// Defines extension functions to express comparisons in sql
extension ComparableExpr<DT extends Comparable<dynamic>> on Expression<DT> {
extension ComparableExpr<DT extends Comparable<dynamic>?> on Expression<DT> {
/// Returns an expression that is true if this expression is strictly bigger
/// than the other expression.
Expression<bool> isBiggerThan(Expression<DT> other) {
@ -84,9 +84,9 @@ class _BetweenExpression extends Expression<bool> {
final Expression higher;
_BetweenExpression(
{@required this.target,
@required this.lower,
@required this.higher,
{required this.target,
required this.lower,
required this.higher,
this.not = false});
@override

View File

@ -19,27 +19,27 @@ class _CustomDateTimeExpression extends CustomExpression<DateTime> {
/// Provides expressions to extract information from date time values, or to
/// calculate the difference between datetimes.
extension DateTimeExpressions on Expression<DateTime> {
extension DateTimeExpressions on Expression<DateTime?> {
/// Extracts the (UTC) year from `this` datetime expression.
Expression<int> get year => _StrftimeSingleFieldExpression('%Y', this);
Expression<int?> get year => _StrftimeSingleFieldExpression('%Y', this);
/// Extracts the (UTC) month from `this` datetime expression.
Expression<int> get month => _StrftimeSingleFieldExpression('%m', this);
Expression<int?> get month => _StrftimeSingleFieldExpression('%m', this);
/// Extracts the (UTC) day from `this` datetime expression.
Expression<int> get day => _StrftimeSingleFieldExpression('%d', this);
Expression<int?> get day => _StrftimeSingleFieldExpression('%d', this);
/// Extracts the (UTC) hour from `this` datetime expression.
Expression<int> get hour => _StrftimeSingleFieldExpression('%H', this);
Expression<int?> get hour => _StrftimeSingleFieldExpression('%H', this);
/// Extracts the (UTC) minute from `this` datetime expression.
Expression<int> get minute => _StrftimeSingleFieldExpression('%M', this);
Expression<int?> get minute => _StrftimeSingleFieldExpression('%M', this);
/// Extracts the (UTC) second from `this` datetime expression.
Expression<int> get second => _StrftimeSingleFieldExpression('%S', this);
Expression<int?> get second => _StrftimeSingleFieldExpression('%S', this);
/// Formats this datetime in the format `year-month-day`.
Expression<String> get date {
Expression<String?> get date {
return FunctionCallExpression(
'DATE',
[this, const Constant<String>('unixepoch')],
@ -68,9 +68,9 @@ extension DateTimeExpressions on Expression<DateTime> {
/// Expression that extracts components out of a date time by using the builtin
/// sqlite function "strftime" and casting the result to an integer.
class _StrftimeSingleFieldExpression extends Expression<int> {
class _StrftimeSingleFieldExpression extends Expression<int?> {
final String format;
final Expression<DateTime> date;
final Expression<DateTime?> date;
_StrftimeSingleFieldExpression(this.format, this.date);

View File

@ -264,7 +264,7 @@ class _Comparison extends _InfixOperator<bool> {
final _ComparisonOperator op;
@override
String get operator => _operatorNames[op];
String get operator => _operatorNames[op]!;
@override
Precedence get precedence {

View File

@ -1,8 +1,5 @@
part of '../query_builder.dart';
// we're not using extensions for this because I'm not sure if / how this could
// look together with NNBD in the future
/// Expression that is true if the inner expression resolves to a null value.
@Deprecated('Use isNull through the SqlIsNull extension')
Expression<bool> isNull(Expression inner) => _NullCheck(inner, true);

View File

@ -1,11 +1,11 @@
part of '../query_builder.dart';
/// Defines methods that operate on a column storing [String] values.
extension StringExpressionOperators on Expression<String> {
extension StringExpressionOperators on Expression<String?> {
/// Whether this column matches the given pattern. For details on what patters
/// are valid and how they are interpreted, check out
/// [this tutorial](http://www.sqlitetutorial.net/sqlite-like/).
Expression<bool> like(String regex) {
Expression<bool?> like(String regex) {
return _LikeOperator(this, Variable.withString(regex));
}
@ -16,7 +16,7 @@ extension StringExpressionOperators on Expression<String> {
///
/// Note that this function is only available when using `moor_ffi`. If you
/// need to support the web or `moor_flutter`, consider using [like] instead.
Expression<bool> regexp(
Expression<bool?> regexp(
String regex, {
bool multiLine = false,
bool caseSensitive = true,
@ -62,7 +62,7 @@ extension StringExpressionOperators on Expression<String> {
/// Note that this is case-insensitive for the English alphabet only.
///
/// This is equivalent to calling [like] with `%<substring>%`.
Expression<bool> contains(String substring) {
Expression<bool?> contains(String substring) {
return like('%$substring%');
}
@ -73,7 +73,7 @@ extension StringExpressionOperators on Expression<String> {
}
/// Performs a string concatenation in sql by appending [other] to `this`.
Expression<String> operator +(Expression<String> other) {
Expression<String> operator +(Expression<String?> other) {
return _BaseInfixOperator(this, '||', other,
precedence: Precedence.stringConcatenation);
}
@ -102,19 +102,19 @@ extension StringExpressionOperators on Expression<String> {
///
/// See also:
/// - https://www.w3resource.com/sqlite/core-functions-length.php
Expression<int> get length {
Expression<int?> get length {
return FunctionCallExpression('LENGTH', [this]);
}
}
/// A `text LIKE pattern` expression that will be true if the first expression
/// matches the pattern given by the second expression.
class _LikeOperator extends Expression<bool> {
class _LikeOperator extends Expression<bool?> {
/// The target expression that will be tested
final Expression<String> target;
final Expression<String?> target;
/// The regex-like expression to test the [target] against.
final Expression<String> regex;
final Expression<String?> regex;
/// The operator to use when matching. Defaults to `LIKE`.
final String operator;

View File

@ -16,7 +16,7 @@ class GenerationContext {
final SqlDialect dialect;
/// The actual [QueryEngine] that's going to execute the generated query.
final QueryEngine executor;
final QueryEngine? executor;
final List<dynamic> _boundVariables = [];
@ -40,8 +40,9 @@ class GenerationContext {
/// Constructs a [GenerationContext] by copying the relevant fields from the
/// database.
GenerationContext.fromDb(this.executor)
: typeSystem = executor.typeSystem,
dialect = executor.executor?.dialect ?? SqlDialect.sqlite;
: typeSystem = executor?.typeSystem ?? SqlTypeSystem.defaultInstance,
// ignore: invalid_null_aware_operator, (doesn't seem to actually work)
dialect = executor?.executor?.dialect ?? SqlDialect.sqlite;
/// Constructs a custom [GenerationContext] by setting the fields manually.
/// See [GenerationContext.fromDb] for a more convenient factory.

View File

@ -35,7 +35,7 @@ class MigrationStrategy {
/// and all migrations ran), but before any other queries will be sent. This
/// makes it a suitable place to populate data after the database has been
/// created or set sqlite `PRAGMAS` that you need.
final OnBeforeOpen /*?*/ beforeOpen;
final OnBeforeOpen? beforeOpen;
/// Construct a migration strategy from the provided [onCreate] and
/// [onUpgrade] methods.
@ -121,7 +121,7 @@ class Migrator {
@experimental
Future<void> alterTable(TableMigration migration) async {
final foreignKeysEnabled =
(await _db.customSelect('PRAGMA foreign_keys').getSingle())
(await _db.customSelect('PRAGMA foreign_keys').getSingle())!
.readBool('foreign_keys');
if (foreignKeysEnabled) {
@ -251,7 +251,7 @@ class Migrator {
// as table constraint if it has already been written on a primary key
// column, even though that column appears in table.$primaryKey because we
// need to know all primary keys for the update(table).replace(row) API
final hasPrimaryKey = table.$primaryKey?.isNotEmpty ?? false;
final hasPrimaryKey = table.$primaryKey.isNotEmpty;
final dontWritePk = dslTable.dontWriteConstraints || hasAutoIncrement;
if (hasPrimaryKey && !dontWritePk) {
context.buffer.write(', PRIMARY KEY (');
@ -266,7 +266,7 @@ class Migrator {
context.buffer.write(')');
}
final constraints = dslTable.customConstraints ?? [];
final constraints = dslTable.customConstraints;
for (var i = 0; i < constraints.length; i++) {
context.buffer..write(', ')..write(constraints[i]);
@ -369,11 +369,11 @@ class Migrator {
/// Executes the custom query.
@Deprecated('Use customStatement in the database class')
Future<void> issueCustomQuery(String sql, [List<dynamic> args]) {
Future<void> issueCustomQuery(String sql, [List<dynamic>? args]) {
return _issueCustomQuery(sql, args);
}
Future<void> _issueCustomQuery(String sql, [List<dynamic> args]) {
Future<void> _issueCustomQuery(String sql, [List<dynamic>? args]) {
return _db.customStatement(sql, args);
}
}
@ -383,7 +383,7 @@ class Migrator {
class OpeningDetails {
/// The schema version before the database has been opened, or `null` if the
/// database has just been created.
final int versionBefore;
final int? versionBefore;
/// The schema version after running migrations.
final int versionNow;
@ -395,7 +395,9 @@ class OpeningDetails {
bool get hadUpgrade => !wasCreated && versionBefore != versionNow;
/// Used internally by moor when opening a database.
const OpeningDetails(this.versionBefore, this.versionNow);
const OpeningDetails(this.versionBefore, this.versionNow)
// Should use null instead of 0 for consistency
: assert(versionBefore != 0);
}
/// Extension providing the [destructiveFallback] strategy.

View File

@ -21,11 +21,11 @@ abstract class GeneratedColumn<T> extends Column<T> {
/// If custom constraints have been specified for this column via
/// [ColumnBuilder.customConstraint], these are kept here. Otherwise, this
/// field is going to be null.
final String $customConstraints;
final String? $customConstraints;
/// The default expression to be used during inserts when no value has been
/// specified. Can be null if no default value is set.
final Expression<T> defaultValue;
final Expression<T>? defaultValue;
/// A function that yields a default column for inserts if no value has been
/// set. This is different to [defaultValue] since the function is written in
@ -33,7 +33,7 @@ abstract class GeneratedColumn<T> extends Column<T> {
/// [defaultValue] and [clientDefault] are non-null.
///
/// See also: [ColumnBuilder.clientDefault].
T Function() clientDefault;
T Function()? clientDefault;
/// Used by generated code.
GeneratedColumn(this.$name, this.tableName, this.$nullable,
@ -48,6 +48,7 @@ abstract class GeneratedColumn<T> extends Column<T> {
if ($customConstraints == null) {
into.buffer.write($nullable ? ' NULL' : ' NOT NULL');
final defaultValue = this.defaultValue;
if (defaultValue != null) {
into.buffer.write(' DEFAULT ');
@ -137,18 +138,18 @@ abstract class GeneratedColumn<T> extends Column<T> {
}
Variable _evaluateClientDefault() {
return Variable<T>(clientDefault());
return Variable<T>(clientDefault!());
}
}
/// Implementation for [TextColumn].
class GeneratedTextColumn extends GeneratedColumn<String>
class GeneratedTextColumn extends GeneratedColumn<String?>
implements TextColumn {
/// Optional. The minimum text length.
final int minTextLength;
final int? minTextLength;
/// Optional. The maximum text length.
final int maxTextLength;
final int? maxTextLength;
/// Used by generated code.
GeneratedTextColumn(
@ -157,8 +158,8 @@ class GeneratedTextColumn extends GeneratedColumn<String>
bool nullable, {
this.minTextLength,
this.maxTextLength,
String $customConstraints,
Expression<String> defaultValue,
String? $customConstraints,
Expression<String?>? defaultValue,
}) : super(name, tableName, nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@ -166,16 +167,16 @@ class GeneratedTextColumn extends GeneratedColumn<String>
final String typeName = 'TEXT';
@override
VerificationResult isAcceptableValue(String value, VerificationMeta meta) {
VerificationResult isAcceptableValue(String? value, VerificationMeta meta) {
// handle nullability check in common column
if (value == null) return super.isAcceptableValue(null, meta);
final length = value.length;
if (minTextLength != null && minTextLength > length) {
if (minTextLength != null && minTextLength! > length) {
return VerificationResult.failure(
'Must at least be $minTextLength characters long.');
}
if (maxTextLength != null && maxTextLength < length) {
if (maxTextLength != null && maxTextLength! < length) {
return VerificationResult.failure(
'Must at most be $maxTextLength characters long.');
}
@ -185,10 +186,10 @@ class GeneratedTextColumn extends GeneratedColumn<String>
}
/// Implementation for [BoolColumn].
class GeneratedBoolColumn extends GeneratedColumn<bool> implements BoolColumn {
class GeneratedBoolColumn extends GeneratedColumn<bool?> implements BoolColumn {
/// Used by generated code
GeneratedBoolColumn(String name, String tableName, bool nullable,
{String $customConstraints, Expression<bool> defaultValue})
{String? $customConstraints, Expression<bool?>? defaultValue})
: super(name, tableName, nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@ -202,7 +203,7 @@ class GeneratedBoolColumn extends GeneratedColumn<bool> implements BoolColumn {
}
/// Implementation for [IntColumn]
class GeneratedIntColumn extends GeneratedColumn<int> implements IntColumn {
class GeneratedIntColumn extends GeneratedColumn<int?> implements IntColumn {
/// Whether this column was declared to be a primary key via a column
/// constraint. The only way to do this in Dart is with
/// [IntColumnBuilder.autoIncrement]. In `.moor` files, declaring a column
@ -226,8 +227,8 @@ class GeneratedIntColumn extends GeneratedColumn<int> implements IntColumn {
bool nullable, {
this.declaredAsPrimaryKey = false,
this.hasAutoIncrement = false,
String $customConstraints,
Expression<int> defaultValue,
String? $customConstraints,
Expression<int?>? defaultValue,
}) : super(name, tableName, nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@ -248,15 +249,15 @@ class GeneratedIntColumn extends GeneratedColumn<int> implements IntColumn {
}
/// Implementation for [DateTimeColumn].
class GeneratedDateTimeColumn extends GeneratedColumn<DateTime>
class GeneratedDateTimeColumn extends GeneratedColumn<DateTime?>
implements DateTimeColumn {
/// Used by generated code.
GeneratedDateTimeColumn(
String $name,
String tableName,
bool $nullable, {
String $customConstraints,
Expression<DateTime> defaultValue,
String? $customConstraints,
Expression<DateTime?>? defaultValue,
}) : super($name, tableName, $nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@ -265,11 +266,11 @@ class GeneratedDateTimeColumn extends GeneratedColumn<DateTime>
}
/// Implementation for [BlobColumn]
class GeneratedBlobColumn extends GeneratedColumn<Uint8List>
class GeneratedBlobColumn extends GeneratedColumn<Uint8List?>
implements BlobColumn {
/// Used by generated code.
GeneratedBlobColumn(String $name, String tableName, bool $nullable,
{String $customConstraints, Expression<Uint8List> defaultValue})
{String? $customConstraints, Expression<Uint8List?>? defaultValue})
: super($name, tableName, $nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@ -278,15 +279,15 @@ class GeneratedBlobColumn extends GeneratedColumn<Uint8List>
}
/// Implementation for [RealColumn]
class GeneratedRealColumn extends GeneratedColumn<double>
class GeneratedRealColumn extends GeneratedColumn<double?>
implements RealColumn {
/// Used by generated code
GeneratedRealColumn(
String $name,
String tableName,
bool $nullable, {
Expression<double> defaultValue,
String $customConstraints,
Expression<double>? defaultValue,
String? $customConstraints,
}) : super($name, tableName, $nullable,
defaultValue: defaultValue, $customConstraints: $customConstraints);

View File

@ -9,12 +9,12 @@ mixin TableInfo<TableDsl extends Table, D extends DataClass> on Table
/// [TableInfo] and [TableDsl] and can thus just return their instance.
TableDsl get asDslTable;
/// The primary key of this table. Can be null or empty if no custom primary
/// key has been specified.
/// The primary key of this table. Can be empty if no custom primary key has
/// been specified.
///
/// Additional to the [Table.primaryKey] columns declared by an user, this
/// also contains auto-increment integers, which are primary key by default.
Set<GeneratedColumn> get $primaryKey => null;
Set<GeneratedColumn> get $primaryKey => const {};
// ensure the primaryKey getter is consistent with $primaryKey, which can
// contain additional columns.
@ -35,7 +35,7 @@ mixin TableInfo<TableDsl extends Table, D extends DataClass> on Table
/// All columns defined in this table.
List<GeneratedColumn> get $columns;
Map<String, GeneratedColumn> _columnsByName;
Map<String, GeneratedColumn>? _columnsByName;
/// Gets all [$columns] in this table, indexed by their (non-escaped) name.
Map<String, GeneratedColumn> get columnsByName {
@ -54,7 +54,7 @@ mixin TableInfo<TableDsl extends Table, D extends DataClass> on Table
}
/// Maps the given row returned by the database into the fitting data class.
D map(Map<String, dynamic> data, {String tablePrefix});
D map(Map<String, dynamic> data, {String? tablePrefix});
/// Converts a [companion] to the real model class, [D].
///
@ -120,13 +120,13 @@ extension TableInfoUtils<TableDsl extends Table, D extends DataClass>
}
/// Like [map], but from a [row] instead of the low-level map.
D mapFromRow(QueryRow row, {String tablePrefix}) {
D mapFromRow(QueryRow row, {String? tablePrefix}) {
return map(row.data, tablePrefix: tablePrefix);
}
/// Like [mapFromRow], but returns null if a non-nullable column of this table
/// is null in [row].
D /*?*/ mapFromRowOrNull(QueryRow row, {String tablePrefix}) {
D? mapFromRowOrNull(QueryRow row, {String? tablePrefix}) {
final resolvedPrefix = tablePrefix == null ? '' : '$tablePrefix.';
final notInRow = $columns
@ -153,7 +153,7 @@ extension TableInfoUtils<TableDsl extends Table, D extends DataClass>
/// `'c2': 'bar'` in [alias].
D mapFromRowWithAlias(QueryRow row, Map<String, String> alias) {
return map({
for (final entry in row.data.entries) alias[entry.key]: entry.value,
for (final entry in row.data.entries) alias[entry.key]!: entry.value,
});
}
}

View File

@ -36,7 +36,7 @@ class DeleteStatement<T extends Table, D extends DataClass> extends Query<T, D>
Future<int> go() async {
final ctx = constructQuery();
return ctx.executor.doWhenOpened((e) async {
return ctx.executor!.doWhenOpened((e) async {
final rows = await e.runDelete(ctx.sql, ctx.boundVariables);
if (rows > 0) {

View File

@ -60,8 +60,8 @@ class InsertStatement<T extends Table, D extends DataClass> {
/// Still, the future will always complete with an error if the insert fails.
Future<int> insert(
Insertable<D> entity, {
InsertMode mode,
DoUpdate<T, D> onConflict,
InsertMode? mode,
DoUpdate<T, D>? onConflict,
}) async {
final ctx = createContext(entity, mode ?? InsertMode.insert,
onConflict: onConflict);
@ -94,7 +94,7 @@ class InsertStatement<T extends Table, D extends DataClass> {
///
/// This method is used internally by moor. Consider using [insert] instead.
GenerationContext createContext(Insertable<D> entry, InsertMode mode,
{DoUpdate<T, D> onConflict}) {
{DoUpdate<T, D>? onConflict}) {
_validateIntegrity(entry);
final rawValues = entry.toColumns(true);
@ -105,7 +105,7 @@ class InsertStatement<T extends Table, D extends DataClass> {
final columnName = column.$name;
if (rawValues.containsKey(columnName)) {
map[columnName] = rawValues[columnName];
map[columnName] = rawValues[columnName]!;
} else {
if (column.clientDefault != null) {
map[columnName] = column._evaluateClientDefault();
@ -165,6 +165,12 @@ class InsertStatement<T extends Table, D extends DataClass> {
ctx.buffer.write(' ON CONFLICT(');
final conflictTarget = onConflict.target ?? table.$primaryKey.toList();
if (conflictTarget.isEmpty) {
throw ArgumentError(
'Table has no primary key, so a conflict target is needed.');
}
var first = true;
for (final target in conflictTarget) {
if (!first) ctx.buffer.write(', ');
@ -190,7 +196,7 @@ class InsertStatement<T extends Table, D extends DataClass> {
return ctx;
}
void _validateIntegrity(Insertable<D> d) {
void _validateIntegrity(Insertable<D>? d) {
if (d == null) {
throw InvalidDataException(
'Cannot write null row into ${table.$tableName}');
@ -254,7 +260,7 @@ class DoUpdate<T extends Table, D extends DataClass> {
/// specifies the uniqueness constraint that will trigger the upsert.
///
/// By default, the primary key of the table will be used.
final List<Column> /*?*/ target;
final List<Column>? target;
/// For an example, see [InsertStatement.insert].
DoUpdate(Insertable<D> Function(T old) update, {this.target})

View File

@ -16,17 +16,17 @@ abstract class Query<T extends Table, D extends DataClass> {
/// The `WHERE` clause for this statement
@protected
Where whereExpr;
Where? whereExpr;
/// The `ORDER BY` clause for this statement
@protected
OrderBy orderByExpr;
OrderBy? orderByExpr;
/// The `LIMIT` clause for this statement.
@protected
Limit limitExpr;
Limit? limitExpr;
GroupBy _groupBy;
GroupBy? _groupBy;
/// Subclasses must override this and write the part of the statement that
/// comes before the where and limit expression..
@ -44,7 +44,7 @@ abstract class Query<T extends Table, D extends DataClass> {
// whether we need to insert a space before writing the next component
var needsWhitespace = false;
void writeWithSpace(Component /*?*/ component) {
void writeWithSpace(Component? component) {
if (component == null) return;
if (needsWhitespace) ctx.writeWhitespace();
@ -96,7 +96,7 @@ abstract class Selectable<T> {
/// one row, for instance because you used `limit(1)` or you know the `where`
/// clause will only allow one row.
/// {@endtemplate}
Future<T> getSingle() async {
Future<T?> getSingle() async {
final list = await get();
final iterator = list.iterator;
@ -119,7 +119,7 @@ abstract class Selectable<T> {
/// will be added to the stream instead.
///
/// {@macro moor_single_query_expl}
Stream<T> watchSingle() {
Stream<T?> watchSingle() {
return watch().transform(singleElements());
}
@ -182,7 +182,7 @@ mixin SingleTableQueryMixin<T extends Table, D extends DataClass>
if (whereExpr == null) {
whereExpr = Where(predicate);
} else {
whereExpr = Where(whereExpr.predicate & predicate);
whereExpr = Where(whereExpr!.predicate & predicate);
}
}
@ -190,7 +190,7 @@ mixin SingleTableQueryMixin<T extends Table, D extends DataClass>
/// [d] will be matched.
void whereSamePrimaryKey(Insertable<D> d) {
assert(
table.$primaryKey != null && table.$primaryKey.isNotEmpty,
table.$primaryKey.isNotEmpty,
'When using Query.whereSamePrimaryKey, which is also called from '
'DeleteStatement.delete and UpdateStatement.replace, the affected table'
'must have a primary key. You can either specify a primary implicitly '
@ -212,10 +212,10 @@ mixin SingleTableQueryMixin<T extends Table, D extends DataClass>
final primaryKeyValues = Map.fromEntries(updatedFields.entries
.where((entry) => primaryKeyColumns.containsKey(entry.key)))
.map((columnName, value) {
return MapEntry(primaryKeyColumns[columnName], value);
return MapEntry(primaryKeyColumns[columnName]!, value);
});
Expression<bool> predicate;
Expression<bool?>? predicate;
for (final entry in primaryKeyValues.entries) {
final comparison =
_Comparison(entry.key, _ComparisonOperator.equal, entry.value);
@ -227,7 +227,7 @@ mixin SingleTableQueryMixin<T extends Table, D extends DataClass>
}
}
whereExpr = Where(predicate);
whereExpr = Where(predicate!);
}
}
@ -236,7 +236,7 @@ mixin LimitContainerMixin<T extends Table, D extends DataClass> on Query<T, D> {
/// Limits the amount of rows returned by capping them at [limit]. If [offset]
/// is provided as well, the first [offset] rows will be skipped and not
/// included in the result.
void limit(int limit, {int offset}) {
void limit(int limit, {int? offset}) {
limitExpr = Limit(limit, offset);
}
}

View File

@ -73,11 +73,11 @@ class QueryRow {
/// Reads an arbitrary value from the row and maps it to a fitting dart type.
/// The dart type [T] must be supported by the type system of the database
/// used (mostly contains booleans, strings, integers and dates).
/// used (mostly contains booleans, strings, numbers and dates).
T read<T>(String key) {
final type = _db.typeSystem.forDartType<T>();
return type.mapFromDatabaseResponse(data[key]);
return type.mapFromDatabaseResponse(data[key]) as T;
}
/// Reads a bool from the column named [key].

View File

@ -36,7 +36,7 @@ class SimpleSelectStatement<T extends Table, D extends DataClass>
}
Future<List<D>> _getWithQuery(GenerationContext ctx) async {
final results = await ctx.executor.doWhenOpened((e) async {
final results = await ctx.executor!.doWhenOpened((e) async {
return await e.runSelect(ctx.sql, ctx.boundVariables);
});
return results.map(table.map).toList();
@ -69,10 +69,10 @@ class SimpleSelectStatement<T extends Table, D extends DataClass>
final statement = JoinedSelectStatement(database, table, joins, distinct);
if (whereExpr != null) {
statement.where(whereExpr.predicate);
statement.where(whereExpr!.predicate);
}
if (orderByExpr != null) {
statement.orderBy(orderByExpr.terms);
statement.orderBy(orderByExpr!.terms);
}
if (limitExpr != null) {
statement.limitExpr = limitExpr;
@ -129,7 +129,7 @@ class TypedResult {
TypedResult(this._parsedData, this.rawData, [this._parsedExpressions]);
final Map<TableInfo, dynamic> _parsedData;
final Map<Expression, dynamic> _parsedExpressions;
final Map<Expression, dynamic>? _parsedExpressions;
/// The raw data contained in this row.
final QueryRow rawData;
@ -142,10 +142,10 @@ class TypedResult {
/// Reads a single column from an [expr]. The expression must have been added
/// as a column, for instance via [JoinedSelectStatement.addColumns].
///
/// To access the underlying columns directly, use
D read<D, T extends SqlType<D>>(Expression<D> expr) {
/// To access the underlying columns directly, use [rawData].
D? read<D>(Expression<D> expr) {
if (_parsedExpressions != null) {
return _parsedExpressions[expr] as D;
return _parsedExpressions![expr] as D;
}
return null;
}

View File

@ -109,11 +109,11 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
/// ])
/// ..where(todos.name.like("%Important") & categories.name.equals("Work"));
/// ```
void where(Expression<bool> predicate) {
void where(Expression<bool?> predicate) {
if (whereExpr == null) {
whereExpr = Where(predicate);
} else {
whereExpr = Where(whereExpr.predicate & predicate);
whereExpr = Where(whereExpr!.predicate & predicate);
}
}
@ -165,7 +165,7 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
/// Groups the result by values in [expressions].
///
/// An optional [having] attribute can be set to exclude certain groups.
void groupBy(Iterable<Expression> expressions, {Expression<bool> having}) {
void groupBy(Iterable<Expression> expressions, {Expression<bool>? having}) {
_groupBy = GroupBy._(expressions.toList(), having);
}
@ -188,7 +188,7 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
}
Future<List<TypedResult>> _getWithQuery(GenerationContext ctx) async {
final results = await ctx.executor.doWhenOpened((e) async {
final results = await ctx.executor!.doWhenOpened((e) async {
try {
return await e.runSelect(ctx.sql, ctx.boundVariables);
} catch (e, s) {

View File

@ -7,7 +7,7 @@ class UpdateStatement<T extends Table, D extends DataClass> extends Query<T, D>
UpdateStatement(QueryEngine database, TableInfo<T, D> table)
: super(database, table);
Map<String, Expression> _updatedFields;
late Map<String, Expression> _updatedFields;
@override
void writeStartPart(GenerationContext ctx) {
@ -31,7 +31,7 @@ class UpdateStatement<T extends Table, D extends DataClass> extends Query<T, D>
Future<int> _performQuery() async {
final ctx = constructQuery();
final rows = await ctx.executor.doWhenOpened((e) async {
final rows = await ctx.executor!.doWhenOpened((e) async {
return await e.runUpdate(ctx.sql, ctx.boundVariables);
});
@ -123,7 +123,7 @@ class UpdateStatement<T extends Table, D extends DataClass> extends Query<T, D>
// if a default value exists and no value is set, apply the default
if (column.defaultValue != null &&
!_updatedFields.containsKey(column.$name)) {
_updatedFields[column.$name] = column.defaultValue;
_updatedFields[column.$name] = column.defaultValue!;
}
}

View File

@ -13,12 +13,11 @@ abstract class TypeConverter<D, S> {
const TypeConverter();
/// Map a value from an object in Dart into something that will be understood
/// by the database. Be aware that [value] is nullable.
S mapToSql(D value);
/// by the database.
S? mapToSql(D? value);
/// Maps a column from the database back to Dart. Be aware that [fromDb] is
/// nullable.
D mapToDart(S fromDb);
/// Maps a column from the database back to Dart.
D? mapToDart(S? fromDb);
}
/// Implementation for an enum to int converter that uses the index of the enum
@ -31,12 +30,12 @@ class EnumIndexConverter<T> extends TypeConverter<T, int> {
const EnumIndexConverter(this.values);
@override
T mapToDart(int fromDb) {
T? mapToDart(int? fromDb) {
return fromDb == null ? null : values[fromDb];
}
@override
int mapToSql(T value) {
int? mapToSql(T? value) {
return (value as dynamic)?.index as int;
}
}

View File

@ -1,5 +1,6 @@
import 'dart:typed_data';
// ignore: import_of_legacy_library_into_null_safe
import 'package:convert/convert.dart';
import 'package:moor/moor.dart';
@ -17,14 +18,14 @@ abstract class SqlType<T> {
/// Maps the [content] to a value that we can send together with a prepared
/// statement to represent the given value.
dynamic mapToSqlVariable(T content);
dynamic mapToSqlVariable(T? content);
/// Maps the given content to a sql literal that can be included in the query
/// string.
String mapToSqlConstant(T content);
String? mapToSqlConstant(T? content);
/// Maps the response from sql back to a readable dart type.
T mapFromDatabaseResponse(dynamic response);
T? mapFromDatabaseResponse(dynamic response);
}
/// A mapper for boolean values in sql. Booleans are represented as integers,
@ -37,14 +38,14 @@ class BoolType extends SqlType<bool> {
String get sqlName => 'INTEGER';
@override
bool mapFromDatabaseResponse(dynamic response) {
bool? mapFromDatabaseResponse(dynamic response) {
// ignore: avoid_returning_null
if (response == null) return null;
return response != 0;
}
@override
String mapToSqlConstant(bool content) {
String mapToSqlConstant(bool? content) {
if (content == null) {
return 'NULL';
}
@ -52,7 +53,7 @@ class BoolType extends SqlType<bool> {
}
@override
int mapToSqlVariable(bool content) {
int? mapToSqlVariable(bool? content) {
if (content == null) {
// ignore: avoid_returning_null
return null;
@ -70,10 +71,12 @@ class StringType extends SqlType<String> {
String get sqlName => 'TEXT';
@override
String mapFromDatabaseResponse(dynamic response) => response?.toString();
String? mapFromDatabaseResponse(dynamic response) => response?.toString();
@override
String mapToSqlConstant(String content) {
String mapToSqlConstant(String? content) {
if (content == null) return 'NULL';
// From the sqlite docs: (https://www.sqlite.org/lang_expr.html)
// A string constant is formed by enclosing the string in single quotes (').
// A single quote within the string can be encoded by putting two single
@ -84,7 +87,7 @@ class StringType extends SqlType<String> {
}
@override
String mapToSqlVariable(String content) => content;
String? mapToSqlVariable(String? content) => content;
}
/// Maps [int] values from and to sql
@ -96,16 +99,16 @@ class IntType extends SqlType<int> {
String get sqlName => 'INTEGER';
@override
int mapFromDatabaseResponse(dynamic response) {
if (response == null || response is int /*?*/) return response as int /*?*/;
int? mapFromDatabaseResponse(dynamic response) {
if (response == null || response is int?) return response as int?;
return int.parse(response.toString());
}
@override
String mapToSqlConstant(int content) => content?.toString() ?? 'NULL';
String mapToSqlConstant(int? content) => content?.toString() ?? 'NULL';
@override
int mapToSqlVariable(int content) {
int? mapToSqlVariable(int? content) {
return content;
}
}
@ -119,7 +122,7 @@ class DateTimeType extends SqlType<DateTime> {
String get sqlName => 'INTEGER';
@override
DateTime mapFromDatabaseResponse(dynamic response) {
DateTime? mapFromDatabaseResponse(dynamic response) {
if (response == null) return null;
final unixSeconds = response as int;
@ -128,14 +131,14 @@ class DateTimeType extends SqlType<DateTime> {
}
@override
String mapToSqlConstant(DateTime content) {
String mapToSqlConstant(DateTime? content) {
if (content == null) return 'NULL';
return (content.millisecondsSinceEpoch ~/ 1000).toString();
}
@override
int mapToSqlVariable(DateTime content) {
int? mapToSqlVariable(DateTime? content) {
// ignore: avoid_returning_null
if (content == null) return null;
@ -152,17 +155,20 @@ class BlobType extends SqlType<Uint8List> {
String get sqlName => 'BLOB';
@override
Uint8List mapFromDatabaseResponse(dynamic response) => response as Uint8List;
Uint8List? mapFromDatabaseResponse(dynamic response) {
return response as Uint8List?;
}
@override
String mapToSqlConstant(Uint8List content) {
String mapToSqlConstant(Uint8List? content) {
if (content == null) return 'NULL';
// BLOB literals are string literals containing hexadecimal data and
// preceded by a single "x" or "X" character. Example: X'53514C697465'
return "x'${hex.encode(content)}'";
}
@override
Uint8List mapToSqlVariable(Uint8List content) => content;
Uint8List? mapToSqlVariable(Uint8List? content) => content;
}
/// Maps [double] values from and to sql
@ -174,12 +180,12 @@ class RealType extends SqlType<double> {
String get sqlName => 'REAL';
@override
double mapFromDatabaseResponse(dynamic response) {
return (response as num)?.toDouble();
double? mapFromDatabaseResponse(dynamic response) {
return (response as num?)?.toDouble();
}
@override
String mapToSqlConstant(num content) {
String mapToSqlConstant(num? content) {
if (content == null) {
return 'NULL';
}
@ -187,5 +193,5 @@ class RealType extends SqlType<double> {
}
@override
num mapToSqlVariable(num content) => content;
num? mapToSqlVariable(num? content) => content;
}

View File

@ -20,7 +20,7 @@ class SqlTypeSystem {
RealType(),
]);
/// Constant field of [SqlTypeSystem.withDefaults()]. This field exists as a
/// Constant field of [SqlTypeSystem.withDefaults]. This field exists as a
/// workaround for an analyzer bug: https://dartbug.com/38658
///
/// Used internally by generated code.

View File

@ -9,8 +9,10 @@ typedef DatabaseOpener = FutureOr<QueryExecutor> Function();
/// A special database executor that delegates work to another [QueryExecutor].
/// The other executor is lazily opened by a [DatabaseOpener].
class LazyDatabase extends QueryExecutor {
QueryExecutor _delegate;
Completer<void> _openDelegate;
late QueryExecutor _delegate;
bool _delegateAvailable = false;
Completer<void>? _openDelegate;
/// The function that will open the database when this [LazyDatabase] gets
/// opened for the first time.
@ -21,17 +23,18 @@ class LazyDatabase extends QueryExecutor {
LazyDatabase(this.opener);
Future<void> _awaitOpened() {
if (_delegate != null) {
if (_delegateAvailable) {
return Future.value();
} else if (_openDelegate != null) {
return _openDelegate.future;
return _openDelegate!.future;
} else {
_openDelegate = Completer();
final delegate = _openDelegate = Completer();
Future.value(opener()).then((database) {
_delegate = database;
_openDelegate.complete();
_delegateAvailable = true;
delegate.complete();
});
return _openDelegate.future;
return delegate.future;
}
}
@ -48,28 +51,30 @@ class LazyDatabase extends QueryExecutor {
_delegate.runBatched(statements);
@override
Future<void> runCustom(String statement, [List args]) =>
Future<void> runCustom(String statement, [List<Object?>? args]) =>
_delegate.runCustom(statement, args);
@override
Future<int> runDelete(String statement, List args) =>
Future<int> runDelete(String statement, List<Object?> args) =>
_delegate.runDelete(statement, args);
@override
Future<int> runInsert(String statement, List args) =>
Future<int> runInsert(String statement, List<Object?> args) =>
_delegate.runInsert(statement, args);
@override
Future<List<Map<String, dynamic>>> runSelect(String statement, List args) =>
_delegate.runSelect(statement, args);
Future<List<Map<String, Object?>>> runSelect(
String statement, List<Object?> args) {
return _delegate.runSelect(statement, args);
}
@override
Future<int> runUpdate(String statement, List args) =>
Future<int> runUpdate(String statement, List<Object?> args) =>
_delegate.runUpdate(statement, args);
@override
Future<void> close() {
if (_delegate != null) {
if (_delegateAvailable) {
return _delegate.close();
} else {
return Future.value();

View File

@ -2,7 +2,7 @@ import 'dart:async';
/// Transforms a stream of lists into a stream of single elements, assuming
/// that each list is a singleton.
StreamTransformer<List<T>, T> singleElements<T>() {
StreamTransformer<List<T>, T?> singleElements<T>() {
return StreamTransformer.fromHandlers(handleData: (data, sink) {
try {
if (data.isEmpty) {

View File

@ -2,7 +2,7 @@ import 'dart:async';
/// Signature of a function that returns the latest current value of a
/// [StartWithValueTransformer].
typedef LatestValue<T> = T Function();
typedef LatestValue<T> = T? Function();
/// Lightweight implementation that turns a [StreamController] into a behavior
/// subject (we try to avoid depending on rxdart because of its size).
@ -29,8 +29,8 @@ class _StartWithValueStream<T> extends Stream<T> {
bool get isBroadcast => _inner.isBroadcast;
@override
StreamSubscription<T> listen(void Function(T event) onData,
{Function onError, void Function() onDone, bool cancelOnError}) {
StreamSubscription<T> listen(void Function(T event)? onData,
{Function? onError, void Function()? onDone, bool? cancelOnError}) {
final data = _value();
return _StartWithValueSubscription(_inner, data, onData,
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
@ -38,32 +38,33 @@ class _StartWithValueStream<T> extends Stream<T> {
}
class _StartWithValueSubscription<T> extends StreamSubscription<T> {
StreamSubscription<T> _inner;
final T initialData;
late final StreamSubscription<T> _inner;
final T? initialData;
bool needsInitialData = true;
void Function(T data) _onData;
void Function(T data)? _onData;
_StartWithValueSubscription(
Stream<T> innerStream, this.initialData, this._onData,
{Function onError, void Function() onDone, bool cancelOnError}) {
{Function? onError, void Function()? onDone, bool? cancelOnError}) {
_inner = innerStream.listen(_wrappedDataCallback(_onData),
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
// Dart's stream contract specifies that listeners are only notified
// after the .listen() code completes. So, we add the initial data in
// a later microtask.
if (initialData != null) {
final data = initialData;
if (data != null) {
scheduleMicrotask(() {
if (needsInitialData) {
_onData?.call(initialData);
_onData?.call(data);
needsInitialData = false;
}
});
}
}
void Function(T data) _wrappedDataCallback(void Function(T data) onData) {
void Function(T data) _wrappedDataCallback(void Function(T data)? onData) {
return (event) {
needsInitialData = false;
onData?.call(event);
@ -71,7 +72,7 @@ class _StartWithValueSubscription<T> extends StreamSubscription<T> {
}
@override
Future<E> asFuture<E>([E futureValue]) => _inner.asFuture();
Future<E> asFuture<E>([E? futureValue]) => _inner.asFuture(futureValue);
@override
Future<void> cancel() {
@ -83,20 +84,20 @@ class _StartWithValueSubscription<T> extends StreamSubscription<T> {
bool get isPaused => _inner.isPaused;
@override
void onData(void Function(T data) handleData) {
void onData(void Function(T data)? handleData) {
_onData = handleData;
_inner.onData(_wrappedDataCallback(handleData));
}
@override
void onDone(void Function() handleDone) => _inner.onDone(handleDone);
void onDone(void Function()? handleDone) => _inner.onDone(handleDone);
@override
void onError(Function handleError) => _inner.onError(handleError);
void onError(Function? handleError) => _inner.onError(handleError);
@override
void pause([Future<void> resumeSignal]) {
void pause([Future<void>? resumeSignal]) {
needsInitialData = false;
_inner.pause(resumeSignal);
}

View File

@ -7,12 +7,12 @@ import 'dart:typed_data';
// This way, projects using moor can run on flutter as long as they don't import
// this file.
Completer<SqlJsModule> _moduleCompleter;
Completer<SqlJsModule>? _moduleCompleter;
/// Calls the `initSqlJs` function from the native sql.js library.
Future<SqlJsModule> initSqlJs() {
if (_moduleCompleter != null) {
return _moduleCompleter.future;
return _moduleCompleter!.future;
}
_moduleCompleter = Completer();
@ -26,7 +26,7 @@ Future<SqlJsModule> initSqlJs() {
(context.callMethod('initSqlJs') as JsObject)
.callMethod('then', [_handleModuleResolved]);
return _moduleCompleter.future;
return _moduleCompleter!.future;
}
// We're extracting this into its own method so that we don't have to call
@ -34,7 +34,7 @@ Future<SqlJsModule> initSqlJs() {
// todo figure out why dart2js generates invalid js when wrapping this in
// allowInterop
void _handleModuleResolved(dynamic module) {
_moduleCompleter.complete(SqlJsModule._(module as JsObject));
_moduleCompleter!.complete(SqlJsModule._(module as JsObject));
}
/// `sql.js` module from the underlying library
@ -43,7 +43,7 @@ class SqlJsModule {
SqlJsModule._(this._obj);
/// Constructs a new [SqlJsDatabase], optionally from the [data] blob.
SqlJsDatabase createDatabase([Uint8List data]) {
SqlJsDatabase createDatabase([Uint8List? data]) {
final dbObj = _createInternally(data);
assert(() {
// set the window.db variable to make debugging easier
@ -54,7 +54,7 @@ class SqlJsModule {
return SqlJsDatabase._(dbObj);
}
JsObject _createInternally(Uint8List data) {
JsObject _createInternally(Uint8List? data) {
final constructor = _obj['Database'] as JsFunction;
if (data != null) {

View File

@ -13,7 +13,7 @@ abstract class MoorWebStorage {
/// Restore the last database version that was saved with [store].
///
/// If no saved data was found, returns null.
Future<Uint8List> restore();
Future<Uint8List?> restore();
/// Store the entire database.
Future<void> store(Uint8List data);
@ -72,8 +72,8 @@ abstract class MoorWebStorage {
}
abstract class _CustomSchemaVersionSave implements MoorWebStorage {
int /*?*/ get schemaVersion;
set schemaVersion(int value);
int? get schemaVersion;
set schemaVersion(int? value);
}
String _persistenceKeyForLocalStorage(String name) {
@ -84,7 +84,7 @@ String _legacyVersionKeyForLocalStorage(String name) {
return 'moor_db_version_$name';
}
Uint8List /*?*/ _restoreLocalStorage(String name) {
Uint8List? _restoreLocalStorage(String name) {
final raw = window.localStorage[_persistenceKeyForLocalStorage(name)];
if (raw != null) {
return bin2str.decode(raw);
@ -101,7 +101,7 @@ class _LocalStorageImpl implements MoorWebStorage, _CustomSchemaVersionSave {
const _LocalStorageImpl(this.name);
@override
int get schemaVersion {
int? get schemaVersion {
final versionStr = window.localStorage[_versionKey];
// ignore: avoid_returning_null
if (versionStr == null) return null;
@ -110,8 +110,14 @@ class _LocalStorageImpl implements MoorWebStorage, _CustomSchemaVersionSave {
}
@override
set schemaVersion(int value) {
window.localStorage[_versionKey] = value.toString();
set schemaVersion(int? value) {
final key = _versionKey;
if (value == null) {
window.localStorage.remove(key);
} else {
window.localStorage[_versionKey] = value.toString();
}
}
@override
@ -121,7 +127,7 @@ class _LocalStorageImpl implements MoorWebStorage, _CustomSchemaVersionSave {
Future<void> open() => Future.value();
@override
Future<Uint8List> restore() async {
Future<Uint8List?> restore() async {
return _restoreLocalStorage(name);
}
@ -141,7 +147,7 @@ class _IndexedDbStorage implements MoorWebStorage {
final bool migrateFromLocalStorage;
final bool inWebWorker;
Database _database;
late Database _database;
_IndexedDbStorage(this.name,
{this.migrateFromLocalStorage = true, this.inWebWorker = false});
@ -153,7 +159,7 @@ class _IndexedDbStorage implements MoorWebStorage {
final indexedDb =
inWebWorker ? WorkerGlobalScope.instance.indexedDB : window.indexedDB;
_database = await indexedDb.open(
_database = await indexedDb!.open(
_objectStoreName,
version: 1,
onUpgradeNeeded: (event) {
@ -188,12 +194,12 @@ class _IndexedDbStorage implements MoorWebStorage {
}
@override
Future<Uint8List> restore() async {
Future<Uint8List?> restore() async {
final transaction =
_database.transactionStore(_objectStoreName, 'readonly');
final store = transaction.objectStore(_objectStoreName);
final result = await store.getObject(name) as Blob /*?*/;
final result = await store.getObject(name) as Blob?;
if (result == null) return null;
final reader = FileReader();

View File

@ -13,7 +13,7 @@ class WebDatabase extends DelegatedDatabase {
/// [name] can be used to identify multiple databases. The optional
/// [initializer] can be used to initialize the database if it doesn't exist.
WebDatabase(String name,
{bool logStatements = false, CreateWebDatabase initializer})
{bool logStatements = false, CreateWebDatabase? initializer})
: super(_WebDelegate(MoorWebStorage(name), initializer),
logStatements: logStatements, isSequential: true);
@ -23,15 +23,17 @@ class WebDatabase extends DelegatedDatabase {
/// constructor of [MoorWebStorage] will use local storage for that, but an
/// IndexedDB-based implementation is available via.
WebDatabase.withStorage(MoorWebStorage storage,
{bool logStatements = false, CreateWebDatabase initializer})
{bool logStatements = false, CreateWebDatabase? initializer})
: super(_WebDelegate(storage, initializer),
logStatements: logStatements, isSequential: true);
}
class _WebDelegate extends DatabaseDelegate {
final MoorWebStorage storage;
final CreateWebDatabase initializer;
SqlJsDatabase _db;
final CreateWebDatabase? initializer;
late SqlJsDatabase _db;
bool _isOpen = false;
bool _inTransaction = false;
@ -56,13 +58,13 @@ class _WebDelegate extends DatabaseDelegate {
@override
DbVersionDelegate get versionDelegate =>
_versionDelegate ??= _WebVersionDelegate(this);
DbVersionDelegate _versionDelegate;
DbVersionDelegate? _versionDelegate;
@override
bool get isOpen => _db != null;
bool get isOpen => _isOpen;
@override
Future<void> open([QueryExecutorUser db]) async {
Future<void> open(QueryExecutorUser db) async {
final dbVersion = db.schemaVersion;
assert(dbVersion >= 1, 'Database schema version needs to be at least 1');
@ -72,11 +74,15 @@ class _WebDelegate extends DatabaseDelegate {
var restored = await storage.restore();
if (restored == null && initializer != null) {
restored = await initializer();
await storage.store(restored);
restored = await initializer?.call();
if (restored != null) {
await storage.store(restored);
}
}
_db = module.createDatabase(restored);
_isOpen = true;
}
@override
@ -100,13 +106,13 @@ class _WebDelegate extends DatabaseDelegate {
}
@override
Future<void> runCustom(String statement, List args) {
Future<void> runCustom(String statement, List<Object?> args) {
_db.runWithArgs(statement, args);
return Future.value();
}
@override
Future<int> runInsert(String statement, List args) async {
Future<int> runInsert(String statement, List<Object?> args) async {
_db.runWithArgs(statement, args);
final insertId = _db.lastInsertId();
await _handlePotentialUpdate();
@ -114,11 +120,11 @@ class _WebDelegate extends DatabaseDelegate {
}
@override
Future<QueryResult> runSelect(String statement, List args) {
Future<QueryResult> runSelect(String statement, List<Object?> args) {
// todo at least for stream queries we should cache prepared statements.
final stmt = _db.prepare(statement)..executeWith(args);
List<String> columnNames;
List<String>? columnNames;
final rows = <List<dynamic>>[];
while (stmt.step()) {
@ -133,7 +139,7 @@ class _WebDelegate extends DatabaseDelegate {
}
@override
Future<int> runUpdate(String statement, List args) {
Future<int> runUpdate(String statement, List<Object?> args) {
_db.runWithArgs(statement, args);
return _handlePotentialUpdate();
}
@ -141,7 +147,10 @@ class _WebDelegate extends DatabaseDelegate {
@override
Future<void> close() async {
await _storeDb();
_db?.close();
if (_isOpen) {
_db.close();
}
await storage.close();
}
@ -181,7 +190,7 @@ class _WebVersionDelegate extends DynamicVersionDelegate {
@override
Future<int> get schemaVersion async {
final storage = delegate.storage;
int version;
int? version;
if (storage is _CustomSchemaVersionSave) {
version = storage.schemaVersion;
}

View File

@ -6,27 +6,50 @@ homepage: https://moor.simonbinder.eu/
issue_tracker: https://github.com/simolus3/moor/issues
environment:
sdk: '>=2.6.0 <3.0.0'
sdk: '>=2.12.0-0 <3.0.0'
dependencies:
meta: ^1.1.8
convert: ^2.1.1
collection: ^1.0.0
synchronized: ^2.1.0
pedantic: ^1.0.0
sqlite3: ^0.1.6
meta: ^1.3.0-nullsafety.6
# We'd prefer convert ^3.0.0 for nullsafety, (we have a dependency_override) for that, but large chunks of the Dart
# ecosystem don't support version 3.0.0 yet, we support older versions for compatibility.
convert: ">=2.1.1 <4.0.0"
collection: ^1.15.0-nullsafety.5
synchronized: ^3.0.0-nullsafety
pedantic: ^1.10.0-nullsafety.3
sqlite3: ^0.1.9-nullsafety
dev_dependencies:
analyzer: ^0.40.6
build_test: ^1.3.0
build_runner_core: ^6.1.0
moor_generator: ^3.2.0
uuid: ^2.0.0
path: ^1.6.4
build_runner: '^1.10.1'
test: ^1.9.0
mockito: ^4.1.0
build_runner: '^1.10.4'
test: ^1.16.0-nullsafety
mockito: ^4.1.3
rxdart: ^0.24.0 # used to test compatibility with stream queries
dependency_overrides:
moor_generator:
path: ../moor_generator
sqlparser:
path: ../sqlparser
path: ../sqlparser
# Remove after https://github.com/dart-lang/mockito/issues/297 is fixed
mockito:
git:
url: https://github.com/simolus3/mockito.git
ref: generate-inheritance
uuid:
git:
url: https://github.com/simolus3/dart-uuid.git
ref: null-safety
crypto:
git:
url: https://github.com/dart-lang/crypto.git
ref: "3.0"
convert: ^3.0.0-nullsafety

View File

@ -1,3 +1,5 @@
//@dart=2.9
import 'package:mockito/mockito.dart';
import 'package:moor/moor.dart';
import 'package:test/test.dart';

View File

@ -2,12 +2,12 @@ import 'package:moor/moor.dart';
import 'package:test/test.dart';
void main() {
final nullable = GeneratedDateTimeColumn('name', null, true);
final nonNull = GeneratedDateTimeColumn('name', null, false);
final nullable = GeneratedDateTimeColumn('name', 'table', true);
final nonNull = GeneratedDateTimeColumn('name', 'table', false);
test('should write column definition', () {
final nonNullQuery = GenerationContext(null, null);
final nullableQuery = GenerationContext(null, null);
final nonNullQuery = GenerationContext.fromDb(null);
final nullableQuery = GenerationContext.fromDb(null);
nonNull.writeColumnDefinition(nonNullQuery);
nullable.writeColumnDefinition(nullableQuery);
@ -16,7 +16,7 @@ void main() {
});
test('can compare', () {
final ctx = GenerationContext(null, null);
final ctx = GenerationContext.fromDb(null);
nonNull.isSmallerThan(currentDateAndTime).writeInto(ctx);
expect(ctx.sql, "name < strftime('%s', CURRENT_TIMESTAMP)");

View File

@ -1,3 +1,4 @@
//@dart=2.9
import 'package:test/test.dart';
import 'package:moor/moor.dart';
@ -13,7 +14,7 @@ void main() {
hasAutoIncrement: true,
);
final context = GenerationContext.fromDb(TodoDb(null));
final context = GenerationContext.fromDb(TodoDb());
column.writeColumnDefinition(context);
expect(
@ -29,7 +30,7 @@ void main() {
hasAutoIncrement: false,
);
final context = GenerationContext.fromDb(TodoDb(null));
final context = GenerationContext.fromDb(TodoDb());
column.writeColumnDefinition(context);
expect(context.sql, equals('foo INTEGER NOT NULL PRIMARY KEY'));

View File

@ -1,3 +1,5 @@
//@dart=2.9
import 'package:mockito/mockito.dart';
import 'package:moor/moor.dart';
import 'package:test/test.dart';

View File

@ -10,14 +10,14 @@ class SyncTypeConverter extends TypeConverter<SyncType, int> {
const SyncTypeConverter();
@override
SyncType mapToDart(int fromDb) {
SyncType? mapToDart(int? fromDb) {
if (fromDb == null) return null;
return SyncType.values[fromDb];
}
@override
int mapToSql(SyncType value) {
int? mapToSql(SyncType? value) {
return value?.index;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,9 @@
import 'package:moor/moor.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:uuid/uuid.dart';
import '../utils/null_executor.dart';
part 'todos.g.dart';
mixin AutoIncrement on Table {
@ -80,12 +83,12 @@ class MyCustomObject {
class CustomConverter extends TypeConverter<MyCustomObject, String> {
const CustomConverter();
@override
MyCustomObject mapToDart(String fromDb) {
MyCustomObject? mapToDart(String? fromDb) {
return fromDb == null ? null : MyCustomObject(fromDb);
}
@override
String mapToSql(MyCustomObject value) {
String? mapToSql(MyCustomObject? value) {
return value?.data;
}
}
@ -111,7 +114,7 @@ class CustomConverter extends TypeConverter<MyCustomObject, String> {
},
)
class TodoDb extends _$TodoDb {
TodoDb(QueryExecutor e) : super(e) {
TodoDb([QueryExecutor? e]) : super(e ?? const NullExecutor()) {
moorRuntimeOptions.dontWarnAboutMultipleDatabases = true;
}
TodoDb.connect(DatabaseConnection connection) : super.connect(connection) {

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ Matcher generates(dynamic sql, [dynamic variables]) {
class _GeneratesSqlMatcher extends Matcher {
final Matcher _matchSql;
final Matcher _matchVariables;
final Matcher? _matchVariables;
_GeneratesSqlMatcher(this._matchSql, this._matchVariables);
@ -44,7 +44,7 @@ class _GeneratesSqlMatcher extends Matcher {
mismatchDescription =
mismatchDescription.add('generated variables $vars, which ');
mismatchDescription = _matchVariables.describeMismatch(
mismatchDescription = _matchVariables!.describeMismatch(
vars, mismatchDescription, matchState['vars_match'] as Map, verbose);
}
return mismatchDescription;
@ -57,9 +57,8 @@ class _GeneratesSqlMatcher extends Matcher {
return false;
}
final component = item as Component;
final ctx = GenerationContext(SqlTypeSystem.defaultInstance, null);
component.writeInto(ctx);
item.writeInto(ctx);
var matches = true;
@ -72,7 +71,7 @@ class _GeneratesSqlMatcher extends Matcher {
final argsMatchState = {};
if (_matchVariables != null &&
!_matchVariables.matches(ctx.boundVariables, argsMatchState)) {
!_matchVariables!.matches(ctx.boundVariables, argsMatchState)) {
matchState['vars'] = ctx.boundVariables;
matchState['vars_match'] = argsMatchState;
matches = false;

View File

@ -1,18 +1,36 @@
import 'dart:async';
// ignore: import_of_legacy_library_into_null_safe
import 'package:mockito/annotations.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:mockito/mockito.dart';
import 'package:moor/moor.dart';
import 'package:moor/src/runtime/executor/stream_queries.dart';
export 'package:mockito/mockito.dart';
import 'mocks.mocks.dart';
export 'mocks.mocks.dart';
class MockExecutor extends Mock implements QueryExecutor {
@GenerateMocks(
[],
customMocks: [
MockSpec<QueryExecutor>(as: #MockExecutorInternal),
MockSpec<TransactionExecutor>(as: #MockTransactionsInternal),
MockSpec<StreamQueryStore>(
as: #MockStreamQueries, returnNullOnMissingStub: true)
],
)
// ignore: unused_element
void _pleaseGenerateMocks() {
// needed so that mockito generates classes for us.
}
class MockExecutor extends MockExecutorInternal {
final MockTransactionExecutor transactions = MockTransactionExecutor();
final OpeningDetails openingDetails;
var _opened = false;
final OpeningDetails? openingDetails;
bool _opened = false;
MockExecutor([this.openingDetails]) {
when(dialect).thenReturn(SqlDialect.sqlite);
when(runSelect(any, any)).thenAnswer((_) {
assert(_opened);
return Future.value([]);
@ -33,6 +51,10 @@ class MockExecutor extends Mock implements QueryExecutor {
assert(_opened);
return Future.value();
});
when(runBatched(any)).thenAnswer((_) {
assert(_opened);
return Future.value();
});
when(beginTransaction()).thenAnswer((_) {
assert(_opened);
return transactions;
@ -42,7 +64,7 @@ class MockExecutor extends Mock implements QueryExecutor {
if (!_opened && openingDetails != null) {
_opened = true;
await (i.positionalArguments.single as QueryExecutorUser)
.beforeOpen(this, openingDetails);
.beforeOpen(this, openingDetails!);
}
_opened = true;
@ -56,23 +78,24 @@ class MockExecutor extends Mock implements QueryExecutor {
}
}
class MockTransactionExecutor extends Mock implements TransactionExecutor {
class MockTransactionExecutor extends MockTransactionsInternal {
MockTransactionExecutor() {
when(dialect).thenReturn(SqlDialect.sqlite);
when(runSelect(any, any)).thenAnswer((_) => Future.value([]));
when(runUpdate(any, any)).thenAnswer((_) => Future.value(0));
when(runDelete(any, any)).thenAnswer((_) => Future.value(0));
when(runInsert(any, any)).thenAnswer((_) => Future.value(0));
when(ensureOpen(any)).thenAnswer((_) => Future.value());
when(runCustom(any, any)).thenAnswer((_) => Future.value());
when(runBatched(any)).thenAnswer((_) => Future.value());
when(ensureOpen(any)).thenAnswer((_) => Future.value(true));
when(send()).thenAnswer((_) => Future.value(null));
when(rollback()).thenAnswer((_) => Future.value(null));
}
}
class MockStreamQueries extends Mock implements StreamQueryStore {}
DatabaseConnection createConnection(QueryExecutor executor,
[StreamQueryStore streams]) {
[StreamQueryStore? streams]) {
return DatabaseConnection(
SqlTypeSystem.defaultInstance, executor, streams ?? StreamQueryStore());
}

View File

@ -0,0 +1,110 @@
import 'package:mockito/mockito.dart' as _i1;
import 'package:moor/src/runtime/executor/executor.dart' as _i2;
import 'package:moor/src/runtime/query_builder/query_builder.dart' as _i3;
import 'dart:async' as _i4;
import 'package:moor/src/runtime/executor/stream_queries.dart' as _i5;
import 'package:moor/src/runtime/api/runtime_api.dart' as _i6;
class _FakeTransactionExecutor extends _i1.Fake
implements _i2.TransactionExecutor {}
/// A class which mocks [QueryExecutor].
///
/// See the documentation for Mockito's code generation for more information.
class MockExecutorInternal extends _i1.Mock implements _i2.QueryExecutor {
MockExecutorInternal() {
_i1.throwOnMissingStub(this);
}
_i3.SqlDialect get dialect =>
super.noSuchMethod(Invocation.getter(#dialect), _i3.SqlDialect.sqlite);
_i4.Future<bool> ensureOpen(_i2.QueryExecutorUser? user) =>
super.noSuchMethod(
Invocation.method(#ensureOpen, [user]), Future.value(false));
_i4.Future<List<Map<String, Object?>>> runSelect(
String? statement, List<Object?>? args) =>
super.noSuchMethod(Invocation.method(#runSelect, [statement, args]),
Future.value(<Map<String, Object?>>[]));
_i4.Future<int> runInsert(String? statement, List<Object?>? args) =>
super.noSuchMethod(
Invocation.method(#runInsert, [statement, args]), Future.value(0));
_i4.Future<int> runUpdate(String? statement, List<Object?>? args) =>
super.noSuchMethod(
Invocation.method(#runUpdate, [statement, args]), Future.value(0));
_i4.Future<int> runDelete(String? statement, List<Object?>? args) =>
super.noSuchMethod(
Invocation.method(#runDelete, [statement, args]), Future.value(0));
_i4.Future<void> runCustom(String? statement, [List<Object?>? args]) =>
super.noSuchMethod(
Invocation.method(#runCustom, [statement, args]), Future.value(null));
_i4.Future<void> runBatched(_i2.BatchedStatements? statements) =>
super.noSuchMethod(
Invocation.method(#runBatched, [statements]), Future.value(null));
_i2.TransactionExecutor beginTransaction() => super.noSuchMethod(
Invocation.method(#beginTransaction, []), _FakeTransactionExecutor());
_i4.Future<void> close() =>
super.noSuchMethod(Invocation.method(#close, []), Future.value(null));
}
/// A class which mocks [TransactionExecutor].
///
/// See the documentation for Mockito's code generation for more information.
class MockTransactionsInternal extends _i1.Mock
implements _i2.TransactionExecutor {
MockTransactionsInternal() {
_i1.throwOnMissingStub(this);
}
_i4.Future<void> send() =>
super.noSuchMethod(Invocation.method(#send, []), Future.value(null));
_i4.Future<void> rollback() =>
super.noSuchMethod(Invocation.method(#rollback, []), Future.value(null));
_i4.Future<bool> ensureOpen(_i2.QueryExecutorUser? user) =>
super.noSuchMethod(
Invocation.method(#ensureOpen, [user]), Future.value(false));
_i4.Future<List<Map<String, Object?>>> runSelect(
String? statement, List<Object?>? args) =>
super.noSuchMethod(Invocation.method(#runSelect, [statement, args]),
Future.value(<Map<String, Object?>>[]));
_i4.Future<int> runInsert(String? statement, List<Object?>? args) =>
super.noSuchMethod(
Invocation.method(#runInsert, [statement, args]), Future.value(0));
_i4.Future<int> runUpdate(String? statement, List<Object?>? args) =>
super.noSuchMethod(
Invocation.method(#runUpdate, [statement, args]), Future.value(0));
_i4.Future<int> runDelete(String? statement, List<Object?>? args) =>
super.noSuchMethod(
Invocation.method(#runDelete, [statement, args]), Future.value(0));
_i4.Future<void> runCustom(String? statement, [List<Object?>? args]) =>
super.noSuchMethod(
Invocation.method(#runCustom, [statement, args]), Future.value(null));
_i4.Future<void> runBatched(_i2.BatchedStatements? statements) =>
super.noSuchMethod(
Invocation.method(#runBatched, [statements]), Future.value(null));
_i2.TransactionExecutor beginTransaction() => super.noSuchMethod(
Invocation.method(#beginTransaction, []), _FakeTransactionExecutor());
_i4.Future<void> close() =>
super.noSuchMethod(Invocation.method(#close, []), Future.value(null));
}
/// A class which mocks [StreamQueryStore].
///
/// See the documentation for Mockito's code generation for more information.
class MockStreamQueries extends _i1.Mock implements _i5.StreamQueryStore {
_i4.Stream<T> registerStream<T>(_i5.QueryStreamFetcher<T>? fetcher) =>
super.noSuchMethod(
Invocation.method(#registerStream, [fetcher]), Stream<T>.empty());
_i4.Stream<Null?> updatesForSync(_i6.TableUpdateQuery? query) =>
super.noSuchMethod(
Invocation.method(#updatesForSync, [query]), Stream<Null?>.empty());
void handleTableUpdates(Set<_i6.TableUpdate>? updates) =>
super.noSuchMethod(Invocation.method(#handleTableUpdates, [updates]));
void markAsClosed(
_i5.QueryStream<dynamic>? stream, dynamic Function()? whenRemoved) =>
super.noSuchMethod(
Invocation.method(#markAsClosed, [stream, whenRemoved]));
void markAsOpened(_i5.QueryStream<dynamic>? stream) =>
super.noSuchMethod(Invocation.method(#markAsOpened, [stream]));
_i4.Future<void> close() =>
super.noSuchMethod(Invocation.method(#close, []), Future.value(null));
}

View File

@ -0,0 +1,52 @@
import 'package:moor/backends.dart';
class NullExecutor implements QueryExecutor {
const NullExecutor();
@override
TransactionExecutor beginTransaction() {
throw UnsupportedError('beginTransaction');
}
@override
Future<bool> ensureOpen(QueryExecutorUser user) {
throw UnsupportedError('ensureOpen');
}
@override
Future<void> runBatched(BatchedStatements statements) {
throw UnsupportedError('runBatched');
}
@override
Future<void> runCustom(String statement, [List<Object?>? args]) {
throw UnsupportedError('runCustom');
}
@override
Future<int> runDelete(String statement, List<Object?> args) {
throw UnsupportedError('runDelete');
}
@override
Future<int> runInsert(String statement, List<Object?> args) {
throw UnsupportedError('runInsert');
}
@override
Future<List<Map<String, Object?>>> runSelect(
String statement, List<Object?> args) {
throw UnsupportedError('runSelect');
}
@override
Future<int> runUpdate(String statement, List<Object?> args) {
throw UnsupportedError('runUpdate');
}
@override
Future<void> close() => Future.value();
@override
SqlDialect get dialect => SqlDialect.sqlite;
}

View File

@ -1,3 +1,4 @@
//@dart=2.9
import 'package:moor/moor.dart';
import 'package:test/test.dart';
@ -19,13 +20,9 @@ void main() {
});
test('can deserialize ints as doubles', () {
final entry = TableWithoutPKData.fromJson({
'notReallyAnId': 3,
'someFloat': 4,
});
const serializer = ValueSerializer.defaults();
expect(entry,
TableWithoutPKData(notReallyAnId: 3, someFloat: 4, custom: null));
expect(serializer.fromJson<double>(3), 3.0);
});
test('default serializer can be overridden globally', () {

View File

@ -1,5 +1,7 @@
import 'package:test/test.dart';
//@dart=2.9
import 'package:mockito/mockito.dart';
import 'package:moor/moor.dart';
import 'package:test/test.dart';
import 'data/tables/todos.dart';
import 'data/utils/mocks.dart';

View File

@ -1,5 +1,7 @@
//@dart=2.9
import 'dart:async';
import 'package:mockito/mockito.dart';
import 'package:moor/moor.dart';
import 'package:test/test.dart';

View File

@ -1,3 +1,4 @@
//@dart=2.9
@TestOn('vm')
import 'dart:io';

View File

@ -1,3 +1,5 @@
//@dart=2.9
import 'package:mockito/mockito.dart';
import 'package:moor/moor.dart';
import 'package:test/test.dart';

View File

@ -1,3 +1,4 @@
//@dart=2.9
import 'package:mockito/mockito.dart';
import 'package:moor/backends.dart';
import 'package:moor/moor.dart';
@ -42,19 +43,20 @@ void main() {
final db = DelegatedDatabase(delegate, isSequential: sequential);
await db.ensureOpen(_FakeExecutorUser());
expect(await db.runSelect(null, null), isEmpty);
expect(await db.runUpdate(null, null), 3);
expect(await db.runInsert(null, null), 4);
await db.runCustom(null);
await db.runBatched(null);
expect(await db.runSelect('select', const []), isEmpty);
expect(await db.runUpdate('update', const []), 3);
expect(await db.runInsert('insert', const []), 4);
await db.runCustom('custom');
final batched = BatchedStatements([], []);
await db.runBatched(batched);
verifyInOrder([
delegate.isOpen,
delegate.runSelect(null, null),
delegate.runUpdate(null, null),
delegate.runInsert(null, null),
delegate.runCustom(null, []),
delegate.runBatched(null),
delegate.runSelect('select', const []),
delegate.runUpdate('update', const []),
delegate.runInsert('insert', const []),
delegate.runCustom('custom', const []),
delegate.runBatched(batched),
]);
});
}
@ -149,12 +151,12 @@ void main() {
final transaction = db.beginTransaction();
await transaction.ensureOpen(_FakeExecutorUser());
await transaction.runSelect(null, null);
await transaction.runSelect('SELECT 1;', const []);
await transaction.send();
verifyInOrder([
delegate.runCustom('BEGIN TRANSACTION', []),
delegate.runSelect(null, null),
delegate.runSelect('SELECT 1;', const []),
delegate.runCustom('COMMIT TRANSACTION', []),
]);
});

View File

@ -1,3 +1,4 @@
//@dart=2.9
import 'package:moor/moor.dart';
import 'package:test/test.dart';

View File

@ -5,8 +5,8 @@ import '../data/tables/todos.dart';
import '../data/utils/expect_equality.dart';
void main() {
final expression = GeneratedIntColumn('col', null, false);
final db = TodoDb(null);
final expression = GeneratedIntColumn('col', 'table', false);
final db = TodoDb();
final comparisons = {
expression.isSmallerThan: '<',
@ -23,7 +23,7 @@ void main() {
};
group('can compare with other expressions', () {
final compare = GeneratedIntColumn('compare', null, false);
final compare = GeneratedIntColumn('compare', 'table', false);
comparisons.forEach((fn, value) {
test('for operator $value', () {
@ -53,8 +53,8 @@ void main() {
group('between', () {
test('other expressions', () {
final low = GeneratedIntColumn('low', null, false);
final high = GeneratedIntColumn('high', null, false);
final low = GeneratedIntColumn('low', 'table', false);
final high = GeneratedIntColumn('high', 'table', false);
final ctx = GenerationContext.fromDb(db);
expression.isBetween(low, high).writeInto(ctx);

View File

@ -1,3 +1,4 @@
//@dart=2.9
import 'package:moor/moor.dart';
import 'package:test/test.dart';
@ -31,7 +32,7 @@ void main() {
}
void testStringMapping(String dart, String expectedLiteral) {
final ctx = GenerationContext.fromDb(TodoDb(null));
final ctx = GenerationContext.fromDb(TodoDb());
final constant = Constant(dart);
constant.writeInto(ctx);

View File

@ -1,3 +1,4 @@
//@dart=2.9
import 'package:moor/moor.dart';
import 'package:test/test.dart';
@ -7,7 +8,7 @@ import '../data/utils/expect_generated.dart';
typedef _Extractor = Expression<int> Function(Expression<DateTime> d);
void main() {
final column = GeneratedDateTimeColumn('val', null, false);
final column = GeneratedDateTimeColumn('val', 'table', false);
group('extracting information via top-level method', () {
final expectedResults = <_Extractor, String>{

View File

@ -1,3 +1,4 @@
//@dart=2.9
@TestOn('vm')
import 'package:moor/ffi.dart';
import 'package:moor/moor.dart';

Some files were not shown because too many files have changed in this diff Show More