updateDurableObjectBindings function
DO bindingとclass migrationを環境内に追加する。既存設定は保持する。
Implementation
String updateDurableObjectBindings(String source,
{required String binding,
required String className,
required String coordinatorBinding,
required String coordinatorClass,
required String tag}) {
for (final name in [
binding,
className,
coordinatorBinding,
coordinatorClass
]) {
if (!RegExp(r"^[A-Za-z_][A-Za-z0-9_]*$").hasMatch(name)) {
throw ArgumentError("DO識別子が不正です。");
}
}
final objectPattern = RegExp(
r'"durable_objects"\s*:\s*\{\s*"bindings"\s*:\s*(\[[\s\S]*?\])\s*\}');
final existing = objectPattern.firstMatch(source);
if (source.contains('"durable_objects"') && existing == null) {
throw StateError("既存DO設定の構造を解釈できません。");
}
final entries =
existing == null ? <dynamic>[] : jsonDecode(existing.group(1)!) as List;
for (final pair in [
[binding, className],
[coordinatorBinding, coordinatorClass]
]) {
final old = entries.where((e) => e["name"] == pair[0]);
if (old.isNotEmpty &&
old.any(
(e) => e["class_name"] != pair[1] || e["script_name"] != null)) {
throw StateError("既存DO bindingの接続先が異なります。");
}
if (old.isEmpty) {
entries.add({"name": pair[0], "class_name": pair[1]});
}
}
final property = '"durable_objects":{"bindings":${jsonEncode(entries)}}';
source = existing == null
? source.replaceFirst("{", "{$property,")
: source.replaceRange(existing.start, existing.end, property);
final found = _doArrayProperty(source, "migrations");
final migrations = found == null ? <dynamic>[] : found.value;
final desired = {
"tag": tag,
"new_sqlite_classes": [className, coordinatorClass]
};
final same = migrations.where((m) => m["tag"] == tag);
if (same.isNotEmpty &&
same.any((m) => jsonEncode(m) != jsonEncode(desired))) {
throw StateError("migration tagが競合しています。");
}
if (same.isEmpty) {
if (migrations.any((m) => (m["new_sqlite_classes"] as List? ?? [])
.any([className, coordinatorClass].contains))) {
throw StateError("classは別tagで登録済みです。");
}
migrations.add(desired);
}
final migrationProperty = '"migrations":${jsonEncode(migrations)}';
return found == null
? source.replaceFirst("{", "{$migrationProperty,")
: source.replaceRange(found.start, found.end, migrationProperty);
}