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

Commit4d2d29d

Browse files
committed
feat: support configuring references
feat: support configuring polymorphic referencesfeat: support `distinct` Ash queries
1 parente7ea1f9 commit4d2d29d

File tree

20 files changed

+872
-82
lines changed

20 files changed

+872
-82
lines changed

‎.formatter.exs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ locals_without_parens = [
55
create?:1,
66
foreign_key_names:1,
77
migrate?:1,
8+
name:1,
9+
on_delete:1,
10+
on_update:1,
811
polymorphic?:1,
12+
polymorphic_name:1,
13+
polymorphic_on_delete:1,
14+
polymorphic_on_update:1,
15+
reference:1,
16+
reference:2,
917
repo:1,
1018
skip_unique_indexes:1,
1119
table:1,

‎lib/ash_postgres.ex‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,26 @@ defmodule AshPostgres do
1919
Extension.get_opt(resource,[:postgres],:table,nil,true)
2020
end
2121

22+
@doc"The configured references for a resource"
23+
defreferences(resource)do
24+
Extension.get_entities(resource,[:postgres,:references])
25+
end
26+
27+
@doc"The configured polymorphic_reference_on_delete for a resource"
28+
defpolymorphic_on_delete(resource)do
29+
Extension.get_opt(resource,[:postgres,:references],:polymorphic_on_delete,nil,true)
30+
end
31+
32+
@doc"The configured polymorphic_reference_on_update for a resource"
33+
defpolymorphic_on_update(resource)do
34+
Extension.get_opt(resource,[:postgres,:references],:polymorphic_on_update,nil,true)
35+
end
36+
37+
@doc"The configured polymorphic_reference_name for a resource"
38+
defpolymorphic_name(resource)do
39+
Extension.get_opt(resource,[:postgres,:references],:polymorphic_on_delete,nil,true)
40+
end
41+
2242
@doc"The configured polymorphic? for a resource"
2343
defpolymorphic?(resource)do
2444
Extension.get_opt(resource,[:postgres],:polymorphic?,nil,true)

‎lib/data_layer.ex‎

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,68 @@ defmodule AshPostgres.DataLayer do
4242
]
4343
}
4444

