Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit830a4ca

Browse files
committed
improvement: consistent foreign key names
fix: force create extensions snapshotimprovement: support custom foreign key error messages
1 parent93ad7d1 commit830a4ca

File tree

6 files changed

+111
-32
lines changed

6 files changed

+111
-32
lines changed

‎.formatter.exs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
locals_without_parens=[
44
base_filter_sql:1,
55
create?:1,
6+
foreign_key_names:1,
67
migrate?:1,
78
polymorphic?:1,
89
repo:1,

‎lib/ash_postgres.ex‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ defmodule AshPostgres do
2929
Extension.get_opt(resource,[:postgres],:unique_index_names,[],true)
3030
end
3131

32+
@doc"The configured foreign_key_names"
33+
defforeign_key_names(resource)do
34+
Extension.get_opt(resource,[:postgres],:foreign_key_names,[],true)
35+
end
36+
3237
@doc"Whether or not the resource should be included when generating migrations"
3338
defmigrate?(resource)do
3439
Extension.get_opt(resource,[:postgres],:migrate?,nil,true)

‎lib/data_layer.ex‎

Lines changed: 97 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,15 @@ defmodule AshPostgres.DataLayer do
8989
default:[],
9090
doc:"""
9191
A list of unique index names that could raise errors, or an mfa to a function that takes a changeset
92-
and returns a list of names in the format `{[:affected, :keys], "name_of_constraint"}`
92+
and returns the list. Must be in the format `{[:affected, :keys], "name_of_constraint"}` or `{[:affected, :keys], "name_of_constraint", "custom error message"}`
93+
"""
94+
],
95+
foreign_key_names:[
96+
type::any,
97+
default:[],
98+
doc:"""
99+
A list of foreign keys that could raise errors, or an mfa to a function that takes a changeset and returns the list.
100+
Must be in the format `{:key, "name_of_constraint"}` or `{:key, "name_of_constraint", "custom error message"}`
93101
"""
94102
],
95103
table:[
@@ -403,7 +411,7 @@ defmodule AshPostgres.DataLayer do
403411
defcreate(resource,changeset)do
404412
changeset.data
405413
|>Map.update!(:__meta__,&Map.put(&1,:source,table(resource,changeset)))
406-
|>ecto_changeset(changeset)
414+
|>ecto_changeset(changeset,:create)
407415
|>repo(resource).insert(repo_opts(changeset))
408416
|>handle_errors()
409417
|>casedo
@@ -470,11 +478,32 @@ defmodule AshPostgres.DataLayer do
470478
Ash.Error.Changes.InvalidAttribute.exception(field:field,message:message,vars:vars)
471479
end
472480

473-
defpecto_changeset(record,changeset)do
474-
record
475-
|>set_table(changeset)
476-
|>Ecto.Changeset.change(changeset.attributes)
477-
|>add_unique_indexes(record.__struct__,changeset.tenant,changeset)
481+
defpecto_changeset(record,changeset,type)do
482+
ecto_changeset=
483+
record
484+
|>set_table(changeset)
485+
|>Ecto.Changeset.change(changeset.attributes)
486+
487+
casetypedo
488+
:create->
489+
ecto_changeset
490+
|>add_unique_indexes(record.__struct__,changeset.tenant,changeset)
491+
|>add_my_foreign_key_constraints(record.__struct__)
492+
|>add_configured_foreign_key_constraints(record.__struct__)
493+
494+
typewhentypein[:upsert,:update]->
495+
ecto_changeset
496+
|>add_unique_indexes(record.__struct__,changeset.tenant,changeset)
497+
|>add_my_foreign_key_constraints(record.__struct__)
498+
|>add_related_foreign_key_constraints(record.__struct__)
499+
|>add_configured_foreign_key_constraints(record.__struct__)
500+
501+
:delete->
502+
ecto_changeset
503+
|>add_unique_indexes(record.__struct__,changeset.tenant,changeset)
504+
|>add_related_foreign_key_constraints(record.__struct__)
505+
|>add_configured_foreign_key_constraints(record.__struct__)
506+
end
478507
end
479508

480509
defpset_table(record,changeset)do
@@ -494,6 +523,55 @@ defmodule AshPostgres.DataLayer do
494523
end
495524
end
496525

526+
defpadd_related_foreign_key_constraints(changeset,resource)do
527+
# TODO: this doesn't guarantee us to get all of them, because if something is related to this
528+
# schema and there is no back-relation, then this won't catch it's foreign key constraints
529+
resource
530+
|>Ash.Resource.Info.relationships()
531+
|>Enum.map(&&1.destination)
532+
|>Enum.uniq()
533+
|>Enum.flat_map(fnrelated->
534+
related
535+
|>Ash.Resource.Info.relationships()
536+
|>Enum.filter(&(&1.destination==resource))
537+
|>Enum.map(&Map.take(&1,[:source,:source_field,:destination_field]))
538+
end)
539+
|>Enum.uniq()
540+
|>Enum.reduce(changeset,fn%{
541+
source:source,
542+
source_field:source_field,
543+
destination_field:destination_field
544+
},
545+
changeset->
546+
Ecto.Changeset.foreign_key_constraint(changeset,destination_field,
547+
name:"#{AshPostgres.table(source)}_#{source_field}_fkey",
548+
message:"would leave records behind"
549+
)
550+
end)
551+
end
552+
553+
defpadd_my_foreign_key_constraints(changeset,resource)do
554+
resource
555+
|>Ash.Resource.Info.relationships()
556+
|>Enum.reduce(changeset,&Ecto.Changeset.foreign_key_constraint(&2,&1.source_field))
557+
end
558+
559+
defpadd_configured_foreign_key_constraints(changeset,resource)do
560+
resource
561+
|>AshPostgres.foreign_key_names()
562+
|>casedo
563+
{m,f,a}->List.wrap(apply(m,f,[changeset|a]))
564+
value->List.wrap(value)
565+
end
566+
|>Enum.reduce(changeset,fn
567+
{key,name},changeset->
568+
Ecto.Changeset.foreign_key_constraint(changeset,key,name:name)
569+
570+
{key,name,message},changeset->
571+
Ecto.Changeset.foreign_key_constraint(changeset,key,name:name,message:message)
572+
end)
573+
end
574+
497575
defpadd_unique_indexes(changeset,resource,tenant,ash_changeset)do
498576
changeset=
499577
resource
@@ -528,8 +606,12 @@ defmodule AshPostgres.DataLayer do
528606
{Ash.Resource.Info.primary_key(resource),table(resource,ash_changeset)<>"_pkey"}|names
529607
]
530608

