migrateScheme method
void
migrateScheme(
- StdMap stored,
- StdMap actual
)
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()}",
);
begin();
try {
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]));
}
if (plan.performRevisionUpgrade)
scheme.upgrader?.call(plan.storedRevision!, plan.actualRevision, this);
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 tokenchars {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.expression),
);
}
for (var pi in plan.makePartialIndexes) {
var index = scheme.getPartialIndex(pi);
_database!.execute(formatMakeIndex(makeIndex, pi, index.columns));
}
var escapedTokenChars = escapeSingleQuotes(sqlLiteral(extraTokenChars));
for (var si in plan.makeSearchIndexes) {
var index = scheme.getSearchIndex(si);
_database!.execute(
makeTable.xFormat([
sqlIdentifier(si),
index.columnsDefStr,
escapedTokenChars,
]),
);
}
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({
...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)],
);
commit();
////
} on Exception {
rollback();
rethrow;
}
}