Skip to content

Commit

Permalink
Add support for changing (insert, update, delete) lists (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitusortner authored Feb 11, 2019
1 parent 8beb1fa commit 1ec207e
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 55 deletions.
20 changes: 15 additions & 5 deletions floor_generator/lib/model/change_method.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,30 @@ class ChangeMethod {
return parameters.first;
}

Entity getEntity(LibraryReader library) {
bool get changesMultipleItems => isList(parameter.type);

ClassElement get flattenedParameterClass {
return _flattenedParameterType.element as ClassElement;
}

Entity getEntity(final LibraryReader library) {
final entityClass = _getEntities(library).firstWhere(
(entity) => entity.displayName == parameter.type.displayName);
(entity) => entity.displayName == _flattenedParameterType.displayName);

return Entity(entityClass);
}

bool changesEntity(LibraryReader library) {
bool changesEntity(final LibraryReader library) {
return _getEntities(library)
.map((clazz) => clazz.displayName)
.any((entity) => entity == parameter.type.displayName);
.any((entity) => entity == _flattenedParameterType.displayName);
}

DartType get _flattenedParameterType {
return changesMultipleItems ? flattenList(parameter.type) : parameter.type;
}

List<ClassElement> _getEntities(LibraryReader library) {
List<ClassElement> _getEntities(final LibraryReader library) {
return library.classes
.where((clazz) =>
!clazz.isAbstract && clazz.metadata.any(isEntityAnnotation))
Expand Down
10 changes: 10 additions & 0 deletions floor_generator/lib/model/entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:analyzer/dart/element/element.dart';
import 'package:floor_generator/misc/constants.dart';
import 'package:floor_generator/misc/type_utils.dart';
import 'package:floor_generator/model/column.dart';
import 'package:source_gen/source_gen.dart';

class Entity {
final ClassElement clazz;
Expand All @@ -26,4 +27,13 @@ class Entity {
List<Column> get columns {
return fields.map((field) => Column(field)).toList();
}

Column get primaryKeyColumn {
return columns.firstWhere(
(column) => column.isPrimaryKey,
orElse: throw InvalidGenerationSourceError(
'There is no primary key defined on the entity $name.',
element: clazz),
);
}
}
20 changes: 15 additions & 5 deletions floor_generator/lib/writer/delete_method_body_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,22 @@ class DeleteMethodBodyWriter implements Writer {

String _generateMethodBody() {
final entity = method.getEntity(library);
final primaryKeyColumn =
entity.columns.firstWhere((column) => column.isPrimaryKey);
final primaryKeyColumn = entity.primaryKeyColumn;
final methodHeadParameterName = method.parameter.name;

return '''
await database.rawDelete('DELETE FROM `${entity.name}` WHERE `${primaryKeyColumn.name}` = \${$methodHeadParameterName.${primaryKeyColumn.field.displayName}}');
''';
if (method.changesMultipleItems) {
return '''
final batch = database.batch();
for (final item in $methodHeadParameterName) {
batch.delete('${entity.name}', where: '${primaryKeyColumn.name} = ?', whereArgs: <int>[item.${primaryKeyColumn.field.displayName}]);
}
await batch.commit(noResult: true);
''';
} else {
return '''
final item = $methodHeadParameterName;
await database.delete('${entity.name}', where: '${primaryKeyColumn.name} = ?', whereArgs: <int>[item.${primaryKeyColumn.field.displayName}]);
''';
}
}
}
47 changes: 27 additions & 20 deletions floor_generator/lib/writer/insert_method_body_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,49 @@ class InsertMethodBodyWriter implements Writer {
}

String _generateMethodBody() {
final parameter = method.parameter;
final methodHeadParameterName = parameter.displayName;
final methodHeadParameterName = method.parameter.displayName;

final columnNames =
method.getEntity(library).columns.map((column) => column.name).toList();
final constructorParameters =
(parameter.type.element as ClassElement).constructors.first.parameters;
method.flattenedParameterClass.constructors.first.parameters;

final keyValueList = <String>[];

for (var i = 0; i < constructorParameters.length; i++) {
final valueMapping =
_getValueMapping(constructorParameters[i], methodHeadParameterName);
final valueMapping = _getValueMapping(constructorParameters[i]);
keyValueList.add("'${columnNames[i]}': $valueMapping");
}

final entityName = method.getEntity(library).name;

return '''
final values = <String, dynamic>{
${keyValueList.join(', ')}
};
await database.insert('$entityName', values);
''';
if (method.changesMultipleItems) {
return '''
final batch = database.batch();
for (final item in $methodHeadParameterName) {
final values = <String, dynamic>{
${keyValueList.join(', ')}
};
batch.insert('$entityName', values);
}
await batch.commit(noResult: true);
''';
} else {
return '''
final item = $methodHeadParameterName;
final values = <String, dynamic>{
${keyValueList.join(', ')}
};
await database.insert('$entityName', values);
''';
}
}

String _getValueMapping(
final ParameterElement parameter,
final String methodParameterName,
) {
String _getValueMapping(final ParameterElement parameter) {
final parameterName = parameter.displayName;

if (isBool(parameter.type)) {
return '$methodParameterName.$parameterName ? 1 : 0';
} else {
return '$methodParameterName.$parameterName';
}
return isBool(parameter.type)
? 'item.$parameterName ? 1 : 0'
: 'item.$parameterName';
}
}
54 changes: 31 additions & 23 deletions floor_generator/lib/writer/update_method_body_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,50 @@ class UpdateMethodBodyWriter implements Writer {
}

String _generateMethodBody() {
final parameter = method.parameter;
final methodHeadParameterName = parameter.displayName;
final methodHeadParameterName = method.parameter.displayName;
final entity = method.getEntity(library);

final columnNames =
method.getEntity(library).columns.map((column) => column.name).toList();
final columnNames = entity.columns.map((column) => column.name).toList();
final constructorParameters =
(parameter.type.element as ClassElement).constructors.first.parameters;
method.flattenedParameterClass.constructors.first.parameters;

final keyValueList = <String>[];

for (var i = 0; i < constructorParameters.length; i++) {
final valueMapping =
_getValueMapping(constructorParameters[i], methodHeadParameterName);
final valueMapping = _getValueMapping(constructorParameters[i]);
keyValueList.add("'${columnNames[i]}': $valueMapping");
}

final entityName = method.getEntity(library).name;
final entityName = entity.name;

return '''
final values = <String, dynamic>{
${keyValueList.join(', ')}
};
await database.update('$entityName', values);
''';
if (method.changesMultipleItems) {
final primaryKeyColumn = entity.primaryKeyColumn;
return '''
final batch = database.batch();
for (final item in $methodHeadParameterName) {
final values = <String, dynamic>{
${keyValueList.join(', ')}
};
batch.update('$entityName', values, where: '${primaryKeyColumn.name} = ?', whereArgs: <int>[item.${primaryKeyColumn.field.displayName}]);
}
await batch.commit(noResult: true);
''';
} else {
return '''
final item = $methodHeadParameterName;
final values = <String, dynamic>{
${keyValueList.join(', ')}
};
await database.update('$entityName', values);
''';
}
}

String _getValueMapping(
final ParameterElement parameter,
final String methodParameterName,
) {
String _getValueMapping(final ParameterElement parameter) {
final parameterName = parameter.displayName;

if (isBool(parameter.type)) {
return '$methodParameterName.$parameterName ? 1 : 0';
} else {
return '$methodParameterName.$parameterName';
}
return isBool(parameter.type)
? 'item.$parameterName ? 1 : 0'
: 'item.$parameterName';
}
}
59 changes: 58 additions & 1 deletion floor_test/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
A2629738704A716927C5F09D /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CCCAC69DC9C43F0F71431B5 /* libPods-Runner.a */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand All @@ -40,6 +41,7 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1CCCAC69DC9C43F0F71431B5 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
Expand All @@ -64,12 +66,20 @@
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
A2629738704A716927C5F09D /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
42D73AD98511CA1C5A98B953 /* Pods */ = {
isa = PBXGroup;
children = (
);
name = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
Expand All @@ -90,7 +100,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
42D73AD98511CA1C5A98B953 /* Pods */,
B800448E65B75CEB46CA6093 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -126,19 +137,29 @@
name = "Supporting Files";
sourceTree = "<group>";
};
B800448E65B75CEB46CA6093 /* Frameworks */ = {
isa = PBXGroup;
children = (
1CCCAC69DC9C43F0F71431B5 /* libPods-Runner.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
2598185974159AE7683BDFDF /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
0F1F0B1C04A35F7521F2EE09 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
Expand Down Expand Up @@ -198,6 +219,42 @@
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
0F1F0B1C04A35F7521F2EE09 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
2598185974159AE7683BDFDF /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down
3 changes: 3 additions & 0 deletions floor_test/ios/Runner.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
</dict>
</plist>
9 changes: 9 additions & 0 deletions floor_test/test/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ abstract class TestDatabase extends FloorDatabase {
@insert
Future<void> insertPerson(Person person);

@insert
Future<void> insertPersons(List<Person> persons);

@update
Future<void> updatePerson(Person person);

@update
Future<void> updatePersons(List<Person> persons);

@delete
Future<void> deletePerson(Person person);

@delete
Future<void> deletePersons(List<Person> person);
}

@Entity(tableName: 'person')
Expand Down
Loading

0 comments on commit 1ec207e

Please sign in to comment.