Add renameColumn method to migrator

This commit is contained in:
Simon Binder 2020-10-11 11:14:02 +02:00
parent fac99e1d6b
commit 9d9658248b
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
5 changed files with 48 additions and 1 deletions

View File

@ -136,6 +136,13 @@ If you're renaming a column in Dart, note that the easiest way is to just rename
`named`: `TextColumn newName => text().named('old_name')()`. That is fully backwards compatible and `named`: `TextColumn newName => text().named('old_name')()`. That is fully backwards compatible and
doesn't require a migration. doesn't require a migration.
If you know your app runs on sqlite 3.25.0 or later (it does if you're using `sqlite3_flutter_libs`),
you can also use the `renameColumn` api in `Migrator`:
```dart
m.renameColumn(yourTable, 'old_column_name', yourTable.newColumn);
```
If you do want to change the actual column name in a table, you can write a `columnTransformer` to If you do want to change the actual column name in a table, you can write a `columnTransformer` to
use an old column with a different name: use an old column with a different name:

View File

@ -12,6 +12,7 @@
- New `generate_values_in_copy_with` [build option](https://moor.simonbinder.eu/docs/advanced-features/builder_options/). - New `generate_values_in_copy_with` [build option](https://moor.simonbinder.eu/docs/advanced-features/builder_options/).
It wraps nullable columns in a `Value` in `copyWith` methods so that they can be set to `null`. It wraps nullable columns in a `Value` in `copyWith` methods so that they can be set to `null`.
- Added `groupConcat`, `cast` and `coalesce` functions to the Dart query builder. - Added `groupConcat`, `cast` and `coalesce` functions to the Dart query builder.
- Added `renameColumn` to `Migrator` to generate `ALTER TABLE RENAME COLUMN` statement.
- Added `VmDatabase.closeExistingInstances()` to close zombie database connections after hot restarts. - Added `VmDatabase.closeExistingInstances()` to close zombie database connections after hot restarts.
## 3.3.1 ## 3.3.1

View File

@ -147,8 +147,10 @@ const sqliteKeywords = {
/// [sqliteKeywords]. /// [sqliteKeywords].
bool isSqliteKeyword(String s) => sqliteKeywords.contains(s.toUpperCase()); bool isSqliteKeyword(String s) => sqliteKeywords.contains(s.toUpperCase());
final _whitespace = RegExp(r'\s');
/// Escapes [s] by wrapping it in backticks if it's an sqlite keyword. /// Escapes [s] by wrapping it in backticks if it's an sqlite keyword.
String escapeIfNeeded(String s) { String escapeIfNeeded(String s) {
if (isSqliteKeyword(s)) return '`$s`'; if (isSqliteKeyword(s) || s.contains(_whitespace)) return '`$s`';
return s; return s;
} }

View File

@ -322,6 +322,34 @@ class Migrator {
return _issueCustomQuery(context.sql); return _issueCustomQuery(context.sql);
} }
/// Changes the name of a column in a [table].
///
/// After renaming a column in a Dart table or a moor file and re-running the
/// generator, you can use [renameColumn] in a migration step to rename the
/// column for existing databases.
///
/// The [table] argument must be set to the table enclosing the changed
/// column. The [oldName] must be set to the old name of the [column] in SQL.
/// For Dart tables, note that moor will transform `camelCase` column names in
/// Dart to `snake_case` column names in SQL.
///
/// __Important compatibility information__: [renameColumn] uses an
/// `ALTER TABLE RENAME COLUMN` internally. Support for that syntax was added
/// in sqlite version 3.25.0, released on 2018-09-15. When you're using
/// Flutter and depend on `sqlite3_flutter_libs`, you're guaranteed to have
/// that version. Otherwise, please ensure that you only use [renameColumn] if
/// you know you'll run on sqlite 3.20.0 or later.
Future<void> renameColumn(
TableInfo table, String oldName, GeneratedColumn column) async {
final context = _createContext();
context.buffer
..write('ALTER TABLE ${escapeIfNeeded(table.$tableName)} ')
..write('RENAME COLUMN ${escapeIfNeeded(oldName)} ')
..write('TO ${column.escapedName};');
return _issueCustomQuery(context.sql);
}
/// Executes the custom query. /// Executes the custom query.
@Deprecated('Use customStatement in the database class') @Deprecated('Use customStatement in the database class')
Future<void> issueCustomQuery(String sql, [List<dynamic> args]) { Future<void> issueCustomQuery(String sql, [List<dynamic> args]) {

View File

@ -101,6 +101,15 @@ void main() {
'is_awesome INTEGER NOT NULL DEFAULT 1 ' 'is_awesome INTEGER NOT NULL DEFAULT 1 '
'CHECK (is_awesome in (0, 1));')); 'CHECK (is_awesome in (0, 1));'));
}); });
test('renames columns', () async {
await db
.createMigrator()
.renameColumn(db.users, 'my name', db.users.name);
verify(mockExecutor
.runCustom('ALTER TABLE users RENAME COLUMN `my name` TO name;'));
});
}); });
test('custom statements', () async { test('custom statements', () async {