fold in migration + runner
This commit is contained in:
parent
a7b6b17114
commit
e4271f21b8
133 changed files with 794 additions and 0 deletions
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
.idea/.name
Normal file → Executable file
0
.idea/.name
Normal file → Executable file
0
.idea/dbnavigator.xml
Normal file → Executable file
0
.idea/dbnavigator.xml
Normal file → Executable file
0
.idea/modules.xml
Normal file → Executable file
0
.idea/modules.xml
Normal file → Executable file
0
.idea/orm.iml
Normal file → Executable file
0
.idea/orm.iml
Normal file → Executable file
0
.idea/runConfigurations/tests_in_has_one_test.xml
Normal file → Executable file
0
.idea/runConfigurations/tests_in_has_one_test.xml
Normal file → Executable file
0
.idea/vcs.xml
Normal file → Executable file
0
.idea/vcs.xml
Normal file → Executable file
0
.travis.yml
Normal file → Executable file
0
.travis.yml
Normal file → Executable file
0
README.md
Normal file → Executable file
0
README.md
Normal file → Executable file
12
angel_migration/.gitignore
vendored
Executable file
12
angel_migration/.gitignore
vendored
Executable file
|
@ -0,0 +1,12 @@
|
|||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
.packages
|
||||
.pub/
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
5
angel_migration/CHANGELOG.md
Executable file
5
angel_migration/CHANGELOG.md
Executable file
|
@ -0,0 +1,5 @@
|
|||
# 2.0.0-alpha.1
|
||||
* Changes to work with `package:angel_orm@2.0.0-dev.15`.
|
||||
|
||||
# 2.0.0-alpha
|
||||
Dart 2 update.
|
21
angel_migration/LICENSE
Executable file
21
angel_migration/LICENSE
Executable file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 The Angel Framework
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
2
angel_migration/README.md
Executable file
2
angel_migration/README.md
Executable file
|
@ -0,0 +1,2 @@
|
|||
# migration
|
||||
A PostgreSQL database migration framework built on Angel's ORM.
|
3
angel_migration/analysis_options.yaml
Executable file
3
angel_migration/analysis_options.yaml
Executable file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
42
angel_migration/example/todo.dart
Executable file
42
angel_migration/example/todo.dart
Executable file
|
@ -0,0 +1,42 @@
|
|||
/// These are straightforward migrations.
|
||||
///
|
||||
/// You will likely never have to actually write these yourself.
|
||||
library angel_migration.example.todo;
|
||||
|
||||
import 'package:angel_migration/angel_migration.dart';
|
||||
|
||||
class UserMigration implements Migration {
|
||||
@override
|
||||
void up(Schema schema) {
|
||||
schema.create('users', (table) {
|
||||
table
|
||||
..serial('id').primaryKey()
|
||||
..varChar('username', length: 32).unique()
|
||||
..varChar('password')
|
||||
..boolean('account_confirmed').defaultsTo(false);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void down(Schema schema) {
|
||||
schema.drop('users');
|
||||
}
|
||||
}
|
||||
|
||||
class TodoMigration implements Migration {
|
||||
@override
|
||||
void up(Schema schema) {
|
||||
schema.create('todos', (table) {
|
||||
table
|
||||
..serial('id').primaryKey()
|
||||
..integer('user_id').references('users', 'id').onDeleteCascade()
|
||||
..varChar('text')
|
||||
..boolean('completed').defaultsTo(false);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void down(Schema schema) {
|
||||
schema.drop('todos');
|
||||
}
|
||||
}
|
4
angel_migration/lib/angel_migration.dart
Executable file
4
angel_migration/lib/angel_migration.dart
Executable file
|
@ -0,0 +1,4 @@
|
|||
export 'src/column.dart';
|
||||
export 'src/migration.dart';
|
||||
export 'src/schema.dart';
|
||||
export 'src/table.dart';
|
86
angel_migration/lib/src/column.dart
Executable file
86
angel_migration/lib/src/column.dart
Executable file
|
@ -0,0 +1,86 @@
|
|||
import 'package:angel_orm/angel_orm.dart';
|
||||
|
||||
class MigrationColumn extends Column {
|
||||
final List<MigrationColumnReference> _references = [];
|
||||
bool _nullable;
|
||||
IndexType _index;
|
||||
dynamic _defaultValue;
|
||||
|
||||
@override
|
||||
bool get isNullable => _nullable;
|
||||
|
||||
@override
|
||||
IndexType get indexType => _index;
|
||||
|
||||
@override
|
||||
get defaultValue => _defaultValue;
|
||||
|
||||
List<MigrationColumnReference> get externalReferences =>
|
||||
new List<MigrationColumnReference>.unmodifiable(_references);
|
||||
|
||||
MigrationColumn(ColumnType type,
|
||||
{bool isNullable: true, int length, IndexType indexType, defaultValue})
|
||||
: super(type: type, length: length) {
|
||||
_nullable = isNullable;
|
||||
_index = indexType;
|
||||
_defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
factory MigrationColumn.from(Column column) => column is MigrationColumn
|
||||
? column
|
||||
: new MigrationColumn(column.type,
|
||||
isNullable: column.isNullable,
|
||||
length: column.length,
|
||||
indexType: column.indexType);
|
||||
|
||||
MigrationColumn notNull() => this.._nullable = false;
|
||||
|
||||
MigrationColumn defaultsTo(value) => this.._defaultValue = value;
|
||||
|
||||
MigrationColumn unique() => this.._index = IndexType.unique;
|
||||
|
||||
MigrationColumn primaryKey() => this.._index = IndexType.primaryKey;
|
||||
|
||||
MigrationColumnReference references(String foreignTable, String foreignKey) {
|
||||
var ref = new MigrationColumnReference._(foreignTable, foreignKey);
|
||||
_references.add(ref);
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
class MigrationColumnReference {
|
||||
final String foreignTable, foreignKey;
|
||||
String _behavior;
|
||||
|
||||
MigrationColumnReference._(this.foreignTable, this.foreignKey);
|
||||
|
||||
String get behavior => _behavior;
|
||||
|
||||
StateError _locked() =>
|
||||
new StateError('Cannot override existing "$_behavior" behavior.');
|
||||
|
||||
void onDeleteCascade() {
|
||||
if (_behavior != null) throw _locked();
|
||||
_behavior = 'ON DELETE CASCADE';
|
||||
}
|
||||
|
||||
void onUpdateCascade() {
|
||||
if (_behavior != null) throw _locked();
|
||||
_behavior = 'ON UPDATE CASCADE';
|
||||
}
|
||||
|
||||
void onNoAction() {
|
||||
if (_behavior != null) throw _locked();
|
||||
_behavior = 'ON UPDATE NO ACTION';
|
||||
}
|
||||
|
||||
void onUpdateSetDefault() {
|
||||
if (_behavior != null) throw _locked();
|
||||
_behavior = 'ON UPDATE SET DEFAULT';
|
||||
}
|
||||
|
||||
void onUpdateSetNull() {
|
||||
if (_behavior != null) throw _locked();
|
||||
_behavior = 'ON UPDATE SET NULL';
|
||||
}
|
||||
}
|
6
angel_migration/lib/src/migration.dart
Executable file
6
angel_migration/lib/src/migration.dart
Executable file
|
@ -0,0 +1,6 @@
|
|||
import 'schema.dart';
|
||||
|
||||
abstract class Migration {
|
||||
void up(Schema schema);
|
||||
void down(Schema schema);
|
||||
}
|
15
angel_migration/lib/src/schema.dart
Executable file
15
angel_migration/lib/src/schema.dart
Executable file
|
@ -0,0 +1,15 @@
|
|||
import 'table.dart';
|
||||
|
||||
abstract class Schema {
|
||||
void drop(String tableName, {bool cascade: false});
|
||||
|
||||
void dropAll(Iterable<String> tableNames, {bool cascade: false}) {
|
||||
tableNames.forEach((n) => drop(n, cascade: cascade));
|
||||
}
|
||||
|
||||
void create(String tableName, void callback(Table table));
|
||||
|
||||
void createIfNotExists(String tableName, void callback(Table table));
|
||||
|
||||
void alter(String tableName, void callback(Table table));
|
||||
}
|
46
angel_migration/lib/src/table.dart
Executable file
46
angel_migration/lib/src/table.dart
Executable file
|
@ -0,0 +1,46 @@
|
|||
import 'package:angel_orm/angel_orm.dart';
|
||||
import 'column.dart';
|
||||
|
||||
abstract class Table {
|
||||
MigrationColumn declareColumn(String name, Column column);
|
||||
|
||||
MigrationColumn declare(String name, ColumnType type) =>
|
||||
declareColumn(name, new MigrationColumn(type));
|
||||
|
||||
MigrationColumn serial(String name) => declare(name, ColumnType.serial);
|
||||
|
||||
MigrationColumn integer(String name) => declare(name, ColumnType.int);
|
||||
|
||||
MigrationColumn float(String name) => declare(name, ColumnType.float);
|
||||
|
||||
MigrationColumn numeric(String name) => declare(name, ColumnType.numeric);
|
||||
|
||||
MigrationColumn boolean(String name) => declare(name, ColumnType.boolean);
|
||||
|
||||
MigrationColumn date(String name) => declare(name, ColumnType.date);
|
||||
|
||||
@deprecated
|
||||
MigrationColumn dateTime(String name) => timeStamp(name, timezone: true);
|
||||
|
||||
MigrationColumn timeStamp(String name, {bool timezone: false}) {
|
||||
if (timezone != true) return declare(name, ColumnType.timeStamp);
|
||||
return declare(name, ColumnType.timeStampWithTimeZone);
|
||||
}
|
||||
|
||||
MigrationColumn text(String name) => declare(name, ColumnType.serial);
|
||||
|
||||
MigrationColumn varChar(String name, {int length}) {
|
||||
if (length == null) return declare(name, ColumnType.varChar);
|
||||
return declareColumn(
|
||||
name, new Column(type: ColumnType.varChar, length: length));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MutableTable extends Table {
|
||||
void rename(String newName);
|
||||
void dropColumn(String name);
|
||||
void renameColumn(String name, String newName);
|
||||
void changeColumnType(String name, ColumnType type);
|
||||
void dropNotNull(String name);
|
||||
void setNotNull(String name);
|
||||
}
|
0
angel_migration/mono_pkg.yaml
Executable file
0
angel_migration/mono_pkg.yaml
Executable file
9
angel_migration/pubspec.yaml
Executable file
9
angel_migration/pubspec.yaml
Executable file
|
@ -0,0 +1,9 @@
|
|||
name: angel_migration
|
||||
version: 2.0.0-alpha.1
|
||||
description: Database migration runtime for Angel's ORM. Use this package to define schemas.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/migration
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
dependencies:
|
||||
angel_orm: ^2.0.0-dev
|
13
angel_migration_runner/.gitignore
vendored
Executable file
13
angel_migration_runner/.gitignore
vendored
Executable file
|
@ -0,0 +1,13 @@
|
|||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
.packages
|
||||
.pub/
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
.dart_tool
|
20
angel_migration_runner/CHANGELOG.md
Executable file
20
angel_migration_runner/CHANGELOG.md
Executable file
|
@ -0,0 +1,20 @@
|
|||
# 2.0.0-alpha.4
|
||||
* Include the names of migration classes when running.
|
||||
|
||||
# 2.0.0-alpha.3
|
||||
* Run migrations in reverse on `rollback`.
|
||||
|
||||
# 2.0.0-alpha.2
|
||||
* Run migrations in reverse on `reset`.
|
||||
|
||||
# 2.0.0-alpha.1
|
||||
* Cast Iterables via `.cast()`, rather than `as`.
|
||||
|
||||
# 2.0.0-alpha
|
||||
* Dart 2 update.
|
||||
|
||||
# 1.0.0-alpha+5
|
||||
`Schema#drop` now has a named `cascade` parameter, of type `bool`.
|
||||
|
||||
# 1.0.0-alpha+1
|
||||
* You can now pass a `connected` parameter.
|
21
angel_migration_runner/LICENSE
Executable file
21
angel_migration_runner/LICENSE
Executable file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 The Angel Framework
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
2
angel_migration_runner/README.md
Executable file
2
angel_migration_runner/README.md
Executable file
|
@ -0,0 +1,2 @@
|
|||
# migration
|
||||
A PostgreSQL database migration framework built on Angel's ORM.
|
3
angel_migration_runner/analysis_options.yaml
Executable file
3
angel_migration_runner/analysis_options.yaml
Executable file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
15
angel_migration_runner/example/main.dart
Executable file
15
angel_migration_runner/example/main.dart
Executable file
|
@ -0,0 +1,15 @@
|
|||
import 'package:angel_migration_runner/angel_migration_runner.dart';
|
||||
import 'package:angel_migration_runner/postgres.dart';
|
||||
import 'package:postgres/postgres.dart';
|
||||
import '../../angel_migration/example/todo.dart';
|
||||
|
||||
var migrationRunner = new PostgresMigrationRunner(
|
||||
new PostgreSQLConnection('127.0.0.1', 5432, 'test',
|
||||
username: 'postgres', password: 'postgres'),
|
||||
migrations: [
|
||||
new UserMigration(),
|
||||
new TodoMigration(),
|
||||
],
|
||||
);
|
||||
|
||||
main(List<String> args) => runMigrations(migrationRunner, args);
|
14
angel_migration_runner/example/todo.sql
Executable file
14
angel_migration_runner/example/todo.sql
Executable file
|
@ -0,0 +1,14 @@
|
|||
-- Generated by running `todo.dart`
|
||||
|
||||
CREATE TABLE "users" (
|
||||
"id" serial,
|
||||
"username" varchar(32) UNIQUE,
|
||||
"password" varchar,
|
||||
"account_confirmed" serial
|
||||
);
|
||||
CREATE TABLE "todos" (
|
||||
"id" serial,
|
||||
"user_id" int REFERENCES "user"("id") ON DELETE CASCADE,
|
||||
"text" varchar,
|
||||
"completed" serial
|
||||
);
|
2
angel_migration_runner/lib/angel_migration_runner.dart
Executable file
2
angel_migration_runner/lib/angel_migration_runner.dart
Executable file
|
@ -0,0 +1,2 @@
|
|||
export 'src/cli.dart';
|
||||
export 'src/runner.dart';
|
3
angel_migration_runner/lib/postgres.dart
Executable file
3
angel_migration_runner/lib/postgres.dart
Executable file
|
@ -0,0 +1,3 @@
|
|||
export 'src/postgres/runner.dart';
|
||||
export 'src/postgres/schema.dart';
|
||||
export 'src/postgres/table.dart';
|
70
angel_migration_runner/lib/src/cli.dart
Executable file
70
angel_migration_runner/lib/src/cli.dart
Executable file
|
@ -0,0 +1,70 @@
|
|||
import 'dart:async';
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'runner.dart';
|
||||
|
||||
/// Runs the Angel Migration CLI.
|
||||
Future runMigrations(MigrationRunner migrationRunner, List<String> args) {
|
||||
var cmd = new CommandRunner('migration_runner', 'Executes Angel migrations.')
|
||||
..addCommand(new _UpCommand(migrationRunner))
|
||||
..addCommand(new _RefreshCommand(migrationRunner))
|
||||
..addCommand(new _ResetCommand(migrationRunner))
|
||||
..addCommand(new _RollbackCommand(migrationRunner));
|
||||
return cmd.run(args).then((_) => migrationRunner.close());
|
||||
}
|
||||
|
||||
class _UpCommand extends Command {
|
||||
_UpCommand(this.migrationRunner);
|
||||
|
||||
String get name => 'up';
|
||||
String get description => 'Runs outstanding migrations.';
|
||||
|
||||
final MigrationRunner migrationRunner;
|
||||
|
||||
@override
|
||||
run() {
|
||||
return migrationRunner.up();
|
||||
}
|
||||
}
|
||||
|
||||
class _ResetCommand extends Command {
|
||||
_ResetCommand(this.migrationRunner);
|
||||
|
||||
String get name => 'reset';
|
||||
String get description => 'Resets the database.';
|
||||
|
||||
final MigrationRunner migrationRunner;
|
||||
|
||||
@override
|
||||
run() {
|
||||
return migrationRunner.reset();
|
||||
}
|
||||
}
|
||||
|
||||
class _RefreshCommand extends Command {
|
||||
_RefreshCommand(this.migrationRunner);
|
||||
|
||||
String get name => 'refresh';
|
||||
String get description =>
|
||||
'Resets the database, and then re-runs all migrations.';
|
||||
|
||||
final MigrationRunner migrationRunner;
|
||||
|
||||
@override
|
||||
run() {
|
||||
return migrationRunner.reset().then((_) => migrationRunner.up());
|
||||
}
|
||||
}
|
||||
|
||||
class _RollbackCommand extends Command {
|
||||
_RollbackCommand(this.migrationRunner);
|
||||
|
||||
String get name => 'rollback';
|
||||
String get description => 'Undoes the last batch of migrations.';
|
||||
|
||||
final MigrationRunner migrationRunner;
|
||||
|
||||
@override
|
||||
run() {
|
||||
return migrationRunner.rollback();
|
||||
}
|
||||
}
|
138
angel_migration_runner/lib/src/postgres/runner.dart
Executable file
138
angel_migration_runner/lib/src/postgres/runner.dart
Executable file
|
@ -0,0 +1,138 @@
|
|||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'package:angel_migration/angel_migration.dart';
|
||||
import 'package:postgres/postgres.dart';
|
||||
import '../runner.dart';
|
||||
import '../util.dart';
|
||||
import 'schema.dart';
|
||||
|
||||
class PostgresMigrationRunner implements MigrationRunner {
|
||||
final Map<String, Migration> migrations = {};
|
||||
final PostgreSQLConnection connection;
|
||||
final Queue<Migration> _migrationQueue = new Queue();
|
||||
bool _connected = false;
|
||||
|
||||
PostgresMigrationRunner(this.connection,
|
||||
{Iterable<Migration> migrations = const [], bool connected: false}) {
|
||||
if (migrations?.isNotEmpty == true) migrations.forEach(addMigration);
|
||||
_connected = connected == true;
|
||||
}
|
||||
|
||||
@override
|
||||
void addMigration(Migration migration) {
|
||||
_migrationQueue.addLast(migration);
|
||||
}
|
||||
|
||||
Future _init() async {
|
||||
while (_migrationQueue.isNotEmpty) {
|
||||
var migration = _migrationQueue.removeFirst();
|
||||
var path = await absoluteSourcePath(migration.runtimeType);
|
||||
migrations.putIfAbsent(path.replaceAll("\\", "\\\\"), () => migration);
|
||||
}
|
||||
|
||||
if (!_connected) {
|
||||
await connection.open();
|
||||
_connected = true;
|
||||
}
|
||||
|
||||
await connection.execute('''
|
||||
CREATE TABLE IF NOT EXISTS "migrations" (
|
||||
id serial,
|
||||
batch integer,
|
||||
path varchar,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
''');
|
||||
}
|
||||
|
||||
@override
|
||||
Future up() async {
|
||||
await _init();
|
||||
var r = await connection.query('SELECT path from migrations;');
|
||||
Iterable<String> existing = r.expand((x) => x).cast<String>();
|
||||
List<String> toRun = [];
|
||||
|
||||
migrations.forEach((k, v) {
|
||||
if (!existing.contains(k)) toRun.add(k);
|
||||
});
|
||||
|
||||
if (toRun.isNotEmpty) {
|
||||
var r = await connection.query('SELECT MAX(batch) from migrations;');
|
||||
int curBatch = r[0][0] ?? 0;
|
||||
int batch = curBatch + 1;
|
||||
|
||||
for (var k in toRun) {
|
||||
var migration = migrations[k];
|
||||
var schema = new PostgresSchema();
|
||||
migration.up(schema);
|
||||
print('Bringing up "$k"...');
|
||||
await schema.run(connection).then((_) {
|
||||
return connection.execute(
|
||||
'INSERT INTO MIGRATIONS (batch, path) VALUES ($batch, \'$k\');');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
print('No migrations found to bring up.');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future rollback() async {
|
||||
await _init();
|
||||
|
||||
var r = await connection.query('SELECT MAX(batch) from migrations;');
|
||||
int curBatch = r[0][0] ?? 0;
|
||||
r = await connection
|
||||
.query('SELECT path from migrations WHERE batch = $curBatch;');
|
||||
Iterable<String> existing = r.expand((x) => x).cast<String>();
|
||||
List<String> toRun = [];
|
||||
|
||||
migrations.forEach((k, v) {
|
||||
if (existing.contains(k)) toRun.add(k);
|
||||
});
|
||||
|
||||
if (toRun.isNotEmpty) {
|
||||
for (var k in toRun.reversed) {
|
||||
var migration = migrations[k];
|
||||
var schema = new PostgresSchema();
|
||||
migration.down(schema);
|
||||
print('Bringing down "$k"...');
|
||||
await schema.run(connection).then((_) {
|
||||
return connection
|
||||
.execute('DELETE FROM migrations WHERE path = \'$k\';');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
print('No migrations found to roll back.');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future reset() async {
|
||||
await _init();
|
||||
var r = await connection
|
||||
.query('SELECT path from migrations ORDER BY batch DESC;');
|
||||
Iterable<String> existing = r.expand((x) => x).cast<String>();
|
||||
var toRun = existing.where(migrations.containsKey);
|
||||
|
||||
if (toRun.isNotEmpty) {
|
||||
for (var k in toRun) {
|
||||
var migration = migrations[k];
|
||||
var schema = new PostgresSchema();
|
||||
migration.down(schema);
|
||||
print('Bringing down "$k"...');
|
||||
await schema.run(connection).then((_) {
|
||||
return connection
|
||||
.execute('DELETE FROM migrations WHERE path = \'$k\';');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
print('No migrations found to roll back.');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future close() {
|
||||
return connection.close();
|
||||
}
|
||||
}
|
58
angel_migration_runner/lib/src/postgres/schema.dart
Executable file
58
angel_migration_runner/lib/src/postgres/schema.dart
Executable file
|
@ -0,0 +1,58 @@
|
|||
import 'dart:async';
|
||||
import 'package:angel_migration/angel_migration.dart';
|
||||
import 'package:postgres/postgres.dart';
|
||||
import 'package:angel_migration_runner/src/postgres/table.dart';
|
||||
|
||||
class PostgresSchema extends Schema {
|
||||
final int _indent;
|
||||
final StringBuffer _buf;
|
||||
|
||||
PostgresSchema._(this._buf, this._indent);
|
||||
|
||||
factory PostgresSchema() => new PostgresSchema._(new StringBuffer(), 0);
|
||||
|
||||
Future run(PostgreSQLConnection connection) => connection.execute(compile());
|
||||
|
||||
String compile() => _buf.toString();
|
||||
|
||||
void _writeln(String str) {
|
||||
for (int i = 0; i < _indent; i++) {
|
||||
_buf.write(' ');
|
||||
}
|
||||
|
||||
_buf.writeln(str);
|
||||
}
|
||||
|
||||
@override
|
||||
void drop(String tableName, {bool cascade: false}) {
|
||||
var c = cascade == true ? ' CASCADE' : '';
|
||||
_writeln('DROP TABLE "$tableName"$c;');
|
||||
}
|
||||
|
||||
@override
|
||||
void alter(String tableName, void callback(MutableTable table)) {
|
||||
var tbl = new PostgresAlterTable(tableName);
|
||||
callback(tbl);
|
||||
_writeln('ALTER TABLE "$tableName"');
|
||||
tbl.compile(_buf, _indent + 1);
|
||||
_buf.write(';');
|
||||
}
|
||||
|
||||
void _create(String tableName, void callback(Table table), bool ifNotExists) {
|
||||
var op = ifNotExists ? ' IF NOT EXISTS' : '';
|
||||
var tbl = new PostgresTable();
|
||||
callback(tbl);
|
||||
_writeln('CREATE TABLE$op "$tableName" (');
|
||||
tbl.compile(_buf, _indent + 1);
|
||||
_buf.writeln();
|
||||
_writeln(');');
|
||||
}
|
||||
|
||||
@override
|
||||
void create(String tableName, void callback(Table table)) =>
|
||||
_create(tableName, callback, false);
|
||||
|
||||
@override
|
||||
void createIfNotExists(String tableName, void callback(Table table)) =>
|
||||
_create(tableName, callback, true);
|
||||
}
|
144
angel_migration_runner/lib/src/postgres/table.dart
Executable file
144
angel_migration_runner/lib/src/postgres/table.dart
Executable file
|
@ -0,0 +1,144 @@
|
|||
import 'dart:collection';
|
||||
import 'package:angel_orm/angel_orm.dart';
|
||||
import 'package:angel_migration/angel_migration.dart';
|
||||
|
||||
abstract class PostgresGenerator {
|
||||
static String columnType(MigrationColumn column) {
|
||||
var str = column.type.name;
|
||||
if (column.length != null)
|
||||
return '$str(${column.length})';
|
||||
else
|
||||
return str;
|
||||
}
|
||||
|
||||
static String compileColumn(MigrationColumn column) {
|
||||
var buf = new StringBuffer(columnType(column));
|
||||
|
||||
if (column.isNullable == false) buf.write(' NOT NULL');
|
||||
|
||||
if (column.indexType == IndexType.unique)
|
||||
buf.write(' UNIQUE');
|
||||
else if (column.indexType == IndexType.primaryKey)
|
||||
buf.write(' PRIMARY KEY');
|
||||
|
||||
for (var ref in column.externalReferences) {
|
||||
buf.write(' ' + compileReference(ref));
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
static String compileReference(MigrationColumnReference ref) {
|
||||
var buf = new StringBuffer(
|
||||
'REFERENCES "${ref.foreignTable}"("${ref.foreignKey}")');
|
||||
if (ref.behavior != null) buf.write(' ' + ref.behavior);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class PostgresTable extends Table {
|
||||
final Map<String, MigrationColumn> _columns = {};
|
||||
|
||||
@override
|
||||
MigrationColumn declareColumn(String name, Column column) {
|
||||
if (_columns.containsKey(name))
|
||||
throw new StateError('Cannot redeclare column "$name".');
|
||||
var col = new MigrationColumn.from(column);
|
||||
_columns[name] = col;
|
||||
return col;
|
||||
}
|
||||
|
||||
void compile(StringBuffer buf, int indent) {
|
||||
int i = 0;
|
||||
|
||||
_columns.forEach((name, column) {
|
||||
var col = PostgresGenerator.compileColumn(column);
|
||||
if (i++ > 0) buf.writeln(',');
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
buf.write(' ');
|
||||
}
|
||||
|
||||
buf.write('"$name" $col');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class PostgresAlterTable extends Table implements MutableTable {
|
||||
final Map<String, MigrationColumn> _columns = {};
|
||||
final String tableName;
|
||||
final Queue<String> _stack = new Queue<String>();
|
||||
|
||||
PostgresAlterTable(this.tableName);
|
||||
|
||||
void compile(StringBuffer buf, int indent) {
|
||||
int i = 0;
|
||||
|
||||
while (_stack.isNotEmpty) {
|
||||
var str = _stack.removeFirst();
|
||||
|
||||
if (i++ > 0) buf.writeln(',');
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
buf.write(' ');
|
||||
}
|
||||
|
||||
buf.write(str);
|
||||
}
|
||||
|
||||
if (i > 0) buf.writeln(';');
|
||||
|
||||
i = 0;
|
||||
_columns.forEach((name, column) {
|
||||
var col = PostgresGenerator.compileColumn(column);
|
||||
if (i++ > 0) buf.writeln(',');
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
buf.write(' ');
|
||||
}
|
||||
|
||||
buf.write('ADD COLUMN "$name" $col');
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
MigrationColumn declareColumn(String name, Column column) {
|
||||
if (_columns.containsKey(name))
|
||||
throw new StateError('Cannot redeclare column "$name".');
|
||||
var col = new MigrationColumn.from(column);
|
||||
_columns[name] = col;
|
||||
return col;
|
||||
}
|
||||
|
||||
@override
|
||||
void dropNotNull(String name) {
|
||||
_stack.add('ALTER COLUMN "$name" DROP NOT NULL');
|
||||
}
|
||||
|
||||
@override
|
||||
void setNotNull(String name) {
|
||||
_stack.add('ALTER COLUMN "$name" SET NOT NULL');
|
||||
}
|
||||
|
||||
@override
|
||||
void changeColumnType(String name, ColumnType type, {int length}) {
|
||||
_stack.add('ALTER COLUMN "$name" TYPE ' +
|
||||
PostgresGenerator.columnType(
|
||||
new MigrationColumn(type, length: length)));
|
||||
}
|
||||
|
||||
@override
|
||||
void renameColumn(String name, String newName) {
|
||||
_stack.add('RENAME COLUMN "$name" TO "$newName"');
|
||||
}
|
||||
|
||||
@override
|
||||
void dropColumn(String name) {
|
||||
_stack.add('DROP COLUMN "$name"');
|
||||
}
|
||||
|
||||
@override
|
||||
void rename(String newName) {
|
||||
_stack.add('RENAME TO "$newName"');
|
||||
}
|
||||
}
|
14
angel_migration_runner/lib/src/runner.dart
Executable file
14
angel_migration_runner/lib/src/runner.dart
Executable file
|
@ -0,0 +1,14 @@
|
|||
import 'dart:async';
|
||||
import 'package:angel_migration/angel_migration.dart';
|
||||
|
||||
abstract class MigrationRunner {
|
||||
void addMigration(Migration migration);
|
||||
|
||||
Future up();
|
||||
|
||||
Future rollback();
|
||||
|
||||
Future reset();
|
||||
|
||||
Future close();
|
||||
}
|
14
angel_migration_runner/lib/src/util.dart
Executable file
14
angel_migration_runner/lib/src/util.dart
Executable file
|
@ -0,0 +1,14 @@
|
|||
import 'dart:async';
|
||||
import 'dart:isolate';
|
||||
import 'dart:mirrors';
|
||||
|
||||
Future<String> absoluteSourcePath(Type type) async {
|
||||
var mirror = reflectType(type);
|
||||
var uri = mirror.location.sourceUri;
|
||||
|
||||
if (uri.scheme == 'package') {
|
||||
uri = await Isolate.resolvePackageUri(uri);
|
||||
}
|
||||
|
||||
return uri.toFilePath() + '#' + MirrorSystem.getName(mirror.simpleName);
|
||||
}
|
0
angel_migration_runner/mono_pkg.yaml
Executable file
0
angel_migration_runner/mono_pkg.yaml
Executable file
12
angel_migration_runner/pubspec.yaml
Executable file
12
angel_migration_runner/pubspec.yaml
Executable file
|
@ -0,0 +1,12 @@
|
|||
name: angel_migration_runner
|
||||
version: 2.0.0-alpha.4
|
||||
description: Command-line based database migration runner for Angel's ORM.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/migration
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
dependencies:
|
||||
angel_migration: ^2.0.0-alpha
|
||||
angel_orm: ^2.0.0-dev.2
|
||||
args: ^1.0.0
|
||||
postgres: ">=0.9.5 <2.0.0"
|
0
angel_orm/.gitignore
vendored
Normal file → Executable file
0
angel_orm/.gitignore
vendored
Normal file → Executable file
0
angel_orm/CHANGELOG.md
Normal file → Executable file
0
angel_orm/CHANGELOG.md
Normal file → Executable file
0
angel_orm/LICENSE
Normal file → Executable file
0
angel_orm/LICENSE
Normal file → Executable file
0
angel_orm/README.md
Normal file → Executable file
0
angel_orm/README.md
Normal file → Executable file
0
angel_orm/analysis_options.yaml
Normal file → Executable file
0
angel_orm/analysis_options.yaml
Normal file → Executable file
0
angel_orm/example/main.angel_serialize.g.part
Normal file → Executable file
0
angel_orm/example/main.angel_serialize.g.part
Normal file → Executable file
0
angel_orm/example/main.dart
Normal file → Executable file
0
angel_orm/example/main.dart
Normal file → Executable file
0
angel_orm/example/main.g.dart
Normal file → Executable file
0
angel_orm/example/main.g.dart
Normal file → Executable file
0
angel_orm/example/main.serializer.g.dart
Normal file → Executable file
0
angel_orm/example/main.serializer.g.dart
Normal file → Executable file
0
angel_orm/lib/angel_orm.dart
Normal file → Executable file
0
angel_orm/lib/angel_orm.dart
Normal file → Executable file
0
angel_orm/lib/src/annotations.dart
Normal file → Executable file
0
angel_orm/lib/src/annotations.dart
Normal file → Executable file
0
angel_orm/lib/src/builder.dart
Normal file → Executable file
0
angel_orm/lib/src/builder.dart
Normal file → Executable file
0
angel_orm/lib/src/migration.dart
Normal file → Executable file
0
angel_orm/lib/src/migration.dart
Normal file → Executable file
0
angel_orm/lib/src/query.dart
Normal file → Executable file
0
angel_orm/lib/src/query.dart
Normal file → Executable file
0
angel_orm/lib/src/relations.dart
Normal file → Executable file
0
angel_orm/lib/src/relations.dart
Normal file → Executable file
0
angel_orm/mono_pkg.yaml
Normal file → Executable file
0
angel_orm/mono_pkg.yaml
Normal file → Executable file
0
angel_orm/pubspec.yaml
Normal file → Executable file
0
angel_orm/pubspec.yaml
Normal file → Executable file
0
angel_orm_generator/.gitignore
vendored
Normal file → Executable file
0
angel_orm_generator/.gitignore
vendored
Normal file → Executable file
0
angel_orm_generator/CHANGELOG.md
Normal file → Executable file
0
angel_orm_generator/CHANGELOG.md
Normal file → Executable file
0
angel_orm_generator/LICENSE
Normal file → Executable file
0
angel_orm_generator/LICENSE
Normal file → Executable file
0
angel_orm_generator/README.md
Normal file → Executable file
0
angel_orm_generator/README.md
Normal file → Executable file
0
angel_orm_generator/analysis_options.yaml
Normal file → Executable file
0
angel_orm_generator/analysis_options.yaml
Normal file → Executable file
0
angel_orm_generator/build.yaml
Normal file → Executable file
0
angel_orm_generator/build.yaml
Normal file → Executable file
0
angel_orm_generator/example/main.dart
Normal file → Executable file
0
angel_orm_generator/example/main.dart
Normal file → Executable file
0
angel_orm_generator/example/main.g.dart
Normal file → Executable file
0
angel_orm_generator/example/main.g.dart
Normal file → Executable file
0
angel_orm_generator/example/main.serializer.g.dart
Normal file → Executable file
0
angel_orm_generator/example/main.serializer.g.dart
Normal file → Executable file
0
angel_orm_generator/lib/angel_orm_generator.dart
Normal file → Executable file
0
angel_orm_generator/lib/angel_orm_generator.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/migration_generator.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/migration_generator.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/orm_build_context.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/orm_build_context.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/orm_generator.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/orm_generator.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/readers.dart
Normal file → Executable file
0
angel_orm_generator/lib/src/readers.dart
Normal file → Executable file
0
angel_orm_generator/mono_pkg.yaml
Normal file → Executable file
0
angel_orm_generator/mono_pkg.yaml
Normal file → Executable file
0
angel_orm_generator/pubspec.yaml
Normal file → Executable file
0
angel_orm_generator/pubspec.yaml
Normal file → Executable file
0
angel_orm_generator/test/belongs_to_test.dart
Normal file → Executable file
0
angel_orm_generator/test/belongs_to_test.dart
Normal file → Executable file
0
angel_orm_generator/test/common.dart
Normal file → Executable file
0
angel_orm_generator/test/common.dart
Normal file → Executable file
0
angel_orm_generator/test/enum_and_nested_test.dart
Normal file → Executable file
0
angel_orm_generator/test/enum_and_nested_test.dart
Normal file → Executable file
0
angel_orm_generator/test/example/car_controller.dart
Normal file → Executable file
0
angel_orm_generator/test/example/car_controller.dart
Normal file → Executable file
0
angel_orm_generator/test/has_many_test.dart
Normal file → Executable file
0
angel_orm_generator/test/has_many_test.dart
Normal file → Executable file
0
angel_orm_generator/test/has_map_test.dart
Normal file → Executable file
0
angel_orm_generator/test/has_map_test.dart
Normal file → Executable file
0
angel_orm_generator/test/has_one_test.dart
Normal file → Executable file
0
angel_orm_generator/test/has_one_test.dart
Normal file → Executable file
0
angel_orm_generator/test/many_to_many_test.dart
Normal file → Executable file
0
angel_orm_generator/test/many_to_many_test.dart
Normal file → Executable file
0
angel_orm_generator/test/migrations/author.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/author.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/book.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/book.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/car.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/car.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/foot.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/foot.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/fruit.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/fruit.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/has_car.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/has_car.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/has_map.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/has_map.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/leg.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/leg.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/role.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/role.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/tree.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/tree.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/user.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/user.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/user_role.sql
Normal file → Executable file
0
angel_orm_generator/test/migrations/user_role.sql
Normal file → Executable file
0
angel_orm_generator/test/models/author.dart
Normal file → Executable file
0
angel_orm_generator/test/models/author.dart
Normal file → Executable file
0
angel_orm_generator/test/models/author.g.dart
Normal file → Executable file
0
angel_orm_generator/test/models/author.g.dart
Normal file → Executable file
0
angel_orm_generator/test/models/book.dart
Normal file → Executable file
0
angel_orm_generator/test/models/book.dart
Normal file → Executable file
0
angel_orm_generator/test/models/book.g.dart
Normal file → Executable file
0
angel_orm_generator/test/models/book.g.dart
Normal file → Executable file
0
angel_orm_generator/test/models/car.dart
Normal file → Executable file
0
angel_orm_generator/test/models/car.dart
Normal file → Executable file
0
angel_orm_generator/test/models/car.g.dart
Normal file → Executable file
0
angel_orm_generator/test/models/car.g.dart
Normal file → Executable file
0
angel_orm_generator/test/models/customer.dart
Normal file → Executable file
0
angel_orm_generator/test/models/customer.dart
Normal file → Executable file
0
angel_orm_generator/test/models/customer.g.dart
Normal file → Executable file
0
angel_orm_generator/test/models/customer.g.dart
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue