Respect tables in the body of a CREATE TRIGGER statement

This commit is contained in:
Simon Binder 2020-01-03 15:38:13 +01:00
parent 4c68b31564
commit 3ee05bf647
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
5 changed files with 164 additions and 143 deletions

View File

@ -174,139 +174,6 @@ class ConfigTable extends Table with TableInfo<ConfigTable, Config> {
bool get dontWriteConstraints => true;
}
class NoId extends DataClass implements Insertable<NoId> {
final Uint8List payload;
NoId({@required this.payload});
factory NoId.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final uint8ListType = db.typeSystem.forDartType<Uint8List>();
return NoId(
payload: uint8ListType
.mapFromDatabaseResponse(data['${effectivePrefix}payload']),
);
}
factory NoId.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return NoId(
payload: serializer.fromJson<Uint8List>(json['payload']),
);
}
factory NoId.fromJsonString(String encodedJson,
{ValueSerializer serializer}) =>
NoId.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson({ValueSerializer serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'payload': serializer.toJson<Uint8List>(payload),
};
}
@override
NoIdsCompanion createCompanion(bool nullToAbsent) {
return NoIdsCompanion(
payload: payload == null && nullToAbsent
? const Value.absent()
: Value(payload),
);
}
NoId copyWith({Uint8List payload}) => NoId(
payload: payload ?? this.payload,
);
@override
String toString() {
return (StringBuffer('NoId(')..write('payload: $payload')..write(')'))
.toString();
}
@override
int get hashCode => $mrjf(payload.hashCode);
@override
bool operator ==(dynamic other) =>
identical(this, other) ||
(other is NoId && other.payload == this.payload);
}
class NoIdsCompanion extends UpdateCompanion<NoId> {
final Value<Uint8List> payload;
const NoIdsCompanion({
this.payload = const Value.absent(),
});
NoIdsCompanion.insert({
@required Uint8List payload,
}) : payload = Value(payload);
NoIdsCompanion copyWith({Value<Uint8List> payload}) {
return NoIdsCompanion(
payload: payload ?? this.payload,
);
}
}
class NoIds extends Table with TableInfo<NoIds, NoId> {
final GeneratedDatabase _db;
final String _alias;
NoIds(this._db, [this._alias]);
final VerificationMeta _payloadMeta = const VerificationMeta('payload');
GeneratedBlobColumn _payload;
GeneratedBlobColumn get payload => _payload ??= _constructPayload();
GeneratedBlobColumn _constructPayload() {
return GeneratedBlobColumn('payload', $tableName, false,
$customConstraints: 'NOT NULL PRIMARY KEY');
}
@override
List<GeneratedColumn> get $columns => [payload];
@override
NoIds get asDslTable => this;
@override
String get $tableName => _alias ?? 'no_ids';
@override
final String actualTableName = 'no_ids';
@override
VerificationContext validateIntegrity(NoIdsCompanion d,
{bool isInserting = false}) {
final context = VerificationContext();
if (d.payload.present) {
context.handle(_payloadMeta,
payload.isAcceptableValue(d.payload.value, _payloadMeta));
} else if (isInserting) {
context.missing(_payloadMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {payload};
@override
NoId map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return NoId.fromData(data, _db, prefix: effectivePrefix);
}
@override
Map<String, Variable> entityToSql(NoIdsCompanion d) {
final map = <String, Variable>{};
if (d.payload.present) {
map['payload'] = Variable<Uint8List, BlobType>(d.payload.value);
}
return map;
}
@override
NoIds createAlias(String alias) {
return NoIds(_db, alias);
}
@override
bool get withoutRowId => true;
@override
bool get dontWriteConstraints => true;
}
class WithDefault extends DataClass implements Insertable<WithDefault> {
final String a;
final int b;
@ -463,6 +330,139 @@ class WithDefaults extends Table with TableInfo<WithDefaults, WithDefault> {
bool get dontWriteConstraints => true;
}
class NoId extends DataClass implements Insertable<NoId> {
final Uint8List payload;
NoId({@required this.payload});
factory NoId.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final uint8ListType = db.typeSystem.forDartType<Uint8List>();
return NoId(
payload: uint8ListType
.mapFromDatabaseResponse(data['${effectivePrefix}payload']),
);
}
factory NoId.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return NoId(
payload: serializer.fromJson<Uint8List>(json['payload']),
);
}
factory NoId.fromJsonString(String encodedJson,
{ValueSerializer serializer}) =>
NoId.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson({ValueSerializer serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'payload': serializer.toJson<Uint8List>(payload),
};
}
@override
NoIdsCompanion createCompanion(bool nullToAbsent) {
return NoIdsCompanion(
payload: payload == null && nullToAbsent
? const Value.absent()
: Value(payload),
);
}
NoId copyWith({Uint8List payload}) => NoId(
payload: payload ?? this.payload,
);
@override
String toString() {
return (StringBuffer('NoId(')..write('payload: $payload')..write(')'))
.toString();
}
@override
int get hashCode => $mrjf(payload.hashCode);
@override
bool operator ==(dynamic other) =>
identical(this, other) ||
(other is NoId && other.payload == this.payload);
}
class NoIdsCompanion extends UpdateCompanion<NoId> {
final Value<Uint8List> payload;
const NoIdsCompanion({
this.payload = const Value.absent(),
});
NoIdsCompanion.insert({
@required Uint8List payload,
}) : payload = Value(payload);
NoIdsCompanion copyWith({Value<Uint8List> payload}) {
return NoIdsCompanion(
payload: payload ?? this.payload,
);
}
}
class NoIds extends Table with TableInfo<NoIds, NoId> {
final GeneratedDatabase _db;
final String _alias;
NoIds(this._db, [this._alias]);
final VerificationMeta _payloadMeta = const VerificationMeta('payload');
GeneratedBlobColumn _payload;
GeneratedBlobColumn get payload => _payload ??= _constructPayload();
GeneratedBlobColumn _constructPayload() {
return GeneratedBlobColumn('payload', $tableName, false,
$customConstraints: 'NOT NULL PRIMARY KEY');
}
@override
List<GeneratedColumn> get $columns => [payload];
@override
NoIds get asDslTable => this;
@override
String get $tableName => _alias ?? 'no_ids';
@override
final String actualTableName = 'no_ids';
@override
VerificationContext validateIntegrity(NoIdsCompanion d,
{bool isInserting = false}) {
final context = VerificationContext();
if (d.payload.present) {
context.handle(_payloadMeta,
payload.isAcceptableValue(d.payload.value, _payloadMeta));
} else if (isInserting) {
context.missing(_payloadMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {payload};
@override
NoId map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return NoId.fromData(data, _db, prefix: effectivePrefix);
}
@override
Map<String, Variable> entityToSql(NoIdsCompanion d) {
final map = <String, Variable>{};
if (d.payload.present) {
map['payload'] = Variable<Uint8List, BlobType>(d.payload.value);
}
return map;
}
@override
NoIds createAlias(String alias) {
return NoIds(_db, alias);
}
@override
bool get withoutRowId => true;
@override
bool get dontWriteConstraints => true;
}
class WithConstraint extends DataClass implements Insertable<WithConstraint> {
final String a;
final int b;
@ -1089,10 +1089,10 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
_$CustomTablesDb.connect(DatabaseConnection c) : super.connect(c);
ConfigTable _config;
ConfigTable get config => _config ??= ConfigTable(this);
NoIds _noIds;
NoIds get noIds => _noIds ??= NoIds(this);
WithDefaults _withDefaults;
WithDefaults get withDefaults => _withDefaults ??= WithDefaults(this);
NoIds _noIds;
NoIds get noIds => _noIds ??= NoIds(this);
WithConstraints _withConstraints;
WithConstraints get withConstraints =>
_withConstraints ??= WithConstraints(this);
@ -1214,11 +1214,11 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
@override
List<DatabaseSchemaEntity> get allSchemaEntities => [
config,
withDefaults,
Trigger(
'CREATE TRIGGER my_trigger AFTER INSERT ON config BEGIN\n INSERT INTO with_defaults VALUES (new.config_key, LENGTH(new.config_value));\nEND;',
'my_trigger'),
noIds,
withDefaults,
withConstraints,
mytable,
email

View File

@ -3,6 +3,7 @@
- Support explicit type arguments for queries in moor files. In
`foo(:bar AS TEXT, :baz AS INT): SELECT :bar, :baz;`, the column type can now be inferred.
Previously, the query would fail because of an unknown type.
- Support `CREATE TRIGGER` statements in moor files
## 2.2.0

View File

@ -2,6 +2,7 @@ import 'package:moor_generator/moor_generator.dart';
import 'package:moor_generator/src/analyzer/errors.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/sql_queries/affected_tables_visitor.dart';
import 'package:moor_generator/src/analyzer/sql_queries/lints/linter.dart';
import 'package:moor_generator/src/analyzer/sql_queries/query_analyzer.dart';
import 'package:sqlparser/sqlparser.dart';
@ -33,6 +34,7 @@ class EntityHandler extends BaseAnalyzer {
for (final trigger in file.declaredEntities.whereType<MoorTrigger>()) {
trigger.on = null;
trigger.bodyReferences.clear();
final declaration = trigger.declaration as MoorTriggerDeclaration;
final node = declaration.node;
@ -46,6 +48,12 @@ class EntityHandler extends BaseAnalyzer {
final linter = Linter(context, mapper);
linter.reportLints();
reportLints(linter.lints, name: trigger.displayName);
// find additional tables that might be referenced in the body
final tablesFinder = ReferencedTablesVisitor();
node.action.acceptWithoutArg(tablesFinder);
final tablesFromBody = tablesFinder.foundTables.map(mapper.tableToMoor);
trigger.bodyReferences.addAll(tablesFromBody);
}
}

View File

@ -14,6 +14,7 @@ class MoorTrigger implements MoorSchemaEntity {
///
/// This field can be null in case the table wasn't resolved.
MoorTable on;
List<MoorTable> bodyReferences = [];
String _create;
@ -28,7 +29,7 @@ class MoorTrigger implements MoorSchemaEntity {
}
@override
Iterable<MoorSchemaEntity> get references => [on];
Iterable<MoorSchemaEntity> get references => {on, ...bodyReferences};
/// The `CREATE TRIGGER` statement that can be used to create this trigger.
String get create {

View File

@ -38,7 +38,7 @@ CREATE TABLE friendships (
table.references,
[
const TypeMatcher<MoorTable>()
.having((table) => table.displayName, 'displayName', 'users')
.having((table) => table.displayName, 'displayName', 'users'),
],
);
});
@ -48,8 +48,16 @@ CREATE TABLE friendships (
'foo|lib/a.moor': '''
import 'b.moor';
CREATE TABLE friendships (
user_a INTEGER REFERENCES users (id),
user_b INTEGER REFERENCES users (id),
PRIMARY KEY(user_a, user_b),
CHECK (user_a != user_b)
);
CREATE TRIGGER my_trigger AFTER DELETE ON users BEGIN
SELECT * FROM users;
DELETE FROM friendships WHERE user_a = old.id OR user_b = old.id;
END;
''',
...definitions,
@ -58,13 +66,16 @@ END;
final file = await state.analyze('package:foo/a.moor');
expect(file.errors.errors, isEmpty);
final trigger = file.currentResult.declaredEntities.single;
final trigger =
file.currentResult.declaredEntities.whereType<MoorTrigger>().single;
expect(
trigger.references,
[
{
const TypeMatcher<MoorTable>().having(
(table) => table.displayName, 'displayName', 'friendships'),
const TypeMatcher<MoorTable>()
.having((table) => table.displayName, 'displayName', 'users')
],
.having((table) => table.displayName, 'displayName', 'users'),
},
);
});
});