mirror of
				https://github.com/wanderer-industries/wanderer
				synced 2025-10-31 06:27:05 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			v1.11.4
			...
			19-add-map
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d622e486f4 | ||
|   | 81926633b0 | ||
|   | e4fe8fdc53 | 
| @@ -60,15 +60,7 @@ config :dart_sass, :version, "1.54.5" | ||||
|  | ||||
| config :tailwind, :version, "3.2.7" | ||||
|  | ||||
| config :wanderer_app, WandererApp.PromEx, | ||||
|   manual_metrics_start_delay: :no_delay, | ||||
|   metrics_server: [ | ||||
|     port: 4021, | ||||
|     path: "/metrics", | ||||
|     protocol: :http, | ||||
|     pool_size: 5, | ||||
|     cowboy_opts: [ip: {0, 0, 0, 0}] | ||||
|   ] | ||||
| config :wanderer_app, WandererApp.PromEx, manual_metrics_start_delay: :no_delay | ||||
|  | ||||
| config :wanderer_app, | ||||
|   grafana_datasource_id: "wanderer" | ||||
|   | ||||
| @@ -18,6 +18,7 @@ defmodule WandererApp.Api.Map do | ||||
|     define(:update, action: :update) | ||||
|     define(:update_acls, action: :update_acls) | ||||
|     define(:update_hubs, action: :update_hubs) | ||||
|     define(:update_options, action: :update_options) | ||||
|     define(:assign_owner, action: :assign_owner) | ||||
|     define(:mark_as_deleted, action: :mark_as_deleted) | ||||
|  | ||||
| @@ -112,6 +113,10 @@ defmodule WandererApp.Api.Map do | ||||
|       accept [:hubs] | ||||
|     end | ||||
|  | ||||
|     update :update_options do | ||||
|       accept [:options] | ||||
|     end | ||||
|  | ||||
|     update :mark_as_deleted do | ||||
|       accept([]) | ||||
|  | ||||
| @@ -167,6 +172,10 @@ defmodule WandererApp.Api.Map do | ||||
|       allow_nil?(true) | ||||
|     end | ||||
|  | ||||
|     attribute :options, :string do | ||||
|       allow_nil? true | ||||
|     end | ||||
|  | ||||
|     create_timestamp(:inserted_at) | ||||
|     update_timestamp(:updated_at) | ||||
|   end | ||||
|   | ||||
| @@ -52,6 +52,15 @@ defmodule WandererApp.Map do | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def get_map_options!(map) do | ||||
|     map | ||||
|     |> Map.get(:options) | ||||
|     |> case do | ||||
|         nil -> %{"layout" => "left_to_right"} | ||||
|         options -> Jason.decode!(options) | ||||
|       end | ||||
|   end | ||||
|  | ||||
|   def update_map(map_id, map_update) do | ||||
|     Cachex.get_and_update(:map_cache, map_id, fn map -> | ||||
|       case map do | ||||
|   | ||||
| @@ -19,46 +19,47 @@ defmodule WandererApp.Map.PositionCalculator do | ||||
|  | ||||
|   def get_system_bounding_rect(_system), do: [{0, 0}, {0, 0}] | ||||
|  | ||||
|   def get_new_system_position(nil, rtree_name) do | ||||
|     {:ok, {x, y}} = rtree_name |> _check_system_available_positions(@start_x, @start_y, 1) | ||||
|   def get_new_system_position(nil, rtree_name, opts) do | ||||
|     {:ok, {x, y}} = rtree_name |> check_system_available_positions(@start_x, @start_y, 1, opts) | ||||
|     %{x: x, y: y} | ||||
|   end | ||||
|  | ||||
|   def get_new_system_position( | ||||
|         %{position_x: start_x, position_y: start_y} = _old_system, | ||||
|         rtree_name | ||||
|         rtree_name, | ||||
|         opts | ||||
|       ) do | ||||
|     {:ok, {x, y}} = rtree_name |> _check_system_available_positions(start_x, start_y, 1) | ||||
|     {:ok, {x, y}} = rtree_name |> check_system_available_positions(start_x, start_y, 1, opts) | ||||
|  | ||||
|     %{x: x, y: y} | ||||
|   end | ||||
|  | ||||
|   defp _check_system_available_positions(_rtree_name, _start_x, _start_y, 100) do | ||||
|     {:ok, {@start_x, @start_y}} | ||||
|   end | ||||
|   defp check_system_available_positions(_rtree_name, _start_x, _start_y, 100, _opts), | ||||
|     do: {:ok, {@start_x, @start_y}} | ||||
|  | ||||
|   defp _check_system_available_positions(rtree_name, start_x, start_y, level) do | ||||
|     possible_positions = _get_available_positions(level, start_x, start_y) | ||||
|   defp check_system_available_positions(rtree_name, start_x, start_y, level, opts) do | ||||
|     possible_positions = get_available_positions(level, start_x, start_y, opts) | ||||
|  | ||||
|     case _get_available_position(possible_positions, rtree_name) do | ||||
|     case get_available_position(possible_positions, rtree_name) do | ||||
|       {:ok, nil} -> | ||||
|         rtree_name |> _check_system_available_positions(start_x, start_y, level + 1) | ||||
|         rtree_name |> check_system_available_positions(start_x, start_y, level + 1, opts) | ||||
|  | ||||
|       {:ok, position} -> | ||||
|         {:ok, position} | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   defp _get_available_position([], _rtree_name), do: {:ok, nil} | ||||
|   defp get_available_position([], _rtree_name), do: {:ok, nil} | ||||
|  | ||||
|   defp _get_available_position([position | rest], rtree_name) do | ||||
|     if _is_available_position(position, rtree_name) do | ||||
|   defp get_available_position([position | rest], rtree_name) do | ||||
|     if is_available_position(position, rtree_name) do | ||||
|       {:ok, position} | ||||
|     else | ||||
|       _get_available_position(rest, rtree_name) | ||||
|       get_available_position(rest, rtree_name) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   defp _is_available_position({x, y} = _position, rtree_name) do | ||||
|   defp is_available_position({x, y} = _position, rtree_name) do | ||||
|     case DDRT.query(get_system_bounding_rect(%{position_x: x, position_y: y}), rtree_name) do | ||||
|       {:ok, []} -> | ||||
|         true | ||||
| @@ -71,9 +72,10 @@ defmodule WandererApp.Map.PositionCalculator do | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def _get_available_positions(level, x, y), do: _adjusted_coordinates(1 + level * 2, x, y) | ||||
|   def get_available_positions(level, x, y, opts), | ||||
|     do: adjusted_coordinates(1 + level * 2, x, y, opts) | ||||
|  | ||||
|   defp _edge_coordinates(n) when n > 1 do | ||||
|   defp edge_coordinates(n, opts) when n > 1 do | ||||
|     min = -div(n, 2) | ||||
|     max = div(n, 2) | ||||
|     # Top edge | ||||
| @@ -90,16 +92,20 @@ defmodule WandererApp.Map.PositionCalculator do | ||||
|     |> Enum.uniq() | ||||
|   end | ||||
|  | ||||
|   defp _sorted_edge_coordinates(n) when n > 1 do | ||||
|     coordinates = _edge_coordinates(n) | ||||
|     middle_right_index = div(n, 2) | ||||
|   defp sorted_edge_coordinates(n, opts) when n > 1 do | ||||
|     coordinates = edge_coordinates(n, opts) | ||||
|     start_index = get_start_index(n, opts[:layout]) | ||||
|  | ||||
|     Enum.slice(coordinates, middle_right_index, length(coordinates) - middle_right_index) ++ | ||||
|       Enum.slice(coordinates, 0, middle_right_index) | ||||
|     Enum.slice(coordinates, start_index, length(coordinates) - start_index) ++ | ||||
|       Enum.slice(coordinates, 0, start_index) | ||||
|   end | ||||
|  | ||||
|   defp _adjusted_coordinates(n, start_x, start_y) when n > 1 do | ||||
|     sorted_coords = _sorted_edge_coordinates(n) | ||||
|   defp get_start_index(n, "left_to_right"), do: div(n, 2) | ||||
|  | ||||
|   defp get_start_index(n, "top_to_bottom"), do: div(n, 2) + n - 1 | ||||
|  | ||||
|   defp adjusted_coordinates(n, start_x, start_y, opts) when n > 1 do | ||||
|     sorted_coords = sorted_edge_coordinates(n, opts) | ||||
|  | ||||
|     Enum.map(sorted_coords, fn {x, y} -> | ||||
|       { | ||||
|   | ||||
| @@ -11,7 +11,8 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|   defstruct [ | ||||
|     :map_id, | ||||
|     :rtree_name, | ||||
|     map: nil | ||||
|     map: nil, | ||||
|     map_opts: [] | ||||
|   ] | ||||
|  | ||||
|   # @ccp1 -1 | ||||
| @@ -795,6 +796,9 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|     } | ||||
|   end | ||||
|  | ||||
|   def handle_event({:options_updated, options}, %{map: map, map_id: map_id} = state), | ||||
|     do: %{state | map_opts: [layout: options.layout]} | ||||
|  | ||||
|   def handle_event({ref, _result}, %{map_id: _map_id} = state) do | ||||
|     Process.demonitor(ref, [:flush]) | ||||
|  | ||||
| @@ -834,12 +838,12 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|          character_id, | ||||
|          location, | ||||
|          old_location, | ||||
|          %{map: map, map_id: map_id, rtree_name: rtree_name} = _state | ||||
|          %{map: map, map_id: map_id, rtree_name: rtree_name, map_opts: map_opts} = _state | ||||
|        ) do | ||||
|     case is_nil(old_location.solar_system_id) and | ||||
|            _can_add_location(map.scope, location.solar_system_id) do | ||||
|       true -> | ||||
|         :ok = maybe_add_system(map_id, location, nil, rtree_name) | ||||
|         :ok = maybe_add_system(map_id, location, nil, rtree_name, map_opts) | ||||
|  | ||||
|       _ -> | ||||
|         case _is_connection_valid( | ||||
| @@ -849,8 +853,8 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|              ) do | ||||
|           true -> | ||||
|             {:ok, character} = WandererApp.Character.get_character(character_id) | ||||
|             :ok = maybe_add_system(map_id, location, old_location, rtree_name) | ||||
|             :ok = maybe_add_system(map_id, old_location, location, rtree_name) | ||||
|             :ok = maybe_add_system(map_id, location, old_location, rtree_name, map_opts) | ||||
|             :ok = maybe_add_system(map_id, old_location, location, rtree_name, map_opts) | ||||
|             :ok = maybe_add_connection(map_id, location, old_location, character) | ||||
|  | ||||
|           _ -> | ||||
| @@ -1097,7 +1101,7 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|        end)} | ||||
|  | ||||
|   defp _add_system( | ||||
|          %{map_id: map_id, rtree_name: rtree_name} = state, | ||||
|          %{map_id: map_id, map_opts: map_opts, rtree_name: rtree_name} = state, | ||||
|          %{ | ||||
|            solar_system_id: solar_system_id, | ||||
|            coordinates: coordinates | ||||
| @@ -1113,7 +1117,7 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|  | ||||
|         _ -> | ||||
|           %{x: x, y: y} = | ||||
|             WandererApp.Map.PositionCalculator.get_new_system_position(nil, rtree_name) | ||||
|             WandererApp.Map.PositionCalculator.get_new_system_position(nil, rtree_name, map_opts) | ||||
|  | ||||
|           %{"x" => x, "y" => y} | ||||
|       end | ||||
| @@ -1255,20 +1259,22 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|  | ||||
|   defp _init_map( | ||||
|          state, | ||||
|          %{characters: characters} = map, | ||||
|          %{characters: characters} = initial_map, | ||||
|          subscription_settings, | ||||
|          systems, | ||||
|          connections | ||||
|        ) do | ||||
|     map = | ||||
|       map | ||||
|       initial_map | ||||
|       |> WandererApp.Map.new() | ||||
|       |> WandererApp.Map.update_subscription_settings!(subscription_settings) | ||||
|       |> WandererApp.Map.add_systems!(systems) | ||||
|       |> WandererApp.Map.add_connections!(connections) | ||||
|       |> WandererApp.Map.add_characters!(characters) | ||||
|  | ||||
|     %{state | map: map} | ||||
|     map_options = WandererApp.Map.get_map_options!(initial_map) | ||||
|  | ||||
|     %{state | map: map, map_opts: [layout: map_options |> Map.get("layout")]} | ||||
|   end | ||||
|  | ||||
|   defp _init_map_systems(state, [] = _systems), do: state | ||||
| @@ -1614,11 +1620,11 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|  | ||||
|   defp maybe_add_connection(_map_id, _location, _old_location, _character), do: :ok | ||||
|  | ||||
|   defp maybe_add_system(map_id, location, old_location, rtree_name) | ||||
|   defp maybe_add_system(map_id, location, old_location, rtree_name, opts) | ||||
|        when not is_nil(location) do | ||||
|     case WandererApp.Map.check_location(map_id, location) do | ||||
|       {:ok, location} -> | ||||
|         {:ok, position} = calc_new_system_position(map_id, old_location, rtree_name) | ||||
|         {:ok, position} = calc_new_system_position(map_id, old_location, rtree_name, opts) | ||||
|  | ||||
|         case WandererApp.MapSystemRepo.get_by_map_and_solar_system_id( | ||||
|                map_id, | ||||
| @@ -1688,14 +1694,14 @@ defmodule WandererApp.Map.Server.Impl do | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   defp maybe_add_system(_map_id, _location, _old_location, _rtree_name), do: :ok | ||||
|   defp maybe_add_system(_map_id, _location, _old_location, _rtree_name, _opts), do: :ok | ||||
|  | ||||
|   defp calc_new_system_position(map_id, old_location, rtree_name) do | ||||
|   defp calc_new_system_position(map_id, old_location, rtree_name, opts), | ||||
|     do: | ||||
|     {:ok, | ||||
|      map_id | ||||
|      |> WandererApp.Map.find_system_by_location(old_location) | ||||
|      |> WandererApp.Map.PositionCalculator.get_new_system_position(rtree_name)} | ||||
|   end | ||||
|      |> WandererApp.Map.PositionCalculator.get_new_system_position(rtree_name, opts)} | ||||
|  | ||||
|   defp _broadcast_acl_updates( | ||||
|          {:ok, | ||||
|   | ||||
| @@ -5,6 +5,8 @@ defmodule WandererAppWeb.MapsLive do | ||||
|  | ||||
|   alias BetterNumber, as: Number | ||||
|  | ||||
|   @pubsub_client Application.compile_env(:wanderer_app, :pubsub_client) | ||||
|  | ||||
|   @impl true | ||||
|   def mount(_params, %{"user_id" => user_id} = _session, socket) when not is_nil(user_id) do | ||||
|     {:ok, active_characters} = WandererApp.Api.Character.active_by_user(%{user_id: user_id}) | ||||
| @@ -112,6 +114,13 @@ defmodule WandererAppWeb.MapsLive do | ||||
|       "auto_renew?" => true | ||||
|     } | ||||
|  | ||||
|     options_form = | ||||
|       map.options | ||||
|       |> case do | ||||
|         nil -> %{"layout" => "left_to_right"} | ||||
|         options -> Jason.decode!(options) | ||||
|       end | ||||
|  | ||||
|     {:ok, estimated_price, discount} = | ||||
|       WandererApp.Map.SubscriptionManager.estimate_price(subscription_form, false) | ||||
|  | ||||
| @@ -130,6 +139,7 @@ defmodule WandererAppWeb.MapsLive do | ||||
|       active_settings_tab: "general", | ||||
|       is_adding_subscription?: false, | ||||
|       selected_subscription: nil, | ||||
|       options_form: options_form |> to_form(), | ||||
|       map_subscriptions: map_subscriptions, | ||||
|       subscription_form: subscription_form |> to_form(), | ||||
|       estimated_price: estimated_price, | ||||
| @@ -142,6 +152,10 @@ defmodule WandererAppWeb.MapsLive do | ||||
|         {"3 Months", "3"}, | ||||
|         {"6 Months", "6"}, | ||||
|         {"1 Year", "12"} | ||||
|       ], | ||||
|       layout_options: [ | ||||
|         {"Left To Right", "left_to_right"}, | ||||
|         {"Top To Bottom", "top_to_bottom"} | ||||
|       ] | ||||
|     ) | ||||
|     |> allow_upload(:settings, | ||||
| @@ -653,6 +667,28 @@ defmodule WandererAppWeb.MapsLive do | ||||
|      |> push_patch(to: ~p"/maps")} | ||||
|   end | ||||
|  | ||||
|   def handle_event( | ||||
|         "update_options", | ||||
|         %{ | ||||
|           "layout" => layout | ||||
|         } = options_form, | ||||
|         %{assigns: %{map_id: map_id, map: map, current_user: current_user}} = socket | ||||
|       ) do | ||||
|     options = %{layout: layout} | ||||
|  | ||||
|     updated_map = | ||||
|       map | ||||
|       |> WandererApp.Api.Map.update_options!(%{options: Jason.encode!(options)}) | ||||
|  | ||||
|     @pubsub_client.broadcast( | ||||
|       WandererApp.PubSub, | ||||
|       "maps:#{map_id}", | ||||
|       {:options_updated, options} | ||||
|     ) | ||||
|  | ||||
|     {:noreply, socket |> assign(map: updated_map, options_form: options_form)} | ||||
|   end | ||||
|  | ||||
|   @impl true | ||||
|   def handle_event("noop", _, socket) do | ||||
|     {:noreply, socket} | ||||
|   | ||||
| @@ -26,7 +26,6 @@ | ||||
|           > | ||||
|             <figure class="absolute z-10 h-200 avatar w-full h-full"> | ||||
|               <img :if={map.scope === :all} class="absolute h-200" src="/images/all_back.webp" /> | ||||
|  | ||||
|               <img | ||||
|                 :if={map.scope === :wormholes} | ||||
|                 class="absolute h-200" | ||||
| @@ -190,7 +189,6 @@ | ||||
| > | ||||
|   <div role="tablist" class="tabs tabs-bordered"> | ||||
|     <a | ||||
|       :if={@map_subscriptions_enabled?} | ||||
|       role="tab" | ||||
|       phx-click="change_settings_tab" | ||||
|       phx-value-tab="general" | ||||
| @@ -201,6 +199,17 @@ | ||||
|     > | ||||
|       <.icon name="hero-wrench-screwdriver-solid" class="w-4 h-4" /> General | ||||
|     </a> | ||||
|     <a | ||||
|       role="tab" | ||||
|       phx-click="change_settings_tab" | ||||
|       phx-value-tab="import" | ||||
|       class={[ | ||||
|         "tab", | ||||
|         classes("tab-active": @active_settings_tab == "import") | ||||
|       ]} | ||||
|     > | ||||
|       <.icon name="hero-wrench-screwdriver-solid" class="w-4 h-4" /> Import/Export | ||||
|     </a> | ||||
|     <a | ||||
|       :if={@map_subscriptions_enabled?} | ||||
|       role="tab" | ||||
| @@ -227,6 +236,27 @@ | ||||
|     </a> | ||||
|   </div> | ||||
|   <.header :if={@active_settings_tab == "general"} class="bordered border-1 border-zinc-800"> | ||||
|     <:actions> | ||||
|       <.form | ||||
|         :let={f} | ||||
|         :if={assigns |> Map.get(:options_form, false)} | ||||
|         for={@options_form} | ||||
|         phx-change="update_options" | ||||
|       > | ||||
|         <div class="stat-title">Map systems layout</div> | ||||
|         <div class="stat-value text-white"> | ||||
|           <.input | ||||
|             type="select" | ||||
|             field={f[:layout]} | ||||
|             class="p-dropdown p-component p-inputwrapper" | ||||
|             placeholder="Map default layout" | ||||
|             options={@layout_options} | ||||
|           /> | ||||
|         </div> | ||||
|       </.form> | ||||
|     </:actions> | ||||
|   </.header> | ||||
|   <.header :if={@active_settings_tab == "import"} class="bordered border-1 border-zinc-800"> | ||||
|     Import/Export Map Settings | ||||
|     <:actions> | ||||
|       <.form :if={assigns |> Map.get(:import_form, false)} for={@import_form} phx-change="import"> | ||||
|   | ||||
							
								
								
									
										21
									
								
								priv/repo/migrations/20241006092351_add_map_options.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								priv/repo/migrations/20241006092351_add_map_options.exs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| defmodule WandererApp.Repo.Migrations.AddMapOptions do | ||||
|   @moduledoc """ | ||||
|   Updates resources based on their most recent snapshots. | ||||
|  | ||||
|   This file was autogenerated with `mix ash_postgres.generate_migrations` | ||||
|   """ | ||||
|  | ||||
|   use Ecto.Migration | ||||
|  | ||||
|   def up do | ||||
|     alter table(:maps_v1) do | ||||
|       add :options, :text | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def down do | ||||
|     alter table(:maps_v1) do | ||||
|       remove :options | ||||
|     end | ||||
|   end | ||||
| end | ||||
							
								
								
									
										186
									
								
								priv/resource_snapshots/repo/maps_v1/20241006092351.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								priv/resource_snapshots/repo/maps_v1/20241006092351.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,186 @@ | ||||
| { | ||||
|   "attributes": [ | ||||
|     { | ||||
|       "allow_nil?": false, | ||||
|       "default": "fragment(\"gen_random_uuid()\")", | ||||
|       "generated?": false, | ||||
|       "primary_key?": true, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "id", | ||||
|       "type": "uuid" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": false, | ||||
|       "default": "nil", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "name", | ||||
|       "type": "text" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": false, | ||||
|       "default": "nil", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "slug", | ||||
|       "type": "text" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": true, | ||||
|       "default": "nil", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "description", | ||||
|       "type": "text" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": true, | ||||
|       "default": "nil", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "personal_note", | ||||
|       "type": "text" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": true, | ||||
|       "default": "[]", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "hubs", | ||||
|       "type": [ | ||||
|         "array", | ||||
|         "text" | ||||
|       ] | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": false, | ||||
|       "default": "\"wormholes\"", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "scope", | ||||
|       "type": "text" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": true, | ||||
|       "default": "false", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "deleted", | ||||
|       "type": "boolean" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": true, | ||||
|       "default": "false", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "only_tracked_characters", | ||||
|       "type": "boolean" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": true, | ||||
|       "default": "nil", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "options", | ||||
|       "type": "text" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": false, | ||||
|       "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "inserted_at", | ||||
|       "type": "utc_datetime_usec" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": false, | ||||
|       "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": null, | ||||
|       "size": null, | ||||
|       "source": "updated_at", | ||||
|       "type": "utc_datetime_usec" | ||||
|     }, | ||||
|     { | ||||
|       "allow_nil?": true, | ||||
|       "default": "nil", | ||||
|       "generated?": false, | ||||
|       "primary_key?": false, | ||||
|       "references": { | ||||
|         "deferrable": false, | ||||
|         "destination_attribute": "id", | ||||
|         "destination_attribute_default": null, | ||||
|         "destination_attribute_generated": null, | ||||
|         "index?": false, | ||||
|         "match_type": null, | ||||
|         "match_with": null, | ||||
|         "multitenancy": { | ||||
|           "attribute": null, | ||||
|           "global": null, | ||||
|           "strategy": null | ||||
|         }, | ||||
|         "name": "maps_v1_owner_id_fkey", | ||||
|         "on_delete": null, | ||||
|         "on_update": null, | ||||
|         "primary_key?": true, | ||||
|         "schema": "public", | ||||
|         "table": "character_v1" | ||||
|       }, | ||||
|       "size": null, | ||||
|       "source": "owner_id", | ||||
|       "type": "uuid" | ||||
|     } | ||||
|   ], | ||||
|   "base_filter": null, | ||||
|   "check_constraints": [], | ||||
|   "custom_indexes": [], | ||||
|   "custom_statements": [], | ||||
|   "has_create_action": true, | ||||
|   "hash": "E5FC6B5F1B9AD5E23163494C7C93A8002F9C812AFC7A26A8C33A344877086A03", | ||||
|   "identities": [ | ||||
|     { | ||||
|       "all_tenants?": false, | ||||
|       "base_filter": null, | ||||
|       "index_name": "maps_v1_unique_slug_index", | ||||
|       "keys": [ | ||||
|         { | ||||
|           "type": "atom", | ||||
|           "value": "slug" | ||||
|         } | ||||
|       ], | ||||
|       "name": "unique_slug", | ||||
|       "nils_distinct?": true, | ||||
|       "where": null | ||||
|     } | ||||
|   ], | ||||
|   "multitenancy": { | ||||
|     "attribute": null, | ||||
|     "global": null, | ||||
|     "strategy": null | ||||
|   }, | ||||
|   "repo": "Elixir.WandererApp.Repo", | ||||
|   "schema": null, | ||||
|   "table": "maps_v1" | ||||
| } | ||||
		Reference in New Issue
	
	Block a user