From a611765cfbbff1d5be2378ae29da0db17da17ddc Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Wed, 2 Oct 2024 18:10:48 +0200 Subject: [PATCH] WIP2 --- backend/.formatter.exs | 1 + .../base_images/base_image/base_image.ex | 12 ++--- .../base_images/base_image_collection.ex | 12 ++--- backend/lib/edgehog/multitenant_resource.ex | 9 ++++ .../20240919153634_reconcile_with_ash.exs | 48 +++++++++++++++++++ 5 files changed, 66 insertions(+), 16 deletions(-) diff --git a/backend/.formatter.exs b/backend/.formatter.exs index 50f564b8b..86fc41508 100644 --- a/backend/.formatter.exs +++ b/backend/.formatter.exs @@ -8,6 +8,7 @@ :ash_json_api, :ash_postgres, :ecto, + :ecto_sql, :phoenix, :absinthe, :skogsra, diff --git a/backend/lib/edgehog/base_images/base_image/base_image.ex b/backend/lib/edgehog/base_images/base_image/base_image.ex index 1248273d8..a119f0a69 100644 --- a/backend/lib/edgehog/base_images/base_image/base_image.ex +++ b/backend/lib/edgehog/base_images/base_image/base_image.ex @@ -211,17 +211,15 @@ defmodule Edgehog.BaseImages.BaseImage do end identities do - # These have to be named this way to match the existing unique indexes - # we already have. Ash uses identities to add a `unique_constraint` to the - # Ecto changeset, so names have to match. There's no need to explicitly add - # :tenant_id in the fields because identity in a multitenant resource are - # automatically scoped to a specific :tenant_id - # TODO: change index names when we generate migrations at the end of the porting - identity :version_base_image_collection_id_tenant_id, [:version, :base_image_collection_id] + identity :version, [:version, :base_image_collection_id] end postgres do table "base_images" repo Edgehog.Repo + + custom_indexes do + index [:base_image_collection_id], unique: false + end end end diff --git a/backend/lib/edgehog/base_images/base_image_collection.ex b/backend/lib/edgehog/base_images/base_image_collection.ex index 76ec2938f..4e3c30b3b 100644 --- a/backend/lib/edgehog/base_images/base_image_collection.ex +++ b/backend/lib/edgehog/base_images/base_image_collection.ex @@ -117,15 +117,9 @@ defmodule Edgehog.BaseImages.BaseImageCollection do end identities do - # These have to be named this way to match the existing unique indexes - # we already have. Ash uses identities to add a `unique_constraint` to the - # Ecto changeset, so names have to match. There's no need to explicitly add - # :tenant_id in the fields because identity in a multitenant resource are - # automatically scoped to a specific :tenant_id - # TODO: change index names when we generate migrations at the end of the porting - identity :handle_tenant_id, [:handle] - identity :name_tenant_id, [:name] - identity :system_model_id_tenant_id, [:system_model_id] + identity :handle, [:handle] + identity :name, [:name] + identity :system_model_id, [:system_model_id] end postgres do diff --git a/backend/lib/edgehog/multitenant_resource.ex b/backend/lib/edgehog/multitenant_resource.ex index a34f0bd81..20119e395 100644 --- a/backend/lib/edgehog/multitenant_resource.ex +++ b/backend/lib/edgehog/multitenant_resource.ex @@ -52,6 +52,15 @@ defmodule Edgehog.MultitenantResource do references do reference :tenant, on_delete: :delete end + + if not unquote(Keyword.get(opts, :tenant_id_in_primary_key?, false)) do + custom_indexes do + # Assumptions: + # - There is a primary key and it's called :id + index [:id], unique: true + index [:tenant_id], all_tenants?: false + end + end end end end diff --git a/backend/priv/repo/migrations/20240919153634_reconcile_with_ash.exs b/backend/priv/repo/migrations/20240919153634_reconcile_with_ash.exs index 6a7a8985b..9b769d883 100644 --- a/backend/priv/repo/migrations/20240919153634_reconcile_with_ash.exs +++ b/backend/priv/repo/migrations/20240919153634_reconcile_with_ash.exs @@ -271,5 +271,53 @@ defmodule Edgehog.Repo.Migrations.ReconcileWithAsh do null: false, default: fragment("(now() AT TIME ZONE 'utc')") end + + # Ash puts :tenant_id first in indexes, while we had it as last merely to have a better Ecto + # error message. We need to swap all things around. + # When we drop the index we don't pass and explicit name because it was generated with the + # Ecto default name. When we create it we pass it explicitly to match what Ash migrations + # expect. + + drop_if_exists unique_index(:base_image_collections, [:handle, :tenant_id]) + + create unique_index(:base_image_collections, [:tenant_id, :handle], + name: "base_image_collections_handle_index" + ) + + drop_if_exists unique_index(:base_image_collections, [:name, :tenant_id]) + + create unique_index(:base_image_collections, [:tenant_id, :name], + name: "base_image_collections_name_index" + ) + + drop_if_exists unique_index(:base_image_collections, [:system_model_id, :tenant_id]) + + create unique_index(:base_image_collections, [:tenant_id, :system_model_id], + name: "base_image_collections_system_model_id_index" + ) + + drop_if_exists index(:base_images, [:base_image_collection_id, :tenant_id]) + create index(:base_images, [:tenant_id, :base_image_collection_id]) + + drop_if_exists unique_index(:base_images, [:handle, :tenant_id]) + create unique_index(:base_images, [:tenant_id, :handle], name: "base_images_handle_index") + + drop_if_exists unique_index(:base_images, [:handle, :tenant_id]) + create unique_index(:base_images, [:tenant_id, :handle], name: "base_images_handle_index") + + # Our MultitenantResource now creates a unique index on `[:tenant_id, :id]` for _all_ resources + # This allows using composite foreign keys to enforce associated resources are on in the same + # tenant at the database level. + # We add just _some_ of those indexes, so we manually create the missing ones + create unique_index(:device_groups, [:tenant_id, :id]) + create unique_index(:hardware_type_part_numbers, [:tenant_id, :id]) + create unique_index(:hardware_types, [:tenant_id, :id]) + create unique_index(:realms, [:tenant_id, :id]) + create unique_index(:system_model_part_numbers, [:tenant_id, :id]) + create unique_index(:system_models, [:tenant_id, :id]) + create unique_index(:tags, [:tenant_id, :id]) + create unique_index(:update_campaign_targets, [:tenant_id, :id]) + + # For end end