45+
@reference%Ash.Dsl.Entity{
46+
name::reference,
47+
describe:"""
48+
Configures the reference for a relationship in resource migrations.
49+
50+
Keep in mind that multiple relationships can theoretically involve the same destination and foreign keys.
51+
In those cases, you only need to configure the `reference` behavior for one of them. Any conflicts will result
52+
in an error, across this resource and any other resources that share a table with this one. For this reason,
53+
instead of adding a reference configuration for `:nothing`, its best to just leave the configuration out, as that
54+
is the default behavior if *no* relationship anywhere has configured the behavior of that reference.
55+
""",
56+
examples:[
57+
"reference :post, on_delete: :delete, on_update: :update, name:\"comments_to_posts_fkey\""
58+
],
59+
args:[:relationship],
60+
target:AshPostgres.Reference,
61+
schema:AshPostgres.Reference.schema()
62+
}
63+
64+
@references%Ash.Dsl.Section{
65+
name::references,
66+
describe:"""
67+
A section for configuring the references (foreign keys) in resource migrations.
68+
69+
This section is only relevant if you are using the migration generator with this resource.
70+
Otherwise, it has no effect.
71+
""",
72+
examples:[
73+
"""
74+
references do
75+
reference :post, on_delete: :delete, on_update: :update, name: "comments_to_posts_fkey"
76+
end
77+
"""
78+
],
79+
entities:[@reference],
80+
schema:[
81+
polymorphic_on_delete:[
82+
type:{:one_of,[:delete,:nilify,:nothing,:restrict]},
83+
doc:
84+
"For polymorphic resources, configures the on_delete behavior of the automatically generated foreign keys to source tables."
85+
],
86+
polymorphic_on_update:[
87+
type:{:one_of,[:update,:nilify,:nothing,:restrict]},
88+
doc:
89+
"For polymorphic resources, configures the on_update behavior of the automatically generated foreign keys to source tables."
90+
],
91+
polymorphic_name:[
92+
type:{:one_of,[:update,:nilify,:nothing,:restrict]},
93+
doc:
94+
"For polymorphic resources, configures the on_update behavior of the automatically generated foreign keys to source tables."
95+
]
96+
]
97+
}
98+
4599
@postgres%Ash.Dsl.Section{
46100
name::postgres,
47101
describe:"""
48102
Postgres data layer configuration
49103
""",
50104
sections:[
51-
@manage_tenant
105+
@manage_tenant,
106+
@references
52107
],
53108
modules:[
54109
:repo
@@ -217,6 +272,7 @@ defmodule AshPostgres.DataLayer do
217272
defcan?(_,:nested_expressions),do:true
218273
defcan?(_,{:query_aggregate,:count}),do:true
219274
defcan?(_,:sort),do:true
275+
defcan?(_,:distinct),do:true
220276
defcan?(_,{:sort,_}),do:true
221277
defcan?(_,_),do:false
222278

@@ -703,6 +759,40 @@ defmodule AshPostgres.DataLayer do
703759
end)
704760
end
705761

762+
@impltrue
763+
defdistinct(query,distinct_on,resource)do
764+
query=default_bindings(query,resource)
765+
766+
query=
767+
query
768+
|>default_bindings(resource)
769+
|>Map.update!(:distinct,fndistinct->
770+
distinct=
771+
distinct||
772+
%Ecto.Query.QueryExpr{
773+
expr:[]
774+
}
775+
776+
expr=
777+
Enum.map(distinct_on,fndistinct_on_field->
778+
binding=
779+
caseMap.fetch(query.__ash_bindings__.aggregates,distinct_on_field)do
780+
{:ok,binding}->
781+
binding
782+
783+
:error->
784+
0
785+
end
786+
787+
{:asc,{{:.,[],[{:&,[],[binding]},distinct_on_field]},[],[]}}
788+
end)
789+
790+
%{distinct|expr:distinct.expr++expr}
791+
end)
792+
793+
{:ok,query}
794+
end
795+
706796
defpsanitize_sort(sort)do
707797
sort
708798
|>List.wrap()

‎lib/migration_generator/migration_generator.ex‎

Lines changed: 72 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -257,23 +257,16 @@ defmodule AshPostgres.MigrationGenerator do
257257
defpmerge_attributes(attributes,table,count)do
258258
attributes
259259
|>Enum.group_by(&&1.name)
260-
|>Enum.map(fn
261-
{_name,[attribute]}->
262-
ifcount>1do
263-
%{attribute|allow_nil?:true}
264-
else
265-
attribute
266-
end
267-
268-
{name,attributes}->
269-
%{
270-
name:name,
271-
type:merge_types(Enum.map(attributes,&&1.type),name,table),
272-
default:merge_defaults(Enum.map(attributes,&&1.default)),
273-
allow_nil?:Enum.any?(attributes,&&1.allow_nil?)||Enum.count(attributes)<count,
274-
references:merge_references(Enum.map(attributes,&&1.references),name,table),
275-
primary_key?:false
276-
}
260+
|>Enum.map(fn{name,attributes}->
261+
%{
262+
name:name,
263+
type:merge_types(Enum.map(attributes,&&1.type),name,table),
264+
default:merge_defaults(Enum.map(attributes,&&1.default)),
265+
allow_nil?:Enum.any?(attributes,&&1.allow_nil?)||Enum.count(attributes)<count,
266+
generated?:Enum.any?(attributes,&&1.generated?),
267+
references:merge_references(Enum.map(attributes,&&1.references),name,table),
268+
primary_key?:false
269+
}
277270
end)
278271
end
279272

@@ -285,16 +278,40 @@ defmodule AshPostgres.MigrationGenerator do
285278
[]->
286279
nil
287280

288-
[reference]->
289-
reference
290-
291281
references->
292-
conflicting_table_field_names=
293-
Enum.map_join(references,"\n",fnreference->
294-
"*#{reference.table}.#{reference.destination_field}"
295-
end)
282+
%{
283+
destination_field:merge_uniq!(references,table,:destination_field,name),
284+
multitenancy:merge_uniq!(references,table,:multitenancy,name),
285+
on_delete:merge_uniq!(references,table,:on_delete,name),
286+
on_update:merge_uniq!(references,table,:on_update,name),
287+
name:merge_uniq!(references,table,:name,name),
288+
table:merge_uniq!(references,table,:table,name)
289+
}
290+
end
291+
end
292+
293+
defpmerge_uniq!(references,table,field,attribute)do
294+
references
295+
|>Enum.map(&Map.get(&1,field))
296+
|>Enum.filter(&&1)
297+
|>Enum.uniq()
298+
|>casedo
299+
[]->
300+
nil
301+
302+
[value]->
303+
value
304+
305+
values->
306+
values=Enum.map_join(values,"\n",&" *#{inspect(&1)}")
307+
308+
raise"""
309+
Conflicting configurations for references for#{table}.#{attribute}:
296310
297-
raise"Conflicting references for `#{table}.#{name}`:\n#{conflicting_table_field_names}"
311+
Values:
312+
313+
#{values}
314+
"""
298315
end
299316
end
300317

@@ -1113,7 +1130,7 @@ defmodule AshPostgres.MigrationGenerator do
11131130

11141131
snapshot_file
11151132
|>File.read!()
1116-
|>load_snapshot()
1133+
|>load_snapshot(snapshot.table)
11171134
end
11181135
else
11191136
get_old_snapshot(folder,snapshot)
@@ -1128,7 +1145,7 @@ defmodule AshPostgres.MigrationGenerator do
11281145
ifFile.exists?(old_snapshot_file)do
11291146
old_snapshot_file
11301147
|>File.read!()
1131-
|>load_snapshot()
1148+
|>load_snapshot(snapshot.table)
11321149
end
11331150
end
11341151

@@ -1212,7 +1229,12 @@ defmodule AshPostgres.MigrationGenerator do
12121229
Map.put(attribute,:references,%{
12131230
destination_field:relationship.source_field,
12141231
multitenancy:multitenancy(relationship.source),
1215-
table:AshPostgres.table(relationship.source)
1232+
table:AshPostgres.table(relationship.source),
1233+
on_delete:AshPostgres.polymorphic_on_delete(relationship.source),
1234+
on_update:AshPostgres.polymorphic_on_update(relationship.source),
1235+
name:
1236+
AshPostgres.polymorphic_name(relationship.source)||
1237+
"#{relationship.context[:data_layer][:table]}_#{relationship.source_field}_fkey"
12161238
})
12171239
else
12181240
attribute
@@ -1289,9 +1311,14 @@ defmodule AshPostgres.MigrationGenerator do
12891311
Enum.find_value(Ash.Resource.Info.relationships(resource),fnrelationship->
12901312
ifattribute.name==relationship.source_field&&relationship.type==:belongs_to&&
12911313
foreign_key?(relationship)do
1314+
configured_reference=configured_reference(resource,attribute.name,relationship.name)
1315+
12921316
%{
12931317
destination_field:relationship.destination_field,
12941318
multitenancy:multitenancy(relationship.destination),
1319+
on_delete:configured_reference.on_delete,
1320+
on_update:configured_reference.on_update,
1321+
name:configured_reference.name,
12951322
table:
12961323
relationship.context[:data_layer][:table]||
12971324
AshPostgres.table(relationship.destination)
@@ -1300,6 +1327,17 @@ defmodule AshPostgres.MigrationGenerator do
13001327
end)
13011328
end
13021329

1330+
defpconfigured_reference(resource,attribute,relationship)do
1331+
resource
1332+
|>AshPostgres.references()
1333+
|>Enum.find(&(&1.relationship==relationship))
1334+
|>Kernel.||(%{
1335+
on_delete:nil,
1336+
on_update:nil,
1337+
name:"#{AshPostgres.table(resource)}_#{attribute}_fkey"
1338+
})
1339+
end
1340+
13031341
defpmigration_type({:array,type}),do:{:array,migration_type(type)}
13041342
defpmigration_type(Ash.Type.CiString),do::citext
13051343
defpmigration_type(Ash.Type.UUID),do::uuid
@@ -1390,15 +1428,15 @@ defmodule AshPostgres.MigrationGenerator do
13901428
type
13911429
end
13921430

1393-
defpload_snapshot(json)do
1431+
defpload_snapshot(json,table)do
13941432
json
13951433
|>Jason.decode!(keys::atoms!)
13961434
|>Map.put_new(:has_create_action,true)
13971435
|>Map.update!(:identities,fnidentities->
13981436
Enum.map(identities,&load_identity/1)
13991437
end)
14001438
|>Map.update!(:attributes,fnattributes->
1401-
Enum.map(attributes,&load_attribute/1)
1439+
Enum.map(attributes,&load_attribute(&1,table))
14021440
end)
14031441
|>Map.update!(:repo,&String.to_atom/1)
14041442
|>Map.put_new(:multitenancy,%{
@@ -1415,7 +1453,7 @@ defmodule AshPostgres.MigrationGenerator do
14151453
|>Map.update!(:attribute,fnattribute->attribute&&String.to_atom(attribute)end)
14161454
end
14171455

1418-
defpload_attribute(attribute)do
1456+
defpload_attribute(attribute,table)do
14191457
attribute
14201458
|>Map.update!(:type,&load_type/1)
14211459
|>Map.update!(:name,&String.to_atom/1)
@@ -1428,6 +1466,9 @@ defmodule AshPostgres.MigrationGenerator do
14281466
references->
14291467
references
14301468
|>Map.update!(:destination_field,&String.to_atom/1)
1469+
|>Map.put_new(:on_delete,nil)
1470+
|>Map.put_new(:on_update,nil)
1471+
|>Map.put_new(:name,"#{table}_#{attribute.name}")
14311472
|>Map.put_new(:multitenancy,%{
14321473
attribute:nil,
14331474
strategy:nil,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp