Skip to content

Commit

Permalink
Generate CREATE TABLE statements in models instead of writer (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitusortner authored Feb 27, 2019
1 parent 85566fa commit 184241d
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 196 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ Future<Person> findPersonByIdAndName(int id, String name);
@Query('SELECT * FROM Person')
Future<List<Person>> findAllPersons(); // select multiple items

@Query('DELETE FROM person')
@Query('DELETE FROM Person')
Future<void> deleteAllPersons(); // query without returning an entity
````

Expand Down
10 changes: 8 additions & 2 deletions floor/lib/src/annotations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,24 @@ class ForeignKey {
final Type entity;

/// [ForeignKeyAction]
/// Action to take when the parent [Entity] is updated from the database.
///
/// By default, [ForeignKeyAction.NO_ACTION] is used.
final int onUpdate;

/// [ForeignKeyAction]
/// Action to take when the parent [Entity] is deleted from the database.
///
/// By default, [ForeignKeyAction.NO_ACTION] is used.
final int onDelete;

/// Declares a foreign key on another [Entity].
const ForeignKey({
@required this.childColumns,
@required this.parentColumns,
@required this.entity,
this.onUpdate,
this.onDelete,
this.onUpdate = ForeignKeyAction.NO_ACTION,
this.onDelete = ForeignKeyAction.NO_ACTION,
});
}

Expand Down
49 changes: 33 additions & 16 deletions floor_generator/lib/model/column.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,26 @@ class Column {
field.displayName;
}

bool get isNullable {
bool get isPrimaryKey => field.metadata.any(isPrimaryKeyAnnotation);

/// The database column definition.
String get definition {
final columnSpecification = StringBuffer();

if (isPrimaryKey) {
return false;
columnSpecification.write(' PRIMARY KEY');
}
if (!_hasColumnInfoAnnotation) {
return true; // all Dart fields are nullable by default
if (_autoGenerate) {
columnSpecification.write(' AUTOINCREMENT');
}
if (!_isNullable) {
columnSpecification.write(' NOT NULL');
}
return field.metadata
.firstWhere(isColumnInfoAnnotation)
.computeConstantValue()
.getField(AnnotationField.COLUMN_INFO_NULLABLE)
.toBoolValue() ??
true;
}

bool get _hasColumnInfoAnnotation {
return field.metadata.any(isColumnInfoAnnotation);
return '`$name` $_type$columnSpecification';
}

String get type {
String get _type {
final type = field.type;
if (isInt(type)) {
return SqlType.INTEGER;
Expand All @@ -57,9 +57,11 @@ class Column {
);
}

bool get isPrimaryKey => field.metadata.any(isPrimaryKeyAnnotation);
bool get _hasColumnInfoAnnotation {
return field.metadata.any(isColumnInfoAnnotation);
}

bool get autoGenerate {
bool get _autoGenerate {
if (!isPrimaryKey) {
return false;
}
Expand All @@ -70,4 +72,19 @@ class Column {
.toBoolValue() ??
false;
}

bool get _isNullable {
if (isPrimaryKey) {
return false;
}
if (!_hasColumnInfoAnnotation) {
return true; // all Dart fields are nullable by default
}
return field.metadata
.firstWhere(isColumnInfoAnnotation)
.computeConstantValue()
.getField(AnnotationField.COLUMN_INFO_NULLABLE)
.toBoolValue() ??
true;
}
}
26 changes: 20 additions & 6 deletions floor_generator/lib/model/entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,25 @@ class Entity {

List<ForeignKey> get foreignKeys {
return clazz.metadata
.firstWhere(isEntityAnnotation)
.computeConstantValue()
.getField(AnnotationField.ENTITY_FOREIGN_KEYS)
?.toListValue()
?.map((object) => ForeignKey(clazz, object))
?.toList();
.firstWhere(isEntityAnnotation)
.computeConstantValue()
.getField(AnnotationField.ENTITY_FOREIGN_KEYS)
?.toListValue()
?.map((object) => ForeignKey(clazz, object))
?.toList() ??
[];
}

String getCreateTableStatement(final LibraryReader library) {
final databaseDefinition =
columns.map((column) => column.definition).toList();

final foreignKeyDefinitions = foreignKeys
.map((foreignKey) => foreignKey.getDefinition(library))
.toList();

databaseDefinition.addAll(foreignKeyDefinitions);

return "'CREATE TABLE IF NOT EXISTS `$name` (${databaseDefinition.join(', ')})'";
}
}
71 changes: 52 additions & 19 deletions floor_generator/lib/model/foreign_key.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,18 @@ class ForeignKey {

ForeignKey(this.entityClass, this.object);

String getDefinition(final LibraryReader library) {
final onUpdateAction = _getAction(_onUpdate);
final onDeleteAction = _getAction(_onDelete);

return 'FOREIGN KEY (${_childColumns.join(', ')}) '
' REFERENCES `${_getParentName(library)}` (${_parentColumns.join(', ')})'
' ON UPDATE $onUpdateAction'
' ON DELETE $onDeleteAction';
}

/// Returns the parent column name referenced with this foreign key.
String getParentName(final LibraryReader library) {
String _getParentName(final LibraryReader library) {
final entityClassName =
object.getField(ForeignKeyField.ENTITY)?.toTypeValue()?.displayName ??
(throw InvalidGenerationSourceError(
Expand All @@ -34,31 +44,54 @@ class ForeignKey {
.name;
}

List<String> get childColumns {
return _getColumns(ForeignKeyField.CHILD_COLUMNS) ??
(throw InvalidGenerationSourceError(
'No child columns defined for foreign key',
element: entityClass,
));
List<String> get _childColumns {
final columns = _getColumns(ForeignKeyField.CHILD_COLUMNS);
if (columns.isEmpty) {
throw InvalidGenerationSourceError(
'No child columns defined for foreign key',
element: entityClass,
);
}
return columns;
}

List<String> get parentColumns {
return _getColumns(ForeignKeyField.PARENT_COLUMNS) ??
(throw InvalidGenerationSourceError(
'No parent columns defined for foreign key',
element: entityClass,
));
List<String> get _parentColumns {
final columns = _getColumns(ForeignKeyField.PARENT_COLUMNS);
if (columns.isEmpty) {
throw InvalidGenerationSourceError(
'No parent columns defined for foreign key',
element: entityClass,
);
}
return columns;
}

int get onUpdate => object.getField(ForeignKeyField.ON_UPDATE)?.toIntValue();
int get _onUpdate => object.getField(ForeignKeyField.ON_UPDATE)?.toIntValue();

int get onDelete => object.getField(ForeignKeyField.ON_DELETE)?.toIntValue();
int get _onDelete => object.getField(ForeignKeyField.ON_DELETE)?.toIntValue();

String _getAction(final int action) {
switch (action) {
case ForeignKeyAction.RESTRICT:
return 'RESTRICT';
case ForeignKeyAction.SET_NULL:
return 'SET_NULL';
case ForeignKeyAction.SET_DEFAULT:
return 'SET_DEFAULT';
case ForeignKeyAction.CASCADE:
return 'CASCADE';
case ForeignKeyAction.NO_ACTION:
default:
return 'NO_ACTION';
}
}

List<String> _getColumns(final String foreignKeyField) {
return object
.getField(foreignKeyField)
?.toListValue()
?.map((object) => object.toStringValue())
?.toList();
.getField(foreignKeyField)
?.toListValue()
?.map((object) => object.toStringValue())
?.toList() ??
[];
}
}
59 changes: 3 additions & 56 deletions floor_generator/lib/writer/database_writer.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:code_builder/code_builder.dart';
import 'package:floor_generator/misc/annotation_expression.dart';
import 'package:floor_generator/misc/constants.dart';
import 'package:floor_generator/misc/type_utils.dart';
import 'package:floor_generator/model/database.dart';
import 'package:floor_generator/model/delete_method.dart';
Expand Down Expand Up @@ -155,60 +154,8 @@ class DatabaseWriter implements Writer {
}

List<String> _generateCreateTableSqlStatements(final List<Entity> entities) {
return entities.map(_generateSql).toList();
}

String _generateSql(final Entity entity) {
final foreignKeys = _generateForeignKeys(entity) ?? '';

final columns = entity.columns.map((column) {
final primaryKey = column.isPrimaryKey ? ' PRIMARY KEY' : '';
final autoIncrement = column.autoGenerate ? ' AUTOINCREMENT' : '';
final nullable = column.isNullable ? '' : ' NOT NULL';

return '`${column.name}` ${column.type}$primaryKey$autoIncrement$nullable';
}).join(', ');

return "'CREATE TABLE IF NOT EXISTS `${entity.name}` ($columns$foreignKeys)'";
}

String _generateForeignKeys(final Entity entity) {
return entity.foreignKeys?.map((foreignKey) {
final childColumns = foreignKey.childColumns.join(', ');
final parentColumns = foreignKey.parentColumns.join(', ');
final parentName = foreignKey.getParentName(library);

final onUpdate = _getOnUpdateAction(foreignKey.onUpdate) ?? '';
final onDelete = _getOnDeleteAction(foreignKey.onDelete) ?? '';

return ', FOREIGN KEY ($childColumns) REFERENCES `$parentName` ($parentColumns)$onUpdate$onDelete';
})?.join();
}

String _getOnUpdateAction(final int action) {
final updateAction = _getAction(action);
return updateAction != null ? ' ON UPDATE $updateAction' : null;
}

String _getOnDeleteAction(final int action) {
final deleteAction = _getAction(action);
return deleteAction != null ? ' ON DELETE $deleteAction' : null;
}

String _getAction(final int action) {
switch (action) {
case ForeignKeyAction.NO_ACTION:
return 'NO_ACTION';
case ForeignKeyAction.RESTRICT:
return 'RESTRICT';
case ForeignKeyAction.SET_NULL:
return 'SET_NULL';
case ForeignKeyAction.SET_DEFAULT:
return 'SET_DEFAULT';
case ForeignKeyAction.CASCADE:
return 'CASCADE';
default:
return null;
}
return entities
.map((entity) => entity.getCreateTableStatement(library))
.toList();
}
}
Loading

0 comments on commit 184241d

Please sign in to comment.