replace method

Future<void> replace(
  1. DynamicMap replaceData
)

Replaces all data in the database inside by giving replaceData.

It also compares the data to the data before it was replaced and sends notifications to monitored documents and collections when data is deleted, updated, or added.

After all data has been replaced, a callback to NoSqlDatabase.onSaved can be registered to add a process such as writing the data as a file after saving.

replaceDataを与えることで中のデータベース内のデータをすべて置き換えます。

また置き換える前のデータと比較し、データの削除や更新、追加が起こった場合、監視対象のドキュメントやコレクションに通知を送信します。

すべてのデータの置き換えが終わったあと、NoSqlDatabase.onSavedのコールバックを登録しておくことで保存後にファイルとして書き出すなどの処理を追加することができます。

Implementation

Future<void> replace(DynamicMap replaceData) async {
  await _initialize();
  // ドキュメントリスナーから現在のパスを取得。
  final cache = <String, DynamicMap>{};
  for (final tmp in _documentListeners.entries) {
    final trimPath = tmp.key.trimQuery().trimString("/");
    if (cache.containsKey(trimPath)) {
      continue;
    }
    final paths = trimPath.split("/");
    if (paths.isEmpty) {
      continue;
    }
    final value = data._readFromPath(paths, 0);
    if (value is! Map) {
      continue;
    }
    cache[trimPath] = value.cast<String, dynamic>();
  }
  // コレクションリスナーから現在のパスを取得。
  for (final tmp in _collectionListeners.entries) {
    final trimPath = tmp.key.trimQuery().trimString("/");
    final paths = trimPath.split("/");
    if (paths.isEmpty) {
      continue;
    }
    final value = data._readFromPath(paths, 0);
    if (value is! DynamicMap) {
      continue;
    }
    final entries = value.toList(
      (key, value) {
        if (value is! Map) {
          return null;
        }
        return MapEntry(
          key,
          Map<String, dynamic>.from(value),
        );
      },
    ).removeEmpty();
    for (final e in entries) {
      final path = "$trimPath/${e.key}";
      if (cache.containsKey(path)) {
        continue;
      }
      cache[path] = value.cast<String, dynamic>();
    }
  }
  // 置き換え
  data = replaceData;
  // キャッシュから
  // 以前存在していたもの→存在しなくなった→removed
  // 以前存在していたもの→まだある→modified
  for (final tmp in cache.entries) {
    final trimPath = tmp.key;
    final paths = trimPath.split("/");
    final value = data._readFromPath(paths, 0);
    if (value is! Map) {
      // Removed.
      notifyDocuments(
        trimPath,
        paths.last,
        {},
        ModelUpdateNotificationStatus.removed,
        ModelAdapterDocumentQuery(query: DocumentModelQuery(trimPath)),
      );
    } else {
      // Modified.
      notifyDocuments(
        trimPath,
        paths.last,
        value.cast<String, dynamic>(),
        ModelUpdateNotificationStatus.modified,
        ModelAdapterDocumentQuery(query: DocumentModelQuery(trimPath)),
      );
    }
  }
  // もう一度コレクションリスナーから現在のパスを取得。
  // 以前存在していなかったもの→存在している→added
  for (final tmp in _collectionListeners.entries) {
    final trimPath = tmp.key.trimQuery().trimString("/");
    final paths = trimPath.split("/");
    if (paths.isEmpty) {
      continue;
    }
    final value = data._readFromPath(paths, 0);
    if (value is! DynamicMap) {
      continue;
    }
    final entries = value.toList(
      (key, value) {
        if (value is! Map) {
          return null;
        }
        return MapEntry(
          key,
          Map<String, dynamic>.from(value),
        );
      },
    ).removeEmpty();
    for (final e in entries) {
      final path = "$trimPath/${e.key}";
      if (cache.containsKey(path)) {
        continue;
      }
      // Added.
      final paths = path.split("/");
      notifyDocuments(
        path,
        paths.last,
        e.value.cast<String, dynamic>(),
        ModelUpdateNotificationStatus.added,
        ModelAdapterDocumentQuery(query: DocumentModelQuery(path)),
      );
    }
  }
  await onSaved?.call(this);
}