Document basic analysis concept

This commit is contained in:
Simon Binder 2022-11-18 16:33:19 +01:00
parent e1ec5faa93
commit 596a35b58e
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
27 changed files with 318 additions and 200 deletions

View File

@ -2,10 +2,7 @@
part of 'main.dart';
// DriftElementId(asset:drift/example/main.dart, todo_category_item_count)
// DriftElementId(asset:drift/example/main.dart, todo_items)
// DriftElementId(asset:drift/example/main.dart, todo_categories)
// DriftElementId(asset:drift/example/main.dart, customViewName)
// ignore_for_file: type=lint
class TodoCategory extends DataClass implements Insertable<TodoCategory> {
final int id;
final String name;

View File

@ -2,6 +2,7 @@
part of 'custom_tables.dart';
// ignore_for_file: type=lint
class NoIdsCompanion extends UpdateCompanion<NoIdRow> {
final Value<Uint8List> payload;
const NoIdsCompanion({
@ -42,11 +43,11 @@ class NoIdsCompanion extends UpdateCompanion<NoIdRow> {
}
}
class $NoIdsTable extends Table with TableInfo<$NoIdsTable, NoIdRow> {
class NoIds extends Table with TableInfo<NoIds, NoIdRow> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$NoIdsTable(this.attachedDatabase, [this._alias]);
NoIds(this.attachedDatabase, [this._alias]);
final VerificationMeta _payloadMeta = const VerificationMeta('payload');
late final GeneratedColumn<Uint8List> payload = GeneratedColumn<Uint8List>(
'payload', aliasedName, false,
@ -85,8 +86,8 @@ class $NoIdsTable extends Table with TableInfo<$NoIdsTable, NoIdRow> {
}
@override
$NoIdsTable createAlias(String alias) {
return $NoIdsTable(attachedDatabase, alias);
NoIds createAlias(String alias) {
return NoIds(attachedDatabase, alias);
}
@override
@ -216,12 +217,11 @@ class WithDefaultsCompanion extends UpdateCompanion<WithDefault> {
}
}
class $WithDefaultsTable extends Table
with TableInfo<$WithDefaultsTable, WithDefault> {
class WithDefaults extends Table with TableInfo<WithDefaults, WithDefault> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$WithDefaultsTable(this.attachedDatabase, [this._alias]);
WithDefaults(this.attachedDatabase, [this._alias]);
final VerificationMeta _aMeta = const VerificationMeta('a');
late final GeneratedColumn<String> a = GeneratedColumn<String>(
'a', aliasedName, true,
@ -269,8 +269,8 @@ class $WithDefaultsTable extends Table
}
@override
$WithDefaultsTable createAlias(String alias) {
return $WithDefaultsTable(attachedDatabase, alias);
WithDefaults createAlias(String alias) {
return WithDefaults(attachedDatabase, alias);
}
@override
@ -420,12 +420,12 @@ class WithConstraintsCompanion extends UpdateCompanion<WithConstraint> {
}
}
class $WithConstraintsTable extends Table
with TableInfo<$WithConstraintsTable, WithConstraint> {
class WithConstraints extends Table
with TableInfo<WithConstraints, WithConstraint> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$WithConstraintsTable(this.attachedDatabase, [this._alias]);
WithConstraints(this.attachedDatabase, [this._alias]);
final VerificationMeta _aMeta = const VerificationMeta('a');
late final GeneratedColumn<String> a = GeneratedColumn<String>(
'a', aliasedName, true,
@ -485,8 +485,8 @@ class $WithConstraintsTable extends Table
}
@override
$WithConstraintsTable createAlias(String alias) {
return $WithConstraintsTable(attachedDatabase, alias);
WithConstraints createAlias(String alias) {
return WithConstraints(attachedDatabase, alias);
}
@override
@ -514,11 +514,11 @@ class Config extends DataClass implements Insertable<Config> {
map['config_value'] = Variable<String>(configValue);
}
if (!nullToAbsent || syncState != null) {
final converter = $ConfigTable.$convertersyncStaten;
final converter = ConfigTable.$convertersyncStaten;
map['sync_state'] = Variable<int>(converter.toSql(syncState));
}
if (!nullToAbsent || syncStateImplicit != null) {
final converter = $ConfigTable.$convertersyncStateImplicitn;
final converter = ConfigTable.$convertersyncStateImplicitn;
map['sync_state_implicit'] =
Variable<int>(converter.toSql(syncStateImplicit));
}
@ -657,11 +657,11 @@ class ConfigCompanion extends UpdateCompanion<Config> {
map['config_value'] = Variable<String>(configValue.value);
}
if (syncState.present) {
final converter = $ConfigTable.$convertersyncStaten;
final converter = ConfigTable.$convertersyncStaten;
map['sync_state'] = Variable<int>(converter.toSql(syncState.value));
}
if (syncStateImplicit.present) {
final converter = $ConfigTable.$convertersyncStateImplicitn;
final converter = ConfigTable.$convertersyncStateImplicitn;
map['sync_state_implicit'] =
Variable<int>(converter.toSql(syncStateImplicit.value));
}
@ -680,11 +680,11 @@ class ConfigCompanion extends UpdateCompanion<Config> {
}
}
class $ConfigTable extends Table with TableInfo<$ConfigTable, Config> {
class ConfigTable extends Table with TableInfo<ConfigTable, Config> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$ConfigTable(this.attachedDatabase, [this._alias]);
ConfigTable(this.attachedDatabase, [this._alias]);
final VerificationMeta _configKeyMeta = const VerificationMeta('configKey');
late final GeneratedColumn<String> configKey = GeneratedColumn<String>(
'config_key', aliasedName, false,
@ -704,7 +704,7 @@ class $ConfigTable extends Table with TableInfo<$ConfigTable, Config> {
type: DriftSqlType.int,
requiredDuringInsert: false,
$customConstraints: '')
.withConverter<SyncType?>($ConfigTable.$convertersyncStaten);
.withConverter<SyncType?>(ConfigTable.$convertersyncStaten);
final VerificationMeta _syncStateImplicitMeta =
const VerificationMeta('syncStateImplicit');
late final GeneratedColumnWithTypeConverter<SyncType?, int>
@ -713,7 +713,7 @@ class $ConfigTable extends Table with TableInfo<$ConfigTable, Config> {
type: DriftSqlType.int,
requiredDuringInsert: false,
$customConstraints: '')
.withConverter<SyncType?>($ConfigTable.$convertersyncStateImplicitn);
.withConverter<SyncType?>(ConfigTable.$convertersyncStateImplicitn);
@override
List<GeneratedColumn> get $columns =>
[configKey, configValue, syncState, syncStateImplicit];
@ -753,18 +753,18 @@ class $ConfigTable extends Table with TableInfo<$ConfigTable, Config> {
.read(DriftSqlType.string, data['${effectivePrefix}config_key'])!,
configValue: attachedDatabase.options.types
.read(DriftSqlType.string, data['${effectivePrefix}config_value']),
syncState: $ConfigTable.$convertersyncStaten.fromSql(attachedDatabase
syncState: ConfigTable.$convertersyncStaten.fromSql(attachedDatabase
.options.types
.read(DriftSqlType.int, data['${effectivePrefix}sync_state'])),
syncStateImplicit: $ConfigTable.$convertersyncStateImplicitn.fromSql(
syncStateImplicit: ConfigTable.$convertersyncStateImplicitn.fromSql(
attachedDatabase.options.types.read(
DriftSqlType.int, data['${effectivePrefix}sync_state_implicit'])),
);
}
@override
$ConfigTable createAlias(String alias) {
return $ConfigTable(attachedDatabase, alias);
ConfigTable createAlias(String alias) {
return ConfigTable(attachedDatabase, alias);
}
static TypeConverter<SyncType, int> $convertersyncState =
@ -955,11 +955,11 @@ class MytableCompanion extends UpdateCompanion<MytableData> {
}
}
class $MytableTable extends Table with TableInfo<$MytableTable, MytableData> {
class Mytable extends Table with TableInfo<Mytable, MytableData> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$MytableTable(this.attachedDatabase, [this._alias]);
Mytable(this.attachedDatabase, [this._alias]);
final VerificationMeta _someidMeta = const VerificationMeta('someid');
late final GeneratedColumn<int> someid = GeneratedColumn<int>(
'someid', aliasedName, false,
@ -1037,8 +1037,8 @@ class $MytableTable extends Table with TableInfo<$MytableTable, MytableData> {
}
@override
$MytableTable createAlias(String alias) {
return $MytableTable(attachedDatabase, alias);
Mytable createAlias(String alias) {
return Mytable(attachedDatabase, alias);
}
@override
@ -1181,12 +1181,12 @@ class EmailCompanion extends UpdateCompanion<EMail> {
}
}
class $EmailTable extends Table
with TableInfo<$EmailTable, EMail>, VirtualTableInfo<$EmailTable, EMail> {
class Email extends Table
with TableInfo<Email, EMail>, VirtualTableInfo<Email, EMail> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$EmailTable(this.attachedDatabase, [this._alias]);
Email(this.attachedDatabase, [this._alias]);
final VerificationMeta _senderMeta = const VerificationMeta('sender');
late final GeneratedColumn<String> sender = GeneratedColumn<String>(
'sender', aliasedName, false,
@ -1253,8 +1253,8 @@ class $EmailTable extends Table
}
@override
$EmailTable createAlias(String alias) {
return $EmailTable(attachedDatabase, alias);
Email createAlias(String alias) {
return Email(attachedDatabase, alias);
}
@override
@ -1381,12 +1381,11 @@ class WeirdTableCompanion extends UpdateCompanion<WeirdData> {
}
}
class $WeirdTableTable extends Table
with TableInfo<$WeirdTableTable, WeirdData> {
class WeirdTable extends Table with TableInfo<WeirdTable, WeirdData> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$WeirdTableTable(this.attachedDatabase, [this._alias]);
WeirdTable(this.attachedDatabase, [this._alias]);
final VerificationMeta _sqlClassMeta = const VerificationMeta('sqlClass');
late final GeneratedColumn<int> sqlClass = GeneratedColumn<int>(
'class', aliasedName, false,
@ -1439,8 +1438,8 @@ class $WeirdTableTable extends Table
}
@override
$WeirdTableTable createAlias(String alias) {
return $WeirdTableTable(attachedDatabase, alias);
WeirdTable createAlias(String alias) {
return WeirdTable(attachedDatabase, alias);
}
@override
@ -1548,10 +1547,10 @@ class MyView extends ViewInfo<MyView, MyViewData> implements HasResultSet {
.read(DriftSqlType.string, data['${effectivePrefix}config_key'])!,
configValue: attachedDatabase.options.types
.read(DriftSqlType.string, data['${effectivePrefix}config_value']),
syncState: $ConfigTable.$convertersyncStaten.fromSql(attachedDatabase
syncState: ConfigTable.$convertersyncStaten.fromSql(attachedDatabase
.options.types
.read(DriftSqlType.int, data['${effectivePrefix}sync_state'])),
syncStateImplicit: $ConfigTable.$convertersyncStateImplicitn.fromSql(
syncStateImplicit: ConfigTable.$convertersyncStateImplicitn.fromSql(
attachedDatabase.options.types.read(
DriftSqlType.int, data['${effectivePrefix}sync_state_implicit'])),
);
@ -1566,12 +1565,12 @@ class MyView extends ViewInfo<MyView, MyViewData> implements HasResultSet {
late final GeneratedColumnWithTypeConverter<SyncType?, int> syncState =
GeneratedColumn<int>('sync_state', aliasedName, true,
type: DriftSqlType.int)
.withConverter<SyncType?>($ConfigTable.$convertersyncStaten);
.withConverter<SyncType?>(ConfigTable.$convertersyncStaten);
late final GeneratedColumnWithTypeConverter<SyncType?, int>
syncStateImplicit = GeneratedColumn<int>(
'sync_state_implicit', aliasedName, true,
type: DriftSqlType.int)
.withConverter<SyncType?>($ConfigTable.$convertersyncStateImplicitn);
.withConverter<SyncType?>(ConfigTable.$convertersyncStateImplicitn);
@override
MyView createAlias(String alias) {
return MyView(attachedDatabase, alias);
@ -1586,16 +1585,15 @@ class MyView extends ViewInfo<MyView, MyViewData> implements HasResultSet {
abstract class _$CustomTablesDb extends GeneratedDatabase {
_$CustomTablesDb(QueryExecutor e) : super(e);
_$CustomTablesDb.connect(DatabaseConnection c) : super.connect(c);
late final $NoIdsTable noIds = $NoIdsTable(this);
late final $WithDefaultsTable withDefaults = $WithDefaultsTable(this);
late final $WithConstraintsTable withConstraints =
$WithConstraintsTable(this);
late final $ConfigTable config = $ConfigTable(this);
late final NoIds noIds = NoIds(this);
late final WithDefaults withDefaults = WithDefaults(this);
late final WithConstraints withConstraints = WithConstraints(this);
late final ConfigTable config = ConfigTable(this);
late final Index valueIdx = Index('value_idx',
'CREATE INDEX IF NOT EXISTS value_idx ON config (config_value)');
late final $MytableTable mytable = $MytableTable(this);
late final $EmailTable email = $EmailTable(this);
late final $WeirdTableTable weirdTable = $WeirdTableTable(this);
late final Mytable mytable = Mytable(this);
late final Email email = Email(this);
late final WeirdTable weirdTable = WeirdTable(this);
late final Trigger myTrigger = Trigger(
'CREATE TRIGGER my_trigger AFTER INSERT ON config BEGIN INSERT INTO with_defaults VALUES (new.config_key, LENGTH(new.config_value));END',
'my_trigger');
@ -1674,11 +1672,11 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
'SELECT config_key FROM config WHERE ${generatedpred.sql} AND(sync_state = ?1 OR sync_state_implicit IN ($expandedvar2))',
variables: [
Variable<int>(NullAwareTypeConverter.wrapToSql(
$ConfigTable.$convertersyncState, var1)),
ConfigTable.$convertersyncState, var1)),
...generatedpred.introducedVariables,
for (var $ in var2)
Variable<int>(NullAwareTypeConverter.wrapToSql(
$ConfigTable.$convertersyncStateImplicit, $))
ConfigTable.$convertersyncStateImplicit, $))
],
readsFrom: {
config,
@ -1686,14 +1684,14 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
}).map((QueryRow row) => row.read<String>('config_key'));
}
Selectable<TableValuedResult> tableValued() {
Selectable<JsonResult> tableValued() {
return customSelect(
'SELECT "key", value FROM config,json_each(config.config_value)WHERE json_valid(config_value)',
variables: [],
readsFrom: {
config,
}).map((QueryRow row) {
return TableValuedResult(
return JsonResult(
row: row,
key: row.read<String>('key'),
value: row.readNullable<String>('value'),
@ -1701,12 +1699,12 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
});
}
Selectable<AnotherResult> another() {
Selectable<JsonResult> another() {
return customSelect(
'SELECT \'one\' AS "key", NULLIF(\'two\', \'another\') AS value',
variables: [],
readsFrom: {}).map((QueryRow row) {
return AnotherResult(
return JsonResult(
row: row,
key: row.read<String>('key'),
value: row.readNullable<String>('value'),
@ -1772,10 +1770,10 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
configKey: row.read<String>('config_key'),
configValue: row.readNullable<String>('config_value'),
syncState: NullAwareTypeConverter.wrapFromSql(
$ConfigTable.$convertersyncState,
ConfigTable.$convertersyncState,
row.readNullable<int>('sync_state')),
syncStateImplicit: NullAwareTypeConverter.wrapFromSql(
$ConfigTable.$convertersyncStateImplicit,
ConfigTable.$convertersyncStateImplicit,
row.readNullable<int>('sync_state_implicit')),
);
});
@ -1875,14 +1873,14 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
const DriftDatabaseOptions(storeDateTimeAsText: true);
}
typedef ReadMultiple$clause = OrderBy Function($ConfigTable config);
typedef ReadDynamic$predicate = Expression<bool> Function($ConfigTable config);
typedef TypeConverterVar$pred = Expression<bool> Function($ConfigTable config);
typedef ReadMultiple$clause = OrderBy Function(ConfigTable config);
typedef ReadDynamic$predicate = Expression<bool> Function(ConfigTable config);
typedef TypeConverterVar$pred = Expression<bool> Function(ConfigTable config);
class TableValuedResult extends CustomResultSet {
class JsonResult extends CustomResultSet {
final String key;
final String? value;
TableValuedResult({
JsonResult({
required QueryRow row,
required this.key,
this.value,
@ -1892,38 +1890,12 @@ class TableValuedResult extends CustomResultSet {
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is TableValuedResult &&
(other is JsonResult &&
other.key == this.key &&
other.value == this.value);
@override
String toString() {
return (StringBuffer('TableValuedResult(')
..write('key: $key, ')
..write('value: $value')
..write(')'))
.toString();
}
}
class AnotherResult extends CustomResultSet {
final String key;
final String? value;
AnotherResult({
required QueryRow row,
required this.key,
this.value,
}) : super(row);
@override
int get hashCode => Object.hash(key, value);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is AnotherResult &&
other.key == this.key &&
other.value == this.value);
@override
String toString() {
return (StringBuffer('AnotherResult(')
return (StringBuffer('JsonResult(')
..write('key: $key, ')
..write('value: $value')
..write(')'))
@ -1962,7 +1934,7 @@ class MultipleResult extends CustomResultSet {
}
typedef Multiple$predicate = Expression<bool> Function(
$WithDefaultsTable d, $WithConstraintsTable c);
WithDefaults d, WithConstraints c);
class ReadRowIdResult extends CustomResultSet {
final int rowid;
@ -2003,7 +1975,7 @@ class ReadRowIdResult extends CustomResultSet {
}
}
typedef ReadRowId$expr = Expression<int> Function($ConfigTable config);
typedef ReadRowId$expr = Expression<int> Function(ConfigTable config);
class NestedResult extends CustomResultSet {
final WithDefault defaults;

View File

@ -2,10 +2,7 @@
part of 'todos.dart';
// DriftElementId(asset:drift/test/generated/todos.dart, category_todo_count_view)
// DriftElementId(asset:drift/test/generated/todos.dart, todos)
// DriftElementId(asset:drift/test/generated/todos.dart, categories)
// DriftElementId(asset:drift/test/generated/todos.dart, todo_with_category_view)
// ignore_for_file: type=lint
class Category extends DataClass implements Insertable<Category> {
final int id;
final String description;
@ -1731,10 +1728,6 @@ class AllTodosWithCategoryResult extends CustomResultSet {
}
}
// DriftElementId(asset:drift/test/generated/todos.dart, users)
// DriftElementId(asset:drift/test/generated/todos.dart, shared_todos)
// DriftElementId(asset:drift/test/generated/todos.dart, table_without_p_k)
// DriftElementId(asset:drift/test/generated/todos.dart, pure_defaults)
mixin _$SomeDaoMixin on DatabaseAccessor<TodoDb> {
$UsersTable get users => attachedDatabase.users;
$SharedTodosTable get sharedTodos => attachedDatabase.sharedTodos;

View File

@ -242,6 +242,6 @@ void main() {
.getSingleOrNull();
verify(mock.runSelect('SELECT * FROM "config" WHERE "sync_state" = ?;',
[$ConfigTable.$convertersyncState.toSql(SyncType.synchronized)]));
[ConfigTable.$convertersyncState.toSql(SyncType.synchronized)]));
});
}

View File

@ -2,18 +2,36 @@ import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:logging/logging.dart';
/// The backend used by drift's analysis implementation to read files and access
/// the Dart analyzer.
abstract class DriftBackend {
/// A logger through which drift's analyzer will emit internal warnings and
/// debugging information.
Logger get log;
/// Resolves a uri and normalizes it into a format used by this backend.
Uri resolveUri(Uri base, String uriString);
/// Reads a file as string.
Future<String> readAsString(Uri uri);
Future<Uri> uriOfDart(Element element) async {
return element.source!.uri;
}
/// Resolves a Dart library by its uri.
///
/// This should also be able to resolve SDK libraries.
/// If no Dart library can be found under that uri, throws a
/// [NotALibraryException].
Future<LibraryElement> readDart(Uri uri);
/// Loads the resolved AST node defining the given [element].
///
/// Depending on how the analyzer is accessed, this may throw an exception if
/// the resolved AST is not available.
/// When the [element] does not have a syntactic representation in the AST,
/// null is returned.
Future<AstNode?> loadElementDeclaration(Element element);
/// Resolves a Dart expression from a string.

View File

@ -1,7 +1,11 @@
import '../results/element.dart';
import 'state.dart';
/// An in-memory cache of analysis results for drift elements.
///
/// At the moment, the cache is not set up to handle changing files.
class DriftAnalysisCache {
final Map<Uri, Map<String, Object?>> serializedElements = {};
final Map<Uri, FileState> knownFiles = {};
final Map<DriftElementId, DiscoveredElement> discoveredElements = {};

View File

@ -16,6 +16,40 @@ import 'cache.dart';
import 'error.dart';
import 'state.dart';
/// The main entrypoint for drift element analysis.
///
/// The purpose of this analyzer is to extract tables, views, databases and
/// other elements of interest to drift from source files. Where possible, the
/// analysis steps should be modular, meaning that they don't require a central
/// entrypoint like a database class. Instead, every element can be analyzed in
/// isolation (except for its dependencies).
///
/// Analysis currently happens in three stages:
///
/// 1. __Discovery__: In this first step, the names and types of drift elements
/// is detected in each file. After this step, we might know that there's a
/// table named "users" in a file named "tables.drift", but we don't know its
/// columns yet. This enables the analysis stage to efficiently resolve
/// references. The step is mainly implemented in [DiscoverStep] and
/// [prepareFileForAnalysis].
/// 2. __Element analysis__: In this step, discovered entries from the first
/// step are fully resolved.
/// Resolving elements happens in a depth-first approach, where dependencies
/// are analyzed before dependants. It is forbidden to have circular references
/// between elements (which is detected and handled gracefully). This step is
/// coordinated by a [DriftResolver], with the classes in `resolver/dart` and
/// `resolver/drift` being responsible for the individual analysis work for
/// different element types.
/// 3. __File analysis__: In this final step, some elements are analyzed again
/// to fully resolve them. This includes drift databases, drift accessors and
/// queries defined in `.drift` files. They require all other elements to be
/// fully analyzed.
/// The main motivation for this being a third step is that the results of
/// resolving queries are very difficult to serialize. At the moment, modular
/// analysis is implemented by serializing the results of the second step
/// (element analysis). By running file analysis later and only for entrypoints
/// where that is required, we obtain a reasonable degree of modularity without
/// having to serialize the complex model of serialized queries.
class DriftAnalysisDriver {
final DriftBackend backend;
final DriftAnalysisCache cache = DriftAnalysisCache();
@ -47,10 +81,15 @@ class DriftAnalysisDriver {
);
}
/// Loads types important for Drift analysis.
Future<KnownDriftTypes> loadKnownTypes() async {
return _knownTypes ??= await KnownDriftTypes.resolve(this);
}
/// For a given file under [uri], attempts to restore serialized analysis
/// results that have been stored before.
///
/// Returns non-null if analysis results were found and successfully restored.
Future<Map<String, Object?>?> readStoredAnalysisResult(Uri uri) async {
final cached = cache.serializedElements[uri];
if (cached != null) return cached;
@ -85,6 +124,7 @@ class DriftAnalysisDriver {
return allRecovered;
}
/// Runs the first step (element discovery) on a file with the given [uri].
Future<FileState> prepareFileForAnalysis(Uri uri,
{bool needsDiscovery = true}) async {
var known = cache.knownFiles[uri] ?? cache.notifyFileChanged(uri);
@ -120,6 +160,11 @@ class DriftAnalysisDriver {
return known;
}
/// Runs the second analysis step (element analysis) on a file.
///
/// The file, as well as all imports, should have undergone the first analysis
/// step (discovery) at this point, so that the resolver is able to
/// recognize dependencies between different elements.
Future<void> _analyzePrepared(FileState state) async {
assert(state.discovery != null);
@ -136,6 +181,8 @@ class DriftAnalysisDriver {
}
}
/// Resolves elements in a file under the given [uri] by doing all the
/// necessary work up until that point.
Future<FileState> resolveElements(Uri uri) async {
var known = cache.stateForUri(uri);
await prepareFileForAnalysis(uri, needsDiscovery: false);
@ -159,6 +206,7 @@ class DriftAnalysisDriver {
return known;
}
/// Fully analyzes a file under the [uri] by running all analysis steps.
Future<FileState> fullyAnalyze(Uri uri) async {
// First, make sure that elements in this file and all imports are fully
// resolved.

View File

@ -3,6 +3,7 @@ import 'package:meta/meta.dart';
import 'package:path/path.dart' show url;
import 'package:sqlparser/sqlparser.dart' hide AnalysisError;
import '../results/database.dart';
import '../results/element.dart';
import '../results/file_results.dart';
import 'error.dart';
@ -20,6 +21,12 @@ class FileState {
String get extension => url.extension(ownUri.path);
/// Whether this file contains a drift database or a drift accessor / DAO.
bool get containsDatabaseAccessor {
return analyzedElements.any((e) => e is BaseDriftAccessor);
}
/// All analyzed [DriftElement]s found in this library.
@visibleForTesting
Iterable<DriftElement> get analyzedElements {
return analysis.values.map((e) => e.result).whereType();

View File

@ -48,6 +48,11 @@ class DriftPreprocessorResult {
Map<String, Object?> toJson() => _$DriftPreprocessorResultToJson(this);
}
/// Processes `.drift` files to extract all embedded Dart snippets.
///
/// To analyze drift files in the build system, we extract these snippets into
/// a standalone Dart file so that we're able to analyze them with the resolvers
/// provided by the build system.
class DriftPreprocessor {
final DriftPreprocessorResult result;
final String temporaryDartFile;

View File

@ -7,6 +7,10 @@ import 'package:collection/collection.dart';
import '../../driver/driver.dart';
import '../../results/results.dart';
/// A collection of elements and Dart types important to Drift.
///
/// These types are used to determine whether a given Dart class has drift-
/// specific annotations or whether it defines a table.
class KnownDriftTypes {
final LibraryElement helperLibrary;
final ClassElement tableElement;

View File

@ -13,6 +13,8 @@ import '../results/element.dart';
import 'dart/helper.dart';
import 'intermediate_state.dart';
/// Finds the name and kind (e.g. table, view, database, index, ...) of entries
/// defined in a given file.
class DiscoverStep {
final DriftAnalysisDriver _driver;
final FileState _file;

View File

@ -336,6 +336,7 @@ class DriftTableResolver extends LocalElementResolver<DiscoveredDriftTable> {
references: references.toList(),
nameOfRowClass: dataClassName,
baseDartName: dartTableName,
fixedEntityInfoName: dartTableName,
existingRowClass: existingRowClass,
withoutRowId: table.withoutRowId,
strict: table.isStrict,

View File

@ -9,6 +9,7 @@ import '../results/results.dart';
import 'queries/query_analyzer.dart';
import 'queries/required_variables.dart';
/// Fully resolves databases and queries after elements have been resolved.
class FileAnalyzer {
final DriftAnalysisDriver driver;

View File

@ -16,13 +16,18 @@ import 'drift/trigger.dart' as drift_trigger;
import 'drift/view.dart' as drift_view;
import 'intermediate_state.dart';
/// Analyzes and resolves drift elements.
class DriftResolver {
final DriftAnalysisDriver driver;
/// The current depth-first path of drift elements being analyzed.
///
/// This path is used to detect and prevent circular references.
final List<DriftElementId> _currentDependencyPath = [];
DriftResolver(this.driver);
/// Resolves a discovered element by analyzing it and its dependencies.
Future<DriftElement> resolveDiscovered(DiscoveredElement discovered) async {
LocalElementResolver resolver;
@ -68,6 +73,13 @@ class DriftResolver {
return resolved;
}
/// Attempts to resolve a dependency for an element if that is allowed.
///
/// It usually _is_ allowed, but there could be a forbidden circular reference
/// in which case the reference is reported to be unavailable.
/// Further, an internal bug in the analyzer could cause a crash analyzing
/// the element. To not cause the entire analysis run to fail, this reports
/// an error message and otherwise continues analysis of other elements.
Future<ResolveReferencedElementResult> resolveReferencedElement(
DriftElementId owner, DriftElementId reference) async {
if (owner == reference) {
@ -117,6 +129,8 @@ class DriftResolver {
'Unknown pending element $reference, this is a bug in drift_dev');
}
/// Resolves a Dart element reference, if the referenced Dart [element]
/// defines an element understood by drift.
Future<ResolveReferencedElementResult> resolveDartReference(
DriftElementId owner, Element element) async {
final uri = await driver.backend.uriOfDart(element.library!);
@ -136,6 +150,12 @@ class DriftResolver {
}
}
/// Resolves a reference in SQL.
///
/// This works by looking at known imports of the file defining the [owner]
/// and using the results of the discovery step to find a known element with
/// the same name. If one exists, it is resolved and returned. Otherwise, an
/// error result is returned.
Future<ResolveReferencedElementResult> resolveReference(
DriftElementId owner, String reference) async {
final candidates = <DriftElementId>[];

View File

@ -10,6 +10,12 @@ import 'driver/driver.dart';
import 'driver/state.dart';
import 'results/results.dart';
/// Serializes [DriftElement]s to JSON.
///
/// By first analyzing elements and later generating code, drift's build setup
/// is more efficient and incremental (as not everything is analyzed again if
/// a single file changes). However, it means that we have to serialize analysis
/// results to read them back in in a later build step.
class ElementSerializer {
Map<String, Object?> serializeElements(Iterable<DriftElement> elements) {
return {
@ -346,6 +352,7 @@ class _DartTypeSerializer extends TypeVisitor<Map<String, Object?>> {
}
}
/// Deserializes the element structure emitted by [ElementSerializer].
class ElementDeserializer {
final Map<Uri, LibraryElement> _loadedLibraries = {};
final List<DriftElementId> _currentlyReading = [];
@ -404,7 +411,12 @@ class ElementDeserializer {
'Analysis data for ${id..libraryUri} not found');
}
assert(!_currentlyReading.contains(id));
if (_currentlyReading.contains(id)) {
throw StateError(
'Circular error when deserializing drift modules. This is a '
'bug in drift_dev!');
}
try {
_currentlyReading.add(id);
@ -445,7 +457,7 @@ class ElementDeserializer {
case 'table':
final columns = [
for (final rawColumn in json['columns'] as List)
await _readColumn(rawColumn as Map),
await _readColumn(rawColumn as Map, id),
];
final columnByName = {
for (final column in columns) column.nameInSql: column,
@ -478,7 +490,7 @@ class ElementDeserializer {
);
}
return DriftTable(
final table = DriftTable(
id,
declaration,
references: references,
@ -504,6 +516,23 @@ class ElementDeserializer {
? (json['custom_constraints'] as List).cast()
: null,
);
for (final column in columns) {
for (var i = 0; i < column.constraints.length; i++) {
final constraint = column.constraints[i];
if (constraint is _PendingReferenceToOwnTable) {
column.constraints[i] = ForeignKeyReference(
columns.singleWhere(
(e) => e.nameInSql == constraint.referencedColumn),
constraint.onUpdate,
constraint.onDelete,
);
}
}
}
return table;
case 'index':
return DriftIndex(
id,
@ -547,7 +576,7 @@ class ElementDeserializer {
case 'view':
final columns = [
for (final rawColumn in json['columns'] as List)
await _readColumn(rawColumn as Map),
await _readColumn(rawColumn as Map, id),
];
final serializedSource = json['source'] as Map;
@ -622,7 +651,7 @@ class ElementDeserializer {
declaredViews: views,
declaredIncludes: includes,
declaredQueries: queries,
schemaVersion: json['schema_version'] as int,
schemaVersion: json['schema_version'] as int?,
accessorTypes: [
for (final dao in json['daos'])
AnnotatedDartCode.fromJson(dao as Map)
@ -646,7 +675,7 @@ class ElementDeserializer {
}
}
Future<DriftColumn> _readColumn(Map json) async {
Future<DriftColumn> _readColumn(Map json, DriftElementId ownTable) async {
final rawConverter = json['typeConverter'] as Map?;
return DriftColumn(
@ -668,7 +697,7 @@ class ElementDeserializer {
documentationComment: json['documentationComment'] as String?,
constraints: [
for (final rawConstraint in json['constraints'] as List)
await _readConstraint(rawConstraint as Map)
await _readConstraint(rawConstraint as Map, ownTable)
],
customConstraints: json['customConstraints'] as String?,
);
@ -701,7 +730,8 @@ class ElementDeserializer {
return value == null ? null : ReferenceAction.values.byName(value);
}
Future<DriftColumnConstraint> _readConstraint(Map json) async {
Future<DriftColumnConstraint> _readConstraint(
Map json, DriftElementId ownTable) async {
final type = json['type'] as String;
switch (type) {
@ -710,11 +740,20 @@ class ElementDeserializer {
case 'primary':
return PrimaryKeyColumn.fromJson(json);
case 'foreign_key':
return ForeignKeyReference(
await _readDriftColumnReference(json['column'] as Map),
_readAction(json['onUpdate'] as String?),
_readAction(json['onDelete'] as String?),
);
final table = DriftElementId.fromJson(json['column']['table'] as Map);
if (table == ownTable) {
return _PendingReferenceToOwnTable(
json['column']['name'] as String,
_readAction(json['onUpdate'] as String?),
_readAction(json['onDelete'] as String?),
);
} else {
return ForeignKeyReference(
await _readDriftColumnReference(json['column'] as Map),
_readAction(json['onUpdate'] as String?),
_readAction(json['onDelete'] as String?),
);
}
case 'generated_as':
return ColumnGeneratedAs.fromJson(json);
case 'check':
@ -767,3 +806,11 @@ class CouldNotDeserializeException implements Exception {
@override
String toString() => message;
}
class _PendingReferenceToOwnTable extends DriftColumnConstraint {
final String referencedColumn;
final ReferenceAction? onUpdate, onDelete;
_PendingReferenceToOwnTable(
this.referencedColumn, this.onUpdate, this.onDelete);
}

View File

@ -6,6 +6,7 @@ import '../../analysis/driver/driver.dart';
import '../../analysis/driver/state.dart';
import '../../analysis/results/results.dart';
import '../../analysis/options.dart';
import '../../utils/string_escaper.dart';
import '../../writer/database_writer.dart';
import '../../writer/drift_accessor_writer.dart';
import '../../writer/import_manager.dart';
@ -32,6 +33,14 @@ enum DriftGenerationMode {
monolithicPart;
bool get isMonolithic => true;
/// Whether the analysis happens in the generating build step.
///
/// For most generation modes, we run analysis work in a previous build step.
/// For backwards compatibility and since the result of the analysis work
/// should not be user-visible, the non-shared part builder runs its analysis
/// work in the generation build step.
bool get embeddedAnalyzer => this == DriftGenerationMode.monolithicPart;
}
class DriftBuilder extends Builder {
@ -74,13 +83,17 @@ class DriftBuilder extends Builder {
final driver = DriftAnalysisDriver(DriftBuildBackend(buildStep), options)
..cacheReader = BuildCacheReader(buildStep);
final fromCache =
await driver.readStoredAnalysisResult(buildStep.inputId.uri);
if (!generationMode.embeddedAnalyzer) {
// An analysis step should have already run for this asset. If we can't
// pick up results from that, there is no code for drift to generate.
final fromCache =
await driver.readStoredAnalysisResult(buildStep.inputId.uri);
if (fromCache == null) {
// Don't do anything! There are no analysis results for this file, so
// there's nothing for drift to generate code for.
return;
if (fromCache == null) {
// Don't do anything! There are no analysis results for this file, so
// there's nothing for drift to generate code for.
return;
}
}
Set<Uri> analyzedUris = {};
@ -98,6 +111,12 @@ class DriftBuilder extends Builder {
final fileResult = await analyze(buildStep.inputId.uri);
// For the monolithic build modes, we only generate code for databases and
// crawl the tables from there.
if (generationMode.isMonolithic && !fileResult.containsDatabaseAccessor) {
return;
}
final generationOptions = GenerationOptions(
imports: ImportManagerForPartFiles(),
);
@ -140,13 +159,19 @@ class DriftBuilder extends Builder {
AccessorGenerationInput(result, resolved, importedQueries);
AccessorWriter(input, writer.child()).write();
}
} else {
writer.leaf().writeln('// ${element.ownId}');
}
}
var generated = writer.writeGenerated();
final output = StringBuffer();
output.writeln('// ignore_for_file: type=lint');
if (generationMode == DriftGenerationMode.monolithicPart) {
final originalFile = buildStep.inputId.pathSegments.last;
output.writeln('part of ${asDartLiteral(originalFile)};');
}
output.write(writer.writeGenerated());
var generated = output.toString();
try {
generated = DartFormatter().format(generated);
} on FormatterException {

View File

@ -68,8 +68,9 @@ abstract class _NodeOrWriter {
/// Returns a Dart expression evaluating to the [converter].
AnnotatedDartCode readConverter(AppliedTypeConverter converter,
{bool forNullable = false}) {
final fieldName =
forNullable ? converter.nullableFieldName : converter.fieldName;
final fieldName = forNullable && converter.canBeSkippedForNulls
? converter.nullableFieldName
: converter.fieldName;
final table = converter.owningColumn.owner;
return AnnotatedDartCode([
@ -95,7 +96,7 @@ abstract class _NodeOrWriter {
..questionMarkIfNullable(makeNullable)
..addText(',')
..addTopLevel(sqlDartType)
..questionMarkIfNullable(makeNullable);
..questionMarkIfNullable(makeNullable || converter.sqlTypeIsNullable);
if (converter.alsoAppliesToJsonConversion) {
b

View File

@ -2,10 +2,6 @@
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class Category extends DataClass implements Insertable<Category> {
final int id;
@ -18,7 +14,7 @@ class Category extends DataClass implements Insertable<Category> {
map['id'] = Variable<int>(id);
map['name'] = Variable<String>(name);
{
final converter = $CategoriesTable.$converter0;
final converter = $CategoriesTable.$convertercolor;
map['color'] = Variable<int>(converter.toSql(color));
}
return map;
@ -123,7 +119,7 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
map['name'] = Variable<String>(name.value);
}
if (color.present) {
final converter = $CategoriesTable.$converter0;
final converter = $CategoriesTable.$convertercolor;
map['color'] = Variable<int>(converter.toSql(color.value));
}
return map;
@ -163,7 +159,7 @@ class $CategoriesTable extends Categories
late final GeneratedColumnWithTypeConverter<Color, int> color =
GeneratedColumn<int>('color', aliasedName, false,
type: DriftSqlType.int, requiredDuringInsert: true)
.withConverter<Color>($CategoriesTable.$converter0);
.withConverter<Color>($CategoriesTable.$convertercolor);
@override
List<GeneratedColumn> get $columns => [id, name, color];
@override
@ -198,7 +194,8 @@ class $CategoriesTable extends Categories
.read(DriftSqlType.int, data['${effectivePrefix}id'])!,
name: attachedDatabase.options.types
.read(DriftSqlType.string, data['${effectivePrefix}name'])!,
color: $CategoriesTable.$converter0.fromSql(attachedDatabase.options.types
color: $CategoriesTable.$convertercolor.fromSql(attachedDatabase
.options.types
.read(DriftSqlType.int, data['${effectivePrefix}color'])!),
);
}
@ -208,7 +205,7 @@ class $CategoriesTable extends Categories
return $CategoriesTable(attachedDatabase, alias);
}
static TypeConverter<Color, int> $converter0 = const ColorConverter();
static TypeConverter<Color, int> $convertercolor = const ColorConverter();
}
class TodoEntry extends DataClass implements Insertable<TodoEntry> {
@ -402,7 +399,7 @@ class $TodoEntriesTable extends TodoEntries
'category', aliasedName, true,
type: DriftSqlType.int,
requiredDuringInsert: false,
defaultConstraints: 'REFERENCES "categories" ("id")');
defaultConstraints: 'REFERENCES categories (id)');
final VerificationMeta _dueDateMeta = const VerificationMeta('dueDate');
@override
late final GeneratedColumn<DateTime> dueDate = GeneratedColumn<DateTime>(
@ -592,7 +589,7 @@ class TextEntries extends Table
}
@override
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
Set<GeneratedColumn> get $primaryKey => const <GeneratedColumn>{};
@override
TextEntrie map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
@ -607,6 +604,8 @@ class TextEntries extends Table
return TextEntries(attachedDatabase, alias);
}
@override
List<String> get customConstraints => const [];
@override
bool get dontWriteConstraints => true;
@override
@ -641,7 +640,7 @@ abstract class _$AppDatabase extends GeneratedDatabase {
id: row.readNullable<int>('id'),
name: row.readNullable<String>('name'),
color: NullAwareTypeConverter.wrapFromSql(
$CategoriesTable.$converter0, row.readNullable<int>('color')),
$CategoriesTable.$convertercolor, row.readNullable<int>('color')),
amount: row.read<int>('amount'),
);
});

View File

@ -2,10 +2,6 @@
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class Note extends DataClass implements Insertable<Note> {
final int id;

View File

@ -2,10 +2,6 @@
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class Entrie extends DataClass implements Insertable<Entrie> {
final int id;
@ -172,6 +168,8 @@ class Entries extends Table with TableInfo<Entries, Entrie> {
return Entries(attachedDatabase, alias);
}
@override
List<String> get customConstraints => const [];
@override
bool get dontWriteConstraints => true;
}

View File

@ -2,10 +2,6 @@
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class User extends DataClass implements Insertable<User> {
final int id;
@ -200,7 +196,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
'next_user', aliasedName, true,
type: DriftSqlType.int,
requiredDuringInsert: false,
defaultConstraints: 'REFERENCES "users" ("id")');
defaultConstraints: 'REFERENCES users (id)');
@override
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
@override
@ -443,13 +439,13 @@ class Groups extends Table with TableInfo<Groups, Group> {
type: DriftSqlType.bool,
requiredDuringInsert: false,
$customConstraints: 'DEFAULT FALSE',
defaultValue: const CustomExpression<bool>('FALSE'));
defaultValue: const CustomExpression('FALSE'));
final VerificationMeta _ownerMeta = const VerificationMeta('owner');
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
'owner', aliasedName, false,
type: DriftSqlType.int,
requiredDuringInsert: true,
$customConstraints: 'NOT NULL REFERENCES users (id)');
$customConstraints: 'NOT NULL REFERENCES users(id)');
@override
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
@override
@ -506,7 +502,7 @@ class Groups extends Table with TableInfo<Groups, Group> {
}
@override
List<String> get customConstraints => const ['PRIMARY KEY (id)'];
List<String> get customConstraints => const ['PRIMARY KEY(id)'];
@override
bool get dontWriteConstraints => true;
}
@ -704,7 +700,7 @@ class Notes extends Table
}
@override
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
Set<GeneratedColumn> get $primaryKey => const <GeneratedColumn>{};
@override
Note map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
@ -723,6 +719,8 @@ class Notes extends Table
return Notes(attachedDatabase, alias);
}
@override
List<String> get customConstraints => const [];
@override
bool get dontWriteConstraints => true;
@override
@ -749,8 +747,8 @@ class GroupCountData extends DataClass {
id: serializer.fromJson<int>(json['id']),
name: serializer.fromJson<String>(json['name']),
birthday: serializer.fromJson<DateTime?>(json['birthday']),
nextUser: serializer.fromJson<int?>(json['nextUser']),
groupCount: serializer.fromJson<int>(json['groupCount']),
nextUser: serializer.fromJson<int?>(json['next_user']),
groupCount: serializer.fromJson<int>(json['group_count']),
);
}
@override
@ -760,8 +758,8 @@ class GroupCountData extends DataClass {
'id': serializer.toJson<int>(id),
'name': serializer.toJson<String>(name),
'birthday': serializer.toJson<DateTime?>(birthday),
'nextUser': serializer.toJson<int?>(nextUser),
'groupCount': serializer.toJson<int>(groupCount),
'next_user': serializer.toJson<int?>(nextUser),
'group_count': serializer.toJson<int>(groupCount),
};
}
@ -818,7 +816,7 @@ class GroupCount extends ViewInfo<GroupCount, GroupCountData>
String get entityName => 'group_count';
@override
String get createViewStmt =>
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users';
'CREATE VIEW group_count AS SELECT\n users.*,\n (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count\n FROM users;';
@override
GroupCount get asDslTable => this;
@override
@ -868,14 +866,14 @@ abstract class _$Database extends GeneratedDatabase {
_$Database.connect(DatabaseConnection c) : super.connect(c);
late final $UsersTable users = $UsersTable(this);
late final Groups groups = Groups(this);
late final GroupCount groupCount = GroupCount(this);
late final Notes notes = Notes(this);
late final GroupCount groupCount = GroupCount(this);
@override
Iterable<TableInfo<Table, dynamic>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities =>
[users, groups, groupCount, notes];
[users, groups, notes, groupCount];
@override
DriftDatabaseOptions get options =>
const DriftDatabaseOptions(storeDateTimeAsText: true);

View File

@ -2,10 +2,6 @@
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class Entrie extends DataClass implements Insertable<Entrie> {
final int id;
@ -172,6 +168,8 @@ class Entries extends Table with TableInfo<Entries, Entrie> {
return Entries(attachedDatabase, alias);
}
@override
List<String> get customConstraints => const [];
@override
bool get dontWriteConstraints => true;
}

View File

@ -1,12 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class User extends DataClass implements Insertable<User> {
final int id;
final String name;
@ -172,6 +166,8 @@ class Users extends Table with TableInfo<Users, User> {
return Users(attachedDatabase, alias);
}
@override
List<String> get customConstraints => const [];
@override
bool get dontWriteConstraints => true;
}

View File

@ -1,4 +1,4 @@
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
name TEXT NOT NULL
);

View File

@ -2,10 +2,6 @@
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class KeyValue extends DataClass implements Insertable<KeyValue> {
final String key;

View File

@ -2,10 +2,6 @@
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class User extends DataClass implements Insertable<User> {
/// The user id
@ -34,7 +30,7 @@ class User extends DataClass implements Insertable<User> {
map['profile_picture'] = Variable<Uint8List>(profilePicture);
}
if (!nullToAbsent || preferences != null) {
final converter = $UsersTable.$converter0;
final converter = $UsersTable.$converterpreferences;
map['preferences'] = Variable<String>(converter.toSql(preferences));
}
return map;
@ -190,7 +186,7 @@ class UsersCompanion extends UpdateCompanion<User> {
map['profile_picture'] = Variable<Uint8List>(profilePicture.value);
}
if (preferences.present) {
final converter = $UsersTable.$converter0;
final converter = $UsersTable.$converterpreferences;
map['preferences'] = Variable<String>(converter.toSql(preferences.value));
}
return map;
@ -243,7 +239,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
late final GeneratedColumnWithTypeConverter<Preferences?, String>
preferences = GeneratedColumn<String>('preferences', aliasedName, true,
type: DriftSqlType.string, requiredDuringInsert: false)
.withConverter<Preferences?>($UsersTable.$converter0);
.withConverter<Preferences?>($UsersTable.$converterpreferences);
@override
List<GeneratedColumn> get $columns =>
[id, name, birthDate, profilePicture, preferences];
@ -295,7 +291,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
.read(DriftSqlType.dateTime, data['${effectivePrefix}birth_date'])!,
profilePicture: attachedDatabase.options.types
.read(DriftSqlType.blob, data['${effectivePrefix}profile_picture']),
preferences: $UsersTable.$converter0.fromSql(attachedDatabase
preferences: $UsersTable.$converterpreferences.fromSql(attachedDatabase
.options.types
.read(DriftSqlType.string, data['${effectivePrefix}preferences'])),
);
@ -306,7 +302,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
return $UsersTable(attachedDatabase, alias);
}
static TypeConverter<Preferences?, String?> $converter0 =
static TypeConverter<Preferences?, String?> $converterpreferences =
const PreferenceConverter();
}
@ -474,7 +470,7 @@ class $FriendshipsTable extends Friendships
'really_good_friends', aliasedName, false,
type: DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints: 'CHECK ("really_good_friends" IN (0, 1))',
defaultConstraints: 'CHECK (really_good_friends IN (0, 1))',
defaultValue: const Constant(false));
@override
List<GeneratedColumn> get $columns =>
@ -592,7 +588,7 @@ abstract class _$Database extends GeneratedDatabase {
],
readsFrom: {
users,
}).map((QueryRow row) => $UsersTable.$converter0
}).map((QueryRow row) => $UsersTable.$converterpreferences
.fromSql(row.readNullable<String>('preferences')));
}

View File

@ -2,10 +2,6 @@
part of 'saves_after_migration_regression_test.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class Foo extends DataClass implements Insertable<Foo> {
final int id;