migrateScheme method
- @protected
- StdMap stored,
- StdMap actual
Migrates a scheme from the stored overall version to the actual one.
Implementation
@protected
void migrateScheme(StdMap stored, StdMap actual) {
var plan = SchemeMigrationPlan(stored, actual, scheme);
log.info(
"Scheme ${stored.isEmpty ? "creation" : "migration"} "
"plan:\n${plan.dump()}",
);
bool afterCalled = false;
try {
if (plan.performRevisionUpgrade)
scheme.upgrader?.before(
plan.storedRevision!,
plan.actualRevision,
this,
);
var dropTable = MessageFormat("DROP TABLE {0}");
var dropIndex = MessageFormat("DROP INDEX {0}");
var dropColumn = MessageFormat(
"ALTER TABLE $tableMapping DROP COLUMN {0}",
);
for (var si in plan.dropSearchIndexes)
_database!.execute(dropTable.xFormat([sqlIdentifier(si)]));
for (var pi in plan.dropPartialIndexes)
_database!.execute(dropIndex.xFormat([sqlIdentifier(pi)]));
for (var vc in plan.dropVirtualColumns.xToList().reversed)
_database!.execute(dropColumn.xFormat([sqlIdentifier(vc)]));
if (plan.dropKindColumnAndIndex) {
_database!.execute(dropIndex.xFormat([columnKind]));
_database!.execute(dropColumn.xFormat([columnKind]));
}
var makeColumn = MessageFormat(
"ALTER TABLE $tableMapping ADD COLUMN {0} AS ({1}) VIRTUAL",
);
var makeIndex = MessageFormat(
"CREATE INDEX {0} ON $tableMapping ({1}) WHERE {2}",
);
var makeTable = MessageFormat(
"CREATE VIRTUAL TABLE {0} "
"USING FTS5($columnKeyId UNINDEXED, {1}, tokenize = "
"'unicode61 remove_diacritics 2 categories {2}')",
);
if (plan.makeKindColumnAndIndex) {
_database!.execute(
formatMakeColumn(
makeColumn,
columnKind,
[],
SqlJX(plan.actualKindPath),
),
);
_database!.execute(
formatMakeIndex(makeIndex, columnKind, [IndexColumn(columnKind)]),
);
}
for (var vc in plan.makeVirtualColumns) {
var column = scheme.getVirtualColumn(vc);
_database!.execute(
formatMakeColumn(makeColumn, vc, column.kinds, column.sql),
);
}
for (var pi in plan.makePartialIndexes) {
var index = scheme.getPartialIndex(pi);
_database!.execute(formatMakeIndex(makeIndex, pi, index.columns));
}
var escapedCategories = escapeSingleQuotes(sqlLiteral(tokenCategories));
for (var si in plan.makeSearchIndexes) {
var index = scheme.getSearchIndex(si);
_database!.execute(
makeTable.xFormat([
sqlIdentifier(si),
index.updater.columnsDdlSql(),
escapedCategories,
]),
);
}
scheme.initializeUpdatersLookup(this);
if (plan.makeSearchIndexes.isNotEmpty) {
var where = SqlI(columnKind).equal(SqlP("@$columnKind"));
QueryId qid = prepare(
columns: [SqlJT(SqlI(columnValue))],
where: where,
limit: queryDefaultLimit,
);
finalize(() {
for (var si in plan.makeSearchIndexes) {
var index = scheme.getSearchIndex(si);
for (var MapEntry(key: kind, value: srGetter)
in index.getters.entries) {
QueryRowPosition? start;
do {
QueryRows rows = query(
qid,
parameters: {"@$columnKind": kind},
start: start,
);
for (var row in rows) {
FullId id = row.id;
SearchRow searchRow = srGetter(
jsonDecode(row.columns.single! as String) as Object,
);
index.updater.insert.executeWith(
StatementParameters.named({
...index.updater.searchRowToParameters(searchRow),
":$columnRowId": id.rowid,
":$columnKeyId": id.keyid,
}),
);
if (!updated())
log.severe(
"Search index migration failed for rowid ${id.rowid}, "
"kind \"$kind\", index name \"${index.name}\"",
);
}
start = rows.length == queryDefaultLimit
? queryRowGetPosition(rows.last)
: null;
} while (start != null);
}
}
}, finale: () => free(qid));
}
_database!.execute(
"INSERT OR REPLACE INTO $tableScheme "
"($columnKeyId, $columnValue) VALUES (?, jsonb(?))",
[keyDefinition, jsonEncode(actual)],
);
afterCalled = true;
if (plan.performRevisionUpgrade) ////
scheme.upgrader?.after(success: true);
////
} catch (_) {
try {
if (!afterCalled && plan.performRevisionUpgrade)
scheme.upgrader?.after(success: false);
} catch (x, st) {
log.severe("SQLite.migrateScheme|after(success: false)", x, st);
}
rethrow;
}
}