diff --git a/lib/kino_db/connection_cell.ex b/lib/kino_db/connection_cell.ex index e92e674..7dab03f 100644 --- a/lib/kino_db/connection_cell.ex +++ b/lib/kino_db/connection_cell.ex @@ -133,29 +133,55 @@ defmodule KinoDB.ConnectionCell do end end - # TODO: Support :refresh_token and :metadata for Goth source type - # See: https://github.com/peburrows/goth/blob/e62ca4afddfabdb3d599c3594fee02c49a2350e4/lib/goth/token.ex#L159-L172 defp to_quoted(%{"type" => "bigquery"} = attrs) do - quote do - credentials = unquote(Macro.escape(attrs["credentials"])) + goth_opts_block = check_bigquery_credentials(attrs) - opts = [ - name: ReqBigQuery.Goth, - http_client: &Req.request/1, - source: {:service_account, credentials, []} - ] + conn_block = + quote do + {:ok, _pid} = Kino.start_child({Goth, opts}) - {:ok, _pid} = Kino.start_child({Goth, opts}) + unquote(quoted_var(attrs["variable"])) = + Req.new(http_errors: :raise) + |> ReqBigQuery.attach( + goth: ReqBigQuery.Goth, + project_id: unquote(attrs["project_id"]), + default_dataset_id: unquote(attrs["default_dataset_id"]) + ) - unquote(quoted_var(attrs["variable"])) = - Req.new(http_errors: :raise) - |> ReqBigQuery.attach( - goth: ReqBigQuery.Goth, - project_id: unquote(attrs["project_id"]), - default_dataset_id: unquote(attrs["default_dataset_id"]) - ) + :ok + end + + join_quoted([goth_opts_block, conn_block]) + end - :ok + defp check_bigquery_credentials(attrs) do + cond do + match?(%{"type" => "service_account"}, attrs["credentials"]) -> + quote do + credentials = unquote(Macro.escape(attrs["credentials"])) + + opts = [ + name: ReqBigQuery.Goth, + http_client: &Req.request/1, + source: {:service_account, credentials} + ] + end + + match?(%{"type" => "authorized_user"}, attrs["credentials"]) -> + quote do + credentials = unquote(Macro.escape(attrs["credentials"])) + + opts = [ + name: ReqBigQuery.Goth, + http_client: &Req.request/1, + source: {:refresh_token, credentials} + ] + end + + true -> + quote do + opts = [name: ReqBigQuery.Goth, http_client: &Req.request/1] + end end end @@ -208,4 +234,17 @@ defmodule KinoDB.ConnectionCell do end defp missing_dep(_ctx), do: nil + + defp join_quoted(quoted_blocks) do + asts = + Enum.flat_map(quoted_blocks, fn + {:__block__, _meta, nodes} -> nodes + node -> [node] + end) + + case asts do + [node] -> node + nodes -> {:__block__, [], nodes} + end + end end diff --git a/mix.lock b/mix.lock index 695b7a4..a5d6276 100644 --- a/mix.lock +++ b/mix.lock @@ -7,8 +7,8 @@ "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, "ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [: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", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"}, "exqlite": {:hex, :exqlite, "0.11.0", "f57519d60e923c29fa5d22537ce178293e5fdf3c950ce20d895dd3fc2c1a68f3", [:make, :mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "e8fae0ced354bcb5f76a6f3d2364844c1f1530d07be211bb32bf57ddb0104834"}, - "finch": {:hex, :finch, "0.11.0", "622d31c224c801444c6003544fa1964a29551895b45c3543f6e4d8b0dab80f71", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "047550448148d828ddea1fb76fa3f0d2d0742eca6919e548fdd8357630cae449"}, - "goth": {:git, "https://github.com/peburrows/goth.git", "e62ca4afddfabdb3d599c3594fee02c49a2350e4", []}, + "finch": {:hex, :finch, "0.12.0", "6bbb3e0bb62dd91cd1217d9682a30f5bfc9b0b74950bf10a0b4d4399c2076892", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "320da3f32459e7dcb77f4271b4f2445ba6c5d32cc3c7cca8e2cff599e24be5a6"}, + "goth": {:hex, :goth, "1.3.0", "db893be00006e4c85e6c92255a078b9eb249e1bc88349fd447f12e93d2f1253e", [:mix], [{:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "3c2c4e085bae945305132bc9bcb4d4d84d5e34e233a900164eb2529ab8bab85d"}, "hpax": {:hex, :hpax, "0.1.1", "2396c313683ada39e98c20a75a82911592b47e5c24391363343bde74f82396ca", [:mix], [], "hexpm", "0ae7d5a0b04a8a60caf7a39fcf3ec476f35cc2cc16c05abea730d3ce6ac6c826"}, "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, "jose": {:hex, :jose, "1.11.2", "f4c018ccf4fdce22c71e44d471f15f723cb3efab5d909ab2ba202b5bf35557b3", [:mix, :rebar3], [], "hexpm", "98143fbc48d55f3a18daba82d34fe48959d44538e9697c08f34200fa5f0947d2"}, @@ -17,14 +17,14 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, - "mint": {:hex, :mint, "1.4.1", "49b3b6ea35a9a38836d2ad745251b01ca9ec062f7cb66f546bf22e6699137126", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "cd261766e61011a9079cccf8fa9d826e7a397c24fbedf0e11b49312bea629b58"}, + "mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"}, "myxql": {:hex, :myxql, "0.6.2", "7346246e73035d6853c189d0478537a347d6e380a7227a5695ac9ecf4eb39959", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "88094d5c90765fd93f2888a60285077fb937b8e5917570f7be2a3a6bf45e0e2a"}, "nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"}, "postgrex": {:hex, :postgrex, "0.16.3", "fac79a81a9a234b11c44235a4494d8565303fa4b9147acf57e48978a074971db", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "aeaae1d2d1322da4e5fe90d241b0a564ce03a3add09d7270fb85362166194590"}, - "req": {:git, "https://github.com/wojtekmach/req.git", "e91967962e03ec22d6a691de993840ae9ddb9c47", []}, - "req_bigquery": {:git, "https://github.com/livebook-dev/req_bigquery.git", "ea0d7e996d0d7102d6794e0bfd561ab22aefbfc9", []}, + "req": {:hex, :req, "0.3.0", "45944bfa0ea21294ad269e2025b9983dd084cc89125c4fc0a8de8a4e7869486b", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "1212a3e047eede0fa7eeb84c30d08206d44bb120df98b6f6b9a9e04910954a71"}, + "req_bigquery": {:git, "https://github.com/livebook-dev/req_bigquery.git", "364adba0ecb32f944c7972f011657f954aca6c35", []}, "table": {:hex, :table, "0.1.1", "e8d3c75bb14b8dac227e17d85a626e695d96c271569e94e4a2d15494a7cb0b49", [:mix], [], "hexpm", "6a73280b2f5ad70474594feeb8c034ad490b97dbd5adaeb678f71c250cbc928c"}, "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"}, } diff --git a/test/kino_db/connection_cell_test.exs b/test/kino_db/connection_cell_test.exs index 5704988..fd210dd 100644 --- a/test/kino_db/connection_cell_test.exs +++ b/test/kino_db/connection_cell_test.exs @@ -74,12 +74,73 @@ defmodule KinoDB.ConnectionCellTest do assert source == """ - credentials = %{} + opts = [name: ReqBigQuery.Goth, http_client: &Req.request/1] + {:ok, _pid} = Kino.start_child({Goth, opts}) + + db = + Req.new(http_errors: :raise) + |> ReqBigQuery.attach(goth: ReqBigQuery.Goth, project_id: "", default_dataset_id: "") + + :ok\ + """ + + credentials = %{ + "private_key" => "foo", + "client_email" => "alice@example.com", + "token_uri" => "/", + "type" => "service_account" + } + + {_kino, source} = + start_smart_cell!(ConnectionCell, put_in(attrs["credentials"], credentials)) + + assert source == + """ + credentials = %{ + "client_email" => "alice@example.com", + "private_key" => "foo", + "token_uri" => "/", + "type" => "service_account" + } + + opts = [ + name: ReqBigQuery.Goth, + http_client: &Req.request/1, + source: {:service_account, credentials} + ] + + {:ok, _pid} = Kino.start_child({Goth, opts}) + + db = + Req.new(http_errors: :raise) + |> ReqBigQuery.attach(goth: ReqBigQuery.Goth, project_id: "", default_dataset_id: "") + + :ok\ + """ + + credentials = %{ + "refresh_token" => "foo", + "client_id" => "alice@example.com", + "client_secret" => "bar", + "type" => "authorized_user" + } + + {_kino, source} = + start_smart_cell!(ConnectionCell, put_in(attrs["credentials"], credentials)) + + assert source == + """ + credentials = %{ + "client_id" => "alice@example.com", + "client_secret" => "bar", + "refresh_token" => "foo", + "type" => "authorized_user" + } opts = [ name: ReqBigQuery.Goth, http_client: &Req.request/1, - source: {:service_account, credentials, []} + source: {:refresh_token, credentials} ] {:ok, _pid} = Kino.start_child({Goth, opts})