531-
Enum.reduce(names,changeset,fn{keys,name},changeset->
532-
Ecto.Changeset.unique_constraint(changeset,List.wrap(keys),name:name)
609+
Enum.reduce(names,changeset,fn
610+
{keys,name},changeset->
611+
Ecto.Changeset.unique_constraint(changeset,List.wrap(keys),name:name)
612+
613+
{keys,name,message},changeset->
614+
Ecto.Changeset.unique_constraint(changeset,List.wrap(keys),name:name,message:message)
533615
end)
534616
end
535617

@@ -546,7 +628,7 @@ defmodule AshPostgres.DataLayer do
546628
else
547629
changeset.data
548630
|>Map.update!(:__meta__,&Map.put(&1,:source,table(resource,changeset)))
549-
|>ecto_changeset(changeset)
631+
|>ecto_changeset(changeset,:upsert)
550632
|>repo(resource).insert(repo_opts)
551633
|>handle_errors()
552634
end
@@ -556,7 +638,7 @@ defmodule AshPostgres.DataLayer do
556638
defupdate(resource,changeset)do
557639
changeset.data
558640
|>Map.update!(:__meta__,&Map.put(&1,:source,table(resource,changeset)))
559-
|>ecto_changeset(changeset)
641+
|>ecto_changeset(changeset,:update)
560642
|>repo(resource).update(repo_opts(changeset))
561643
|>handle_errors()
562644
|>casedo
@@ -572,7 +654,10 @@ defmodule AshPostgres.DataLayer do
572654

573655
@impltrue
574656
defdestroy(resource,%{data:record}=changeset)do
575-
caserepo(resource).delete(record,repo_opts(changeset))do
657+
record
658+
|>ecto_changeset(changeset,:delete)
659+
|>repo(resource).delete(repo_opts(changeset))
660+
|>casedo
576661
{:ok,_record}->
577662
:ok
578663

‎lib/migration_generator/migration_generator.ex‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ defmodule AshPostgres.MigrationGenerator do
127127
snapshot_contents=Jason.encode!(repo.installed_extensions(),pretty:true)
128128

129129
contents=format(contents,opts)
130-
create_file(snapshot_file,snapshot_contents)
130+
create_file(snapshot_file,snapshot_contents,force:true)
131131
create_file(migration_file,contents)
132132
end
133133
end

‎lib/migration_generator/operation.ex‎

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ defmodule AshPostgres.MigrationGenerator.Operation do
7575
[
7676
"type:#{inspect(attribute.type)}",
7777
"column:#{inspect(destination_field)}",
78-
"name:\"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\"",
7978
"prefix:\"public\""
8079
],
8180
")",
@@ -121,8 +120,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
121120
"references(:#{table}",
122121
[
123122
"type:#{inspect(attribute.type)}",
124-
"column:#{inspect(destination_field)}",
125-
"name:\"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\""
123+
"column:#{inspect(destination_field)}"
126124
],
127125
")",
128126
maybe_add_default(attribute.default),
@@ -233,16 +231,13 @@ defmodule AshPostgres.MigrationGenerator.Operation do
233231

234232
defpreference(%{strategy::context},%{
235233
type:type,
236-
name:name,
237234
references:%{
238235
multitenancy:%{strategy::context},
239236
table:table,
240237
destination_field:destination_field
241238
}
242239
})do
243-
"references(:#{table}, type:#{inspect(type)}, column:#{inspect(destination_field)}, name:\"\#\{prefix()\}_#{
244-
table
245-
}_#{name}_fkey\")"
240+
"references(:#{table}, type:#{inspect(type)}, column:#{inspect(destination_field)})"
246241
end
247242

248243
defpreference(%{strategy::attribute,attribute:source_attribute},%{
@@ -302,22 +297,14 @@ defmodule AshPostgres.MigrationGenerator.Operation do
302297
# We only need to drop it before altering an attribute with `references/3`
303298
defstruct[:attribute,:table,:multitenancy,:direction,no_phase:true]
304299

305-
defup(%{attribute:attribute,table:table,multitenancy:multitenancy,direction::up})do
306-
ifmultitenancy&&multitenancy.strategy==:contextdo
307-
"drop constraint(:#{table},\"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\")"
308-
else
309-
"drop constraint(:#{table},\"#{table}_#{attribute.name}_fkey\")"
310-
end
300+
defup(%{attribute:attribute,table:table,direction::up})do
301+
"drop constraint(:#{table},\"#{table}_#{attribute.name}_fkey\")"
311302
end
312303

313304
defup(_),do:""
314305

315-
defdown(%{attribute:attribute,table:table,multitenancy:multitenancy,direction::down})do
316-
ifmultitenancy&&multitenancy.strategy==:contextdo
317-
"drop constraint(:#{table},\"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\")"
318-
else
319-
"drop constraint(:#{table},\"#{table}_#{attribute.name}_fkey\")"
320-
end
306+
defdown(%{attribute:attribute,table:table,direction::down})do
307+
"drop constraint(:#{table},\"#{table}_#{attribute.name}_fkey\")"
321308
end
322309

323310
defdown(_),do:""

‎lib/repo.ex‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ defmodule AshPostgres.Repo do
1616
1717
* `"uuid-ossp"` - Sets UUID primary keys defaults in the migration generator
1818
* `"pg_trgm"` - Makes the `AshPostgres.Predicates.Trigram` custom predicate available
19+
* "citext" - Allows case insensitive fields to be used
1920
2021
```
2122
def installed_extensions() do

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp