diff --git a/aqueduct/lib/src/cli/scripts/get_schema.dart b/aqueduct/lib/src/cli/scripts/get_schema.dart index 550f1cc99..fc6c76340 100644 --- a/aqueduct/lib/src/cli/scripts/get_schema.dart +++ b/aqueduct/lib/src/cli/scripts/get_schema.dart @@ -5,6 +5,8 @@ import 'package:aqueduct/src/cli/command.dart'; import 'package:aqueduct/src/cli/mixins/project.dart'; import 'package:isolate_executor/isolate_executor.dart'; +import 'script_utils.dart'; + class GetSchemaExecutable extends Executable> { GetSchemaExecutable(Map message) : super(message); @@ -20,17 +22,11 @@ class GetSchemaExecutable extends Executable> { return {"error": e.message}; } } - - static List importsForPackage(String packageName) => [ - "package:aqueduct/aqueduct.dart", - "package:$packageName/$packageName.dart", - "package:runtime/runtime.dart" - ]; } Future getProjectSchema(CLIProject project) async { final response = await IsolateExecutor.run(GetSchemaExecutable({}), - imports: GetSchemaExecutable.importsForPackage(project.libraryName), + imports: importsForPackage(project.libraryName), packageConfigURI: project.packageConfigUri, logHandler: project.displayProgress); diff --git a/aqueduct/lib/src/cli/scripts/migration_builder.dart b/aqueduct/lib/src/cli/scripts/migration_builder.dart index d7b6e64c2..ae9452eda 100644 --- a/aqueduct/lib/src/cli/scripts/migration_builder.dart +++ b/aqueduct/lib/src/cli/scripts/migration_builder.dart @@ -5,6 +5,8 @@ import 'package:aqueduct/src/cli/command.dart'; import 'package:aqueduct/src/cli/mixins/project.dart'; import 'package:isolate_executor/isolate_executor.dart'; +import 'script_utils.dart'; + class MigrationBuilderExecutable extends Executable> { MigrationBuilderExecutable(Map message) : inputSchema = @@ -39,12 +41,6 @@ class MigrationBuilderExecutable extends Executable> { return {"error": e.message}; } } - - static List importsForPackage(String packageName) => [ - "package:aqueduct/aqueduct.dart", - "package:$packageName/$packageName.dart", - "package:runtime/runtime.dart" - ]; } class MigrationBuilderResult { @@ -63,8 +59,7 @@ Future generateMigrationFileForProject( final resultMap = await IsolateExecutor.run( MigrationBuilderExecutable.input(initialSchema, inputVersion), packageConfigURI: project.packageConfigUri, - imports: - MigrationBuilderExecutable.importsForPackage(project.packageName), + imports: importsForPackage(project.packageName), logHandler: project.displayProgress); if (resultMap.containsKey("error")) { diff --git a/aqueduct/lib/src/cli/scripts/script_utils.dart b/aqueduct/lib/src/cli/scripts/script_utils.dart new file mode 100644 index 000000000..ff39cf78e --- /dev/null +++ b/aqueduct/lib/src/cli/scripts/script_utils.dart @@ -0,0 +1,5 @@ +List importsForPackage(String packageName) => [ + "package:aqueduct/aqueduct.dart", + "package:runtime/runtime.dart", + "package:$packageName/$packageName.dart" + ]; diff --git a/aqueduct/lib/src/db/managed/entity.dart b/aqueduct/lib/src/db/managed/entity.dart index bd5ca7fb0..c3cae8e85 100644 --- a/aqueduct/lib/src/db/managed/entity.dart +++ b/aqueduct/lib/src/db/managed/entity.dart @@ -184,25 +184,8 @@ class ManagedEntity implements APIComponentDocumenter { /// on this entity was selected. Returns that attribute. ManagedAttributeDescription identifyAttribute( T propertyIdentifier(U x)) { - final keyPaths = identifyProperties(propertyIdentifier); - if (keyPaths.length != 1) { - throw ArgumentError( - "Invalid property selector. Cannot access more than one property for this operation."); - } - - final firstKeyPath = keyPaths.first; - if (firstKeyPath.dynamicElements != null) { - throw ArgumentError( - "Invalid property selector. Cannot access subdocuments for this operation."); - } - - final elements = firstKeyPath.path; - if (elements.length > 1) { - throw ArgumentError( - "Invalid property selector. Cannot use relationships for this operation."); - } - - final propertyName = elements.first.name; + final propertyName = _getPropertyName(propertyIdentifier, + "Invalid property selector. Cannot use relationships for this operation."); var attribute = attributes[propertyName]; if (attribute == null) { if (relationships.containsKey(propertyName)) { @@ -227,25 +210,8 @@ class ManagedEntity implements APIComponentDocumenter { ManagedRelationshipDescription identifyRelationship( T propertyIdentifier(U x)) { - final keyPaths = identifyProperties(propertyIdentifier); - if (keyPaths.length != 1) { - throw ArgumentError( - "Invalid property selector. Cannot access more than one property for this operation."); - } - - final firstKeyPath = keyPaths.first; - if (firstKeyPath.dynamicElements != null) { - throw ArgumentError( - "Invalid property selector. Cannot access subdocuments for this operation."); - } - - final elements = firstKeyPath.path; - if (elements.length > 1) { - throw ArgumentError( - "Invalid property selector. Cannot identify a nested relationship for this operation."); - } - - final propertyName = elements.first.name; + final propertyName = _getPropertyName(propertyIdentifier, + "Invalid property selector. Cannot identify a nested relationship for this operation."); var desc = relationships[propertyName]; if (desc == null) { throw ArgumentError( @@ -339,6 +305,28 @@ class ManagedEntity implements APIComponentDocumenter { final obj = document(context); context.schema.register(name, obj, representation: instanceType); } + + String _getPropertyName( + T propertiesIdentifier(U x), String errorMessage) { + final keyPaths = identifyProperties(propertiesIdentifier); + if (keyPaths.length != 1) { + throw ArgumentError( + "Invalid property selector. Cannot access more than one property for this operation."); + } + + final firstKeyPath = keyPaths.first; + if (firstKeyPath.dynamicElements != null) { + throw ArgumentError( + "Invalid property selector. Cannot access subdocuments for this operation."); + } + + final elements = firstKeyPath.path; + if (elements.length > 1) { + throw ArgumentError(errorMessage); + } + + return elements.first.name; + } } abstract class ManagedEntityRuntime { diff --git a/aqueduct/lib/src/db/postgresql/postgresql_query.dart b/aqueduct/lib/src/db/postgresql/postgresql_query.dart index 842c4e1aa..7f26f285b 100644 --- a/aqueduct/lib/src/db/postgresql/postgresql_query.dart +++ b/aqueduct/lib/src/db/postgresql/postgresql_query.dart @@ -44,14 +44,8 @@ class PostgresQuery extends Object buffer.write("VALUES (${builder.sqlValuesToInsert}) "); } - if ((builder.returning?.length ?? 0) > 0) { - buffer.write("RETURNING ${builder.sqlColumnsToReturn}"); - } - - final results = await context.persistentStore - .executeQuery(buffer.toString(), builder.variables, timeoutInSeconds); - - return builder.instancesForRows(results as List>).first; + return _returningInstancesForRows(builder, buffer) + .then((value) => value.first); } @override @@ -70,14 +64,7 @@ class PostgresQuery extends Object throw canModifyAllInstancesError; } - if ((builder.returning?.length ?? 0) > 0) { - buffer.write("RETURNING ${builder.sqlColumnsToReturn}"); - } - - final results = await context.persistentStore - .executeQuery(buffer.toString(), builder.variables, timeoutInSeconds); - - return builder.instancesForRows(results as List>); + return _returningInstancesForRows(builder, buffer); } @override @@ -180,10 +167,7 @@ class PostgresQuery extends Object buffer.write("OFFSET $offset "); } - final results = await context.persistentStore - .executeQuery(buffer.toString(), builder.variables, timeoutInSeconds); - - return builder.instancesForRows(results as List>); + return _instancesForRows(builder, buffer); } void validatePageDescriptor() { @@ -200,6 +184,24 @@ class PostgresQuery extends Object } } + Future> _returningInstancesForRows( + PostgresQueryBuilder builder, StringBuffer buffer) async { + if ((builder.returning?.length ?? 0) > 0) { + buffer.write("RETURNING ${builder.sqlColumnsToReturn}"); + } + + return _instancesForRows(builder, buffer); + } + + Future> _instancesForRows( + PostgresQueryBuilder builder, StringBuffer buffer) async { + final results = await context.persistentStore + .executeQuery(buffer.toString(), builder.variables, timeoutInSeconds); + + return builder + .instancesForRows(results as List>); + } + static final StateError canModifyAllInstancesError = StateError( "Invalid Query. Query is either update or delete query with no WHERE clause. To confirm this query is correct, set 'canModifyAllInstances' to true."); } diff --git a/aqueduct/lib/src/db/schema/schema_builder.dart b/aqueduct/lib/src/db/schema/schema_builder.dart index ede48d3f3..4fa277b4b 100644 --- a/aqueduct/lib/src/db/schema/schema_builder.dart +++ b/aqueduct/lib/src/db/schema/schema_builder.dart @@ -95,10 +95,7 @@ class SchemaBuilder { /// Validates and deletes a table in [schema]. void deleteTable(String tableName) { - var table = schema.tableForName(tableName); - if (table == null) { - throw SchemaException("Table $tableName does not exist."); - } + var table = _getTable(tableName); schema.removeTable(table); @@ -111,12 +108,9 @@ class SchemaBuilder { /// Alters a table in [schema]. void alterTable(String tableName, void modify(SchemaTable targetTable)) { - var existingTable = schema.tableForName(tableName); - if (existingTable == null) { - throw SchemaException("Table $tableName does not exist."); - } - + var existingTable = _getTable(tableName); var newTable = SchemaTable.from(existingTable); + modify(newTable); schema.replaceTable(existingTable, newTable); @@ -165,10 +159,7 @@ class SchemaBuilder { /// Validates and adds a column to a table in [schema]. void addColumn(String tableName, SchemaColumn column, {String unencodedInitialValue}) { - var table = schema.tableForName(tableName); - if (table == null) { - throw SchemaException("Table $tableName does not exist."); - } + var table = _getTable(tableName); table.addColumn(column); if (store != null) { @@ -182,15 +173,8 @@ class SchemaBuilder { /// Validates and deletes a column in a table in [schema]. void deleteColumn(String tableName, String columnName) { - var table = schema.tableForName(tableName); - if (table == null) { - throw SchemaException("Table $tableName does not exist."); - } - - var column = table.columnForName(columnName); - if (column == null) { - throw SchemaException("Column $columnName does not exists."); - } + var table = _getTable(tableName); + var column = _getColumn(table, columnName); table.removeColumn(column); @@ -203,15 +187,8 @@ class SchemaBuilder { /// Validates and renames a column in a table in [schema]. void renameColumn(String tableName, String columnName, String newName) { - var table = schema.tableForName(tableName); - if (table == null) { - throw SchemaException("Table $tableName does not exist."); - } - - var column = table.columnForName(columnName); - if (column == null) { - throw SchemaException("Column $columnName does not exists."); - } + var table = _getTable(tableName); + var column = _getColumn(table, columnName); table.renameColumn(column, newName); @@ -238,17 +215,10 @@ class SchemaBuilder { void alterColumn(String tableName, String columnName, void modify(SchemaColumn targetColumn), {String unencodedInitialValue}) { - var table = schema.tableForName(tableName); - if (table == null) { - throw SchemaException("Table $tableName does not exist."); - } - - var existingColumn = table[columnName]; - if (existingColumn == null) { - throw SchemaException("Column $columnName does not exist."); - } - + var table = _getTable(tableName); + var existingColumn = _getColumn(table, columnName); var newColumn = SchemaColumn.from(existingColumn); + modify(newColumn); if (existingColumn.type != newColumn.type) { @@ -332,7 +302,8 @@ class SchemaBuilder { } if (store == null && innerCommands.isNotEmpty) { - commands.add("database.alterColumn(\"$tableName\", \"$columnName\", (c) {${innerCommands.join(";")};});"); + commands.add( + "database.alterColumn(\"$tableName\", \"$columnName\", (c) {${innerCommands.join(";")};});"); } } @@ -380,9 +351,10 @@ class SchemaBuilder { addColumn(difference.actualTable.name, c); if (!c.isNullable && c.defaultValue == null) { - changeList?.add("WARNING: This migration may fail if table '${difference.actualTable.name}' already has rows. " - "Add an 'unencodedInitialValue' to the statement 'database.addColumn(\"${difference.actualTable.name}\", " - "SchemaColumn(\"${c.name}\", ...)'."); + changeList?.add( + "WARNING: This migration may fail if table '${difference.actualTable.name}' already has rows. " + "Add an 'unencodedInitialValue' to the statement 'database.addColumn(\"${difference.actualTable.name}\", " + "SchemaColumn(\"${c.name}\", ...)'."); } }); @@ -405,10 +377,12 @@ class SchemaBuilder { }); if (columnDiff.expectedColumn.isNullable && - !columnDiff.actualColumn.isNullable && columnDiff.actualColumn.defaultValue == null) { - changeList?.add("WARNING: This migration may fail if table '${difference.actualTable.name}' already has rows. " - "Add an 'unencodedInitialValue' to the statement 'database.addColumn(\"${difference.actualTable.name}\", " - "SchemaColumn(\"${columnDiff.actualColumn.name}\", ...)'."); + !columnDiff.actualColumn.isNullable && + columnDiff.actualColumn.defaultValue == null) { + changeList?.add( + "WARNING: This migration may fail if table '${difference.actualTable.name}' already has rows. " + "Add an 'unencodedInitialValue' to the statement 'database.addColumn(\"${difference.actualTable.name}\", " + "SchemaColumn(\"${columnDiff.actualColumn.name}\", ...)'."); } }); @@ -425,6 +399,24 @@ class SchemaBuilder { } } + SchemaTable _getTable(String tableName) { + var table = schema.tableForName(tableName); + if (table == null) { + throw SchemaException("Table $tableName does not exist."); + } + + return table; + } + + SchemaColumn _getColumn(SchemaTable table, String columnName) { + var column = table.columnForName(columnName); + if (column == null) { + throw SchemaException("Column $columnName does not exist."); + } + + return column; + } + static String _getNewTableExpression(SchemaTable table) { var builder = StringBuffer(); builder.write('database.createTable(SchemaTable("${table.name}", [');