Cloud Firestoreのセキュリティルールにかつて存在した`writeFields`を覚えていますか?
覚えてますか?...僕は最近までその存在をすっかり忘れていました。
かれはいつ消えたのか、代わりとなる機能MapDiff
についてお話します。
request.writeFields
かつて存在したCloud Firestoreのセキュリティルールには、かつてrequest.writeFields
という変数がありました。
主にcreate
とupdate
のオペレーションのルールを書くときに、変更を加えようとしているフィールドのオブジェクトを参照することが可能でした。
例えば以下のドキュメントが存在し、
{
name: 'Taro',
age: 29,
country: 'Japan'
}
以下のデータを書き込みupdate
を行う場合、
{
nickName: 'tarotaro',
age: 30
}
request.writeFields
を参照すると以下のオブジェクトが参照できました。
{
nickName: 'tarotaro',
age: 30
}
resource.data
では現在のドキュメントフィールドの状態を、request.resource.data
では書き込みが成功した場合の将来のドキュメントフィールドの状態を取得するため、「何が書き込まれ更新されるのか」という差分を取得するにはこのrequest.writeFields
がとても便利でした。
しかし...
しかし、これは2018年の10月ごろからDeprecatedになり、公式のドキュメントからもリファレンスが削除されました。
しばらくはそのまま使えていたのですが、(僕も正確なタイミングは知らないのですが)おそらく2020年の3月頃にはRemovedされ完全に消えてしまったようです。
- Oct 4, 2018: deprecated
- Mar 4, 2020:
Map.diff()
replaceswriteFields
functionality
と記述があります。
MapDiff
代わりに登場したwriteFields
が消える少し前、2020年2月ごろに、MapDiff
という型と、2つのMap型の変数からMapDiff
型を生成するdiff()
関数が登場しました。
このリリースに関してはリリースノートにてアナウンスがあり、その後Firebaseのブログでも紹介されていました。
新しく登場したMapDiff
により、それまで不可能だったオブジェクトの差分を取得することができるようになりました。
map1.diff(map2) // type of `MapDiff`
MapDiff
の持つ5つの関数
MapDiff
は5つの関数を持ちます。
-
addedKeys()
: 2つのmapを比べて、追加されたフィールドのkeyのセットを返します -
removedKeys()
: 2つのmapを比べて、削除されたフィールドのkeyのセットを返します -
changedKeys()
: 2つのmapを比べて、変更されたフィールドのkeyのセットを返します -
affectedKeys()
: 2つのmapを比べて、影響が生じたフィールドのkeyのセットを返します。つまりaddedKeys() + removedKeys() + updatedKeys()
を表します - unchangedKeys(): 2つのmapを比べて2つに共通して存在しているフィールドのうち、変更を受けなかったフィールドのkeyのセットを返します
書き込み前後での差分を取得する
request.resource.data.diff(resource.data)
これでwriteのオペレーションにて、書き込み前後で生じたdiffの情報が取得できます。
あとは必要に応じてどういう差分が生じたのか、そのkeyのセットを取得してセキュリティルールの構築に役立てます。
request.resource.data.diff(resource.data).addedKeys()
request.resource.data.diff(resource.data).removedKeys()
request.resource.data.diff(resource.data).changedKeys()
request.resource.data.diff(resource.data).affectedKeys()
request.resource.data.diff(resource.data).unchangedKeys()
関数化して扱いやすく
次のように関数化して使用すると記述量も減らせて楽に記述することが可能になります。
function dataDiff() {
return incomingData().diff(existingData());
}
function incomingData() {
return request.resource.data;
}
function existingData() {
return resource.data;
}
allow create: if dataDiff().unchangedKeys() == [...].toSet();
参考
最後に
もし記事が役に立った!参考になった!という場合はLikeしてもらえると嬉しいです 🙌
今後の技術ネタの投稿のモチベーションになります。
サポートもお待ちしています 🐈
Discussion