MigrationGenerator almost ported
This commit is contained in:
parent
23f776c2f9
commit
b57067cae4
5 changed files with 157 additions and 146 deletions
5
angel_orm_generator/lib/src/builder/orm/lib_core.dart
Normal file
5
angel_orm_generator/lib/src/builder/orm/lib_core.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import 'package:code_builder/code_builder.dart';
|
||||||
|
|
||||||
|
final TypeReference $void = new TypeReference((b) => b.symbol = 'void');
|
||||||
|
|
||||||
|
final Expression override = new CodeExpression(new Code('override'));
|
|
@ -2,17 +2,19 @@ import 'dart:async';
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:angel_orm/angel_orm.dart';
|
import 'package:angel_orm/angel_orm.dart';
|
||||||
import 'package:build/build.dart';
|
import 'package:build/build.dart';
|
||||||
import 'package:code_builder/dart/core.dart';
|
|
||||||
import 'package:code_builder/code_builder.dart';
|
import 'package:code_builder/code_builder.dart';
|
||||||
import 'package:source_gen/source_gen.dart' hide LibraryBuilder;
|
import 'package:source_gen/source_gen.dart' hide LibraryBuilder;
|
||||||
import 'build_context.dart';
|
import 'build_context.dart';
|
||||||
import 'postgres_build_context.dart';
|
import 'postgres_build_context.dart';
|
||||||
|
import 'lib_core.dart' as lib$core;
|
||||||
|
|
||||||
class MigrationGenerator extends GeneratorForAnnotation<ORM> {
|
class MigrationGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
static final ParameterBuilder _schemaParam = parameter('schema', [
|
static final Parameter _schemaParam = new Parameter((b) {
|
||||||
new TypeBuilder('Schema'),
|
b
|
||||||
]);
|
..name = 'schema'
|
||||||
static final ReferenceBuilder _schema = reference('schema');
|
..type = new TypeReference((b) => b.symbol = 'Schema');
|
||||||
|
});
|
||||||
|
static final Expression _schema = new CodeExpression(new Code('schema'));
|
||||||
|
|
||||||
/// If `true` (default), then field names will automatically be (de)serialized as snake_case.
|
/// If `true` (default), then field names will automatically be (de)serialized as snake_case.
|
||||||
final bool autoSnakeCaseNames;
|
final bool autoSnakeCaseNames;
|
||||||
|
@ -37,165 +39,168 @@ class MigrationGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
resolver, autoSnakeCaseNames != false, autoIdAndDateFields != false);
|
resolver, autoSnakeCaseNames != false, autoIdAndDateFields != false);
|
||||||
var lib = generateMigrationLibrary(ctx, element, resolver, buildStep);
|
var lib = generateMigrationLibrary(ctx, element, resolver, buildStep);
|
||||||
if (lib == null) return null;
|
if (lib == null) return null;
|
||||||
return prettyToSource(lib.buildAst());
|
var emitter = new DartEmitter();
|
||||||
|
return lib.accept(emitter).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryBuilder generateMigrationLibrary(PostgresBuildContext ctx,
|
Library generateMigrationLibrary(PostgresBuildContext ctx,
|
||||||
ClassElement element, Resolver resolver, BuildStep buildStep) {
|
ClassElement element, Resolver resolver, BuildStep buildStep) {
|
||||||
var lib = new LibraryBuilder()
|
return new Library((lib) {
|
||||||
..addDirective(
|
lib.directives.add([
|
||||||
new ImportBuilder('package:angel_migration/angel_migration.dart'));
|
new Directive.import('package:angel_migration/angel_migration.dart'),
|
||||||
|
]);
|
||||||
|
|
||||||
var clazz = new ClassBuilder('${ctx.modelClassName}Migration',
|
lib.body.add(new Class((b) {
|
||||||
asExtends: new TypeBuilder('Migration'));
|
b.name = '${ctx.modelClassName}Migration';
|
||||||
clazz..addMethod(buildUpMigration(ctx, lib))..addMethod(buildDownMigration(ctx));
|
b.extend = new Reference('Migration');
|
||||||
|
}));
|
||||||
|
|
||||||
return lib..addMember(clazz);
|
lib.methods.add(buildUpMigration(ctx, lib));
|
||||||
|
lib.methods.add(buildDownMigration(ctx));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBuilder buildUpMigration(PostgresBuildContext ctx, LibraryBuilder lib) {
|
Method buildUpMigration(PostgresBuildContext ctx, LibraryBuilder lib) {
|
||||||
var meth = new MethodBuilder('up')..addPositional(_schemaParam);
|
return new Method((meth) {
|
||||||
var closure = new MethodBuilder.closure()
|
meth.name = 'up';
|
||||||
..addPositional(parameter('table'));
|
meth.annotations.add(lib$core.override);
|
||||||
var table = reference('table');
|
meth.requiredParameters.add(_schemaParam);
|
||||||
|
|
||||||
List<String> dup = [];
|
var closure = new Method((closure) {
|
||||||
bool hasOrmImport = false;
|
closure.requiredParameters.add(new Parameter((b) => b.name = 'table'));
|
||||||
ctx.columnInfo.forEach((name, col) {
|
var table = new Reference('table');
|
||||||
var key = ctx.resolveFieldName(name);
|
|
||||||
|
|
||||||
if (dup.contains(key))
|
List<String> dup = [];
|
||||||
return;
|
bool hasOrmImport = false;
|
||||||
else {
|
ctx.columnInfo.forEach((name, col) {
|
||||||
if (key != 'id' || autoIdAndDateFields == false) {
|
var key = ctx.resolveFieldName(name);
|
||||||
// Check for relationships that might duplicate
|
|
||||||
for (var rName in ctx.relationships.keys) {
|
if (dup.contains(key))
|
||||||
var relationship = ctx.populateRelationship(rName);
|
return;
|
||||||
if (relationship.localKey == key) return;
|
else {
|
||||||
|
if (key != 'id' || autoIdAndDateFields == false) {
|
||||||
|
// Check for relationships that might duplicate
|
||||||
|
for (var rName in ctx.relationships.keys) {
|
||||||
|
var relationship = ctx.populateRelationship(rName);
|
||||||
|
if (relationship.localKey == key) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dup.add(key);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dup.add(key);
|
String methodName;
|
||||||
}
|
List<Expression> positional = [literal(key)];
|
||||||
|
Map<String, Expression> named = {};
|
||||||
|
|
||||||
String methodName;
|
if (autoIdAndDateFields != false && name == 'id') methodName = 'serial';
|
||||||
List<ExpressionBuilder> positional = [literal(key)];
|
|
||||||
Map<String, ExpressionBuilder> named = {};
|
|
||||||
|
|
||||||
if (autoIdAndDateFields != false && name == 'id') methodName = 'serial';
|
if (methodName == null) {
|
||||||
|
switch (col.type) {
|
||||||
|
case ColumnType.VAR_CHAR:
|
||||||
|
methodName = 'varchar';
|
||||||
|
if (col.length != null) named['length'] = literal(col.length);
|
||||||
|
break;
|
||||||
|
case ColumnType.SERIAL:
|
||||||
|
methodName = 'serial';
|
||||||
|
break;
|
||||||
|
case ColumnType.INT:
|
||||||
|
methodName = 'integer';
|
||||||
|
break;
|
||||||
|
case ColumnType.FLOAT:
|
||||||
|
methodName = 'float';
|
||||||
|
break;
|
||||||
|
case ColumnType.NUMERIC:
|
||||||
|
methodName = 'numeric';
|
||||||
|
break;
|
||||||
|
case ColumnType.BOOLEAN:
|
||||||
|
methodName = 'boolean';
|
||||||
|
break;
|
||||||
|
case ColumnType.DATE:
|
||||||
|
methodName = 'date';
|
||||||
|
break;
|
||||||
|
case ColumnType.DATE_TIME:
|
||||||
|
methodName = 'dateTime';
|
||||||
|
break;
|
||||||
|
case ColumnType.TIME_STAMP:
|
||||||
|
methodName = 'timeStamp';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!hasOrmImport) {
|
||||||
|
hasOrmImport = true;
|
||||||
|
lib.directives.add(new Directive.import('package:angel_orm/angel_orm.dart'));
|
||||||
|
}
|
||||||
|
|
||||||
if (methodName == null) {
|
Expression provColumn;
|
||||||
switch (col.type) {
|
|
||||||
case ColumnType.VAR_CHAR:
|
if (col.length == null) {
|
||||||
methodName = 'varchar';
|
methodName = 'declare';
|
||||||
if (col.length != null) named['length'] = literal(col.length);
|
provColumn = new CodeExpression(new Code("new ColumnType('${col.type.name}')"));
|
||||||
break;
|
} else {
|
||||||
case ColumnType.SERIAL:
|
methodName = 'declareColumn';
|
||||||
methodName = 'serial';
|
provColumn = new CodeExpression(new Code("new Column({type: new Column('${col.type.name}'), length: ${col.length})"));
|
||||||
break;
|
}
|
||||||
case ColumnType.INT:
|
|
||||||
methodName = 'integer';
|
positional.add(provColumn);
|
||||||
break;
|
break;
|
||||||
case ColumnType.FLOAT:
|
|
||||||
methodName = 'float';
|
|
||||||
break;
|
|
||||||
case ColumnType.NUMERIC:
|
|
||||||
methodName = 'numeric';
|
|
||||||
break;
|
|
||||||
case ColumnType.BOOLEAN:
|
|
||||||
methodName = 'boolean';
|
|
||||||
break;
|
|
||||||
case ColumnType.DATE:
|
|
||||||
methodName = 'date';
|
|
||||||
break;
|
|
||||||
case ColumnType.DATE_TIME:
|
|
||||||
methodName = 'dateTime';
|
|
||||||
break;
|
|
||||||
case ColumnType.TIME_STAMP:
|
|
||||||
methodName = 'timeStamp';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!hasOrmImport) {
|
|
||||||
hasOrmImport = true;
|
|
||||||
lib.addDirective(new ImportBuilder('package:angel_orm/angel_orm.dart'));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ExpressionBuilder provColumn;
|
var field = table.property(methodName).call(positional, named);
|
||||||
var colType = new TypeBuilder('Column');
|
var cascade = <Expression Function(Expression)>[];
|
||||||
var columnTypeType = new TypeBuilder('ColumnType');
|
|
||||||
|
|
||||||
if (col.length == null) {
|
if (col.defaultValue != null) {
|
||||||
methodName = 'declare';
|
cascade
|
||||||
provColumn = columnTypeType.newInstance([
|
.add((e) => e.property('defaultsTo').call([literal(col.defaultValue)]));
|
||||||
literal(col.type.name),
|
}
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
methodName = 'declareColumn';
|
|
||||||
provColumn = colType.newInstance([], named: {
|
|
||||||
'type': columnTypeType.newInstance([
|
|
||||||
literal(col.type.name),
|
|
||||||
]),
|
|
||||||
'length': literal(col.length),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
positional.add(provColumn);
|
if (col.index == IndexType.PRIMARY_KEY ||
|
||||||
break;
|
(autoIdAndDateFields != false && name == 'id'))
|
||||||
}
|
cascade.add((e) => e.property('primaryKey').call([]));
|
||||||
}
|
else if (col.index == IndexType.UNIQUE)
|
||||||
|
cascade.add((e) => e.property('unique').call([]));
|
||||||
|
|
||||||
var field = table.invoke(methodName, positional, namedArguments: named);
|
if (col.nullable != true) cascade.add((e) => e.property('notNull').call([]));
|
||||||
var cascade = <ExpressionBuilder Function(ExpressionBuilder)>[];
|
|
||||||
|
|
||||||
if (col.defaultValue != null) {
|
field = cascade.isEmpty
|
||||||
cascade.add((e) => e.invoke('defaultsTo', [literal(col.defaultValue)]));
|
? field
|
||||||
}
|
: field.cascade((e) => cascade.map((f) => f(e)).toList());
|
||||||
|
closure.addStatement(field);
|
||||||
|
});
|
||||||
|
|
||||||
if (col.index == IndexType.PRIMARY_KEY ||
|
ctx.relationships.forEach((name, r) {
|
||||||
(autoIdAndDateFields != false && name == 'id'))
|
var relationship = ctx.populateRelationship(name);
|
||||||
cascade.add((e) => e.invoke('primaryKey', []));
|
|
||||||
else if (col.index == IndexType.UNIQUE)
|
|
||||||
cascade.add((e) => e.invoke('unique', []));
|
|
||||||
|
|
||||||
if (col.nullable != true) cascade.add((e) => e.invoke('notNull', []));
|
if (relationship.isBelongsTo) {
|
||||||
|
var key = relationship.localKey;
|
||||||
|
|
||||||
field = cascade.isEmpty
|
var field = table.property('integer').call([literal(key)]);
|
||||||
? field
|
// .references('user', 'id').onDeleteCascade()
|
||||||
: field.cascade((e) => cascade.map((f) => f(e)).toList());
|
var ref = field.property('references').call([
|
||||||
closure.addStatement(field);
|
literal(relationship.foreignTable),
|
||||||
|
literal(relationship.foreignKey),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (relationship.cascadeOnDelete != false && relationship.isSingular)
|
||||||
|
ref = ref.property('onDeleteCascade').call([]);
|
||||||
|
return closure.addStatement(ref);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
meth.addStatement(_schema.property('create').call([
|
||||||
|
literal(ctx.tableName),
|
||||||
|
closure,
|
||||||
|
]));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.relationships.forEach((name, r) {
|
|
||||||
var relationship = ctx.populateRelationship(name);
|
|
||||||
|
|
||||||
if (relationship.isBelongsTo) {
|
|
||||||
var key = relationship.localKey;
|
|
||||||
|
|
||||||
var field = table.invoke('integer', [literal(key)]);
|
|
||||||
// .references('user', 'id').onDeleteCascade()
|
|
||||||
var ref = field.invoke('references', [
|
|
||||||
literal(relationship.foreignTable),
|
|
||||||
literal(relationship.foreignKey),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (relationship.cascadeOnDelete != false && relationship.isSingular)
|
|
||||||
ref = ref.invoke('onDeleteCascade', []);
|
|
||||||
return closure.addStatement(ref);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
meth.addStatement(_schema.invoke('create', [
|
|
||||||
literal(ctx.tableName),
|
|
||||||
closure,
|
|
||||||
]));
|
|
||||||
return meth..addAnnotation(lib$core.override);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBuilder buildDownMigration(PostgresBuildContext ctx) {
|
Method buildDownMigration(PostgresBuildContext ctx) {
|
||||||
return method('down', [
|
return new Method((b) {
|
||||||
_schemaParam,
|
b.name = 'down';
|
||||||
_schema.invoke('drop', [literal(ctx.tableName)]),
|
b.requiredParameters.add(_schemaParam);
|
||||||
])
|
b.annotations.add(lib$core.override);
|
||||||
..addAnnotation(lib$core.override);
|
b.body.add(new Code("schema.drop('${ctx.tableName}')"));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,13 @@ import 'package:analyzer/dart/ast/ast.dart';
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:angel_orm/angel_orm.dart';
|
import 'package:angel_orm/angel_orm.dart';
|
||||||
import 'package:build/build.dart';
|
import 'package:build/build.dart';
|
||||||
import 'package:code_builder/dart/async.dart';
|
|
||||||
import 'package:code_builder/dart/core.dart';
|
|
||||||
import 'package:code_builder/code_builder.dart';
|
import 'package:code_builder/code_builder.dart';
|
||||||
import 'package:inflection/inflection.dart';
|
import 'package:inflection/inflection.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:recase/recase.dart';
|
import 'package:recase/recase.dart';
|
||||||
import 'package:source_gen/source_gen.dart' hide LibraryBuilder;
|
import 'package:source_gen/source_gen.dart' hide LibraryBuilder;
|
||||||
import 'build_context.dart';
|
import 'build_context.dart';
|
||||||
|
import 'lib_core.dart' as lib$core;
|
||||||
import 'postgres_build_context.dart';
|
import 'postgres_build_context.dart';
|
||||||
|
|
||||||
const List<String> RELATIONS = const ['or'];
|
const List<String> RELATIONS = const ['or'];
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'package:analyzer/dart/ast/ast.dart';
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:angel_orm/angel_orm.dart';
|
import 'package:angel_orm/angel_orm.dart';
|
||||||
import 'package:build/build.dart';
|
import 'package:build/build.dart';
|
||||||
import 'package:code_builder/dart/core.dart';
|
|
||||||
import 'package:code_builder/code_builder.dart';
|
import 'package:code_builder/code_builder.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:recase/recase.dart';
|
import 'package:recase/recase.dart';
|
||||||
|
|
|
@ -7,8 +7,8 @@ environment:
|
||||||
sdk: ">=1.19.0"
|
sdk: ">=1.19.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_orm: ^1.0.0-alpha
|
angel_orm: ^1.0.0-alpha
|
||||||
angel_serialize_generator: ^1.0.0-alpha
|
angel_serialize_generator: ^2.0.0
|
||||||
code_builder: ^1.0.0
|
code_builder: ^3.0.0
|
||||||
inflection: ^0.4.1
|
inflection: ^0.4.1
|
||||||
meta: ^1.0.0
|
meta: ^1.0.0
|
||||||
recase: ^1.0.0
|
recase: ^1.0.0
|
||||||
|
@ -17,5 +17,8 @@ dev_dependencies:
|
||||||
angel_framework: ^1.0.0
|
angel_framework: ^1.0.0
|
||||||
angel_migration: ^1.0.0-alpha
|
angel_migration: ^1.0.0-alpha
|
||||||
angel_test: ^1.0.0
|
angel_test: ^1.0.0
|
||||||
build_runner: ^0.5.0
|
build_runner: ^0.7.0
|
||||||
test: ^0.12.0
|
test: ^0.12.0
|
||||||
|
dependency_overrides:
|
||||||
|
angel_orm:
|
||||||
|
path: ../angel_orm
|
||||||
|
|
Loading…
Reference in a new issue