Skip to content

Commit af97c54

Browse files
committed
improvement: add custom migration types, and repo level override
1 parent ab89e0e commit af97c54

File tree

7 files changed

+165
-10
lines changed

7 files changed

+165
-10
lines changed

.formatter.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ locals_without_parens = [
1414
index: 2,
1515
message: 1,
1616
migrate?: 1,
17+
migration_types: 1,
1718
name: 1,
1819
on_delete: 1,
1920
on_update: 1,

lib/ash_postgres.ex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ defmodule AshPostgres do
2424
Extension.get_entities(resource, [:postgres, :references])
2525
end
2626

27+
@doc "A keyword list of customized migration types"
28+
def migration_types(resource) do
29+
Extension.get_opt(resource, [:postgres], :migration_types, nil, true)
30+
end
31+
2732
@doc "The configured check_constraints for a resource"
2833
def check_constraints(resource) do
2934
Extension.get_entities(resource, [:postgres, :check_constraints])

lib/data_layer.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ defmodule AshPostgres.DataLayer do
237237
doc:
238238
"Whether or not to include this resource in the generated migrations with `mix ash.generate_migrations`"
239239
],
240+
migration_types: [
241+
type: :keyword_list,
242+
default: [],
243+
doc:
244+
"A keyword list of attribute names to the ecto migration type that should be used for that attribute. Only necessary if you need to override the defaults."
245+
],
240246
base_filter_sql: [
241247
type: :string,
242248
doc:

lib/migration_generator/migration_generator.ex

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,22 @@ defmodule AshPostgres.MigrationGenerator do
344344
|> Enum.map(fn {attr, i} -> Map.put(attr, :order, i) end)
345345
|> Enum.group_by(& &1.name)
346346
|> Enum.map(fn {name, attributes} ->
347+
size =
348+
attributes
349+
|> Enum.map(& &1.size)
350+
|> Enum.filter(& &1)
351+
|> case do
352+
[] ->
353+
nil
354+
355+
sizes ->
356+
Enum.max(sizes)
357+
end
358+
347359
%{
348360
name: name,
349361
type: merge_types(Enum.map(attributes, & &1.type), name, table),
362+
size: size,
350363
default: merge_defaults(Enum.map(attributes, & &1.default)),
351364
allow_nil?: Enum.any?(attributes, & &1.allow_nil?) || Enum.count(attributes) < count,
352365
generated?: Enum.any?(attributes, & &1.generated?),
@@ -1643,11 +1656,32 @@ defmodule AshPostgres.MigrationGenerator do
16431656
|> Enum.map(fn attribute ->
16441657
default = default(attribute, repo)
16451658

1659+
type =
1660+
AshPostgres.migration_types(resource)[attribute.name] || migration_type(attribute.type)
1661+
1662+
type =
1663+
if :erlang.function_exported(repo, :override_migration_type, 1) do
1664+
repo.override_migration_type(type)
1665+
else
1666+
type
1667+
end
1668+
1669+
{type, size} =
1670+
case type do
1671+
{:varchar, size} ->
1672+
{:varchar, size}
1673+
1674+
{:binary, size} ->
1675+
{:binary, size}
1676+
1677+
other ->
1678+
{other, nil}
1679+
end
1680+
16461681
attribute
16471682
|> Map.put(:default, default)
1648-
|> Map.update!(:type, fn type ->
1649-
migration_type(type)
1650-
end)
1683+
|> Map.put(:size, size)
1684+
|> Map.put(:type, type)
16511685
end)
16521686
|> Enum.map(fn attribute ->
16531687
references = find_reference(resource, table, attribute)
@@ -1788,17 +1822,25 @@ defmodule AshPostgres.MigrationGenerator do
17881822
snapshot
17891823
|> Map.update!(:attributes, fn attributes ->
17901824
Enum.map(attributes, fn attribute ->
1791-
%{attribute | type: sanitize_type(attribute.type)}
1825+
%{attribute | type: sanitize_type(attribute.type, attribute[:size])}
17921826
end)
17931827
end)
17941828
|> Jason.encode!(pretty: true)
17951829
end
17961830

1797-
defp sanitize_type({:array, type}) do
1798-
["array", sanitize_type(type)]
1831+
defp sanitize_type({:array, type}, size) do
1832+
["array", sanitize_type(type, size)]
17991833
end
18001834

1801-
defp sanitize_type(type) do
1835+
defp sanitize_type(:varchar, size) when not is_nil(size) do
1836+
["varchar", size]
1837+
end
1838+
1839+
defp sanitize_type(:binary, size) when not is_nil(size) do
1840+
["binary", size]
1841+
end
1842+
1843+
defp sanitize_type(type, _) do
18021844
type
18031845
end
18041846

@@ -1856,9 +1898,24 @@ defmodule AshPostgres.MigrationGenerator do
18561898
end
18571899

18581900
defp load_attribute(attribute, table) do
1901+
type = load_type(attribute.type)
1902+
1903+
{type, size} =
1904+
case type do
1905+
{:varchar, size} ->
1906+
{:varchar, size}
1907+
1908+
{:binary, size} ->
1909+
{:binary, size}
1910+
1911+
other ->
1912+
{other, nil}
1913+
end
1914+
18591915
attribute
1860-
|> Map.update!(:type, &load_type/1)
18611916
|> Map.update!(:name, &String.to_atom/1)
1917+
|> Map.put(:type, type)
1918+
|> Map.put(:size, size)
18621919
|> Map.put_new(:default, "nil")
18631920
|> Map.update!(:default, &(&1 || "nil"))
18641921
|> Map.update!(:references, fn
@@ -1897,6 +1954,14 @@ defmodule AshPostgres.MigrationGenerator do
18971954
{:array, load_type(type)}
18981955
end
18991956

1957+
defp load_type(["varchar", size]) do
1958+
{:varchar, size}
1959+
end
1960+
1961+
defp load_type(["binary", size]) do
1962+
{:binary, size}
1963+
end
1964+
19001965
defp load_type(type) do
19011966
String.to_atom(type)
19021967
end

lib/migration_generator/operation.ex

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
8686
"with: [#{source_attribute}: :#{destination_attribute}], match: :full"
8787
end
8888

89+
size =
90+
if attribute[:size] do
91+
"size: #{attribute[:size]}"
92+
end
93+
8994
[
9095
"add #{inspect(attribute.name)}",
9196
"references(:#{table}",
@@ -95,7 +100,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do
95100
"name: #{inspect(reference.name)}",
96101
"type: #{inspect(reference_type(attribute, reference))}",
97102
on_delete(reference),
98-
on_update(reference)
103+
on_update(reference),
104+
size
99105
],
100106
")",
101107
maybe_add_default(attribute.default),
@@ -117,6 +123,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
117123
} = reference
118124
} = attribute
119125
}) do
126+
size =
127+
if attribute[:size] do
128+
"size: #{attribute[:size]}"
129+
end
130+
120131
[
121132
"add #{inspect(attribute.name)}",
122133
"references(:#{table}",
@@ -125,6 +136,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
125136
"prefix: \"public\"",
126137
"name: #{inspect(reference.name)}",
127138
"type: #{inspect(reference_type(attribute, reference))}",
139+
size,
128140
on_delete(reference),
129141
on_update(reference)
130142
],
@@ -145,11 +157,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
145157
}
146158
} = attribute
147159
}) do
160+
size =
161+
if attribute.size do
162+
"size: #{attribute.size}"
163+
end
164+
148165
[
149166
"add #{inspect(attribute.name)}",
150167
inspect(attribute.type),
151168
maybe_add_default(attribute.default),
152169
maybe_add_primary_key(attribute.primary_key?),
170+
size,
153171
maybe_add_null(attribute.allow_nil?)
154172
]
155173
|> join()
@@ -167,6 +185,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
167185
} = reference
168186
} = attribute
169187
}) do
188+
size =
189+
if attribute[:size] do
190+
"size: #{attribute[:size]}"
191+
end
192+
170193
[
171194
"add #{inspect(attribute.name)}",
172195
"references(:#{table}",
@@ -175,6 +198,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
175198
"name: #{inspect(reference.name)}",
176199
"type: #{inspect(reference_type(attribute, reference))}",
177200
"prefix: prefix()",
201+
size,
178202
on_delete(reference),
179203
on_update(reference)
180204
],
@@ -197,6 +221,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
197221
} = reference
198222
} = attribute
199223
}) do
224+
size =
225+
if attribute[:size] do
226+
"size: #{attribute[:size]}"
227+
end
228+
200229
[
201230
"add #{inspect(attribute.name)}",
202231
"references(:#{table}",
@@ -205,6 +234,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
205234
"name: #{inspect(reference.name)}",
206235
"type: #{inspect(reference_type(attribute, reference))}",
207236
"prefix: \"public\"",
237+
size,
208238
on_delete(reference),
209239
on_update(reference)
210240
],
@@ -221,13 +251,19 @@ defmodule AshPostgres.MigrationGenerator.Operation do
221251
%{references: %{table: table, destination_field: destination_field} = reference} =
222252
attribute
223253
}) do
254+
size =
255+
if attribute[:size] do
256+
"size: #{attribute[:size]}"
257+
end
258+
224259
[
225260
"add #{inspect(attribute.name)}",
226261
"references(:#{table}",
227262
[
228263
"column: #{inspect(destination_field)}",
229264
"name: #{inspect(reference.name)}",
230265
"type: #{inspect(reference_type(attribute, reference))}",
266+
size,
231267
on_delete(reference),
232268
on_update(reference)
233269
],
@@ -260,11 +296,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
260296
end
261297

262298
def up(%{attribute: attribute}) do
299+
size =
300+
if attribute[:size] do
301+
"size: #{attribute[:size]}"
302+
end
303+
263304
[
264305
"add #{inspect(attribute.name)}",
265306
"#{inspect(attribute.type)}",
266307
maybe_add_null(attribute.allow_nil?),
267308
maybe_add_default(attribute.default),
309+
size,
268310
maybe_add_primary_key(attribute.primary_key?)
269311
]
270312
|> join()
@@ -342,10 +384,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
342384
} = reference
343385
} = attribute
344386
) do
387+
size =
388+
if attribute[:size] do
389+
"size: #{attribute[:size]}"
390+
end
391+
345392
join([
346393
"references(:#{table}, column: #{inspect(destination_field)}",
347394
"name: #{inspect(reference.name)}",
348395
"type: #{inspect(reference_type(attribute, reference))}",
396+
size,
349397
"prefix: prefix()",
350398
on_delete(reference),
351399
on_update(reference),
@@ -369,11 +417,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
369417
"with: [#{source_attribute}: :#{destination_attribute}], match: :full"
370418
end
371419

420+
size =
421+
if attribute[:size] do
422+
"size: #{attribute[:size]}"
423+
end
424+
372425
join([
373426
"references(:#{table}, column: #{inspect(destination_field)}",
374427
with_match,
375428
"name: #{inspect(reference.name)}",
376429
"type: #{inspect(reference_type(attribute, reference))}",
430+
size,
377431
on_delete(reference),
378432
on_update(reference),
379433
")"
@@ -390,10 +444,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
390444
} = reference
391445
} = attribute
392446
) do
447+
size =
448+
if attribute[:size] do
449+
"size: #{attribute[:size]}"
450+
end
451+
393452
join([
394453
"references(:#{table}, column: #{inspect(destination_field)}, prefix: \"public\"",
395454
"name: #{inspect(reference.name)}",
396455
"type: #{inspect(reference_type(attribute, reference))}",
456+
size,
397457
on_delete(reference),
398458
on_update(reference),
399459
")"
@@ -410,10 +470,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
410470
} = reference
411471
} = attribute
412472
) do
473+
size =
474+
if attribute[:size] do
475+
"size: #{attribute[:size]}"
476+
end
477+
413478
join([
414479
"references(:#{table}, column: #{inspect(destination_field)}",
415480
"name: #{inspect(reference.name)}",
416481
"type: #{inspect(reference_type(attribute, reference))}",
482+
size,
417483
on_delete(reference),
418484
on_update(reference),
419485
")"

lib/repo.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ defmodule AshPostgres.Repo do
3535
@callback migrations_path() :: String.t()
3636
@doc "The default prefix(postgres schema) to use when building queries"
3737
@callback default_prefix() :: String.t()
38+
@doc "Allows overriding a given migration type for *all* fields, for example if you wanted to always use :timestamptz for :utc_datetime fields"
39+
@callback override_migration_type(atom) :: atom
3840

3941
defmacro __using__(opts) do
4042
quote bind_quoted: [opts: opts] do
@@ -48,6 +50,7 @@ defmodule AshPostgres.Repo do
4850
def tenant_migrations_path, do: nil
4951
def migrations_path, do: nil
5052
def default_prefix, do: "public"
53+
def override_migration_type(type), do: type
5154

5255
def all_tenants do
5356
raise """
@@ -77,7 +80,8 @@ defmodule AshPostgres.Repo do
7780
installed_extensions: 0,
7881
all_tenants: 0,
7982
tenant_migrations_path: 0,
80-
default_prefix: 0
83+
default_prefix: 0,
84+
override_migration_type: 1
8185
end
8286
end
8387
end

0 commit comments

Comments
 (0)