Skip to content

Commit

Permalink
feat: Support transient identities and traits (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
khvn26 authored Aug 30, 2024
1 parent d10e496 commit 909410d
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 15 deletions.
27 changes: 15 additions & 12 deletions lib/flagsmith_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -152,28 +152,30 @@ defmodule Flagsmith.Client do
@spec get_identity_flags(
Configuration.t() | Keyword.t(),
String.t(),
list(map() | Schemas.Traits.Trait.t())
list(map() | Schemas.Traits.Trait.t()),
boolean()
) ::
{:ok, Schemas.Flags.t()} | {:error, term()}
def get_identity_flags(configuration_or_opts \\ [], identifier, traits)
def get_identity_flags(configuration_or_opts \\ [], identifier, traits, transient \\ false)

def get_identity_flags(
%Configuration{enable_local_evaluation: local?} = config,
identifier,
traits
traits,
transient
) do
case local? do
true -> Flagsmith.Client.Poller.get_identity_flags(config, identifier, traits)
false -> get_identity_flags_request(config, identifier, traits)
false -> get_identity_flags_request(config, identifier, traits, transient)
end
end

def get_identity_flags(opts, identifier, traits) when is_list(opts),
do: get_identity_flags(new(opts), identifier, traits)
def get_identity_flags(opts, identifier, traits, transient) when is_list(opts),
do: get_identity_flags(new(opts), identifier, traits, transient)

@doc false
def get_identity_flags_request(%Configuration{} = config, identifier, traits) do
query = build_identity_params(identifier, traits)
def get_identity_flags_request(%Configuration{} = config, identifier, traits, transient) do
query = build_identity_params(identifier, traits, transient)

case Tesla.post(http_client(config), @api_paths.identities, query) do
{:ok, %{status: status, body: body}} when status >= 200 and status < 300 ->
Expand Down Expand Up @@ -375,15 +377,16 @@ defmodule Flagsmith.Client do
feature_flag
end

defp build_identity_params(identifier, [_ | _] = traits) do
defp build_identity_params(identifier, [_ | _] = traits, transient) do
%{
identifier: identifier,
traits: Schemas.Traits.Trait.from(traits)
traits: Schemas.Traits.Trait.from(traits),
transient: transient
}
end

defp build_identity_params(identifier, _),
do: %{identifier: identifier}
defp build_identity_params(identifier, _, transient),
do: %{identifier: identifier, transient: transient}

@doc false
@spec auth_middleware(environment_key :: String.t()) ::
Expand Down
5 changes: 3 additions & 2 deletions lib/schemas/traits/trait.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ defmodule Flagsmith.Schemas.Traits.Trait do
Ecto schema representing a Flagsmith trait definition.
"""

@derive {Jason.Encoder, only: [:trait_key, :trait_value]}
@derive {Jason.Encoder, only: [:trait_key, :trait_value, :transient]}

@primary_key {:id, :id, autogenerate: false}
typed_embedded_schema do
field(:trait_key, :string)
field(:trait_value, __MODULE__.Value)
field(:transient, :boolean, default: false)
end

@doc false
Expand Down Expand Up @@ -44,7 +45,7 @@ defmodule Flagsmith.Schemas.Traits.Trait do

def from(%{} = params) do
%__MODULE__{}
|> cast(params, [:trait_value, :trait_key, :id])
|> cast(params, [:trait_value, :trait_key, :transient, :id])
|> validate_required([:trait_value])
|> apply_changes()
end
Expand Down
46 changes: 45 additions & 1 deletion test/flagsmith_client_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ defmodule Flagsmith.Client.Test do
expect(Tesla.Adapter.Mock, :call, fn tesla_env, _options ->
assert_request(
tesla_env,
body: "{\"identifier\":\"super1234324\"}",
body: "{\"transient\":false,\"identifier\":\"super1234324\"}",
query: [],
headers: [{@environment_header, config.environment_key}],
url: Path.join([@api_url, @api_paths.identities]) <> "/",
Expand Down Expand Up @@ -315,6 +315,50 @@ defmodule Flagsmith.Client.Test do
# we also assert that no poller was initiated by making sure there's no pid
assert :undefined = Flagsmith.Client.Poller.whereis(config.environment_key)
end

test "get_identity_flags for transient identity", %{config: config} do
# set expectation for the http call
expect(Tesla.Adapter.Mock, :call, fn tesla_env, _options ->
assert_request(
tesla_env,
body: "{\"transient\":true,\"identifier\":\"super1234324\"}",
query: [],
headers: [{@environment_header, config.environment_key}],
url: Path.join([@api_url, @api_paths.identities]) <> "/",
method: :post
)

{:ok, %Tesla.Env{status: 200, body: Test.Generators.map_identity()}}
end)

Flagsmith.Client.get_identity_flags(config, "super1234324", [], true)
end

test "get_identity_flags for transient traits", %{config: config} do
# set expectation for the http call
expect(Tesla.Adapter.Mock, :call, fn tesla_env, _options ->
assert_request(
tesla_env,
body:
"{\"transient\":false,\"identifier\":\"super1234324\",\"traits\":[{\"trait_key\":\"foo\",\"trait_value\":{\"value\":\"bar\",\"type\":\"string\"},\"transient\":false},{\"trait_key\":\"transient\",\"trait_value\":{\"value\":\"bar\",\"type\":\"string\"},\"transient\":true}]}",
query: [],
headers: [{@environment_header, config.environment_key}],
url: Path.join([@api_url, @api_paths.identities]) <> "/",
method: :post
)

{:ok, %Tesla.Env{status: 200, body: Test.Generators.map_identity()}}
end)

Flagsmith.Client.get_identity_flags(
config,
"super1234324",
[
%{trait_key: "foo", trait_value: "bar"},
%{trait_key: "transient", trait_value: "bar", transient: true}
]
)
end
end

describe "failure tests" do
Expand Down

0 comments on commit 909410d

Please sign in to comment.