From a3d359302892b66169c72e66bc32e689df14c3ae Mon Sep 17 00:00:00 2001 From: James Harton Date: Wed, 26 Oct 2022 10:43:45 +1300 Subject: [PATCH] improvement: update CI to staple-actions and get (most) checks passing. --- .doctor.exs | 2 +- .formatter.exs | 4 +- .github/workflows/elixir_lib.yml | 154 ++++++++++++++++++++++++++ .github/workflows/mix_credo.yml | 36 ------ .github/workflows/mix_doctor.yml | 36 ------ .github/workflows/mix_format.yml | 37 ------- .github/workflows/mix_git_ops.yml | 82 -------------- .github/workflows/mix_hex_audit.yml | 35 ------ .github/workflows/mix_test.yml | 54 --------- .gitignore | 2 + LICENSE | 18 +++ README.md | 59 ++++++++-- lib/ash_gen_server/application.ex | 3 +- lib/ash_gen_server/data_layer.ex | 22 ++-- lib/ash_gen_server/query.ex | 8 +- lib/ash_gen_server/registry.ex | 4 +- lib/ash_gen_server/server.ex | 4 +- mix.exs | 33 +++++- mix.lock | 2 + test/support/time_travel.ex | 2 +- test/support/time_travel/character.ex | 22 ++-- test/support/time_travel/machine.ex | 34 +++--- test/support/time_travel/registry.ex | 4 +- 23 files changed, 309 insertions(+), 348 deletions(-) create mode 100644 .github/workflows/elixir_lib.yml delete mode 100644 .github/workflows/mix_credo.yml delete mode 100644 .github/workflows/mix_doctor.yml delete mode 100644 .github/workflows/mix_format.yml delete mode 100644 .github/workflows/mix_git_ops.yml delete mode 100644 .github/workflows/mix_hex_audit.yml delete mode 100644 .github/workflows/mix_test.yml create mode 100644 LICENSE diff --git a/.doctor.exs b/.doctor.exs index 8c2ddfb..45368c7 100644 --- a/.doctor.exs +++ b/.doctor.exs @@ -5,7 +5,7 @@ min_module_spec_coverage: 0, min_overall_doc_coverage: 50, min_overall_spec_coverage: 0, - moduledoc_required: true, + min_overall_moduledoc_coverage: 100, exception_moduledoc_required: true, raise: false, reporter: Doctor.Reporters.Full, diff --git a/.formatter.exs b/.formatter.exs index 1b8cfa1..eeb1051 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,8 +1,8 @@ [ - import_deps: [:ash], + import_deps: [:spark], inputs: [ "*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}" ], - plugins: [Ash.ResourceFormatter] + plugins: [Spark.Formatter] ] diff --git a/.github/workflows/elixir_lib.yml b/.github/workflows/elixir_lib.yml new file mode 100644 index 0000000..23284f1 --- /dev/null +++ b/.github/workflows/elixir_lib.yml @@ -0,0 +1,154 @@ +name: Elixir Library + +on: + push: + +jobs: + deps: + name: mix deps.get + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-deps-get@main + + auditor: + name: mix hex.audit + runs-on: ubuntu-latest + needs: deps + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-hex-audit@main + + build-test: + name: MIX_ENV=test mix.compile + runs-on: ubuntu-latest + needs: deps + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/install-elixir@main + - uses: team-alembic/staple-actions/actions/mix-compile@main + with: + mix-env: test + + formatter: + name: mix format --check-formatted + runs-on: ubuntu-latest + needs: build-test + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-format@main + with: + mix-env: test + + credo: + name: mix credo --strict + runs-on: ubuntu-latest + needs: build-test + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-credo@main + with: + mix-env: test + + doctor: + name: mix doctor --full --raise + runs-on: ubuntu-latest + needs: build-test + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-doctor@main + with: + mix-env: test + + test: + name: mix test + runs-on: ubuntu-latest + needs: build-test + services: + postgres: + image: postgres + env: + POSTGRES_HOST_AUTH_METHOD: trust + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-test@main + with: + mix-env: test + env: + PGUSER: postgres + PGPASS: postgres + PGHOST: postgres + + dialyzer: + name: mix dialyzer + runs-on: ubuntu-latest + needs: build-test + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-dialyzer@main + with: + mix-env: test + + build-dev: + name: MIX_ENV=dev mix.compile + runs-on: ubuntu-latest + needs: + - credo + - doctor + - formatter + - auditor + - test + - dialyzer + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-compile@main + with: + mix-env: dev + + build-docs: + name: mix docs + runs-on: ubuntu-latest + needs: build-dev + steps: + - uses: actions/checkout@v3 + - uses: team-alembic/staple-actions/actions/mix-docs@main + with: + mix-env: dev + - uses: actions/upload-pages-artifact@v1 + with: + path: doc/ + + deploy-docs: + name: Deploy docs to GitHub pages. + runs-on: ubuntu-latest + needs: build-docs + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub pages + id: deployment + uses: actions/deploy-pages@v1 + + git-ops: + name: mix git-ops.release + runs-on: ubuntu-latest + needs: build-dev + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: team-alembic/staple-actions/actions/git-ops@main + with: + mix-env: dev diff --git a/.github/workflows/mix_credo.yml b/.github/workflows/mix_credo.yml deleted file mode 100644 index 26643ba..0000000 --- a/.github/workflows/mix_credo.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: mix credo --strict - -on: - pull_request: - branches: - - main - -jobs: - test: - runs-on: ubuntu-latest - env: - MIX_ENV: test - strategy: - matrix: - elixir: [1.13.4] - otp: [25.0.3] - - steps: - - uses: actions/checkout@v2 - - uses: erlef/setup-beam@v1 - with: - elixir-version: ${{ matrix.elixir }} - otp-version: ${{ matrix.otp }} - - name: Retrieve Mix Dependencies Cache - uses: actions/cache@v1 - id: mix-cache - with: - path: deps - key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} - - name: Install Mix Dependencies - if: steps.mix-cache.outputs.cache-hit != 'true' - run: | - mix local.rebar --force - mix local.hex --force - mix deps.get - - run: mix credo --strict diff --git a/.github/workflows/mix_doctor.yml b/.github/workflows/mix_doctor.yml deleted file mode 100644 index 2043b8e..0000000 --- a/.github/workflows/mix_doctor.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: mix doctor - -on: - pull_request: - branches: - - main - -jobs: - test: - runs-on: ubuntu-latest - env: - MIX_ENV: test - strategy: - matrix: - elixir: [1.13.4] - otp: [25.0.3] - - steps: - - uses: actions/checkout@v2 - - uses: erlef/setup-beam@v1 - with: - elixir-version: ${{ matrix.elixir }} - otp-version: ${{ matrix.otp }} - - name: Retrieve Mix Dependencies Cache - uses: actions/cache@v1 - id: mix-cache - with: - path: deps - key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} - - name: Install Mix Dependencies - if: steps.mix-cache.outputs.cache-hit != 'true' - run: | - mix local.rebar --force - mix local.hex --force - mix deps.get - - run: mix doctor --full --raise diff --git a/.github/workflows/mix_format.yml b/.github/workflows/mix_format.yml deleted file mode 100644 index 8a5fb2f..0000000 --- a/.github/workflows/mix_format.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: mix format --check-formatted - -on: - pull_request: - branches: - - main - -jobs: - test: - runs-on: ubuntu-latest - env: - MIX_ENV: test - strategy: - matrix: - elixir: [1.13.4] - otp: [25.0.3] - - steps: - - uses: actions/checkout@v2 - - uses: erlef/setup-beam@v1 - with: - elixir-version: ${{ matrix.elixir }} - otp-version: ${{ matrix.otp }} - - name: Retrieve Mix Dependencies Cache - uses: actions/cache@v1 - id: mix-cache - with: - path: deps - key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} - - name: Install Mix Dependencies - if: steps.mix-cache.outputs.cache-hit != 'true' - run: | - mix local.rebar --force - mix local.hex --force - mix deps.get - - name: Check Formatting - run: mix format --check-formatted diff --git a/.github/workflows/mix_git_ops.yml b/.github/workflows/mix_git_ops.yml deleted file mode 100644 index f1835b9..0000000 --- a/.github/workflows/mix_git_ops.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: mix git_ops.release -on: - push: - branches: - - main - -jobs: - maybe_release: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - uses: erlef/setup-beam@v1 - with: - elixir-version: "1.13.4" - otp-version: "25.0.3" - - name: Retrieve Mix Dependencies Cache - uses: actions/cache@v1 - id: mix-cache - with: - path: deps - key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} - - name: Install Mix Dependencies - if: steps.mix-cache.outputs.cache-hit != 'true' - run: | - mix local.rebar --force - mix local.hex --force - mix deps.get - - name: Configure git author - run: git config user.email '25500012+github-actions[bot]@users.noreply.github.com' ; git config user.name 'github-actions' - - name: Retrieving the current app version - id: original-app-info - run: MIX_ENV=test mix git_ops.project_info --format github-actions - - name: Run mix git_ops.release - run: MIX_ENV=test mix git_ops.release --yes || true - - name: Checking for new app version - id: app-info - run: MIX_ENV=test mix git_ops.project_info --format github-actions - - name: Building hex package - if: ${{ steps.original-app-info.outputs.app_version != steps.app-info.outputs.app_version }} - run: mix hex.build -o ${{ steps.app-info.outputs.app_name }}-${{ steps.app-info.outputs.app_version }}.tar - - name: Building hex docs - if: ${{ steps.original-app-info.outputs.app_version != steps.app-info.outputs.app_version }} - run: MIX_ENV=test mix docs && tar zcvf ${{ steps.app-info.outputs.app_name }}-${{ steps.app-info.outputs.app_version }}-docs.tar.gz doc/ - - name: Pushing new tag - if: ${{ steps.original-app-info.outputs.app_version != steps.app-info.outputs.app_version }} - run: git push "https://${{ github.actor }}:${{ github.token }}@github.com/${{ github.repository }}" HEAD:${{ github.ref }} refs/tags/v${{ steps.app-info.outputs.app_version }} - - name: Creating new Github release - if: ${{ steps.original-app-info.outputs.app_version != steps.app-info.outputs.app_version }} - id: create-release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ github.token }} - with: - tag_name: v${{ steps.app-info.outputs.app_version }} - release_name: Release ${{ steps.app-info.outputs.app_name }} ${{ steps.app-info.outputs.app_version }} - body: Autogenerated by git_ops release. - - name: Uploading hex package as release artifact - if: ${{ steps.original-app-info.outputs.app_version != steps.app-info.outputs.app_version }} - id: upload-package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ github.token }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: ${{ steps.app-info.outputs.app_name }}-${{ steps.app-info.outputs.app_version }}.tar - asset_name: ${{ steps.app-info.outputs.app_name }}-${{ steps.app-info.outputs.app_version }}.tar - asset_content_type: application/x-tar - - name: Uploading documentation as release artifact - if: ${{ steps.original-app-info.outputs.app_version != steps.app-info.outputs.app_version }} - id: upload-docs - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ github.token }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: ${{ steps.app-info.outputs.app_name }}-${{ steps.app-info.outputs.app_version }}-docs.tar.gz - asset_name: ${{ steps.app-info.outputs.app_name }}-${{ steps.app-info.outputs.app_version }}-docs.tar.gz - asset_content_type: application/gzip -# - name: Publishing hex package -# if: ${{ steps.original-app-info.outputs.app_version != steps.app-info.outputs.app_version }} -# run: mix hex.publish --yes diff --git a/.github/workflows/mix_hex_audit.yml b/.github/workflows/mix_hex_audit.yml deleted file mode 100644 index df334cf..0000000 --- a/.github/workflows/mix_hex_audit.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: mix hex.audit -on: - pull_request: - branches: - - main - -jobs: - test: - runs-on: ubuntu-latest - env: - MIX_ENV: test - strategy: - matrix: - elixir: [1.13.4] - otp: [25.0.3] - - steps: - - uses: actions/checkout@v2 - - uses: erlef/setup-beam@v1 - with: - elixir-version: ${{ matrix.elixir }} - otp-version: ${{ matrix.otp }} - - name: Retrieve Mix Dependencies Cache - uses: actions/cache@v1 - id: mix-cache - with: - path: deps - key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} - - name: Install Mix Dependencies - if: steps.mix-cache.outputs.cache-hit != 'true' - run: | - mix local.rebar --force - mix local.hex --force - mix deps.get - - run: mix hex.audit diff --git a/.github/workflows/mix_test.yml b/.github/workflows/mix_test.yml deleted file mode 100644 index 98dbf29..0000000 --- a/.github/workflows/mix_test.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: mix test - -on: - pull_request: - branches: - - main - -jobs: - test: - runs-on: ubuntu-latest - env: - MIX_ENV: test - strategy: - matrix: - elixir: [1.13.4] - otp: [25.0.3] - - services: - postgres: - image: postgres - env: - POSTGRES_HOST_AUTH_METHOD: trust - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - steps: - - uses: actions/checkout@v2 - - uses: erlef/setup-beam@v1 - with: - elixir-version: ${{ matrix.elixir }} - otp-version: ${{ matrix.otp }} - - name: Retrieve Mix Dependencies Cache - uses: actions/cache@v1 - id: mix-cache - with: - path: deps - key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} - - name: Install Mix Dependencies - if: steps.mix-cache.outputs.cache-hit != 'true' - run: | - mix local.rebar --force - mix local.hex --force - mix deps.get - - run: mix test - env: - MIX_ENV: test - PGUSER: postgres - PGPASS: postgres - PGHOST: postgres diff --git a/.gitignore b/.gitignore index b1cffd0..1a5de17 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ ash_gen_server-*.tar # Temporary files, for example, from tests. /tmp/ + +/priv/plts diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5b151aa --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +Copyright 2022 Alembic Pty Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 9462d69..48c0c47 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,38 @@ An Ash Datalayer backed by individual GenServers. -If you want in-memory storage of resources then take a look at -`Ash.DataLayer.Ets`. +This package provides an +[`Ash.DataLayer`](https://ash-hq.org/docs/module/ash/latest/ash-datalayer) which +stores resources in emphemeral GenServers. The main use-case for this is two fold: + + 1. Ability to automatically remove resources after an inactivity timeout. + 2. (Potential) ability to migrate resources across a cluster during deploys to + allow access to continue without failure. + 3. before and after hooks for changesets and queries are run within the server + process, making registration, etc, possible. ## Caveats - + * When a resource using this datalayer is created it spawns an instance of `AshGenServer.Server` and performs all operations on the data within it. This means that your actions must pay the price of a `GenServer.call/3` to read or modify the data. - + * When destroying a resource it's process is terminated and it's internal state is lost. - + * If, for some reason, the `AshGenServer.Server` process crashes or exits for an abnormal reason the supervisor will restart it **with the changeset used by the `create` action** - this means that any updates performed since creation will be lost. - + * Any resource using this data source **must** have at least one primary key field. - + * Retrieving a resource by primary key is an optimised case, but any other queries will pay the price of having to query every `AshGenServer.Server` process in sequence. - + ## Installation If [available in Hex](https://hex.pm/docs/publish), the package can be installed @@ -40,7 +47,37 @@ def deps do end ``` -Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) -and published on [HexDocs](https://hexdocs.pm). Once published, the docs can -be found at . +## Usage + +This package assumes that you have [Ash](https://ash-hq.org) installed and +configured. See the Ash documentation for details. + +Once installed you can easily define a resource which is backed by a GenServer: + +```elixir +defmodule MyApp.EphemeralResource do + use Ash.Resource, data_layer: AshGenServer.DataLayer + + attributes do + uuid_primary_key :id + attribute :temporary_data, :string + end +end +``` + +## Documentation + +Documentation for the latest release will be [available on +hexdocs](https://hexdocs.pm/ash_gen_server) and for the [`main` +branch](https://team-alembic.github.io/ash_gen_server). + +## Contributing + + * To contribute updates, fixes or new features please fork and open a + pull-request against `main`. + * Please use [conventional + commits](https://www.conventionalcommits.org/en/v1.0.0/) - this allows us to + dynamically generate the changelog. + * Feel free to ask any questions on out [GitHub discussions + page](https://github.com/team-alembic/ash_gen_server/discussions). diff --git a/lib/ash_gen_server/application.ex b/lib/ash_gen_server/application.ex index 76225df..931d1c2 100644 --- a/lib/ash_gen_server/application.ex +++ b/lib/ash_gen_server/application.ex @@ -1,10 +1,9 @@ defmodule AshGenServer.Application do - # See https://hexdocs.pm/elixir/Application.html - # for more information on OTP Applications @moduledoc false use Application + @doc false @impl true def start(_type, _args) do children() diff --git a/lib/ash_gen_server/data_layer.ex b/lib/ash_gen_server/data_layer.ex index 5af5b62..1139f27 100644 --- a/lib/ash_gen_server/data_layer.ex +++ b/lib/ash_gen_server/data_layer.ex @@ -6,27 +6,27 @@ defmodule AshGenServer.DataLayer do `Ash.DataLayer.Ets`. ## Caveats - + * When a resource using this datalayer is created it spawns an instance of `AshGenServer.Server` and performs all operations on the data within it. This means that your actions must pay the price of a `GenServer.call/3` to read or modify the data. - + * When destroying a resource it's process is terminated and it's internal state is lost. - + * If, for some reason, the `AshGenServer.Server` process crashes or exits for an abnormal reason the supervisor will restart it **with the changeset used by the `create` action** - this means that any updates performed since creation will be lost. - + * Any resource using this data source **must** have at least one primary key field. - + * Retrieving a resource by primary key is an optimised case, but any other queries will pay the price of having to query every `AshGenServer.Server` process in sequence. - + """ @gen_server %Spark.Dsl.Section{ @@ -85,7 +85,7 @@ defmodule AshGenServer.DataLayer do @doc false @impl true - @spec filter(Query.t(), Filter.t(), Resource.t()) :: Query.t() + @spec filter(Query.t(), Filter.t(), Resource.t()) :: {:ok, Query.t()} def filter(%{resource: resource, filter: nil} = query, filter, resource), do: {:ok, %{query | filter: filter}} @@ -96,23 +96,23 @@ defmodule AshGenServer.DataLayer do @doc false @impl true - @spec limit(Query.t(), limit, Resource.t()) :: Query.t() when limit: non_neg_integer() + @spec limit(Query.t(), limit, Resource.t()) :: {:ok, Query.t()} when limit: non_neg_integer() def limit(%{resource: resource} = query, limit, resource), do: {:ok, %{query | limit: limit}} @doc false @impl true - @spec offset(Query.t(), offset, Resource.t()) :: Query.t() when offset: non_neg_integer() + @spec offset(Query.t(), offset, Resource.t()) :: {:ok, Query.t()} when offset: non_neg_integer() def offset(%{resource: resource} = query, offset, resource), do: {:ok, %{query | offset: offset}} @doc false @impl true - @spec sort(Query.t(), Sort.t(), Resource.t()) :: Query.t() + @spec sort(Query.t(), Sort.t(), Resource.t()) :: {:ok, Query.t()} def sort(%{resource: resource} = query, sort, resource), do: {:ok, %{query | sort: sort}} @doc false @impl true - @spec run_query(Query.t(), Resource.t()) :: {:ok, Enum.t(Resource.t())} | {:error, any} + @spec run_query(Query.t(), Resource.t()) :: {:ok, [Resource.record()]} | {:error, any} def run_query(%Query{resource: resource, filter: nil} = query, resource), do: do_slow_query(query, resource) diff --git a/lib/ash_gen_server/query.ex b/lib/ash_gen_server/query.ex index ec28ec8..2c96233 100644 --- a/lib/ash_gen_server/query.ex +++ b/lib/ash_gen_server/query.ex @@ -6,10 +6,10 @@ defmodule AshGenServer.Query do @type t :: %__MODULE__{ resource: Ash.Resource.t(), - filter: Ash.Filter.t(), + filter: nil | Ash.Filter.t(), api: Ash.Api.t(), - limit: non_neg_integer(), - offset: non_neg_integer(), - sort: Ash.Sort.t() + limit: nil | non_neg_integer(), + offset: nil | non_neg_integer(), + sort: nil | Ash.Sort.t() } end diff --git a/lib/ash_gen_server/registry.ex b/lib/ash_gen_server/registry.ex index 6f1c22b..475cdf7 100644 --- a/lib/ash_gen_server/registry.ex +++ b/lib/ash_gen_server/registry.ex @@ -14,7 +14,7 @@ defmodule AshGenServer.Registry do This is the key that's actually stored in the Registry. """ - @type resource_key :: {Ash.resource(), primary_key} + @type resource_key :: {Ash.Resource.t(), primary_key} @typedoc """ A map containing the primary key field(s) and value(s) for a the resource. @@ -51,7 +51,7 @@ defmodule AshGenServer.Registry do @doc """ Find all the processes registered to the provided resource. """ - @spec find_servers_by_resource(Ash.resource()) :: [{primary_key, pid}] + @spec find_servers_by_resource(Ash.Resource.t()) :: [{primary_key, pid}] def find_servers_by_resource(resource) do Registry.select(__MODULE__, [ { diff --git a/lib/ash_gen_server/server.ex b/lib/ash_gen_server/server.ex index c989eb9..ce422ec 100644 --- a/lib/ash_gen_server/server.ex +++ b/lib/ash_gen_server/server.ex @@ -42,7 +42,7 @@ defmodule AshGenServer.Server do @doc false @impl true - @spec init(list) :: {:ok, t} | {:error, any} + @spec init(list) :: {:ok, t} | {:stop, {:error, any}} def init([resource, changeset]) do primary_key = primary_key_from_resource_and_changeset(resource, changeset) @@ -67,7 +67,7 @@ defmodule AshGenServer.Server do {:ok, state} else {:error, {:already_registered, _}} -> {:stop, :already_exists} - {:error, reason} -> {:error, reason} + {:error, reason} -> {:stop, {:error, reason}} end end diff --git a/mix.exs b/mix.exs index 2d630e7..a4a8228 100644 --- a/mix.exs +++ b/mix.exs @@ -9,10 +9,25 @@ defmodule AshGenServer.MixProject do version: @version, elixir: "~> 1.13", start_permanent: Mix.env() == :prod, + preferred_cli_env: [ci: :test], + aliases: aliases(), deps: deps(), package: package(), elixirc_paths: elixirc_paths(Mix.env()), - consolidate_protocols: Mix.env() != :test + consolidate_protocols: Mix.env() != :test, + dialyzer: [ + plt_add_apps: [:mix, :ex_unit, :ash], + plt_core_path: "priv/plts", + plt_file: {:no_warn, "priv/plts/dialyzer.plt"} + ], + docs: [ + main: "readme", + extras: ["README.md"], + formatters: ["html"], + filter_modules: ~r/^Elixir.AshGenServer/, + source_url_pattern: + "https://github.com/team-alembic/ash_gen_server/blob/main/%{path}#L%{line}" + ] ] end @@ -47,9 +62,23 @@ defmodule AshGenServer.MixProject do [ {:ash, "~> 2.2"}, {:credo, "~> 1.6", only: [:dev, :test]}, - {:ex_doc, ">= 0.0.0", only: [:dev, :test]}, + {:dialyxir, "~> 1.2", only: [:dev, :test], runtime: false}, {:doctor, "~> 0.18", only: [:dev, :test]}, + {:ex_doc, ">= 0.0.0", only: [:dev, :test]}, {:git_ops, "~> 2.4", only: [:dev, :test], runtime: false} ] end + + defp aliases do + [ + ci: [ + "format --check-formatted", + "doctor --full --raise", + "credo --strict", + "dialyzer", + "hex.audit", + "test" + ] + ] + end end diff --git a/mix.lock b/mix.lock index 529a199..57cccc5 100644 --- a/mix.lock +++ b/mix.lock @@ -6,10 +6,12 @@ "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, + "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, "doctor": {:hex, :doctor, "0.20.0", "2a8ff8f87eaf3fc78f20ffcfa7a3181f2bdb6a115a4abd52582e6156a89649a5", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "36ba43bdf7d799c41e1dc00b3429eb48bc5d4dc3f63b181ca1aa8829ec638862"}, "earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"}, "ecto": {:hex, :ecto, "3.9.1", "67173b1687afeb68ce805ee7420b4261649d5e2deed8fe5550df23bab0bc4396", [:mix], [{:decimal, "~> 1.6 or ~> 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", "c80bb3d736648df790f7f92f81b36c922d9dd3203ca65be4ff01d067f54eb304"}, "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ets": {:hex, :ets, "0.8.1", "8ff9bcda5682b98493f8878fc9dbd990e48d566cba8cce59f7c2a78130da29ea", [:mix], [], "hexpm", "6be41b50adb5bc5c43626f25ea2d0af1f4a242fb3fad8d53f0c67c20b78915cc"}, "ex_doc": {:hex, :ex_doc, "0.29.0", "4a1cb903ce746aceef9c1f9ae8a6c12b742a5461e6959b9d3b24d813ffbea146", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "f096adb8bbca677d35d278223361c7792d496b3fc0d0224c9d4bc2f651af5db1"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, diff --git a/test/support/time_travel.ex b/test/support/time_travel.ex index e4b6673..c943698 100644 --- a/test/support/time_travel.ex +++ b/test/support/time_travel.ex @@ -5,6 +5,6 @@ defmodule TimeTravel do use Ash.Api, otp_app: :ash_gen_server resources do - registry TimeTravel.Registry + registry(TimeTravel.Registry) end end diff --git a/test/support/time_travel/character.ex b/test/support/time_travel/character.ex index b3afb08..7860352 100644 --- a/test/support/time_travel/character.ex +++ b/test/support/time_travel/character.ex @@ -12,29 +12,29 @@ defmodule TimeTravel.Character do } actions do - create :create + create(:create) read :read do - primary? true + primary?(true) end - destroy :destroy + destroy(:destroy) update :travel_in_time do - argument :target_year, :integer, allow_nil?: false + argument(:target_year, :integer, allow_nil?: false) - change TimeTravel.CharacterTravelChange + change(TimeTravel.CharacterTravelChange) end end attributes do - uuid_primary_key :id + uuid_primary_key(:id) - attribute :name, :string, allow_nil?: false - attribute :nickname, :string - attribute :current_year, :integer, allow_nil?: false + attribute(:name, :string, allow_nil?: false) + attribute(:nickname, :string) + attribute(:current_year, :integer, allow_nil?: false) - create_timestamp :created_at - update_timestamp :updated_at + create_timestamp(:created_at) + update_timestamp(:updated_at) end end diff --git a/test/support/time_travel/machine.ex b/test/support/time_travel/machine.ex index 56084e0..32d0082 100644 --- a/test/support/time_travel/machine.ex +++ b/test/support/time_travel/machine.ex @@ -14,40 +14,40 @@ defmodule TimeTravel.Machine do } actions do - create :create + create(:create) read :read do - primary? true + primary?(true) end - destroy :destroy + destroy(:destroy) update :travel_in_time do - argument :occupants, {:array, TimeTravel.Character} - argument :target_year, :integer, allow_nil?: false - change TimeTravel.MachineTravelChange + argument(:occupants, {:array, TimeTravel.Character}) + argument(:target_year, :integer, allow_nil?: false) + change(TimeTravel.MachineTravelChange) end update :retrofit do - argument :power_source, :string, allow_nil?: false - change TimeTravel.MachineRetrofitChange + argument(:power_source, :string, allow_nil?: false) + change(TimeTravel.MachineRetrofitChange) end update :charge do - change TimeTravel.MachineChargeChange + change(TimeTravel.MachineChargeChange) end end attributes do - uuid_primary_key :id + uuid_primary_key(:id) - attribute :name, :string, allow_nil?: false - attribute :model, :string - attribute :manufacturer, :string - attribute :power_source, :string - attribute :has_power?, :boolean, allow_nil?: false, default: false + attribute(:name, :string, allow_nil?: false) + attribute(:model, :string) + attribute(:manufacturer, :string) + attribute(:power_source, :string) + attribute(:has_power?, :boolean, allow_nil?: false, default: false) - create_timestamp :created_at - update_timestamp :updated_at + create_timestamp(:created_at) + update_timestamp(:updated_at) end end diff --git a/test/support/time_travel/registry.ex b/test/support/time_travel/registry.ex index 6f6f4fb..1987d09 100644 --- a/test/support/time_travel/registry.ex +++ b/test/support/time_travel/registry.ex @@ -3,7 +3,7 @@ defmodule TimeTravel.Registry do use Ash.Registry, extensions: [Ash.Registry.ResourceValidations] entries do - entry TimeTravel.Character - entry TimeTravel.Machine + entry(TimeTravel.Character) + entry(TimeTravel.Machine) end end