Реалізація міграції схеми бази даних (SQLite Migration) в мобільних додатках
Пряма робота з SQLite без ORM-прошарку — React Native, Flutter, Capacitor, або нативний Android/iOS з SQLiteOpenHelper. Тут немає автоматичної інфраструктури міграцій — тільки SQL та ваші руки. Головна пастка: SQLite крайньо обмежений у ALTER TABLE, і на Android API < 29 доступних операцій ще менше.
SQLiteOpenHelper (Android) — базова механіка
class AppDatabase(context: Context) : SQLiteOpenHelper(context, "app.db", null, DB_VERSION) {
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(CREATE_TABLE_TRANSACTIONS)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
if (oldVersion < 2) migrate1to2(db)
if (oldVersion < 3) migrate2to3(db)
if (oldVersion < 4) migrate3to4(db)
}
}
Це ланцюг if-перевірок, а не when чи switch. Користувач із версією 1 послідовно пройде всі міграції до поточної. Пропускати версії не можна — тільки додавати нові блоки.
Flutter: sqflite та drift
sqflite — найпопулярніший SQLite-пакет для Flutter. Міграції через onUpgrade:
final db = await openDatabase(
'app.db',
version: 3,
onCreate: (db, version) async {
await db.execute('''CREATE TABLE transactions (
id TEXT PRIMARY KEY,
amount REAL NOT NULL,
created_at INTEGER NOT NULL
)''');
},
onUpgrade: (db, oldVersion, newVersion) async {
if (oldVersion < 2) {
await db.execute('ALTER TABLE transactions ADD COLUMN category TEXT DEFAULT ""');
}
if (oldVersion < 3) {
// Пересоздання таблиці для переименування колонки
await _recreateTransactionsTable(db);
}
},
);
drift (раніше moor) — типізований ORM поверх SQLite для Flutter/Dart з декларативними міграціями. Генерує код зі схеми, має Migrator з createTable, addColumn, renameColumn. Для проектів середнього розміру — переважніше sqflite.
React Native: react-native-sqlite-storage / expo-sqlite
expo-sqlite з SQLite 3.39+:
const db = SQLite.openDatabase('app.db');
db.transaction(tx => {
tx.executeSql('PRAGMA user_version', [], (_, result) => {
const version = result.rows.item(0).user_version;
if (version < 1) {
tx.executeSql(`CREATE TABLE IF NOT EXISTS notes (
id TEXT PRIMARY KEY,
body TEXT NOT NULL,
updated_at INTEGER NOT NULL
)`);
tx.executeSql('PRAGMA user_version = 1');
}
if (version < 2) {
tx.executeSql('ALTER TABLE notes ADD COLUMN title TEXT DEFAULT ""');
tx.executeSql('PRAGMA user_version = 2');
}
});
});
PRAGMA user_version — вбудований механізм SQLite для зберігання версії схеми.
Пересоздання таблиці: універсальний рецепт
SQLite підтримує тільки ADD COLUMN із всіх ALTER TABLE операцій (до 3.35.0). Переименувати колонку, видалити її, змінити тип — лише через пересоздання:
BEGIN TRANSACTION;
CREATE TABLE transactions_new (
id TEXT NOT NULL PRIMARY KEY,
amount REAL NOT NULL,
description TEXT NOT NULL DEFAULT '', -- переименовано з 'note'
created_at INTEGER NOT NULL
);
INSERT INTO transactions_new (id, amount, description, created_at)
SELECT id, amount, note, created_at FROM transactions;
DROP TABLE transactions;
ALTER TABLE transactions_new RENAME TO transactions;
-- Відновлюємо індекси
CREATE INDEX idx_transactions_created_at ON transactions(created_at);
COMMIT;
Все всередину транзакції — якщо щось пішло не так, дані не потеряні. Відновлення індексів після RENAME — обов'язково: вони не переносяться автоматично.
Зовнішні ключі при пересоздані
Якщо є зовнішні ключі — тимчасово вимикаємо їх під час пересоздання:
PRAGMA foreign_keys = OFF;
BEGIN TRANSACTION;
-- ... пересоздання таблиці ...
COMMIT;
PRAGMA foreign_keys = ON;
PRAGMA integrity_check;
PRAGMA integrity_check після — переконуємось, що дані консистентні.
Тестування
Тестування міграцій SQLite без ORM — ручне. Потрібен тест, який:
- Відкриває базу версії N (із заготовленого файлу або створює програмно)
- Вставляє тестові дані
- Викликає
onUpgradeдо версії N+1 - Перевіряє структуру та дані через
PRAGMA table_info
Для Flutter/drift — SchemaVerifier з пакету drift_dev.
Обсяг роботи
- Аналіз поточної схеми та версії
- Написання SQL-міграцій для всіх змін
- Трансакційне пересоздання таблиць при необхідності
- Відновлення індексів та зовнішніх ключів
- Тести з реальними даними
Строки
Прості ADD COLUMN міграції: 0,5 дня. Структурні зміни (пересоздання таблиць, зовнішні ключі, індекси) з тестами: 1–2 дні.







