Skip to content

Commit

Permalink
toSetLiteral wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mqus committed Apr 27, 2021
1 parent 02733df commit a47443c
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 14 deletions.
11 changes: 11 additions & 0 deletions floor_generator/lib/misc/extension/iterable_extension.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:collection';
import 'string_extension.dart';

extension IterableExtension<T> on Iterable<T> {
Iterable<T> sortedByDescending(Comparable Function(T element) selector) {
Expand All @@ -24,3 +25,13 @@ extension IterableExtension<T> on Iterable<T> {
}
}
}

extension StringIterableExtension on Iterable<String> {
String toSetLiteral({bool withConst = true}) {
final content = distinctBy((element) => element)
.map<String>((e) => e.toLiteral())
.join(', ');
final cnst = withConst ? 'const ' : '';
return '$cnst{$content}';
}
}
20 changes: 15 additions & 5 deletions floor_generator/lib/writer/dao_writer.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:code_builder/code_builder.dart';
import 'package:floor_generator/misc/extension/string_extension.dart';
import 'package:floor_generator/misc/extension/iterable_extension.dart';
import 'package:floor_generator/value_object/dao.dart';
import 'package:floor_generator/value_object/deletion_method.dart';
import 'package:floor_generator/value_object/entity.dart';
Expand Down Expand Up @@ -86,7 +87,8 @@ class DaoWriter extends Writer {
// create a special change handler which decides case-by-case:
// if the insertion happens with onConflict:replace, consider the insertion like a deletion.
// if it will not replace (e.g. abort or ignore), only output the single entity at most.
final changeHandler = _generateChangeHandler(foreignKeyRelationships.getAffectedByDelete(entity), entity);
final changeHandler = _generateChangeHandler(
foreignKeyRelationships.getAffectedByDelete(entity), entity);

constructorBuilder
..initializers.add(Code(
Expand Down Expand Up @@ -223,18 +225,26 @@ class DaoWriter extends Writer {
///
/// The affected set can be generated with [getAffectedByUpdateEntities]
/// and [getAffectedByDeleteEntities]
String _generateChangeHandler(final Set<Entity> affected ,[Entity? insertionEntity]) {
String _generateChangeHandler(final Set<Entity> affected,
[Entity? insertionEntity]) {
final toNotify = streamEntities.intersection(affected);

if (toNotify.isNotEmpty || dbHasViewStreams) {
// if there are streaming views, create a new handler even if the set
// is empty. This will only trigger a reload of the views.
final set = 'const {${toNotify.map((e) => e.name.toLiteral()).join(', ')}}';
final set = toNotify.map((e) => e.name).toSetLiteral();
if (insertionEntity == null) {
return ', () => changeListener.add($set)';
} else {
final singleSet = 'const {${streamEntities.contains(insertionEntity)?insertionEntity.name.toLiteral():''}}';
return ', (isReplace) => changeListener.add(isReplace?$set:$singleSet)';
final singleSet = (streamEntities.contains(insertionEntity)
? {insertionEntity.name}
: <String>{})
.toSetLiteral();
if (singleSet == set) {
return ', (isReplace) => changeListener.add($set)';
} else {
return ', (isReplace) => changeListener.add(isReplace?$set:$singleSet)';
}
}
} else {
// do not generate a Handler if the listener doesn't have to be updated
Expand Down
25 changes: 25 additions & 0 deletions floor_generator/test/misc/extension/iterable_extension_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,31 @@ void main() {
expect(actual, equals([_Box(1), _Box(0), _Box(2)]));
});
});

group('toSetLiteral', () {
test('empty Set from empty set', () {
expect(<String>{}.toSetLiteral(), equals('const {}'));
});

test('empty Set from empty list', () {
expect(<String>[].toSetLiteral(), equals('const {}'));
});

test('empty Set from empty set without const', () {
expect(<String>{}.toSetLiteral(withConst: false), equals('{}'));
});

test('set with elements', () {
expect(<String>{'that', 'escaped \'String\''}.toSetLiteral(),
equals("const {'that', 'escaped \'String\''}"));
});

test('list with duplicate elements only shows distinct elements', () {
expect(
<String>['that', 'escaped \'String\'', 'that', 'that'].toSetLiteral(),
equals("const {'that', 'escaped \'String\''}"));
});
});
}

class _Box {
Expand Down
90 changes: 81 additions & 9 deletions floor_generator/test/writer/dao_writer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:floor_generator/processor/entity_processor.dart';
import 'package:floor_generator/processor/view_processor.dart';
import 'package:floor_generator/value_object/dao.dart';
import 'package:floor_generator/value_object/entity.dart';
import 'package:floor_generator/value_object/foreign_key.dart';
import 'package:floor_generator/value_object/primary_key.dart';
import 'package:floor_generator/writer/dao_writer.dart';
import 'package:source_gen/source_gen.dart';
Expand Down Expand Up @@ -129,7 +130,7 @@ void main() {
'Person',
(Person item) =>
<String, Object?>{'id': item.id, 'name': item.name},
changeListener),
(isReplace) => changeListener.add(const {'Person'})),
_personUpdateAdapter = UpdateAdapter(
database,
'Person',
Expand Down Expand Up @@ -180,6 +181,83 @@ void main() {
'''));
});

test('create DAO stream query with onconflict:replace insert', () async {
final dao = await _createDao('''
@dao
abstract class PersonDao {
@Query('SELECT * FROM person')
Stream<List<Person>> findAllPersonsAsStream();
@Insert(onConflict: OnConflictStrategy.replace)
Future<void> insertPerson(Person person);
@update
Future<void> updatePerson(Person person);
@delete
Future<void> deletePerson(Person person);
}
''');

final streamEntities = {
...dao.streamEntities,
// add a simulated entity which should be affected if a Person is replaced
Entity(
FakeClassElement(),
'Dog',
[],
PrimaryKey([], false),
[
ForeignKey(
'Person',
['id'],
['owner_id'],
annotations.ForeignKeyAction.noAction,
annotations.ForeignKeyAction.setDefault)
],
[],
false,
'',
'',
null)
};

final actual = DaoWriter(dao, streamEntities, dao.streamViews.isNotEmpty,
emptyForeignKeyMap())
.write();

expect(actual, equalsDart(r'''
class _$PersonDao extends PersonDao {
_$PersonDao(this.database, this.changeListener)
: _queryAdapter = QueryAdapter(database, changeListener),
_personInsertionAdapter = InsertionAdapter(
database,
'Person',
(Person item) =>
<String, Object?>{'id': item.id, 'name': item.name},
(isReplace) => changeListener.add(isReplace? const {'Person','Dog'}: const {'Person'}));
final sqflite.DatabaseExecutor database;
final StreamController<Set<String>> changeListener;
final QueryAdapter _queryAdapter;
final InsertionAdapter<Person> _personInsertionAdapter;
@override
Stream<List<Person>> findAllPersonsAsStream() {
return _queryAdapter.queryListStream('SELECT * FROM person', mapper: (Map<String, Object?> row) => Person(row['id'] as int, row['name'] as String), queryableName: 'Person', isView: false);
}
@override
Future<void> insertPerson(Person person) async {
await _personInsertionAdapter.insert(person, OnConflictStrategy.abort);
}
}
'''));
});

test('create DAO aware of other entity stream query', () async {
final dao = await _createDao('''
@dao
Expand Down Expand Up @@ -207,7 +285,7 @@ void main() {
'Person',
(Person item) =>
<String, Object?>{'id': item.id, 'name': item.name},
changeListener),
(isReplace) => changeListener.add(const {'Person'})),
_personUpdateAdapter = UpdateAdapter(
database,
'Person',
Expand Down Expand Up @@ -336,12 +414,6 @@ void main() {
abstract class PersonDao {
@insert
Future<void> insertPerson(Person person);
@update
Future<void> updatePerson(Person person);
@delete
Future<void> deletePerson(Person person);
}
''');
// simulate DB is aware of no streamed entity but at least a single View
Expand All @@ -355,7 +427,7 @@ void main() {
'Person',
(Person item) =>
<String, Object?>{'id': item.id, 'name': item.name},
changeListener),
(isReplace) => changeListener.add(const {})),
_personUpdateAdapter = UpdateAdapter(
database,
'Person',
Expand Down

0 comments on commit a47443c

Please sign in to comment.