ensure method

  1. @override
Future<void> ensure(
  1. DVRecordShape shape
)
override

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);
}