Skip to content

Commit 8787615

Browse files
authored
test: reproduce a bug with a complex calculation (#593)
* reproduce a bug with a complex calculation * no unused vars
1 parent 1f064f5 commit 8787615

File tree

7 files changed

+347
-0
lines changed

7 files changed

+347
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{
2+
"attributes": [
3+
{
4+
"allow_nil?": false,
5+
"default": "fragment(\"gen_random_uuid()\")",
6+
"generated?": false,
7+
"precision": null,
8+
"primary_key?": true,
9+
"references": null,
10+
"scale": null,
11+
"size": null,
12+
"source": "id",
13+
"type": "uuid"
14+
},
15+
{
16+
"allow_nil?": true,
17+
"default": "nil",
18+
"generated?": false,
19+
"precision": null,
20+
"primary_key?": false,
21+
"references": null,
22+
"scale": null,
23+
"size": null,
24+
"source": "name",
25+
"type": "text"
26+
},
27+
{
28+
"allow_nil?": true,
29+
"default": "nil",
30+
"generated?": false,
31+
"precision": null,
32+
"primary_key?": false,
33+
"references": null,
34+
"scale": null,
35+
"size": null,
36+
"source": "level",
37+
"type": "bigint"
38+
},
39+
{
40+
"allow_nil?": true,
41+
"default": "nil",
42+
"generated?": false,
43+
"precision": null,
44+
"primary_key?": false,
45+
"references": {
46+
"deferrable": false,
47+
"destination_attribute": "id",
48+
"destination_attribute_default": null,
49+
"destination_attribute_generated": null,
50+
"index?": false,
51+
"match_type": null,
52+
"match_with": null,
53+
"multitenancy": {
54+
"attribute": null,
55+
"global": null,
56+
"strategy": null
57+
},
58+
"name": "complex_calculations_folder_items_folder_id_fkey",
59+
"on_delete": null,
60+
"on_update": null,
61+
"primary_key?": true,
62+
"schema": "public",
63+
"table": "complex_calculations_folders"
64+
},
65+
"scale": null,
66+
"size": null,
67+
"source": "folder_id",
68+
"type": "uuid"
69+
}
70+
],
71+
"base_filter": null,
72+
"check_constraints": [],
73+
"custom_indexes": [],
74+
"custom_statements": [],
75+
"has_create_action": false,
76+
"hash": "C7BC97676F202A744482B4095560986B265E6BCB74F6E69C1330034FBC4981E5",
77+
"identities": [],
78+
"multitenancy": {
79+
"attribute": null,
80+
"global": null,
81+
"strategy": null
82+
},
83+
"repo": "Elixir.AshPostgres.TestRepo",
84+
"schema": null,
85+
"table": "complex_calculations_folder_items"
86+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"attributes": [
3+
{
4+
"allow_nil?": false,
5+
"default": "fragment(\"gen_random_uuid()\")",
6+
"generated?": false,
7+
"precision": null,
8+
"primary_key?": true,
9+
"references": null,
10+
"scale": null,
11+
"size": null,
12+
"source": "id",
13+
"type": "uuid"
14+
},
15+
{
16+
"allow_nil?": true,
17+
"default": "nil",
18+
"generated?": false,
19+
"precision": null,
20+
"primary_key?": false,
21+
"references": null,
22+
"scale": null,
23+
"size": null,
24+
"source": "some_integer_setting",
25+
"type": "bigint"
26+
},
27+
{
28+
"allow_nil?": true,
29+
"default": "nil",
30+
"generated?": false,
31+
"precision": null,
32+
"primary_key?": false,
33+
"references": null,
34+
"scale": null,
35+
"size": null,
36+
"source": "level",
37+
"type": "ltree"
38+
}
39+
],
40+
"base_filter": null,
41+
"check_constraints": [],
42+
"custom_indexes": [],
43+
"custom_statements": [],
44+
"has_create_action": false,
45+
"hash": "1982E0DAF0B5B22502A5747ED8533C6F1D58E882E1132FAB0939EC13F2CFC5AF",
46+
"identities": [],
47+
"multitenancy": {
48+
"attribute": null,
49+
"global": null,
50+
"strategy": null
51+
},
52+
"repo": "Elixir.AshPostgres.TestRepo",
53+
"schema": null,
54+
"table": "complex_calculations_folders"
55+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationsFolderAndItems do
2+
@moduledoc """
3+
Updates resources based on their most recent snapshots.
4+
5+
This file was autogenerated with `mix ash_postgres.generate_migrations`
6+
"""
7+
8+
use Ecto.Migration
9+
10+
def up do
11+
create table(:complex_calculations_folder_items, primary_key: false) do
12+
add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true)
13+
add(:name, :text)
14+
add(:level, :bigint)
15+
add(:folder_id, :uuid)
16+
end
17+
18+
create table(:complex_calculations_folders, primary_key: false) do
19+
add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true)
20+
end
21+
22+
alter table(:complex_calculations_folder_items) do
23+
modify(
24+
:folder_id,
25+
references(:complex_calculations_folders,
26+
column: :id,
27+
name: "complex_calculations_folder_items_folder_id_fkey",
28+
type: :uuid,
29+
prefix: "public"
30+
)
31+
)
32+
end
33+
34+
alter table(:complex_calculations_folders) do
35+
add(:some_integer_setting, :bigint)
36+
add(:level, :ltree)
37+
end
38+
end
39+
40+
def down do
41+
alter table(:complex_calculations_folders) do
42+
remove(:level)
43+
remove(:some_integer_setting)
44+
end
45+
46+
drop(
47+
constraint(
48+
:complex_calculations_folder_items,
49+
"complex_calculations_folder_items_folder_id_fkey"
50+
)
51+
)
52+
53+
alter table(:complex_calculations_folder_items) do
54+
modify(:folder_id, :uuid)
55+
end
56+
57+
drop(table(:complex_calculations_folders))
58+
59+
drop(table(:complex_calculations_folder_items))
60+
end
61+
end

