Skip to content
This repository was archived by the owner on Mar 18, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions aqueduct/lib/src/cli/scripts/get_schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<Map<String, dynamic>> {
GetSchemaExecutable(Map<String, dynamic> message) : super(message);

Expand All @@ -20,17 +22,11 @@ class GetSchemaExecutable extends Executable<Map<String, dynamic>> {
return {"error": e.message};
}
}

static List<String> importsForPackage(String packageName) => [
"package:aqueduct/aqueduct.dart",
"package:$packageName/$packageName.dart",
"package:runtime/runtime.dart"
];
}

Future<Schema> 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);

Expand Down
11 changes: 3 additions & 8 deletions aqueduct/lib/src/cli/scripts/migration_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<Map<String, dynamic>> {
MigrationBuilderExecutable(Map<String, dynamic> message)
: inputSchema =
Expand Down Expand Up @@ -39,12 +41,6 @@ class MigrationBuilderExecutable extends Executable<Map<String, dynamic>> {
return {"error": e.message};
}
}

static List<String> importsForPackage(String packageName) => [
"package:aqueduct/aqueduct.dart",
"package:$packageName/$packageName.dart",
"package:runtime/runtime.dart"
];
}

class MigrationBuilderResult {
Expand All @@ -63,8 +59,7 @@ Future<MigrationBuilderResult> 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")) {
Expand Down
5 changes: 5 additions & 0 deletions aqueduct/lib/src/cli/scripts/script_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
List<String> importsForPackage(String packageName) => [
"package:aqueduct/aqueduct.dart",
"package:runtime/runtime.dart",
"package:$packageName/$packageName.dart"
];
64 changes: 26 additions & 38 deletions aqueduct/lib/src/db/managed/entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -184,25 +184,8 @@ class ManagedEntity implements APIComponentDocumenter {
/// on this entity was selected. Returns that attribute.
ManagedAttributeDescription identifyAttribute<T, U extends ManagedObject>(
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)) {
Expand All @@ -227,25 +210,8 @@ class ManagedEntity implements APIComponentDocumenter {
ManagedRelationshipDescription
identifyRelationship<T, U extends ManagedObject>(
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(
Expand Down Expand Up @@ -339,6 +305,28 @@ class ManagedEntity implements APIComponentDocumenter {
final obj = document(context);
context.schema.register(name, obj, representation: instanceType);
}

String _getPropertyName<T, U extends ManagedObject>(
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 {
Expand Down
42 changes: 22 additions & 20 deletions aqueduct/lib/src/db/postgresql/postgresql_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,8 @@ class PostgresQuery<InstanceType extends ManagedObject> 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<InstanceType>(results as List<List<dynamic>>).first;
return _returningInstancesForRows(builder, buffer)
.then((value) => value.first);
}

@override
Expand All @@ -70,14 +64,7 @@ class PostgresQuery<InstanceType extends ManagedObject> 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<List<dynamic>>);
return _returningInstancesForRows(builder, buffer);
}

@override
Expand Down Expand Up @@ -180,10 +167,7 @@ class PostgresQuery<InstanceType extends ManagedObject> extends Object
buffer.write("OFFSET $offset ");
}

final results = await context.persistentStore
.executeQuery(buffer.toString(), builder.variables, timeoutInSeconds);

return builder.instancesForRows(results as List<List<dynamic>>);
return _instancesForRows(builder, buffer);
}

void validatePageDescriptor() {
Expand All @@ -200,6 +184,24 @@ class PostgresQuery<InstanceType extends ManagedObject> extends Object
}
}

Future<List<InstanceType>> _returningInstancesForRows(
PostgresQueryBuilder builder, StringBuffer buffer) async {
if ((builder.returning?.length ?? 0) > 0) {
buffer.write("RETURNING ${builder.sqlColumnsToReturn}");
}

return _instancesForRows(builder, buffer);
}

Future<List<InstanceType>> _instancesForRows(
PostgresQueryBuilder builder, StringBuffer buffer) async {
final results = await context.persistentStore
.executeQuery(buffer.toString(), builder.variables, timeoutInSeconds);

return builder
.instancesForRows<InstanceType>(results as List<List<dynamic>>);
}

static final StateError canModifyAllInstancesError = StateError(
"Invalid Query<T>. Query is either update or delete query with no WHERE clause. To confirm this query is correct, set 'canModifyAllInstances' to true.");
}
90 changes: 41 additions & 49 deletions aqueduct/lib/src/db/schema/schema_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);

Expand Down Expand Up @@ -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) {
Expand All @@ -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);

Expand All @@ -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);

Expand All @@ -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) {
Expand Down Expand Up @@ -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(";")};});");
}
}

Expand Down Expand Up @@ -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}\", ...)'.");
}
});

Expand All @@ -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}\", ...)'.");
}
});

Expand All @@ -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}", [');
Expand Down