updateKvVectorCoordinatorBinding function

String updateKvVectorCoordinatorBinding(
  1. String source, {
  2. required String binding,
  3. required String className,
  4. required String tag,
})

KV Vectorize coordinator用DO bindingとclass migrationを冪等に追加する。

Implementation

String updateKvVectorCoordinatorBinding(String source,
    {required String binding, required String className, required String tag}) {
  for (final name in [binding, className]) {
    if (!RegExp(r"^[A-Za-z_][A-Za-z0-9_]*$").hasMatch(name)) {
      throw ArgumentError("KV vector coordinator識別子が不正です。");
    }
  }
  final bindingPattern = RegExp(
      r'"durable_objects"\s*:\s*\{\s*"bindings"\s*:\s*(\[[\s\S]*?\])\s*\}');
  final found = bindingPattern.firstMatch(source);
  final bindings = found == null
      ? <dynamic>[]
      : jsonDecode(found.group(1)!) as List<dynamic>;
  final same = bindings.where((value) => value["name"] == binding);
  if (same.any((value) => value["class_name"] != className)) {
    throw StateError("既存KV coordinator bindingの接続先が異なります。");
  }
  if (same.isEmpty) {
    bindings.add({"name": binding, "class_name": className});
  }
  final property = '"durable_objects":{"bindings":${jsonEncode(bindings)}}';
  source = found == null
      ? source.replaceFirst("{", "{$property,")
      : source.replaceRange(found.start, found.end, property);
  final migrationMatch = _kvArrayProperty(source, "migrations");
  final migrations =
      migrationMatch == null ? <dynamic>[] : migrationMatch.value;
  final desired = {
    "tag": tag,
    "new_sqlite_classes": [className]
  };
  final tagged = migrations.where((value) => value["tag"] == tag);
  if (tagged.any((value) => jsonEncode(value) != jsonEncode(desired))) {
    throw StateError("KV coordinator migration tagが競合しています。");
  }
  if (tagged.isEmpty) {
    migrations.add(desired);
  }
  final migrationProperty = '"migrations":${jsonEncode(migrations)}';
  return migrationMatch == null
      ? source.replaceFirst("{", "{$migrationProperty,")
      : source.replaceRange(
          migrationMatch.start, migrationMatch.end, migrationProperty);
}