defmodule Chalk.Query do
alias Chalk.Client
alias Chalk.Client.Request
alias Chalk.Common.ChalkError
alias Chalk.Common.ChalkException
defmodule FeatureMeta do
@derive Jason.Encoder
defstruct cache_hit: nil,
chosen_resolver_fqn: nil,
primitive_type: nil,
version: nil
@type t :: %__MODULE__{
cache_hit: boolean(),
chosen_resolver_fqn: String.t(),
primitive_type: String.t(),
version: integer()
}
end
defmodule FeatureResult do
@derive Jason.Encoder
defstruct error: nil,
field: nil,
meta: nil,
pkey: nil,
ts: nil,
value: nil
@type t :: %__MODULE__{
error: ChalkError.t(),
field: String.t(),
meta: FeatureMeta.t(),
pkey: String.t(),
ts: String.t(),
value: any()
}
end
defmodule QueryMeta do
@derive Jason.Encoder
defstruct deployment_id: nil,
environment_id: nil,
environment_name: nil,
execution_duration_s: nil,
query_hash: nil,
query_id: nil,
query_timestamp: nil
@type t :: %__MODULE__{
deployment_id: String.t(),
environment_id: String.t(),
environment_name: String.t(),
execution_duration_s: float(),
query_hash: String.t(),
query_id: String.t(),
query_timestamp: String.t()
}
end
defmodule OnlineQueryResponse do
@derive Jason.Encoder
defstruct data: [],
errors: [],
meta: nil
@type t :: %__MODULE__{
data: [FeatureResult.t()],
errors: [ChalkError.t()],
meta: QueryMeta.t()
}
end
@doc """
Execute an online query
"""
@spec online(
%{
required(:inputs) => %{
String.t() => String.t()
},
required(:outputs) => [String.t()],
optional(:staleness) => %{
String.t() => String.t()
},
optional(:context) => %{
optional(:environment) => String.t(),
optional(:tags) => [String.t()]
},
optional(:deployment_id) => String.t(),
optional(:query_name) => String.t()
},
map()
) :: {:ok, OnlineQueryResponse.t()} | {:error, any()}
def online(params, config \\ %{}) do
request_operation("v1/query/online", params, config)
end
defp request_operation(endpoint, params, config) do
c = config[:client] || Chalk
params =
if deployment_id = Map.get(config, :deployment_id, System.get_env("DEPLOYMENT_ID")) do
# prefer the deployment_id in params, if it exists
Map.put_new(params, :deployment_id, deployment_id)
else
params
end
Request
|> struct(method: :post, endpoint: endpoint, body: params)
|> Request.add_metadata(config)
|> c.send_request(Client.new(config))
|> c.handle_response(&map_query_response(&1))
end
defp map_query_response(body) do
Poison.Decode.decode(body, %{
as: %OnlineQueryResponse{
data: [
%FeatureResult{
error: %ChalkError{
exception: %ChalkException{}
},
meta: %FeatureMeta{}
}
],
errors: [
%ChalkError{
exception: %ChalkException{}
}
],
meta: %QueryMeta{}
}
})
end
end