diff --git a/README.md b/README.md index b56ed28..d9423be 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ Collection of utilities for [absinthe](https://hexdocs.pm/absinthe). [![absinthe_utils in hex.pm](https://img.shields.io/hexpm/v/absinthe_utils?style=flat)][hexpm] + [![absinthe_utils documentation](https://img.shields.io/badge/hex.pm-docs-green.svg?style=flat)][hexdocs] ## Installation @@ -21,7 +22,7 @@ end Documentation can be found in [HexDocs]. -# Main features +# Main Features: - `AbsintheUtils.Middleware.ArgLoader`: Middleware for loading entities in `field` arguments. - `AbsintheUtils.Middleware.DeprecatedArgs`: Middleware for handling deprecated or renamed `field` @@ -30,5 +31,10 @@ Documentation can be found in [HexDocs]. - `AbsintheUtils.Scalars.UUID`: UUID scalar. - `AbsintheUtils.Scalars.StrictNaiveDateTime`: NaiveDatetime that does not accept ISO8601 with offset. +# Code standards / re-usable patterns: + +- `AbsintheUtils.Types.DateFilterTypes`: Date `from`/`to` filters. +- `AbsintheUtils.Types.PaginationTypes`: Pagination params and details. + [hexpm]: https://hex.pm/packages/absinthe_utils [hexdocs]: https://hexdocs.pm/absinthe_utils diff --git a/lib/scalars/strict_naive_datetime.ex b/lib/scalars/strict_naive_datetime.ex index 1c52dd5..0fd7223 100644 --- a/lib/scalars/strict_naive_datetime.ex +++ b/lib/scalars/strict_naive_datetime.ex @@ -21,8 +21,15 @@ defmodule AbsintheUtils.Scalars.StrictNaiveDateTime do **Usage:** - Import the type in your schema `import_types(AbsintheUtils.Scalars.StrictNaiveDateTime)` and you will be able - to use the `:strict_naive_datetime` type. + 1. In your schema, import the type: + ``` + import_types(AbsintheUtils.Scalars.StrictNaiveDateTime) + ``` + + 2. Use the type in your schema: + ``` + field :my_field, :strict_naive_datetime + ``` **Acknowledgements:** diff --git a/lib/types/date_filter_types.ex b/lib/types/date_filter_types.ex new file mode 100644 index 0000000..8ae447f --- /dev/null +++ b/lib/types/date_filter_types.ex @@ -0,0 +1,38 @@ +defmodule AbsintheUtils.Types.DateFilterTypes do + @moduledoc """ + Absinthe input objects for date and datetime filtering. + + Usage: + + 1. Import the required type in your Absinthe schema. + ``` + import_types(AbsintheUtils.Scalars.StrictNaiveDateTime) + import_types(AbsintheUtils.Types.DateFilterTypes) + ``` + + 2. Use the `:date_filter` and `:datetime_filter` input objects in your queries or mutations. + Example: + ``` + input do + field :created_at, :datetime_filter + end + ``` + """ + + use Absinthe.Schema.Notation + + input_object :date_filter do + field(:from, :date) + field(:to, :date) + end + + input_object :datetime_filter do + field(:from, :datetime) + field(:to, :datetime) + end + + input_object :strict_naive_datetime_filter do + field(:from, :strict_naive_datetime) + field(:to, :strict_naive_datetime) + end +end diff --git a/lib/types/pagination_types.ex b/lib/types/pagination_types.ex new file mode 100644 index 0000000..4903f69 --- /dev/null +++ b/lib/types/pagination_types.ex @@ -0,0 +1,38 @@ +defmodule AbsintheUtils.Types.PaginationTypes do + @moduledoc """ + Absinthe types for pagination parameters and details. + + Usage: + 1. Import the required type in your Absinthe schema. + ``` + import_types(AbsintheUtils.Types.PaginationTypes) + ``` + + 2. Use the `:pagination_params` input object and `:pagination_details` object in your queries or mutations. + ``` + input do + field :pagination, :pagination_params + end + ``` + + """ + + use Absinthe.Schema.Notation + + input_object :pagination_params do + field(:page, non_null(:integer)) + field(:page_size, non_null(:integer)) + end + + object :pagination_details do + field(:page_size, non_null(:integer)) + field(:page_number, non_null(:integer)) + field(:total_entries, non_null(:integer)) + field(:total_pages, non_null(:integer)) + end + + enum :sorting_direction do + value(:asc) + value(:desc) + end +end diff --git a/mix.exs b/mix.exs index 5c51778..e048c5d 100644 --- a/mix.exs +++ b/mix.exs @@ -59,7 +59,7 @@ defmodule AbsintheUtils.MixProject do {:absinthe_plug, "~> 1.5"}, {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, {:ecto, ">= 0.0.0", only: [:dev, :test], runtime: false}, - {:ex_doc, "~> 0.29", only: :dev, runtime: false}, + {:ex_doc, "~> 0.38", only: :dev, runtime: false}, {:jason, ">= 1.1.0", only: [:dev, :test], runtime: false} ] end diff --git a/mix.lock b/mix.lock index e8dd148..ff06df2 100644 --- a/mix.lock +++ b/mix.lock @@ -6,7 +6,7 @@ "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, - "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, + "ex_doc": {:hex, :ex_doc, "0.38.4", "ab48dff7a8af84226bf23baddcdda329f467255d924380a0cf0cee97bb9a9ede", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "f7b62346408a83911c2580154e35613eb314e0278aeea72ed7fedef9c1f165b2"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, diff --git a/test/middleware/arg_loader_test.exs b/test/middleware/arg_loader_test.exs index 47f4ab4..2d0cd0b 100644 --- a/test/middleware/arg_loader_test.exs +++ b/test/middleware/arg_loader_test.exs @@ -321,7 +321,7 @@ defmodule AbsintheUtilsTest.Middleware.ArgLoaderTest do load_function: fn _context, input_value -> SampleRepository.get_user(input_value) end, - nil_is_not_found: true + nil_is_not_found: false ] } ) @@ -1410,6 +1410,53 @@ defmodule AbsintheUtilsTest.Middleware.ArgLoaderTest do ) end + test "optional argument passed as nil" do + assert {:ok, + %{ + data: %{ + "complexInput" => %{ + "processedInput" => %{ + "user1" => %{"id" => "2", "name" => "Bob"}, + "user2" => nil + } + } + } + }} === + Absinthe.run( + @query, + TestSchema, + variables: %{ + "complexInputObject" => %{ + "user1Id" => "2", + "user2Id" => nil + } + } + ) + end + + test "optional argument not passed" do + assert {:ok, + %{ + data: %{ + "complexInput" => %{ + "processedInput" => %{ + "user1" => %{"id" => "2", "name" => "Bob"}, + "user2" => nil + } + } + } + }} === + Absinthe.run( + @query, + TestSchema, + variables: %{ + "complexInputObject" => %{ + "user1Id" => "2" + } + } + ) + end + test "not found" do assert {:ok, %{ @@ -1418,7 +1465,7 @@ defmodule AbsintheUtilsTest.Middleware.ArgLoaderTest do extensions: %{code: "NOT_FOUND"}, message: "The entity(ies) provided in the following arg(s), could not be found: " <> - "complexInputObject.user2Id, complexInputObject.user1Id" + "complexInputObject.user1Id" } ] }} =