NotionRubyMapping に List data source templates を実装(2) : hkob の雑記録 (378)

はじめに

hkob の雑記録の第378回目(通算775日目)は、NotionRubyMapping に List data source templates を実装してみます。昨日はテストまで執筆したので、今日は Template object からテスト・実装していきます。

Template object のテストと実装

まず、テンプレートオブジェクトのテストを記載するために、template_object.json ファイルを作成しておきます。

{
  "id": "88f4a106-b84b-4d35-9c2d-256bcd55901f",
  "name": "template",
  "is_default": true
}

これを使ったテストを作成します。基本的に create_from_json だけ動作すればいいと思います。

# frozen_string_literal: true

module NotionRubyMapping
  RSpec.describe TemplateObject do
    tc = TestConnection.instance
    template_json = tc.read_json "template_object"

    describe "create from json" do
      let(:target) { TemplateObject.new json: template_json }

      it_behaves_like "property values json", {
        "id" => "88f4a106-b84b-4d35-9c2d-256bcd55901f",
        "name" => "template",
        "is_default" => true,
      }
      it { expect(target.id).to eq "88f4a106-b84b-4d35-9c2d-256bcd55901f" }
      it { expect(target.name).to eq "template" }
      it { expect(target.is_default).to eq true }
    end
  end
end

これが通過するように TemplateObject を実装します。

module NotionRubyMapping
  class TemplateObject
    def initialize(json: json)
      @id = json["id"]
      @name = json["name"]
      @is_default = json["is_default"]
    end
    attr_reader :id, :name, :is_default

    def property_values_json
      {
        "id" => @id,
        "name" => @name,
        "is_default" => @is_default
      }
    end
  end
end

DataSource#templates の実装

昨日、DataSource#templates のテストを記述しました。こちらは API 呼び出しをして、返却された JSON から List object を作成すればいいので以下のようになります。

    # @param [Integer] page_size
    # @return [NotionRubyMapping::List] List of Template object
    def templates(page_size: nil)
      json = @nc.list_data_source_templates_request(id, page_size: page_size)
      List.new type: "template", value: id, json: json, query: Query.new
    end

list_data_source_templates_request は API 呼び出しをするだけです。query_data_source などと異なり、この API は GET なので、payload で指定することができないためパスに含める必要があります。

    # @param [String] data_source_id
    # @param [Integer] page_size
    # @param [String] start_cursor
    # @return [Hash] response hash
    def list_data_source_templates_request(data_source_id, page_size: nil, start_cursor: nil)
      options = []
      options << "page_size=#{page_size}" if page_size
      options << "start_cursor=#{start_cursor}" if start_cursor
      option_str = options.empty? ? "" : "?" + options.join("&")
      request :get, list_data_source_templates_path(data_source_id, option_str)
    end

昨日、list_data_source_templates_path を作成してしまいましたが、引数が増えたので、テストを追加します。

    describe "list_data_source_templates_path" do
      it { expect(nc.list_data_source_templates_path("ABC")).to eq "v1/data_sources/ABC/templates" }

      it {
        expect(nc.list_data_source_templates_path("DEF",
                                                  "?page_size=1")).to eq "v1/data_sources/DEF/templates?page_size=1"
      }
    end

実装も修正します。

    # @param [String] data_source_id
    # @param [String] options
    # @return [String] path
    def list_data_source_templates_path(data_source_id, options = "")
      "v1/data_sources/#{data_source_id}/templates#{options}"
    end

WebMock の stub も変更になるので修正します。

    def list_data_source_templates
      generate_stubs_sub :get, __method__, :list_data_source_templates_path, {
        no_limit: [DATA_SOURCE_ID, 200],
        limit_1: [[DATA_SOURCE_ID, "?page_size=1"], 200],
        next_1: [[DATA_SOURCE_ID, "?start_cursor=2e5d8e4e-98ab-808f-8c3a-f0819e3b3567"], 200],
      }
    end

ここまでで、無事に API 呼び出しは実行でき、response までは取得できました。あとは、response から List object が生成する部分を実装すればよいことになります。

  1) NotionRubyMapping::DataSource templates when no limit is expected to eq 2
     Failure/Error: it { expect(templates.count).to eq 2 }

       expected: 2
            got: 0

       (compared using ==)
     # ./spec/notion_ruby_mapping/blocks/data_source_spec.rb:59:in 'block (4 levels) in <module:NotionRubyMapping>'

response から List object を生成

まず、List の initialize で template type に対応するようにします。@template の中には Data source の id が保持されます。

    def initialize(json: nil, id: nil, type: nil, value: nil, query: nil)
      super(json: json, id: id)
      @has_more = @json["has_more"]
      @load_all_contents = !@has_more

      case type
      when "comment_parent"
        @comment_parent = value
      when "data_source"
        @data_source = value
      when "parent"
        @parent = value
      when "property"
        @property = value
      when "user_object"
        @user_object = value
      when "search"
        @search = value
      when "template"
        @template = value
      end
      @query = query
      @index = 0
      @has_content = true
    end

通常の List object では results キーに情報が入っていますが、template の場合は templates キーに含まれています。このため、results メソッドで場合分けをすればよさそうです。

    # @return [Hash]
    def results
      @json[@template ? "templates" : "results"]
    end

あとは、each で TemplateObject を作成する部分だけです。each_sub の部分で Pagination の部分は汎化しておいたので、次の query 呼び出しと一つ一つのオブジェクト生成のブロック呼び出しだけ指定するだけで済みました。

    # @return [NotionRubyMapping::List, Enumerator]
    # @see <https://www.notion.so/hkob/List-9a0b32335e0d48849a785ce5e162c760#12e1c261a0944a4095776b7515bef4a1>
    def each(&block)
      return enum_for(:each) if block.nil?

      if @parent
     (中略)
      elsif @template
        each_sub base: @template,
                 query: -> { @nc.list_data_source_templates_request @template, start_cursor: @query.start_cursor },
                 create_object: ->(json) { TemplateObject.new json: json },
                 &block
      end
      self
    end

これでテストは無事に全て通過しました。全て読めた場合も、Pagination した場合も全てのテンプレートが無事に取得できていることがわかります。

  templates
    when no limit
      is expected to eq 2
      is expected to eq ["template", "another template"]
      is expected to eq ["88f4a106-b84b-4d35-9c2d-256bcd55901f", "2e5d8e4e-98ab-808f-8c3a-f0819e3b3567"]
    when limit 1
      is expected to eq 2
      is expected to eq ["template", "another template"]
      is expected to eq ["88f4a106-b84b-4d35-9c2d-256bcd55901f", "2e5d8e4e-98ab-808f-8c3a-f0819e3b3567"]

おわりに

List data source templates API は List object を返却しませんが、内容的には List object と同様の Pagination をするので、NotionRubyMapping では List object に集約してしまいました。そのおかげで実装はほとんど修正の必要がなく、記述することができました。

hkob.notion.site