ensure method
The collection exists with shape's fields.
Implementation
@override
Future<void> ensure(DVRecordShape shape) async {
final DVDatabaseAdapter database = _database ?? const DVDatabase().adapter;
final Set<String> done = _ensured[database] ??= <String>{};
final String ensured = _shapeKey(shape);
if (done.contains(ensured)) return;
final String table = _collection(shape.collection);
final String columns = <String>[
for (final MapEntry<String, DVFieldType> field in shape.fields.entries)
field.key == shape.key
// MySQL cannot index TEXT without a prefix length, so a text key
// is VARCHAR(255), as the framework's other keyed tables are.
? '${_name(field.key)} ${field.value == DVFieldType.text ? 'VARCHAR(255)' : field.value.sql} PRIMARY KEY'
: '${_name(field.key)} ${field.value.sql}',
].join(', ');
// Through the framework-table check: every column typed, and on
// PostgreSQL and MySQL an integer column an earlier release made 32 bits
// wide is widened, or refused with its plan when it has rows.
await dvEnsureFrameworkTable(
database,
'CREATE TABLE IF NOT EXISTS $table ($columns)',
);
// A table from an earlier release keeps the columns it was made with.
// Selecting a column the table lacks fails on SQLite, PostgreSQL and
// MySQL alike, and ADD COLUMN is the one ALTER all three share -- the
// same repair dartvel db migrate makes for a model.
for (final MapEntry<String, DVFieldType> field in shape.fields.entries) {
final String column = _name(field.key);
try {
await _query('SELECT $column FROM $table LIMIT 0', const <Object?>[]);
} on Object {
await _execute(
'ALTER TABLE $table ADD COLUMN $column ${field.value.sql}',
const <Object?>[],
);
}
}
for (final DVRecordIndex index in shape.indexes) {
final String columns = index.fields.map(_name).join(', ');
try {
await _execute(
'CREATE ${index.unique ? 'UNIQUE ' : ''}INDEX IF NOT EXISTS '
'${_name(index.nameOn(shape.collection))} ON $table ($columns)',
const <Object?>[],
);
} on Object {
// MySQL has no IF NOT EXISTS for an index, and a unique index over
// values that already repeat cannot be made. Either way the caller
// checks the rule on every write, which is what holds it; the index
// is what makes that check fast where the engine agreed to one.
}
}
done.add(ensured);
}