Skip to content

Commit

Permalink
Use :context instead of :prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
JesseStimpson committed Aug 18, 2024
1 parent 507b094 commit 7c02b00
Show file tree
Hide file tree
Showing 19 changed files with 176 additions and 151 deletions.
8 changes: 4 additions & 4 deletions bench/scripts/get_bench.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ users =
1..limit
|> Enum.map(fn _ -> User.sample_data() end)

FDBRepo.insert_all(User, users, prefix: tenant)
FDBRepo.insert_all(User, users, context: tenant)

test_user = Enum.random(users)

jobs = %{
"FDB Repo.get/3" => fn _ ->
FDBRepo.get(User, test_user.id, prefix: tenant)
FDBRepo.get(User, test_user.id, context: tenant)
end,
"FDB Repo.get_by/3" => fn _ ->
FDBRepo.get_by(User, [uuid: test_user.uuid], prefix: tenant)
FDBRepo.get_by(User, [uuid: test_user.uuid], context: tenant)
end
}

Expand All @@ -47,4 +47,4 @@ Benchee.run(
)

{:ok, _pid} = FDBRepo.start_link(log: false)
FDBRepo.delete_all(User, prefix: tenant)
FDBRepo.delete_all(User, context: tenant)
4 changes: 2 additions & 2 deletions bench/scripts/insert_bench.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ inputs = %{

jobs = %{
"FDB Repo.insert!/1" => fn entry ->
FDBRepo.insert(entry.(), prefix: tenant)
FDBRepo.insert(entry.(), context: tenant)
end
}

Expand All @@ -29,4 +29,4 @@ Benchee.run(
]
)

