From b671f4ec3e8d6cfcaa8119e950b1e031aafa3cf1 Mon Sep 17 00:00:00 2001 From: Brian Alexander Date: Sat, 11 May 2024 14:21:38 -0600 Subject: [PATCH] perspectives --- lib/sanity.ex | 16 +++--- test/integration_test.exs | 100 +++++++++++++++++++++++--------------- test/sanity_test.exs | 46 ++++++------------ 3 files changed, 84 insertions(+), 78 deletions(-) diff --git a/lib/sanity.ex b/lib/sanity.ex index b534aef..c3e4827 100644 --- a/lib/sanity.ex +++ b/lib/sanity.ex @@ -281,11 +281,11 @@ defmodule Sanity do doc: ~S'Number of results to fetch per request. The Sanity docs say: "In the general case, we recommend a batch size of no more than 5,000. If your documents are very large, a smaller batch size is better."' ], - drafts: [ - type: {:in, [:exclude, :include, :only]}, - default: :exclude, + perspective: [ + type: :string, + default: "published", doc: - "Use `:exclude` to exclude drafts, `:include` to include drafts along with published docs, or `:only` to fetch drafts and not published documents." + ~S'Perspective to use. Common values are `"published"`, `"previewDrafts"`, and `"raw"`. See the [docs](https://www.sanity.io/docs/perspectives) for details.' ], projection: [ type: :string, @@ -355,14 +355,14 @@ defmodule Sanity do defp stream_page(opts, page_query) do query = - [opts[:query], drafts_query(opts[:drafts]), page_query] + [opts[:query], page_query] |> Enum.filter(& &1) |> Enum.map(&"(#{&1})") |> Enum.join(" && ") results = "*[#{query}] | order(_id) [0..#{opts[:batch_size] - 1}] #{opts[:projection]}" - |> query(opts[:variables]) + |> query(opts[:variables], perspective: opts[:perspective]) |> opts[:request_module].request!(opts[:request_opts]) |> result!() @@ -373,10 +373,6 @@ defmodule Sanity do end end - defp drafts_query(:exclude), do: "!(_id in path('drafts.**'))" - defp drafts_query(:include), do: nil - defp drafts_query(:only), do: "_id in path('drafts.**')" - @doc """ Generates a request for the [asset endpoint](https://www.sanity.io/docs/http-api-assets). diff --git a/test/integration_test.exs b/test/integration_test.exs index fe09417..2e1406c 100644 --- a/test/integration_test.exs +++ b/test/integration_test.exs @@ -127,45 +127,69 @@ defmodule Sanity.MutateIntegrationTest do |> Sanity.request(Keyword.put(config, :cdn, true)) end - test "stream", %{config: config} do - type = "streamItem#{:rand.uniform(1_000_000)}" - - Sanity.mutate(Enum.map(1..5, &%{create: %{_type: type, title: "item #{&1}"}})) - |> Sanity.request!(config) - - Sanity.mutate([ - %{create: %{_id: "drafts.a-#{:rand.uniform(1_000_000)}", _type: type, title: "my draft"}} - ]) - |> Sanity.request!(config) + describe "stream" do + test "with multiple batches", %{config: config} do + type = "streamItem#{:rand.uniform(1_000_000)}" + + Sanity.mutate(Enum.map(1..5, &%{create: %{_type: type, title: "item #{&1}"}})) + |> Sanity.request!(config) + + Sanity.mutate([ + %{create: %{_id: "drafts.a-#{:rand.uniform(1_000_000)}", _type: type, title: "my draft"}} + ]) + |> Sanity.request!(config) + + assert [ + %{"title" => "item 1"}, + %{"title" => "item 2"}, + %{"title" => "item 3"}, + %{"title" => "item 4"}, + %{"title" => "item 5"} + ] = + Sanity.stream(query: "_type == '#{type}'", batch_size: 2, request_opts: config) + |> Enum.to_list() + |> Enum.sort_by(& &1["title"]) + end - assert [ - %{"title" => "item 1"}, - %{"title" => "item 2"}, - %{"title" => "item 3"}, - %{"title" => "item 4"}, - %{"title" => "item 5"} - ] = - Sanity.stream(query: "_type == '#{type}'", batch_size: 2, request_opts: config) - |> Enum.to_list() - |> Enum.sort_by(& &1["title"]) - - # Only draft documents - assert [%{"title" => "my draft"}] = - Sanity.stream(query: "_type == '#{type}'", drafts: :only, request_opts: config) - |> Enum.to_list() - - # Include both drafts and published documents - assert [ - %{"title" => "item 1"}, - %{"title" => "item 2"}, - %{"title" => "item 3"}, - %{"title" => "item 4"}, - %{"title" => "item 5"}, - %{"title" => "my draft"} - ] = - Sanity.stream(query: "_type == '#{type}'", drafts: :include, request_opts: config) - |> Enum.to_list() - |> Enum.sort_by(& &1["title"]) + test "with perspectives", %{config: config} do + type = "streamItem#{:rand.uniform(1_000_000)}" + id = "my-id-#{:rand.uniform(1_000_000)}" + + Sanity.mutate([ + %{create: %{_id: id, _type: type, title: "published item"}}, + %{create: %{_id: "drafts.#{id}", _type: type, title: "draft item"}} + ]) + |> Sanity.request!(config) + + # Published (default) + assert [%{"_id" => ^id, "title" => "published item"}] = + Sanity.stream( + query: "_type == '#{type}'", + request_opts: config + ) + |> Enum.to_list() + + # Preview drafts + assert [%{"_id" => ^id, "title" => "draft item"}] = + Sanity.stream( + query: "_type == '#{type}'", + perspective: "previewDrafts", + request_opts: config + ) + |> Enum.to_list() + + # Raw + assert [ + %{"_id" => "drafts." <> ^id, "title" => "draft item"}, + %{"_id" => ^id, "title" => "published item"} + ] = + Sanity.stream( + query: "_type == '#{type}'", + perspective: "raw", + request_opts: config + ) + |> Enum.to_list() + end end test "timeout error", %{config: config} do diff --git a/test/sanity_test.exs b/test/sanity_test.exs index 277b0cb..1c3b53e 100644 --- a/test/sanity_test.exs +++ b/test/sanity_test.exs @@ -258,7 +258,8 @@ defmodule SanityTest do test "opts[:drafts] == :exclude (default)" do Mox.expect(MockSanity, :request!, fn %Request{query_params: query_params}, _ -> assert query_params == %{ - "query" => "*[(!(_id in path('drafts.**')))] | order(_id) [0..999] { ... }" + "query" => "*[] | order(_id) [0..999] { ... }", + "perspective" => "published" } %Response{body: %{"result" => [%{"_id" => "a"}]}} @@ -267,40 +268,24 @@ defmodule SanityTest do Sanity.stream(request_module: MockSanity, request_opts: @request_config) |> Enum.to_list() end - test "opts[:drafts] == :include" do + test "opts[:perspective]" do Mox.expect(MockSanity, :request!, fn %Request{query_params: query_params}, _ -> assert query_params == %{ - "query" => "*[] | order(_id) [0..999] { ... }" + "query" => "*[] | order(_id) [0..999] { ... }", + "perspective" => "previewDrafts" } %Response{body: %{"result" => [%{"_id" => "a"}]}} end) - Sanity.stream(drafts: :include, request_module: MockSanity, request_opts: @request_config) + Sanity.stream( + perspective: "previewDrafts", + request_module: MockSanity, + request_opts: @request_config + ) |> Enum.to_list() end - test "opts[:drafts] == :only" do - Mox.expect(MockSanity, :request!, fn %Request{query_params: query_params}, _ -> - assert query_params == %{ - "query" => "*[(_id in path('drafts.**'))] | order(_id) [0..999] { ... }" - } - - %Response{body: %{"result" => [%{"_id" => "a"}]}} - end) - - Sanity.stream(drafts: :only, request_module: MockSanity, request_opts: @request_config) - |> Enum.to_list() - end - - test "opts[:drafts] == :invalid" do - assert_raise NimbleOptions.ValidationError, - "invalid value for :drafts option: expected one of [:exclude, :include, :only], got: :invalid", - fn -> - Sanity.stream(drafts: :invalid, request_opts: @request_config) - end - end - test "opts[:variables] invalid" do assert_raise NimbleOptions.ValidationError, "invalid value for :variables option: expected map, got: []", @@ -318,7 +303,8 @@ defmodule SanityTest do test "pagination" do Mox.expect(MockSanity, :request!, fn %Request{query_params: query_params}, _ -> assert query_params == %{ - "query" => "*[(!(_id in path('drafts.**')))] | order(_id) [0..4] { ... }" + "query" => "*[] | order(_id) [0..4] { ... }", + "perspective" => "published" } results = Enum.map(1..5, &%{"_id" => "doc-#{&1}"}) @@ -327,8 +313,8 @@ defmodule SanityTest do Mox.expect(MockSanity, :request!, fn %Request{query_params: query_params}, _ -> assert query_params == %{ - "query" => - "*[(!(_id in path('drafts.**'))) && (_id > $pagination_last_id)] | order(_id) [0..4] { ... }", + "query" => "*[(_id > $pagination_last_id)] | order(_id) [0..4] { ... }", + "perspective" => "published", "$pagination_last_id" => "\"doc-5\"" } @@ -357,8 +343,8 @@ defmodule SanityTest do Mox.expect(MockSanity, :request!, fn %Request{query_params: query_params}, _request_opts -> assert query_params == %{ "$type" => "\"page\"", - "query" => - "*[(_type == $type) && (!(_id in path('drafts.**')))] | order(_id) [0..999] { _id, title }" + "query" => "*[(_type == $type)] | order(_id) [0..999] { _id, title }", + "perspective" => "published" } %Response{body: %{"result" => [%{"_id" => "a", "title" => "home"}]}}