test/complex_calculations_test.exs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,4 +373,34 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do
373373
assert doc_before.is_active_with_timezone == false
374374
assert doc_after.is_active_with_timezone == true
375375
end
376+
377+
test "gnarly parent bug with some weird ltree setup" do
378+
_folder_a =
379+
Ash.Seed.seed!(
380+
AshPostgres.Test.Support.ComplexCalculations.Folder,
381+
%{some_integer_setting: 1, level: "a"}
382+
)
383+
384+
_folder_b =
385+
Ash.Seed.seed!(
386+
AshPostgres.Test.Support.ComplexCalculations.Folder,
387+
%{some_integer_setting: nil, level: "a.b"}
388+
)
389+
390+
folder_c =
391+
Ash.Seed.seed!(
392+
AshPostgres.Test.Support.ComplexCalculations.Folder,
393+
%{some_integer_setting: nil, level: "a.b.c"}
394+
)
395+
396+
folder_c_item =
397+
Ash.Seed.seed!(
398+
AshPostgres.Test.Support.ComplexCalculations.FolderItem,
399+
%{name: "Item in C", level: 1, folder_id: folder_c.id}
400+
)
401+
402+
# reproduction: this raises Unknown Error
403+
# * ** (Postgrex.Error) ERROR 42846 (cannot_coerce) cannot cast type bigint to ltree
404+
assert Ash.calculate!(folder_c_item, :folder_setting) == 1
405+
end
376406
end

test/support/complex_calculations/domain.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ defmodule AshPostgres.Test.ComplexCalculations.Domain do
99
resource(AshPostgres.Test.ComplexCalculations.Channel)
1010
resource(AshPostgres.Test.ComplexCalculations.DMChannel)
1111
resource(AshPostgres.Test.ComplexCalculations.ChannelMember)
12+
resource(AshPostgres.Test.Support.ComplexCalculations.Folder)
13+
resource(AshPostgres.Test.Support.ComplexCalculations.FolderItem)
1214
end
1315

1416
authorization do
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
defmodule AshPostgres.Test.Support.ComplexCalculations.Folder do
2+
@moduledoc """
3+
A tree structure using the ltree type.
4+
"""
5+
6+
alias AshPostgres.Test.Support.ComplexCalculations.Folder
7+
8+
use Ash.Resource,
9+
domain: AshPostgres.Test.ComplexCalculations.Domain,
10+
data_layer: AshPostgres.DataLayer
11+
12+
@default_integer_setting 5
13+
14+
postgres do
15+
table "complex_calculations_folders"
16+
repo(AshPostgres.TestRepo)
17+
end
18+
19+
attributes do
20+
uuid_primary_key(:id)
21+
22+
attribute(:some_integer_setting, :integer,
23+
public?: true,
24+
description: "Some setting that can be inherited. No real semantic meaning, just for demo"
25+
)
26+
27+
attribute(:level, AshPostgres.Ltree, public?: true)
28+
end
29+
30+
actions do
31+
defaults([:read])
32+
end
33+
34+
relationships do
35+
has_many :ancestors, Folder do
36+
public?(true)
37+
no_attributes?(true)
38+
39+
# use ltree @> operator to get all ancestors
40+
filter(expr(fragment("? @> ? AND ? < ?", level, parent(level), nlevel, parent(nlevel))))
41+
end
42+
43+
has_many :items, AshPostgres.Test.Support.ComplexCalculations.FolderItem do
44+
public?(true)
45+
end
46+
end
47+
48+
calculations do
49+
calculate(:nlevel, :integer, expr(fragment("nlevel(?)", level)))
50+
51+
calculate(
52+
:effective_integer_setting,
53+
:integer,
54+
expr(
55+
if is_nil(some_integer_setting) do
56+
# closest ancestor with a non-nil setting, or the default
57+
first(
58+
ancestors,
59+
query: [
60+
sort: [nlevel: :desc],
61+
filter: expr(not is_nil(some_integer_setting))
62+
],
63+
field: :some_integer_setting
64+
) || @default_integer_setting
65+
else
66+
some_integer_setting
67+
end
68+
),
69+
description: """
70+
The effective integer setting, inheriting from ancestors if not explicitly set,
71+
or defaulting to #{@default_integer_setting} if none are set. No real semantic meaning, just for demo
72+
"""
73+
)
74+
end
75+
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
defmodule AshPostgres.Test.Support.ComplexCalculations.FolderItem do
2+
@moduledoc false
3+
use Ash.Resource,
4+
domain: AshPostgres.Test.ComplexCalculations.Domain,
5+
data_layer: AshPostgres.DataLayer
6+
7+
postgres do
8+
table "complex_calculations_folder_items"
9+
repo(AshPostgres.TestRepo)
10+
end
11+
12+
attributes do
13+
uuid_primary_key(:id)
14+
attribute(:name, :string, public?: true)
15+
16+
attribute(:level, :integer,
17+
public?: true,
18+
description: """
19+
No real semantic meaning here, just for demo, this *deliberately* is named the same as the ltree level column in Folder,
20+
but is NOT related to it in any way
21+
"""
22+
)
23+
end
24+
25+
actions do
26+
defaults([:read])
27+
end
28+
29+
calculations do
30+
calculate(:folder_setting, :integer, expr(folder.effective_integer_setting))
31+
end
32+
33+
relationships do
34+
belongs_to(:folder, AshPostgres.Test.Support.ComplexCalculations.Folder) do
35+
public?(true)
36+
end
37+
end
38+
end

0 commit comments

Comments
 (0)