13
7

More than 1 year has passed since last update.

freezed の toJson で Firebase の createdAt と updatedAt を実現する

Last updated at Posted at 2022-02-19

やりたいこと

freezed (というか内部の json_serializable) では toJson, fromJson 時に変換する関数を定義することが出来る。(以下参照)

それを使って、プロパティにつけるだけで Firebase での updatedAt(書き込み時にタイムスタンプ更新)createdAt(作成時のみタイムスタンプ) の挙動を実現したい。

@freezed
class Group with _$Group {
  const factory Group({
    // 作成日
    @CreatedAtField() DateTime? createdAt,
    // 更新日
    @UpdatedAtField() DateTime? updatedAt,
    // 名前
    required String name,
  }) = _Group;

  const Group._();

  factory Group.fromJson(Map<String, dynamic> json) => _$GroupFromJson(json);
}

要件

toJson 時に以下のような出力になればいい

  • CreatedAtField はその値を見て
    • null の時は FieldValue.serverTimestamp() を出力(初回時のみ書き込み)
    • DateTime の時はその値を Timestamp に変換して出力(初回以降はその値のまま)
  • UpdatedAtField は常に FieldValue.serverTimestamp() を出力(毎回書き込み)

実装

以下のようなアノテーションを作れば OK

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

// プロパティにつけると変換時、そのプロパティが null なら FieldValue.serverTimestamp() に変換する
// これにより、クライアント側で作成したときのみサーバー側で時間が書き込まれるため、createdAt の挙動になる
class CreatedAtField implements JsonConverter<DateTime?, dynamic> {
  const CreatedAtField();

  @override
  DateTime? fromJson(dynamic timestamp) {
    timestamp as Timestamp?;
    return timestamp?.toDate();
  }

  // nullの時は toJson 時 FieldValue.serverTimestamp() を返すことで、createdAt の挙動になる
  @override
  dynamic toJson(DateTime? dateTime) {
    if (dateTime == null) return FieldValue.serverTimestamp();
    return dateTime;
  }
}

// プロパティにつけると変換時、必ず FieldValue.serverTimestamp() に変換される
// これにより、updatedAt の挙動になる
class UpdatedAtField implements JsonConverter<DateTime?, dynamic> {
  const UpdatedAtField();

  @override
  DateTime? fromJson(dynamic timestamp) {
    timestamp as Timestamp?;
    return timestamp?.toDate();
  }

  @override
  FieldValue toJson(DateTime? date) {
    return FieldValue.serverTimestamp();
  }
}

これで以下のように使えるようになりました!

// 作成日
@CreatedAtField() DateTime? createdAt,
// 更新日
@UpdatedAtField() DateTime? updatedAt,
13
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7