From b2e6c14386ced434d8fadd8ee56f885a1f14ff66 Mon Sep 17 00:00:00 2001 From: Tobe O Date: Sun, 9 Dec 2018 12:44:16 -0500 Subject: [PATCH] gen migrations --- README.md | 17 +- angel_orm/lib/src/annotations.dart | 10 +- angel_orm_generator/CHANGELOG.md | 3 + angel_orm_generator/build.yaml | 2 + .../lib/angel_orm_generator.dart | 1 + .../lib/src/migration_generator.dart | 246 ++++++++++++++++++ angel_orm_generator/pubspec.yaml | 8 +- angel_orm_generator/test/models/author.dart | 1 + angel_orm_generator/test/models/author.g.dart | 21 ++ angel_orm_generator/test/models/book.dart | 1 + angel_orm_generator/test/models/book.g.dart | 23 ++ angel_orm_generator/test/models/car.dart | 1 + angel_orm_generator/test/models/car.g.dart | 24 ++ .../test/models/customer.g.dart | 20 ++ angel_orm_generator/test/models/foot.g.dart | 22 ++ angel_orm_generator/test/models/fruit.dart | 1 + angel_orm_generator/test/models/fruit.g.dart | 22 ++ angel_orm_generator/test/models/leg.dart | 1 + angel_orm_generator/test/models/leg.g.dart | 21 ++ angel_orm_generator/test/models/order.g.dart | 24 ++ angel_orm_generator/test/models/tree.dart | 1 + angel_orm_generator/test/models/tree.g.dart | 21 ++ angel_orm_generator/test/models/user.dart | 1 + angel_orm_generator/test/models/user.g.dart | 56 ++++ 24 files changed, 540 insertions(+), 8 deletions(-) create mode 100644 angel_orm_generator/lib/src/migration_generator.dart diff --git a/README.md b/README.md index a4711424..dc8fc753 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,19 @@ part 'car.g.dart'; @serializable @orm -class _Car extends Model { - String make; - String description; - bool familyFriendly; - DateTime recalledAt; +abstract class _Car extends Model { + String get make; + + String get description; + + bool get familyFriendly; + + DateTime get recalledAt; } + +// You can disable migration generation. +@Orm(generateMigrations: false) +abstract class _NoMigrations extends Model {} ``` Models can use the `@Alias()` annotation; `package:angel_orm` obeys it. diff --git a/angel_orm/lib/src/annotations.dart b/angel_orm/lib/src/annotations.dart index 636cc648..e2f735b0 100644 --- a/angel_orm/lib/src/annotations.dart +++ b/angel_orm/lib/src/annotations.dart @@ -1,9 +1,17 @@ const Orm orm = const Orm(); class Orm { + /// The name of the table to query. + /// + /// Inferred if not present. final String tableName; + + /// Whether to generate migrations for this model. + /// + /// Defaults to [:true:]. + final bool generateMigrations; - const Orm({this.tableName}); + const Orm({this.tableName, this.generateMigrations: true}); } class Join { diff --git a/angel_orm_generator/CHANGELOG.md b/angel_orm_generator/CHANGELOG.md index a7fbbbc2..7141514b 100644 --- a/angel_orm_generator/CHANGELOG.md +++ b/angel_orm_generator/CHANGELOG.md @@ -1,3 +1,6 @@ +# 2.0.0-dev.1 +* Generate migration files. + # 2.0.0-dev * Dart 2 updates, and more. diff --git a/angel_orm_generator/build.yaml b/angel_orm_generator/build.yaml index 10c42b78..ba5de6e8 100644 --- a/angel_orm_generator/build.yaml +++ b/angel_orm_generator/build.yaml @@ -2,11 +2,13 @@ builders: angel_orm: import: "package:angel_orm_generator/angel_orm_generator.dart" builder_factories: + - migrationBuilder - ormBuilder auto_apply: root_package build_to: cache build_extensions: .dart: + - ".angel_migration.g.part" - ".angel_orm.g.part" required_inputs: - angel_serialize.g.part diff --git a/angel_orm_generator/lib/angel_orm_generator.dart b/angel_orm_generator/lib/angel_orm_generator.dart index 3774cb96..a853cf9d 100644 --- a/angel_orm_generator/lib/angel_orm_generator.dart +++ b/angel_orm_generator/lib/angel_orm_generator.dart @@ -1,4 +1,5 @@ //export 'src/mongodb_orm_generator.dart'; +export 'src/migration_generator.dart'; export 'src/orm_build_context.dart'; export 'src/orm_generator.dart'; export 'src/readers.dart'; diff --git a/angel_orm_generator/lib/src/migration_generator.dart b/angel_orm_generator/lib/src/migration_generator.dart new file mode 100644 index 00000000..7ef38d44 --- /dev/null +++ b/angel_orm_generator/lib/src/migration_generator.dart @@ -0,0 +1,246 @@ +import 'dart:async'; +import 'package:analyzer/dart/element/element.dart'; +import 'package:angel_orm/angel_orm.dart'; +import 'package:build/build.dart'; +import 'package:code_builder/code_builder.dart'; +import 'package:dart_style/dart_style.dart'; +import 'package:source_gen/source_gen.dart' hide LibraryBuilder; +import 'orm_build_context.dart'; + +Builder migrationBuilder(BuilderOptions options) { + return new SharedPartBuilder([ + new MigrationGenerator( + autoSnakeCaseNames: options.config['auto_snake_case_names'] != false, + autoIdAndDateFields: options.config['auto_id_and_date_fields'] != false) + ], 'angel_migration'); +} + +class MigrationGenerator extends GeneratorForAnnotation { + static final Parameter _schemaParam = new Parameter((b) => b + ..name = 'schema' + ..type = refer('Schema')); + static final Reference _schema = refer('schema'); + + /// If `true` (default), then field names will automatically be (de)serialized as snake_case. + final bool autoSnakeCaseNames; + + /// If `true` (default), then the schema will automatically add id, created_at and updated_at fields. + final bool autoIdAndDateFields; + + const MigrationGenerator( + {this.autoSnakeCaseNames: true, this.autoIdAndDateFields: true}); + + @override + Future generateForAnnotatedElement( + Element element, ConstantReader annotation, BuildStep buildStep) async { + if (element is! ClassElement) + throw 'Only classes can be annotated with @ORM().'; + + var generateMigrations = + annotation.peek('generateMigrations')?.boolValue ?? true; + + if (!generateMigrations) { + return null; + } + + var resolver = await buildStep.resolver; + var ctx = await buildOrmContext( + element as ClassElement, + annotation, + buildStep, + resolver, + autoSnakeCaseNames != false, + autoIdAndDateFields != false); + var lib = generateMigrationLibrary( + ctx, element as ClassElement, resolver, buildStep); + if (lib == null) return null; + return new DartFormatter().format(lib.accept(new DartEmitter()).toString()); + } + + Library generateMigrationLibrary(OrmBuildContext ctx, ClassElement element, + Resolver resolver, BuildStep buildStep) { + return new Library((lib) { + lib.body.add(new Class((clazz) { + clazz + ..name = '${ctx.buildContext.modelClassName}Migration' + ..extend = refer('Migration') + ..methods + .addAll([buildUpMigration(ctx, lib), buildDownMigration(ctx)]); + })); + }); + } + + Method buildUpMigration(OrmBuildContext ctx, LibraryBuilder lib) { + return new Method((meth) { + meth + ..name = 'up' + ..annotations.add(refer('override')) + ..requiredParameters.add(_schemaParam); + + //var closure = new Method.closure()..addPositional(parameter('table')); + var closure = new Method((closure) { + closure + ..requiredParameters.add(new Parameter((b) => b..name = 'table')) + ..body = new Block((closureBody) { + var table = refer('table'); + + List dup = []; + ctx.columns.forEach((name, col) { + var key = ctx.buildContext.resolveFieldName(name); + + if (dup.contains(key)) + return; + else { + if (key != 'id' || autoIdAndDateFields == false) { + // Check for relationships that might duplicate + for (var rName in ctx.relations.keys) { + var relationship = ctx.relations[rName]; + if (relationship.localKey == key) return; + } + } + + dup.add(key); + } + + String methodName; + List positional = [literal(key)]; + Map named = {}; + + if (autoIdAndDateFields != false && name == 'id') + methodName = 'serial'; + + if (methodName == null) { + switch (col.type) { + case ColumnType.varChar: + 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.dateTime: + methodName = 'dateTime'; + break; + case ColumnType.timeStamp: + methodName = 'timeStamp'; + break; + default: + Expression provColumn; + var colType = refer('Column'); + var columnTypeType = refer('ColumnType'); + + if (col.length == null) { + methodName = 'declare'; + provColumn = columnTypeType.newInstance([ + literal(col.type.name), + ]); + } else { + methodName = 'declareColumn'; + provColumn = colType.newInstance([], { + 'type': columnTypeType.newInstance([ + literal(col.type.name), + ]), + 'length': literal(col.length), + }); + } + + positional.add(provColumn); + break; + } + } + + var field = table.property(methodName).call(positional, named); + var cascade = []; + + if (col.defaultValue != null) { + cascade + .add(refer('defaultsTo').call([literal(col.defaultValue)])); + } + + if (col.indexType == IndexType.primaryKey || + (autoIdAndDateFields != false && name == 'id')) { + cascade.add(refer('primaryKey').call([])); + } else if (col.indexType == IndexType.unique) { + cascade.add(refer('unique').call([])); + } + + if (col.isNullable != true) + cascade.add(refer('notNull').call([])); + + if (cascade.isNotEmpty) { + var b = new StringBuffer() + ..writeln(field.accept(new DartEmitter())); + + for (var ex in cascade) { + b + ..write('..') + ..writeln(ex.accept(new DartEmitter())); + } + + field = new CodeExpression(new Code(b.toString())); + } + + closureBody.addExpression(field); + }); + + ctx.relations.forEach((name, r) { + var relationship = r; + + if (relationship.type == RelationshipType.belongsTo) { + var key = relationship.localKey; + + var field = table.property('integer').call([literal(key)]); + // .references('user', 'id').onDeleteCascade() + var ref = field.property('references').call([ + literal(relationship.foreignTable), + literal(relationship.foreignKey), + ]); + + if (relationship.cascadeOnDelete != false && + const [RelationshipType.hasOne, RelationshipType.belongsTo] + .contains(relationship.type)) + ref = ref.property('onDeleteCascade').call([]); + closureBody.addExpression(ref); + } + }); + }); + }); + + meth.body = new Block((b) { + b.addExpression(_schema.property('create').call([ + literal(ctx.tableName), + closure.closure, + ])); + }); + }); + } + + Method buildDownMigration(OrmBuildContext ctx) { + return new Method((b) { + b + ..name = 'down' + ..annotations.add(refer('override')) + ..requiredParameters.add(_schemaParam) + ..body = new Block((b) { + b.addExpression( + _schema.property('drop').call([literalString(ctx.tableName)])); + }); + }); + } +} diff --git a/angel_orm_generator/pubspec.yaml b/angel_orm_generator/pubspec.yaml index e5f961b0..f65afc1f 100644 --- a/angel_orm_generator/pubspec.yaml +++ b/angel_orm_generator/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_orm_generator -version: 2.0.0-dev +version: 2.0.0-dev.1 description: Code generators for Angel's ORM. Generates query builder classes. author: Tobe O homepage: https://github.com/angel-dart/orm @@ -14,6 +14,7 @@ dependencies: build: ">=0.12.0 <2.0.0" build_config: ^0.3.0 code_builder: ^3.0.0 + dart_style: ^1.0.0 inflection: git: url: https://github.com/thosakwe/dart-inflection.git @@ -24,7 +25,10 @@ dependencies: source_gen: ^0.9.0 dev_dependencies: angel_framework: ^2.0.0-alpha - #angel_migration: ^1.0.0-alpha + angel_migration: + git: + url: https://github.com/angel-dart/migration + path: angel_migration #angel_test: ^1.0.0 build_runner: ^1.0.0 collection: ^1.0.0 diff --git a/angel_orm_generator/test/models/author.dart b/angel_orm_generator/test/models/author.dart index 3e1e7b39..f0b070a5 100644 --- a/angel_orm_generator/test/models/author.dart +++ b/angel_orm_generator/test/models/author.dart @@ -1,6 +1,7 @@ library angel_orm.generator.models.author; import 'package:angel_model/angel_model.dart'; +import 'package:angel_migration/angel_migration.dart'; import 'package:angel_orm/angel_orm.dart'; import 'package:angel_serialize/angel_serialize.dart'; part 'author.g.dart'; diff --git a/angel_orm_generator/test/models/author.g.dart b/angel_orm_generator/test/models/author.g.dart index 1f87a6e7..3d345415 100644 --- a/angel_orm_generator/test/models/author.g.dart +++ b/angel_orm_generator/test/models/author.g.dart @@ -2,6 +2,27 @@ part of angel_orm.generator.models.author; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class AuthorMigration extends Migration { + @override + up(Schema schema) { + schema.create('authors', (table) { + table.serial('id')..primaryKey(); + table.varChar('name'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('authors'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/book.dart b/angel_orm_generator/test/models/book.dart index e20b5ea1..c81e7021 100644 --- a/angel_orm_generator/test/models/book.dart +++ b/angel_orm_generator/test/models/book.dart @@ -1,5 +1,6 @@ library angel_orm.generator.models.book; +import 'package:angel_migration/angel_migration.dart'; import 'package:angel_model/angel_model.dart'; import 'package:angel_orm/angel_orm.dart'; import 'package:angel_serialize/angel_serialize.dart'; diff --git a/angel_orm_generator/test/models/book.g.dart b/angel_orm_generator/test/models/book.g.dart index 2cc2b695..be61700e 100644 --- a/angel_orm_generator/test/models/book.g.dart +++ b/angel_orm_generator/test/models/book.g.dart @@ -2,6 +2,29 @@ part of angel_orm.generator.models.book; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class BookMigration extends Migration { + @override + up(Schema schema) { + schema.create('books', (table) { + table.serial('id')..primaryKey(); + table.varChar('name'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + table.integer('author_id').references('authors', 'id'); + table.integer('partner_author_id').references('authors', 'id'); + }); + } + + @override + down(Schema schema) { + schema.drop('books'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/car.dart b/angel_orm_generator/test/models/car.dart index 07521d09..a7f67dcd 100644 --- a/angel_orm_generator/test/models/car.dart +++ b/angel_orm_generator/test/models/car.dart @@ -1,5 +1,6 @@ library angel_orm.generator.models.car; +import 'package:angel_migration/angel_migration.dart'; import 'package:angel_model/angel_model.dart'; import 'package:angel_orm/angel_orm.dart'; import 'package:angel_serialize/angel_serialize.dart'; diff --git a/angel_orm_generator/test/models/car.g.dart b/angel_orm_generator/test/models/car.g.dart index 22380d04..431ab9bd 100644 --- a/angel_orm_generator/test/models/car.g.dart +++ b/angel_orm_generator/test/models/car.g.dart @@ -2,6 +2,30 @@ part of angel_orm.generator.models.car; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class CarMigration extends Migration { + @override + up(Schema schema) { + schema.create('cars', (table) { + table.serial('id')..primaryKey(); + table.varChar('make'); + table.varChar('description'); + table.boolean('family_friendly'); + table.timeStamp('recalled_at'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('cars'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/customer.g.dart b/angel_orm_generator/test/models/customer.g.dart index 59049d51..819b5ab9 100644 --- a/angel_orm_generator/test/models/customer.g.dart +++ b/angel_orm_generator/test/models/customer.g.dart @@ -2,6 +2,26 @@ part of angel_orm_generator.test.models.customer; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class CustomerMigration extends Migration { + @override + up(Schema schema) { + schema.create('customers', (table) { + table.serial('id')..primaryKey(); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('customers'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/foot.g.dart b/angel_orm_generator/test/models/foot.g.dart index 59d71290..feeaf456 100644 --- a/angel_orm_generator/test/models/foot.g.dart +++ b/angel_orm_generator/test/models/foot.g.dart @@ -2,6 +2,28 @@ part of angel_orm_generator.test.models.foot; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class FootMigration extends Migration { + @override + up(Schema schema) { + schema.create('feet', (table) { + table.serial('id')..primaryKey(); + table.integer('leg_id'); + table.integer('n_toes'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('feet'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/fruit.dart b/angel_orm_generator/test/models/fruit.dart index d7417b08..33206053 100644 --- a/angel_orm_generator/test/models/fruit.dart +++ b/angel_orm_generator/test/models/fruit.dart @@ -1,5 +1,6 @@ library angel_orm_generator.test.models.fruit; +import 'package:angel_migration/angel_migration.dart'; import 'package:angel_model/angel_model.dart'; import 'package:angel_orm/angel_orm.dart'; import 'package:angel_serialize/angel_serialize.dart'; diff --git a/angel_orm_generator/test/models/fruit.g.dart b/angel_orm_generator/test/models/fruit.g.dart index 27db0bfe..5b6fd7e1 100644 --- a/angel_orm_generator/test/models/fruit.g.dart +++ b/angel_orm_generator/test/models/fruit.g.dart @@ -2,6 +2,28 @@ part of angel_orm_generator.test.models.fruit; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class FruitMigration extends Migration { + @override + up(Schema schema) { + schema.create('fruits', (table) { + table.serial('id')..primaryKey(); + table.integer('tree_id'); + table.varChar('common_name'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('fruits'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/leg.dart b/angel_orm_generator/test/models/leg.dart index 40ff716e..be004363 100644 --- a/angel_orm_generator/test/models/leg.dart +++ b/angel_orm_generator/test/models/leg.dart @@ -1,5 +1,6 @@ library angel_orm_generator.test.models.leg; +import 'package:angel_migration/angel_migration.dart'; import 'package:angel_model/angel_model.dart'; import 'package:angel_orm/angel_orm.dart'; import 'package:angel_serialize/angel_serialize.dart'; diff --git a/angel_orm_generator/test/models/leg.g.dart b/angel_orm_generator/test/models/leg.g.dart index c9a07800..0d4283cd 100644 --- a/angel_orm_generator/test/models/leg.g.dart +++ b/angel_orm_generator/test/models/leg.g.dart @@ -2,6 +2,27 @@ part of angel_orm_generator.test.models.leg; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class LegMigration extends Migration { + @override + up(Schema schema) { + schema.create('legs', (table) { + table.serial('id')..primaryKey(); + table.varChar('name'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('legs'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/order.g.dart b/angel_orm_generator/test/models/order.g.dart index cd6ee1c4..8751bb8e 100644 --- a/angel_orm_generator/test/models/order.g.dart +++ b/angel_orm_generator/test/models/order.g.dart @@ -2,6 +2,30 @@ part of angel_orm_generator.test.models.order; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class OrderMigration extends Migration { + @override + up(Schema schema) { + schema.create('orders', (table) { + table.serial('id')..primaryKey(); + table.integer('customer_id'); + table.integer('employee_id'); + table.timeStamp('order_date'); + table.integer('shipper_id'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('orders'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/tree.dart b/angel_orm_generator/test/models/tree.dart index dcaa1c58..7be2b332 100644 --- a/angel_orm_generator/test/models/tree.dart +++ b/angel_orm_generator/test/models/tree.dart @@ -1,5 +1,6 @@ library angel_orm_generator.test.models.tree; +import 'package:angel_migration/angel_migration.dart'; import 'package:angel_model/angel_model.dart'; import 'package:angel_orm/angel_orm.dart'; import 'package:angel_serialize/angel_serialize.dart'; diff --git a/angel_orm_generator/test/models/tree.g.dart b/angel_orm_generator/test/models/tree.g.dart index d1482697..46233e31 100644 --- a/angel_orm_generator/test/models/tree.g.dart +++ b/angel_orm_generator/test/models/tree.g.dart @@ -2,6 +2,27 @@ part of angel_orm_generator.test.models.tree; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class TreeMigration extends Migration { + @override + up(Schema schema) { + schema.create('trees', (table) { + table.serial('id')..primaryKey(); + table.declare('rings', new ColumnType('smallint')); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('trees'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** diff --git a/angel_orm_generator/test/models/user.dart b/angel_orm_generator/test/models/user.dart index f2c47343..2ba02c00 100644 --- a/angel_orm_generator/test/models/user.dart +++ b/angel_orm_generator/test/models/user.dart @@ -1,5 +1,6 @@ library angel_orm_generator.test.models.user; +import 'package:angel_migration/angel_migration.dart'; import 'package:angel_model/angel_model.dart'; import 'package:angel_orm/angel_orm.dart'; import 'package:angel_serialize/angel_serialize.dart'; diff --git a/angel_orm_generator/test/models/user.g.dart b/angel_orm_generator/test/models/user.g.dart index e360ebf7..18425a27 100644 --- a/angel_orm_generator/test/models/user.g.dart +++ b/angel_orm_generator/test/models/user.g.dart @@ -2,6 +2,62 @@ part of angel_orm_generator.test.models.user; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class UserMigration extends Migration { + @override + up(Schema schema) { + schema.create('users', (table) { + table.serial('id')..primaryKey(); + table.varChar('username'); + table.varChar('password'); + table.varChar('email'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('users'); + } +} + +class RoleMigration extends Migration { + @override + up(Schema schema) { + schema.create('roles', (table) { + table.serial('id')..primaryKey(); + table.varChar('name'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('roles'); + } +} + +class UserRoleMigration extends Migration { + @override + up(Schema schema) { + schema.create('user_roles', (table) { + table.serial('id')..primaryKey(); + table.integer('user_id').references('users', 'id'); + table.integer('role_id').references('roles', 'id'); + }); + } + + @override + down(Schema schema) { + schema.drop('user_roles'); + } +} + // ************************************************************************** // OrmGenerator // **************************************************************************