mirror of https://github.com/AMT-Cheif/drift.git
Don't consider rowid aliases required (#445)
This commit is contained in:
parent
8d9b0874b9
commit
5b675a811b
|
@ -14,6 +14,8 @@
|
||||||
- __Breaking__: Remove the second type variable on `Expression` and subclasses.
|
- __Breaking__: Remove the second type variable on `Expression` and subclasses.
|
||||||
- __Breaking__: Remove `customSelectStream` from `QueryEngine`. The `customSelect`
|
- __Breaking__: Remove `customSelectStream` from `QueryEngine`. The `customSelect`
|
||||||
method now returns an `Selectable` (like `customSelectQuery`, which in turn has been deprecated).
|
method now returns an `Selectable` (like `customSelectQuery`, which in turn has been deprecated).
|
||||||
|
- __Breaking__: Columns that are aliases to sqlite's `rowid` column are now longer considered required
|
||||||
|
for inserts
|
||||||
- Experimentally support IndexedDB to store sqlite data on the web
|
- Experimentally support IndexedDB to store sqlite data on the web
|
||||||
- Moor will no longer wait for query stream listeners to receive a done event when closing a database
|
- Moor will no longer wait for query stream listeners to receive a done event when closing a database
|
||||||
or transaction.
|
or transaction.
|
||||||
|
|
|
@ -93,8 +93,9 @@ class _LintingVisitor extends RecursiveVisitor<void, void> {
|
||||||
|
|
||||||
// second, check that no required columns are left out
|
// second, check that no required columns are left out
|
||||||
final specifiedTable = linter.mapper.tableToMoor(e.table.resolved as Table);
|
final specifiedTable = linter.mapper.tableToMoor(e.table.resolved as Table);
|
||||||
final required =
|
final required = specifiedTable.columns
|
||||||
specifiedTable.columns.where((c) => c.requiredDuringInsert).toList();
|
.where(specifiedTable.isColumnRequiredForInsert)
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (required.isNotEmpty && e.source is DefaultValues) {
|
if (required.isNotEmpty && e.source is DefaultValues) {
|
||||||
linter.lints.add(AnalysisError(
|
linter.lints.add(AnalysisError(
|
||||||
|
|
|
@ -170,15 +170,6 @@ class MoorColumn implements HasDeclaration {
|
||||||
ColumnType.real: 'GeneratedRealColumn',
|
ColumnType.real: 'GeneratedRealColumn',
|
||||||
}[type];
|
}[type];
|
||||||
|
|
||||||
/// Whether this column is required for insert statements, meaning that a
|
|
||||||
/// non-absent value must be provided for an insert statement to be valid.
|
|
||||||
bool get requiredDuringInsert {
|
|
||||||
final hasDefault = defaultArgument != null || clientDefaultCode != null;
|
|
||||||
final aliasForPk = type == ColumnType.integer &&
|
|
||||||
features.any((f) => f is PrimaryKey || f is AutoIncrement);
|
|
||||||
return !nullable && !hasDefault && !aliasForPk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The class inside the moor library that represents the same sql type as
|
/// The class inside the moor library that represents the same sql type as
|
||||||
/// this column.
|
/// this column.
|
||||||
String get sqlTypeName => sqlTypes[type];
|
String get sqlTypeName => sqlTypes[type];
|
||||||
|
|
|
@ -69,8 +69,20 @@ class MoorTable implements MoorSchemaEntity {
|
||||||
/// The set of primary keys, if they have been explicitly defined by
|
/// The set of primary keys, if they have been explicitly defined by
|
||||||
/// overriding `primaryKey` in the table class. `null` if the primary key has
|
/// overriding `primaryKey` in the table class. `null` if the primary key has
|
||||||
/// not been defined that way.
|
/// not been defined that way.
|
||||||
|
///
|
||||||
|
/// For the full primary key, see [fullPrimaryKey].
|
||||||
final Set<MoorColumn> primaryKey;
|
final Set<MoorColumn> primaryKey;
|
||||||
|
|
||||||
|
/// The primary key for this table.
|
||||||
|
///
|
||||||
|
/// Unlikely [primaryKey], this method is not limited to the `primaryKey`
|
||||||
|
/// override in Dart table declarations.
|
||||||
|
Set<MoorColumn> get fullPrimaryKey {
|
||||||
|
if (primaryKey != null) return primaryKey;
|
||||||
|
|
||||||
|
return columns.where((c) => c.features.any((f) => f is PrimaryKey)).toSet();
|
||||||
|
}
|
||||||
|
|
||||||
/// When non-null, the generated table class will override the `withoutRowId`
|
/// When non-null, the generated table class will override the `withoutRowId`
|
||||||
/// getter on the table class with this value.
|
/// getter on the table class with this value.
|
||||||
final bool overrideWithoutRowId;
|
final bool overrideWithoutRowId;
|
||||||
|
@ -138,6 +150,30 @@ class MoorTable implements MoorSchemaEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines whether [column] would be required for inserts performed via
|
||||||
|
/// companions.
|
||||||
|
bool isColumnRequiredForInsert(MoorColumn column) {
|
||||||
|
assert(columns.contains(column));
|
||||||
|
|
||||||
|
if (column.defaultArgument != null ||
|
||||||
|
column.clientDefaultCode != null ||
|
||||||
|
column.nullable) {
|
||||||
|
// default value would be applied, so it's not required for inserts
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A column isn't required if it's an alias for the rowid, as explained
|
||||||
|
// at https://www.sqlite.org/lang_createtable.html#rowid
|
||||||
|
final isWithoutRowId = overrideWithoutRowId ?? false;
|
||||||
|
final fullPk = fullPrimaryKey;
|
||||||
|
final isAliasForRowId = !isWithoutRowId &&
|
||||||
|
column.type == ColumnType.integer &&
|
||||||
|
fullPk.length == 1 &&
|
||||||
|
fullPk.single == column;
|
||||||
|
|
||||||
|
return !isAliasForRowId;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get displayName {
|
String get displayName {
|
||||||
if (isFromSql) {
|
if (isFromSql) {
|
||||||
|
|
|
@ -235,7 +235,7 @@ class TableWriter {
|
||||||
'$getterName.isAcceptableValue(d.$getterName.value, $metaName));')
|
'$getterName.isAcceptableValue(d.$getterName.value, $metaName));')
|
||||||
..write('}');
|
..write('}');
|
||||||
|
|
||||||
if (column.requiredDuringInsert) {
|
if (table.isColumnRequiredForInsert(column)) {
|
||||||
_buffer
|
_buffer
|
||||||
..write(' else if (isInserting) {\n')
|
..write(' else if (isInserting) {\n')
|
||||||
..write('context.missing($metaName);\n')
|
..write('context.missing($metaName);\n')
|
||||||
|
|
|
@ -59,7 +59,7 @@ class UpdateCompanionWriter {
|
||||||
for (final column in table.columns) {
|
for (final column in table.columns) {
|
||||||
final param = column.dartGetterName;
|
final param = column.dartGetterName;
|
||||||
|
|
||||||
if (column.requiredDuringInsert) {
|
if (table.isColumnRequiredForInsert(column)) {
|
||||||
requiredColumns.add(column);
|
requiredColumns.add(column);
|
||||||
|
|
||||||
_buffer.write('@required ${column.dartTypeName} $param,');
|
_buffer.write('@required ${column.dartTypeName} $param,');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: moor_generator
|
name: moor_generator
|
||||||
description: Dev-dependency to generate table and dataclasses together with the moor package.
|
description: Dev-dependency to generate table and dataclasses together with the moor package.
|
||||||
version: 2.4.0
|
version: 3.0.0-dev
|
||||||
repository: https://github.com/simolus3/moor
|
repository: https://github.com/simolus3/moor
|
||||||
homepage: https://moor.simonbinder.eu/
|
homepage: https://moor.simonbinder.eu/
|
||||||
issue_tracker: https://github.com/simolus3/moor/issues
|
issue_tracker: https://github.com/simolus3/moor/issues
|
||||||
|
@ -22,7 +22,7 @@ dependencies:
|
||||||
cli_util: ^0.1.0
|
cli_util: ^0.1.0
|
||||||
|
|
||||||
# Moor-specific analysis
|
# Moor-specific analysis
|
||||||
moor: ^2.3.0
|
moor: ^3.0.0-dev
|
||||||
sqlparser: ^0.7.0
|
sqlparser: ^0.7.0
|
||||||
|
|
||||||
# Dart analysis
|
# Dart analysis
|
||||||
|
|
|
@ -65,6 +65,14 @@ void main() {
|
||||||
TextColumn get archivedBy => text()();
|
TextColumn get archivedBy => text()();
|
||||||
DateTimeColumn get archivedOn => dateTime()();
|
DateTimeColumn get archivedOn => dateTime()();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WithAliasForRowId extends Table {
|
||||||
|
IntColumn get id => integer()();
|
||||||
|
TextColumn get name => text()();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column> get primaryKey => {id};
|
||||||
|
}
|
||||||
'''
|
'''
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -175,6 +183,13 @@ void main() {
|
||||||
expect(table.columns.any((column) => column.hasAI), isFalse);
|
expect(table.columns.any((column) => column.hasAI), isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('recognizes aliases for rowid', () async {
|
||||||
|
final table = await parse('WithAliasForRowId');
|
||||||
|
final idColumn = table.columns.singleWhere((c) => c.name.name == 'id');
|
||||||
|
|
||||||
|
expect(table.isColumnRequiredForInsert(idColumn), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
group('inheritance', () {
|
group('inheritance', () {
|
||||||
test('from abstract classes or mixins', () async {
|
test('from abstract classes or mixins', () async {
|
||||||
final table = await parse('Foos');
|
final table = await parse('Foos');
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import 'package:build/build.dart';
|
import 'package:build/build.dart';
|
||||||
|
import 'package:moor_generator/src/analyzer/runner/results.dart';
|
||||||
import 'package:moor_generator/src/analyzer/runner/steps.dart';
|
import 'package:moor_generator/src/analyzer/runner/steps.dart';
|
||||||
import 'package:moor_generator/src/analyzer/session.dart';
|
import 'package:moor_generator/src/analyzer/session.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
import '../../utils/test_backend.dart';
|
import '../../utils/test_backend.dart';
|
||||||
|
import '../utils.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
const content = '''
|
const content = '''
|
||||||
|
@ -46,4 +48,34 @@ usersWithLongName: SELECT * FROM users WHERE LENGTH(name) > 25
|
||||||
|
|
||||||
backend.finish();
|
backend.finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('recognizes aliases to rowid', () async {
|
||||||
|
final state = TestState.withContent({
|
||||||
|
'foo|lib/a.moor': '''
|
||||||
|
CREATE TABLE users (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE users2 (
|
||||||
|
id INTEGER,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
'''
|
||||||
|
});
|
||||||
|
|
||||||
|
final result = await state.analyze('package:foo/a.moor');
|
||||||
|
final file = result.currentResult as ParsedMoorFile;
|
||||||
|
|
||||||
|
final users1 = file.declaredTables.singleWhere((t) => t.sqlName == 'users');
|
||||||
|
final users2 =
|
||||||
|
file.declaredTables.singleWhere((t) => t.sqlName == 'users2');
|
||||||
|
|
||||||
|
expect(users1.isColumnRequiredForInsert(users1.columns[0]), isFalse);
|
||||||
|
expect(users1.isColumnRequiredForInsert(users1.columns[1]), isTrue);
|
||||||
|
|
||||||
|
expect(users2.isColumnRequiredForInsert(users2.columns[0]), isFalse);
|
||||||
|
expect(users2.isColumnRequiredForInsert(users2.columns[1]), isTrue);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue