Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JET-2026] feature: use dynamic repo to execute action #8

Merged
merged 7 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ import Config
config :resource_kit, ResourceKit.Deref, adapter: ResourceKit.Deref.Local

config :resource_kit, ResourceKitCLI.Endpoint, server: true

config :resource_kit, ResourceKit.Repo,
server: true,
fahchen marked this conversation as resolved.
Show resolved Hide resolved
hostname: "localhost",
database: "resource_kit_dev",
username: "postgres",
password: "postgres"
vanppo marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config :resource_kit, ResourceKit.Deref,
adapter: {ResourceKit.Deref.Local, directory: "test/fixtures"}

config :resource_kit, ResourceKit.Repo,
server: true,
hostname: "localhost",
database: "resource_kit_test",
username: "postgres",
Expand Down
3 changes: 1 addition & 2 deletions lib/resource_kit/action/skeleton.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ defmodule ResourceKit.Action.Skeleton do
end

defp __execute__(action, references, params, opts) do
root = Keyword.fetch!(opts, :root)
context = %ExecuteToken.Context{root: root, current: root}
context = ExecuteToken.Context.new(opts)

%ExecuteToken{action: action, references: references, params: params, context: context}
|> Pluggable.run([&__MODULE__.execute(&1, [])])
Expand Down
11 changes: 5 additions & 6 deletions lib/resource_kit/application.ex
fahchen marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ defmodule ResourceKit.Application do

@impl Application
def start(_type, _args) do
Supervisor.start_link(children(), strategy: :one_for_one, name: __MODULE__)
end
children = [
ResourceKit.Repo.Supervisor,
ResourceKitCLI.Endpoint
]

if Mix.env() === :test do
defp children, do: [ResourceKit.Repo]
else
defp children, do: [ResourceKitCLI.Endpoint]
Supervisor.start_link(children, strategy: :one_for_one, name: __MODULE__)
end
end
21 changes: 10 additions & 11 deletions lib/resource_kit/pipeline/execute/run.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,23 @@ defmodule ResourceKit.Pipeline.Execute.Run do

@behaviour Pluggable

use TypedStruct

typedstruct module: Options do
field :repo, module(), default: ResourceKit.Repo
end

alias ResourceKit.Pipeline.Execute.Token

@impl Pluggable
def init(args), do: struct(Options, args)
def init(args), do: args

@impl Pluggable
def call(%Token{halted: true} = token, _opts), do: token

def call(%Token{} = token, %Options{repo: repo}) do
token
|> Token.fetch_assign!(:multi)
|> repo.transaction()
def call(%Token{} = token, _opts) do
%Token{context: %Token.Context{dynamic: dynamic}} = token

dynamic
|> ResourceKit.Repo.execute(fn repo ->
token
|> Token.fetch_assign!(:multi)
|> repo.transaction()
end)
|> case do
{:ok, changes} -> Token.put_assign(token, :changes, changes)
{:error, _operation, reason, _changes} -> Token.put_error(token, reason)
Expand Down
21 changes: 17 additions & 4 deletions lib/resource_kit/pipeline/execute/token.ex
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
defmodule ResourceKit.Pipeline.Execute.Token do
@moduledoc false

use TypedStruct
use ResourceKit.Pipeline.Token

alias ResourceKit.Types

alias ResourceKit.Schema.Ref

typedstruct module: Context do
field :root, URI.t(), enforce: true
field :current, URI.t(), enforce: true
defmodule Context do
@moduledoc false

use TypedStruct

typedstruct do
field :root, URI.t(), enforce: true
field :current, URI.t(), enforce: true
field :dynamic, atom() | pid(), enforce: true
fahchen marked this conversation as resolved.
Show resolved Hide resolved
end

def new(args) do
root = Keyword.fetch!(args, :root)
dynamic = Keyword.fetch!(args, :dynamic)

struct(__MODULE__, root: root, current: root, dynamic: dynamic)
end
end

token do
Expand Down
11 changes: 11 additions & 0 deletions lib/resource_kit/repo.ex
fahchen marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@ defmodule ResourceKit.Repo do
use Ecto.Repo,
otp_app: :resource_kit,
adapter: Ecto.Adapters.Postgres

@type repo() :: atom() | pid()
fahchen marked this conversation as resolved.
Show resolved Hide resolved

@spec execute(dynamic :: repo(), callback :: (Ecto.Repo.t() -> result)) :: result
when result: var
def execute(dynamic, callback) do
put_dynamic_repo(dynamic)
callback.(__MODULE__)
after
put_dynamic_repo(__MODULE__)
end
end
25 changes: 25 additions & 0 deletions lib/resource_kit/repo/supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule ResourceKit.Repo.Supervisor do
@moduledoc false

use Supervisor

@spec start_link(args :: keyword()) :: Supervisor.on_start()
def start_link(args) do
Supervisor.start_link(__MODULE__, configuration(args), name: __MODULE__)
end

@impl Supervisor
def init(args) do
if Keyword.get(args, :server, false) do
Supervisor.init([ResourceKit.Repo], strategy: :one_for_one)
else
:ignore
end
end

defp configuration(args) do
:resource_kit
|> Application.get_env(ResourceKit.Repo, [])
|> Keyword.merge(args)
end
end
2 changes: 1 addition & 1 deletion lib/resource_kit_cli/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ defmodule ResourceKitCLI.Endpoint do
:resource_kit
|> Application.get_env(__MODULE__, [])
|> Keyword.merge(args)
|> Keyword.put(:plug, ResourceKitPlug.Router)
|> Keyword.put(:plug, ResourceKitCLI.Plug)
end
end
12 changes: 12 additions & 0 deletions lib/resource_kit_cli/plug.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule ResourceKitCLI.Plug do
@moduledoc false

use Plug.Builder

plug :put_dynamic
plug ResourceKitPlug.Router

defp put_dynamic(conn, _opts) do
ResourceKitPlug.Router.put_dynamic(conn, ResourceKit.Repo)
end
end
8 changes: 4 additions & 4 deletions lib/resource_kit_plug/controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ defmodule ResourceKitPlug.Controller do

for type <- [:insert, :list] do
@spec unquote(type)(request :: map(), ctx :: PhxJsonRpc.Router.Context.t()) :: map()
def unquote(type)(request, _ctx) do
def unquote(type)(request, %PhxJsonRpc.Router.Context{meta_data: %{dynamic: dynamic}}) do
with {:ok, request} <- cast_request(request),
{:ok, action} <- fetch_action(request),
{:ok, result} <- run(request, unquote(type), action) do
{:ok, result} <- run(request, unquote(type), action, dynamic: dynamic) do
result
end
end
Expand Down Expand Up @@ -53,8 +53,8 @@ defmodule ResourceKitPlug.Controller do
end
end

defp run(%Request{uri: uri, params: params}, type, action) do
case apply(ResourceKit, type, [action, params, [root: uri]]) do
defp run(%Request{uri: uri, params: params}, type, action, opts) do
case apply(ResourceKit, type, [action, params, Keyword.put(opts, :root, uri)]) do
{:ok, result} ->
{:ok, result}

Expand Down
15 changes: 14 additions & 1 deletion lib/resource_kit_plug/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,32 @@ defmodule ResourceKitPlug.Router do

use Plug.Router

@dynamic_private :__dynamic_private__
fahchen marked this conversation as resolved.
Show resolved Hide resolved

plug Plug.Logger
plug Plug.Parsers, parsers: [{:json, json_decoder: Jason}]
plug :match
plug :dispatch

@spec put_dynamic(conn :: Plug.Conn.t(), dynamic :: ResourceKit.Repo.repo()) :: Plug.Conn.t()
def put_dynamic(%Plug.Conn{} = conn, dynamic) do
put_private(conn, @dynamic_private, dynamic)
end

post "/rpc/actions", do: handle(conn, ResourceKitPlug.Service)

defp handle(%Plug.Conn{} = conn, service) do
import PhxJsonRpcWeb.Views.Helpers

{:ok, dynamic} = fetch_dynamic(conn)

fahchen marked this conversation as resolved.
Show resolved Hide resolved
conn
|> put_resp_header("content-type", "application/json; charset=utf-8")
|> send_json(conn.params |> service.handle() |> render_json())
|> send_json(conn.params |> service.handle(%{dynamic: dynamic}) |> render_json())
end

defp fetch_dynamic(%Plug.Conn{private: private}) do
Map.fetch(private, @dynamic_private)
end

defp send_json(%Plug.Conn{} = conn, data) do
Expand Down
6 changes: 4 additions & 2 deletions test/resource_kit/action/insert_movie_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ defmodule ResourceKit.Action.InsertMovieTest do
"release_date" => ~D[2024-04-30],
"created_at" => ~U[2023-12-22 14:23:07.000000Z],
"tags" => ["Animation", "Comedy"]
}} = ResourceKit.insert(action, params, root: root)
}} = ResourceKit.insert(action, params, root: root, dynamic: ResourceKit.Repo)
end

@tag jsons: [action: "actions/insert_movie.json"]
Expand All @@ -54,7 +54,9 @@ defmodule ResourceKit.Action.InsertMovieTest do
"tags" => ["Animation", "Comedy"]
}

assert {:error, changeset} = ResourceKit.insert(action, params, root: root)
assert {:error, changeset} =
ResourceKit.insert(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?(%{release_date: ["is invalid"]}, errors_on(changeset))
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,6 @@ defmodule ResourceKit.Action.InsertMovieWithCommentsByRefAssociationSchemaTest d
]
}
]
}} = ResourceKit.insert(action, params, root: root)
}} = ResourceKit.insert(action, params, root: root, dynamic: ResourceKit.Repo)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,6 @@ defmodule ResourceKit.Action.InsertMovieWithCommentsTest do
]
}
]
}} = ResourceKit.insert(action, params, root: root)
}} = ResourceKit.insert(action, params, root: root, dynamic: ResourceKit.Repo)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ defmodule ResourceKit.Action.ListDirectorsWithMoviesByRefAssociationSchemaTest d
params = %{"pagination" => %{"offset" => 0, "limit" => 2}}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?(
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ defmodule ResourceKit.Action.ListDirectorsWithMoviesTest do
params = %{"pagination" => %{"offset" => 0, "limit" => 2}}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?(
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ defmodule ResourceKit.Action.ListDirectorsWithMoviesThroughTest do
params = %{"pagination" => %{"offset" => 0, "limit" => 2}}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?(
[
Expand Down
4 changes: 2 additions & 2 deletions test/resource_kit/action/list_movies_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ defmodule ResourceKit.Action.ListMoviesTest do
}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?([%{"标题" => "Longlegs"}, %{"标题" => "Trap"}], data)
assert match?(%{"offset" => 0, "limit" => 2, "total" => 3}, pagination)
Expand All @@ -99,7 +99,7 @@ defmodule ResourceKit.Action.ListMoviesTest do
}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?([%{"标题" => "Twisters"}], data)
assert match?(%{"offset" => 2, "limit" => 2, "total" => 3}, pagination)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ defmodule ResourceKit.Action.ListMoviesWithDirectorTest do
params = %{"pagination" => %{"offset" => 0, "limit" => 2}}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?(
[
Expand Down
2 changes: 1 addition & 1 deletion test/resource_kit/action/list_movies_with_poster_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ defmodule ResourceKit.Action.ListMoviesWithPosterTest do
params = %{"pagination" => %{"offset" => 0, "limit" => 2}}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?(
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ defmodule ResourceKit.Action.ListMoviesWithPosterThroughTest do
params = %{"pagination" => %{"offset" => 0, "limit" => 2}}

assert {:ok, %{"data" => data, "pagination" => pagination}} =
ResourceKit.list(action, params, root: root)
ResourceKit.list(action, params, root: root, dynamic: ResourceKit.Repo)

assert match?(
[
Expand Down
11 changes: 6 additions & 5 deletions test/resource_kit/pipeline/execute/build_params_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ defmodule ResourceKit.Pipeline.Execute.BuildParamsTest do
action: action,
references: %{},
params: params,
context: %Execute.Token.Context{root: uri, current: uri}
context: Execute.Token.Context.new(root: uri, dynamic: ResourceKit.Repo)
}

assert %Execute.Token{halted: false} = token = Execute.BuildParams.call(token, [])
Expand Down Expand Up @@ -59,7 +59,7 @@ defmodule ResourceKit.Pipeline.Execute.BuildParamsTest do
action: action,
references: %{},
params: params,
context: %Execute.Token.Context{root: uri, current: uri}
context: Execute.Token.Context.new(root: uri, dynamic: ResourceKit.Repo)
}

assert %Execute.Token{halted: false} = token = Execute.BuildParams.call(token, [])
Expand Down Expand Up @@ -94,7 +94,7 @@ defmodule ResourceKit.Pipeline.Execute.BuildParamsTest do
action: action,
references: %{},
params: params,
context: %Execute.Token.Context{root: uri, current: uri}
context: Execute.Token.Context.new(root: uri, dynamic: ResourceKit.Repo)
}

assert %Execute.Token{halted: false} = token = Execute.BuildParams.call(token, [])
Expand Down Expand Up @@ -183,8 +183,9 @@ defmodule ResourceKit.Pipeline.Execute.BuildParamsTest do
defp build_token(ctx, params) do
%{jsons: jsons, action: action} = ctx

uri = jsons |> Keyword.fetch!(:action) |> URI.new!()
context = %Execute.Token.Context{root: uri, current: uri}
root = jsons |> Keyword.fetch!(:action) |> URI.new!()
context = Execute.Token.Context.new(root: root, dynamic: ResourceKit.Repo)

%Execute.Token{action: action, references: %{}, params: params, context: context}
end
end
3 changes: 1 addition & 2 deletions test/resource_kit/pipeline/execute/build_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ defmodule ResourceKit.Pipeline.Execute.BuildTest do
end

defp build_token(action) do
uri = URI.new!("uri")
context = %Token.Context{root: uri, current: uri}
context = Token.Context.new(root: URI.new!("uri"), dynamic: ResourceKit.Repo)

Token.put_assign(
%Token{action: action, references: %{}, params: %{}, context: context},
Expand Down
Loading