From d170685ded4f079504a16cc64dc5fb4e4f372e42 Mon Sep 17 00:00:00 2001 From: Ivan Ivanov Date: Tue, 14 Nov 2023 11:36:40 +0200 Subject: [PATCH] backup --- lib/sanbase/queries/menu/menu.ex | 26 +-- lib/sanbase/queries/menu/menu_item.ex | 56 ++++++ lib/sanbase/queries/menus.ex | 25 +++ .../graphql/schema/queries/menu_queries.ex | 110 ++++++++++ .../graphql/schema/types/menu_types.ex | 27 +++ .../20231110093800_create_menus_table.exs | 51 +++++ ...231110093800_create_queries_menu_table.exs | 29 --- priv/repo/structure.sql | 189 ++++++++++++++++++ 8 files changed, 466 insertions(+), 47 deletions(-) create mode 100644 lib/sanbase/queries/menu/menu_item.ex create mode 100644 lib/sanbase/queries/menus.ex create mode 100644 lib/sanbase_web/graphql/schema/queries/menu_queries.ex create mode 100644 lib/sanbase_web/graphql/schema/types/menu_types.ex create mode 100644 priv/repo/migrations/20231110093800_create_menus_table.exs delete mode 100644 priv/repo/migrations/20231110093800_create_queries_menu_table.exs diff --git a/lib/sanbase/queries/menu/menu.ex b/lib/sanbase/queries/menu/menu.ex index 1248c26426..f562aa5e85 100644 --- a/lib/sanbase/queries/menu/menu.ex +++ b/lib/sanbase/queries/menu/menu.ex @@ -4,19 +4,18 @@ defmodule Sanbase.Queries.Menu do import Ecto.Query import Ecto.Changeset + alias __MODULE__.MenuItem alias __MODULE__, as: Menu - schema "queries_menus" do + schema "menus" do field(:name, :string) field(:description, :string) - field(:order, :integer) - belongs_to(:parent, Menu, foreign_key: :parent_id) - belongs_to(:root_parentx, Menu, foreign_key: :root_parent_id) - has_many(:submenus, Menu, foreign_key: :submenu_id) + has_many(:menu_items, MenuItem) - belongs_to(:query, Sanbase.Query) - belongs_to(:dashboard, Sanbase.Dashboard) + # Build a hierarchy of menus. + belongs_to(:parent, Menu, foreign_key: :parent_id) + belongs_to(:root_parent, Menu, foreign_key: :root_parent_id) timestamps() end @@ -26,12 +25,8 @@ defmodule Sanbase.Queries.Menu do |> cast(attrs, [ :name, :description, - :order, :parent_id, - :root_parent_id, - :query_id, - :dashboard_id, - :submenu_id + :root_parent_id ]) |> validate_required([:name]) end @@ -39,7 +34,6 @@ defmodule Sanbase.Queries.Menu do def create(attrs \\ %{}) do %Menu{} |> changeset(attrs) - |> Repo.insert() end def update(menu, attrs) do @@ -53,10 +47,6 @@ defmodule Sanbase.Queries.Menu do end def get(id) do - Repo.get(Menu, id) - end - - def list do - Repo.all(Menu) + from(m in Menu, where: m.id == ^id) end end diff --git a/lib/sanbase/queries/menu/menu_item.ex b/lib/sanbase/queries/menu/menu_item.ex new file mode 100644 index 0000000000..4292fedec5 --- /dev/null +++ b/lib/sanbase/queries/menu/menu_item.ex @@ -0,0 +1,56 @@ +defmodule Sanbase.Queries.Menu.MenuItem do + use Ecto.Schema + + import Ecto.Query + import Ecto.Changeset + + alias Sanbase.Queries.Menu + alias Sanbase.Queries.Query + alias Sanbase.Queries.Dashboard + + schema "menu_items" do + belongs_to(:menu, Menu, foreign_key: :menu_id) + belongs_to(:root_menu, Menu, foreign_key: :root_menu_id) + + belongs_to(:query, Query, foreign_key: :query_id) + belongs_to(:dashboard, Dashboard, foreign_key: :dashboard_id) + + field(:position, :integer) + + timestamps() + end + + def changeset(menu, attrs \\ %{}) do + menu + |> cast(attrs, [ + :menu_id, + :query_id, + :dashboard_id, + :position + ]) + end + + def create(attrs \\ %{}) do + %__MODULE__{} + |> changeset(attrs) + |> Repo.insert() + end + + def update(menu, attrs) do + menu + |> changeset(attrs) + |> Repo.update() + end + + def delete(menu) do + Repo.delete(menu) + end + + def get(id) do + Repo.get(Menu, id) + end + + def list do + Repo.all(Menu) + end +end diff --git a/lib/sanbase/queries/menus.ex b/lib/sanbase/queries/menus.ex new file mode 100644 index 0000000000..1ee0e0d6f9 --- /dev/null +++ b/lib/sanbase/queries/menus.ex @@ -0,0 +1,25 @@ +defmodule Sanbase.Menus do + alias Sanbase.Queries.Menu + alias Sanbase.Queries.Menu.MenuItem + + def create_menu(args) do + Menu.create(args) + |> Sanbase.Repo.insert() + end + + def add_menu_item(menu_id, item_args) do + with {:ok, root_parent_id} <- get_root_parent_id(menu_id), + {:ok, position} <- MenuItem.get_next_position(root_parent_id) do + MenuItem.create(%{menu_id: menu_id, root_menu_id: root_parent_id} ++ item_args) + |> Sanbase.Repo.insert() + end + + MenuItem.create(%{menu_id: menu_id} ++ item_args) + end + + defp get_root_parent_id(menu_id) do + query = Menu.get(menu_id) |> select(:root_parent_id) + + {:ok, root_parent_id} = Sanbase.Repo.one(query) + end +end diff --git a/lib/sanbase_web/graphql/schema/queries/menu_queries.ex b/lib/sanbase_web/graphql/schema/queries/menu_queries.ex new file mode 100644 index 0000000000..2c10fe54c3 --- /dev/null +++ b/lib/sanbase_web/graphql/schema/queries/menu_queries.ex @@ -0,0 +1,110 @@ +defmodule SanbaseWeb.Graphql.Schema.MenuQueriesQueries do + @moduledoc ~s""" + Queries and mutations for working with short urls + """ + use Absinthe.Schema.Notation + + alias SanbaseWeb.Graphql.Resolvers.MenuResolver + alias SanbaseWeb.Graphql.Middlewares.JWTAuth + + object :menu_queries do + field :get_menu, :string do + meta(access: :free) + arg(:id, non_null(:integer)) + + middleware(JWTAuth) + + resolve(&MenuResolver.get_menu/3) + end + end + + object :menu_mutations do + field :create_menu, :string do + arg(:params, :menu_create_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.create_menu/3) + end + + field :update_menu, :string do + arg(:id, non_null(:id)) + arg(:params, :menu_update_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.update_menu/3) + end + + field :delete_menu, :string do + arg(:id, non_null(:string)) + + middleware(JWTAuth) + + resolve(&MenuResolver.delete_menu/3) + end + + field :add_menu_item, :string do + arg(:menu_id, non_null(:string)) + arg(:item_params, :menu_item_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.add_menu_item/3) + end + + field :create_menu_question, :string do + arg(:menu_uuid, non_null(:string)) + + arg(:params, :menu_question_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.create_question/3) + end + + field :update_menu_question, :menu do + arg(:question_uuid, non_null(:string)) + arg(:params, :menu_question_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.update_question/3) + end + + field :delete_menu_question, :menu do + arg(:question_uuid, non_null(:string)) + + middleware(JWTAuth) + + resolve(&MenuResolver.delete_question/3) + end + + field :create_menu_answer, :menu_answer do + arg(:question_uuid, non_null(:string)) + arg(:params, :menu_answer_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.create_answer/3) + end + + field :update_menu_answer, :menu_answer do + arg(:answer_uuid, non_null(:string)) + arg(:params, :menu_answer_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.update_answer/3) + end + + field :delete_menu_answer, :menu_answer do + arg(:answer_uuid, non_null(:string)) + arg(:params, :menu_answer_params_input_object) + + middleware(JWTAuth) + + resolve(&MenuResolver.delete_answer/3) + end + end +end diff --git a/lib/sanbase_web/graphql/schema/types/menu_types.ex b/lib/sanbase_web/graphql/schema/types/menu_types.ex new file mode 100644 index 0000000000..b89134cd13 --- /dev/null +++ b/lib/sanbase_web/graphql/schema/types/menu_types.ex @@ -0,0 +1,27 @@ +defmodule SanbaseWeb.Graphql.MenuTypes do + use Absinthe.Schema.Notation + + input_object :menu_create_params_input_object do + field(:name, non_null(:string)) + field(:description, :string) + + @desc ~s""" + If the menu is a sub-menu, this field should be set to the parent menu's id. + If this field is not set or explicitly set to null, the menu will be created as + a top-level menu + """ + field(:parent_id, :integer, default_value: nil) + end + + input_object :menu_update_params_input_object do + field(:name, :string) + field(:description, :string) + + @desc ~s""" + If the menu is a sub-menu, this field should be set to the parent menu's id. + If this field is not set or explicitly set to null, the menu will be created as + a top-level menu + """ + field(:parent_id, :integer, default_value: nil) + end +end diff --git a/priv/repo/migrations/20231110093800_create_menus_table.exs b/priv/repo/migrations/20231110093800_create_menus_table.exs new file mode 100644 index 0000000000..c8801a97a9 --- /dev/null +++ b/priv/repo/migrations/20231110093800_create_menus_table.exs @@ -0,0 +1,51 @@ +defmodule Sanbase.Repo.Migrations.CreatesMenusTable do + use Ecto.Migration + + def change do + create table(:menus) do + add(:name, :string) + add(:description, :string) + + add(:parent_id, references(:menus, on_delete: :delete_all)) + add(:root_parent_id, references(:menus, on_delete: :delete_all)) + + add(:position, :integer) + + add(:user_id, references(:users, on_delete: :delete_all)) + + add(:is_admin_controlled, :boolean, default: false) + + timestamps() + end + + # When searching for all sub-menus of a menu, the `where` clause will + # find these submenus by the root_parent_id, hence the index. The + # parent_id is used only to build the hierarchy after that. + create(index(:menus, [:root_parent_id])) + create(index(:menus, [:user_id])) + + create table(:menu_items) do + add(:menu_id, references(:menus, on_delete: :delete_all)) + add(:root_menu_id, references(:menus, on_delete: :delete_all)) + + add(:query_id, references(:queries, on_delete: :delete_all)) + add(:dashboard_id, references(:dashboards, on_delete: :delete_all)) + + add(:position, :integer) + + timestamps() + end + + # When searching for all menu items of a menu, the `where` clause will + # find these items by the root_menu_id, hence the index. The + # menu_id is used only to build the hierarchy after that. + create(index(:menu_items, [:root_menu_id])) + + fk_check = """ + (CASE WHEN query_id IS NULL THEN 0 ELSE 1 END) + + (CASE WHEN dashboard_id IS NULL THEN 0 ELSE 1 END) = 1 + """ + + create(constraint(:menu_items, :only_one_fk, check: fk_check)) + end +end diff --git a/priv/repo/migrations/20231110093800_create_queries_menu_table.exs b/priv/repo/migrations/20231110093800_create_queries_menu_table.exs deleted file mode 100644 index da3bf971ed..0000000000 --- a/priv/repo/migrations/20231110093800_create_queries_menu_table.exs +++ /dev/null @@ -1,29 +0,0 @@ -defmodule Sanbase.Repo.Migrations.CreateQueriesMenuTable do - use Ecto.Migration - - def change do - create table(:menus) do - add(:name, :string) - add(:description, :string) - - add(:parent_id, references(:menus, on_delete: :delete_all)) - add(:root_parent_id, references(:menus, on_delete: :delete_all)) - - add(:user_id, references(:users, on_delete: :delete_all)) - - add(:is_admin_controlled, :boolean, default: false) - - timestamps() - end - - create table(:menu_items) do - arg(:query_id, references(:queries, on_delete: :delete_all)) - arg(:dashboard_id, references(:dashboards, on_delete: :delete_all)) - arg(:menu_id, references(:menus, on_delete: :delete_all)) - - arg(:position, :integer) - - timestamps() - end - end -end diff --git a/priv/repo/structure.sql b/priv/repo/structure.sql index a5e14d36c7..5f43872a87 100644 --- a/priv/repo/structure.sql +++ b/priv/repo/structure.sql @@ -2005,6 +2005,87 @@ CREATE SEQUENCE public.market_segments_id_seq ALTER SEQUENCE public.market_segments_id_seq OWNED BY public.market_segments.id; +-- +-- Name: menu_items; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.menu_items ( + id bigint NOT NULL, + menu_id bigint, + root_menu_id bigint, + query_id bigint, + dashboard_id bigint, + "position" integer, + inserted_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + CONSTRAINT only_one_fk CHECK ((( +CASE + WHEN (query_id IS NULL) THEN 0 + ELSE 1 +END + +CASE + WHEN (dashboard_id IS NULL) THEN 0 + ELSE 1 +END) = 1)) +); + + +-- +-- Name: menu_items_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.menu_items_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: menu_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.menu_items_id_seq OWNED BY public.menu_items.id; + + +-- +-- Name: menus; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.menus ( + id bigint NOT NULL, + name character varying(255), + description character varying(255), + parent_id bigint, + root_parent_id bigint, + "position" integer, + user_id bigint, + is_admin_controlled boolean DEFAULT false, + inserted_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: menus_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.menus_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: menus_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.menus_id_seq OWNED BY public.menus.id; + + -- -- Name: metrics; Type: TABLE; Schema: public; Owner: - -- @@ -4755,6 +4836,20 @@ ALTER TABLE ONLY public.list_items ALTER COLUMN id SET DEFAULT nextval('public.l ALTER TABLE ONLY public.market_segments ALTER COLUMN id SET DEFAULT nextval('public.market_segments_id_seq'::regclass); +-- +-- Name: menu_items id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menu_items ALTER COLUMN id SET DEFAULT nextval('public.menu_items_id_seq'::regclass); + + +-- +-- Name: menus id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menus ALTER COLUMN id SET DEFAULT nextval('public.menus_id_seq'::regclass); + + -- -- Name: metrics id; Type: DEFAULT; Schema: public; Owner: - -- @@ -5590,6 +5685,22 @@ ALTER TABLE ONLY public.market_segments ADD CONSTRAINT market_segments_pkey PRIMARY KEY (id); +-- +-- Name: menu_items menu_items_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menu_items + ADD CONSTRAINT menu_items_pkey PRIMARY KEY (id); + + +-- +-- Name: menus menus_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menus + ADD CONSTRAINT menus_pkey PRIMARY KEY (id); + + -- -- Name: metrics metrics_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -6621,6 +6732,27 @@ CREATE UNIQUE INDEX list_items_user_list_id_project_id_index ON public.list_item CREATE UNIQUE INDEX market_segments_name_index ON public.market_segments USING btree (name); +-- +-- Name: menu_items_root_menu_id_index; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX menu_items_root_menu_id_index ON public.menu_items USING btree (root_menu_id); + + +-- +-- Name: menus_root_parent_id_index; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX menus_root_parent_id_index ON public.menus USING btree (root_parent_id); + + +-- +-- Name: menus_user_id_index; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX menus_user_id_index ON public.menus USING btree (user_id); + + -- -- Name: metrics_name_index; Type: INDEX; Schema: public; Owner: - -- @@ -7757,6 +7889,62 @@ ALTER TABLE ONLY public.list_items ADD CONSTRAINT list_items_user_list_id_fkey FOREIGN KEY (user_list_id) REFERENCES public.user_lists(id) ON DELETE CASCADE; +-- +-- Name: menu_items menu_items_dashboard_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menu_items + ADD CONSTRAINT menu_items_dashboard_id_fkey FOREIGN KEY (dashboard_id) REFERENCES public.dashboards(id) ON DELETE CASCADE; + + +-- +-- Name: menu_items menu_items_menu_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menu_items + ADD CONSTRAINT menu_items_menu_id_fkey FOREIGN KEY (menu_id) REFERENCES public.menus(id) ON DELETE CASCADE; + + +-- +-- Name: menu_items menu_items_query_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menu_items + ADD CONSTRAINT menu_items_query_id_fkey FOREIGN KEY (query_id) REFERENCES public.queries(id) ON DELETE CASCADE; + + +-- +-- Name: menu_items menu_items_root_menu_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menu_items + ADD CONSTRAINT menu_items_root_menu_id_fkey FOREIGN KEY (root_menu_id) REFERENCES public.menus(id) ON DELETE CASCADE; + + +-- +-- Name: menus menus_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menus + ADD CONSTRAINT menus_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES public.menus(id) ON DELETE CASCADE; + + +-- +-- Name: menus menus_root_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menus + ADD CONSTRAINT menus_root_parent_id_fkey FOREIGN KEY (root_parent_id) REFERENCES public.menus(id) ON DELETE CASCADE; + + +-- +-- Name: menus menus_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.menus + ADD CONSTRAINT menus_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + -- -- Name: monitored_twitter_handles monitored_twitter_handles_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -8929,3 +9117,4 @@ INSERT INTO public."schema_migrations" (version) VALUES (20231023123140); INSERT INTO public."schema_migrations" (version) VALUES (20231026084628); INSERT INTO public."schema_migrations" (version) VALUES (20231030143950); INSERT INTO public."schema_migrations" (version) VALUES (20231101104145); +INSERT INTO public."schema_migrations" (version) VALUES (20231110093800);