FDBRepo.delete_all(User, prefix: tenant)
FDBRepo.delete_all(User, context: tenant)
20 changes: 10 additions & 10 deletions lib/ecto/adapters/foundationdb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ defmodule Ecto.Adapters.FoundationDB do
Each tenant you create has a separate keyspace from all others, and a given FoundationDB
Transaction is guaranteed to be isolated to a particular tenant's keyspace.
You'll use the Ecto `:prefix` option to specify the relevant tenant for each Ecto operation
You'll use the Ecto `:context` option to specify the relevant tenant for each Ecto operation
in your application.
Creating a schema to be used in a tenant.
Expand Down Expand Up @@ -108,10 +108,10 @@ defmodule Ecto.Adapters.FoundationDB do
Querying for a struct using the primary key.
```elixir
MyApp.Repo.get!(User, user.id, prefix: tenant)
MyApp.Repo.get!(User, user.id, context: tenant)
```
When a struct is retrieved from a tenant (using `:prefix`), that struct's metadata
When a struct is retrieved from a tenant (using `:context`), that struct's metadata
holds onto the tenant reference. This helps to protect your application from a
struct accidentally crossing tenant boundaries due to some unforeseen bug.
Expand Down Expand Up @@ -155,7 +155,7 @@ defmodule Ecto.Adapters.FoundationDB do
```elixir
iex> query = from(u in User, where: u.department == ^"Engineering")
iex> MyApp.Repo.all(query, prefix: tenant)
iex> MyApp.Repo.all(query, context: tenant)
```
Retrieve all users with a birthyear from 1992 to 1994 (with a Between constraint):
Expand All @@ -164,7 +164,7 @@ defmodule Ecto.Adapters.FoundationDB do
iex> query = from(u in User,
...> where: u.birthyear >= ^1992 and u.birthyear <= ^1994
...> )
iex> MyApp.Repo.all(query, prefix: tenant)
iex> MyApp.Repo.all(query, context: tenant)
```
Retrieve all Engineers born in August 1992:
Expand All @@ -175,7 +175,7 @@ defmodule Ecto.Adapters.FoundationDB do
...> u.department == ^"Engineering" and
...> u.birthdate >= ^~D[1992-08-01] and u.birthdate < ^~D[1992-09-01]
...> )
iex> MyApp.Repo.all(query, prefix: tenant)
iex> MyApp.Repo.all(query, context: tenant)
```
**Order matters!**: When you create an index using multiple fields, the FDB key that stores the index will be extended with
Expand All @@ -202,7 +202,7 @@ defmodule Ecto.Adapters.FoundationDB do
```elixir
MyApp.Repo.transaction(fn ->
# Ecto work
end, prefix: tenant)
end, context: tenant)
```
It also exposes a FoundationDB-specific transaction:
Expand Down Expand Up @@ -237,15 +237,15 @@ defmodule Ecto.Adapters.FoundationDB do
MyApp.Repo.insert(%User{name: "John"})
...
Phoenix.PubSub.broadcast("my_topic", "new_user") # Not safe! :(
end, prefix: tenant)
end, context: tenant)
```
```elixir
# Instead, do this:
MyApp.Repo.transaction(fn ->
MyApp.Repo.insert(%User{name: "John"})
...
end, prefix: tenant)
end, context: tenant)
Phoenix.PubSub.broadcast("my_topic", "new_user") # Safe :)
```
Expand Down Expand Up @@ -477,7 +477,7 @@ defmodule Ecto.Adapters.FoundationDB do

@spec usetenant(Ecto.Schema.schema(), any()) :: Ecto.Schema.schema()
def usetenant(struct, tenant) do
Ecto.put_meta(struct, prefix: tenant)
Ecto.put_meta(struct, context: tenant)
end

@doc """
Expand Down
57 changes: 29 additions & 28 deletions lib/ecto/adapters/foundationdb/ecto_adapter_queryable.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do
}
}, {_limit, limit_fn}, %{}, ordering_fn}},
params,
_options
options
) do
{context, query = %Ecto.Query{prefix: tenant}} = assert_tenancy!(query, adapter_opts)
{schema_context, tenant, query} = assert_tenancy!(query, adapter_opts, options)

tenant
|> execute_all(adapter_meta, context, query, params)
|> execute_all(adapter_meta, schema_context, query, params)
|> ordering_fn.()
|> limit_fn.()
|> select(Fields.parse_select_fields(select_fields))
Expand All @@ -60,11 +60,11 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do
wheres: wheres
}, {nil, _limit_fn}, %{}, _ordering_fn}},
params,
_options
options
) do
{context, %Ecto.Query{prefix: tenant}} = assert_tenancy!(query, adapter_opts)
{schema_context, tenant, _query} = assert_tenancy!(query, adapter_opts, options)

plan = QueryPlan.get(source, schema, context, wheres, [], params)
plan = QueryPlan.get(source, schema, schema_context, wheres, [], params)
num = Query.delete(tenant, adapter_meta, plan)

{num, []}
Expand All @@ -76,12 +76,12 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do
_query_cache =
{:nocache, {:update_all, query, {nil, _limit_fn}, %{}, _ordering_fn}},
params,
_options
options
) do
{context, query = %Ecto.Query{prefix: tenant}} = assert_tenancy!(query, adapter_opts)
{schema_context, tenant, query} = assert_tenancy!(query, adapter_opts, options)

num =
execute_update_all(tenant, adapter_meta, context, query, params)
execute_update_all(tenant, adapter_meta, schema_context, query, params)

{num, []}
end
Expand All @@ -95,10 +95,10 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do
params,
options
) do
{context, query = %Ecto.Query{prefix: tenant}} = assert_tenancy!(query, adapter_opts)
{schema_context, tenant, query} = assert_tenancy!(query, adapter_opts, options)

tenant
|> stream_all(adapter_meta, context, query, params, options)
|> stream_all(adapter_meta, schema_context, query, params, options)
end

# Extract limit from an `Ecto.Query`
Expand All @@ -107,32 +107,33 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do

defp assert_tenancy!(
query = %Ecto.Query{
prefix: tenant,
from: %Ecto.Query.FromExpr{source: {source, schema}}
},
_adapter_opts
_adapter_opts,
query_options
) do
context = Schema.get_context!(source, schema)
tenant = query_options[:context]
schema_context = Schema.get_context!(source, schema)

case Tx.safe?(tenant, Schema.get_option(context, :usetenant)) do
case Tx.safe?(tenant, Schema.get_option(schema_context, :usetenant)) do
{false, :unused_tenant} ->
raise IncorrectTenancy, """
FoundatioDB Adapter is expecting the query for schema \
#{inspect(schema)} to specify no tentant in the prefix metadata, \
but a non-nil prefix was provided.
#{inspect(schema)} to specify no tentant in the context metadata, \
but a non-nil context was provided.
Add `usetenant: true` to your schema's `@schema_context`.
Alternatively, remove the `prefix: tenant` from your query.
Alternatively, remove the `context: tenant` from your query.
"""

{false, :missing_tenant} ->
raise IncorrectTenancy, """
FoundationDB Adapter is expecting the query for schema \
#{inspect(schema)} to include a tenant in the prefix metadata, \
but a nil prefix was provided.
#{inspect(schema)} to include a tenant in the context metadata, \
but a nil context was provided.
Use `prefix: tenant` in your query.
Use `context: tenant` in your query.
Alternatively, remove `usetenant: true` from your schema's \
`@schema_context` if you do not want to use a tenant for this schema.
Expand All @@ -142,14 +143,14 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do
raise Unsupported, "Non-tenant transactions are not yet implemented."

true ->
{context, query}
{schema_context, tenant, query}
end
end

defp execute_all(
tenant,
adapter_meta,
context,
schema_context,
%Ecto.Query{
from: %Ecto.Query.FromExpr{source: {source, schema}},
wheres: wheres
Expand All @@ -166,30 +167,30 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do
# 3. Use :erlfdb.get, :erlfdb.get_range
# 4. Post-get filtering (Remove :not_found, remove index conflicts, )
# 5. Arrange fields based on the select input
plan = QueryPlan.get(source, schema, context, wheres, [], params)
plan = QueryPlan.get(source, schema, schema_context, wheres, [], params)
{objs, _continuation} = Query.all(tenant, adapter_meta, plan)
objs
end

defp execute_update_all(
tenant,
adapter_meta = %{opts: _adapter_opts},
context,
schema_context,
%Ecto.Query{
from: %Ecto.Query.FromExpr{source: {source, schema}},
wheres: wheres,
updates: updates
},
params
) do
plan = QueryPlan.get(source, schema, context, wheres, updates, params)
plan = QueryPlan.get(source, schema, schema_context, wheres, updates, params)
Query.update(tenant, adapter_meta, plan)
end

defp stream_all(
tenant,
adapter_meta,
context,
schema_context,
%Ecto.Query{
select: %Ecto.Query.SelectExpr{
fields: select_fields
Expand Down Expand Up @@ -218,7 +219,7 @@ defmodule Ecto.Adapters.FoundationDB.EctoAdapterQueryable do
end

start_fun = fn ->
plan = QueryPlan.get(source, schema, context, wheres, [], params)
plan = QueryPlan.get(source, schema, schema_context, wheres, [], params)

%{
adapter_meta: adapter_meta,
Expand Down
Loading

0 comments on commit 7c02b00

Please sign in to comment.