mirror of
https://github.com/ash-project/ash_postgres.git
synced 2024-09-19 13:03:14 +12:00
test: add failing test to demonstrate potential bug (#164)
1) test complex calculation (AshPostgres.Test.ComplexCalculationsTest) test/complex_calculations_test.exs:5 ** (RuntimeError) Error while building reference: latest_documentation_status code: |> AshPostgres.Test.ComplexCalculations.Api.load!([ stacktrace: (ash_postgres 1.3.41) lib/expr.ex:846: AshPostgres.Expr.do_dynamic_expr/5 (ash_postgres 1.3.41) lib/expr.ex:109: AshPostgres.Expr.do_dynamic_expr/5 (ash_postgres 1.3.41) lib/expr.ex:356: AshPostgres.Expr.do_dynamic_expr/5 (ash_postgres 1.3.41) lib/expr.ex:968: anonymous fn/6 in AshPostgres.Expr.do_dynamic_expr/5 (ecto 3.10.3) lib/ecto/query/builder/dynamic.ex:76: Ecto.Query.Builder.Dynamic.expand/3 (stdlib 5.0.2) lists.erl:1706: :lists.mapfoldl_1/3 (elixir 1.15.4) lib/macro.ex:653: Macro.do_traverse/4 (stdlib 5.0.2) lists.erl:1706: :lists.mapfoldl_1/3 (stdlib 5.0.2) lists.erl:1707: :lists.mapfoldl_1/3 (elixir 1.15.4) lib/macro.ex:653: Macro.do_traverse/4 (stdlib 5.0.2) lists.erl:1706: :lists.mapfoldl_1/3 (stdlib 5.0.2) lists.erl:1707: :lists.mapfoldl_1/3 (elixir 1.15.4) lib/macro.ex:653: Macro.do_traverse/4 (stdlib 5.0.2) lists.erl:1706: :lists.mapfoldl_1/3 (elixir 1.15.4) lib/macro.ex:653: Macro.do_traverse/4 (stdlib 5.0.2) lists.erl:1706: :lists.mapfoldl_1/3 (elixir 1.15.4) lib/macro.ex:653: Macro.do_traverse/4 (ecto 3.10.3) lib/ecto/query/builder/dynamic.ex:59: Ecto.Query.Builder.Dynamic.partially_expand/6 (ecto 3.10.3) lib/ecto/query/builder/select.ex:235: Ecto.Query.Builder.Select.expand_nested/3 (ecto 3.10.3) lib/ecto/query/builder/select.ex:274: Ecto.Query.Builder.Select.expand_nested_pair/3 (elixir 1.15.4) lib/enum.ex:1825: anonymous fn/3 in Enum.map_reduce/3 (stdlib 5.0.2) maps.erl:416: :maps.fold_1/4 (elixir 1.15.4) lib/enum.ex:2522: Enum.map_reduce/3 (ecto 3.10.3) lib/ecto/query/builder/select.ex:257: Ecto.Query.Builder.Select.expand_nested/3 (ecto 3.10.3) lib/ecto/query/builder/select.ex:205: Ecto.Query.Builder.Select.select!/5 (elixir 1.15.4) lib/enum.ex:2510: Enum."-reduce/3-lists^foldl/2-0-"/3 (ash_postgres 1.3.41) lib/aggregate.ex:121: anonymous fn/6 in AshPostgres.Aggregate.add_aggregates/6 (elixir 1.15.4) lib/enum.ex:4830: Enumerable.List.reduce/3 (elixir 1.15.4) lib/enum.ex:2564: Enum.reduce_while/3 (ash_postgres 1.3.41) lib/aggregate.ex:53: AshPostgres.Aggregate.add_aggregates/6 (ash 2.13.3) lib/ash/query/aggregate.ex:570: anonymous fn/6 in Ash.Query.Aggregate.value_request/9 (ash 2.13.3) lib/ash/engine/engine.ex:537: anonymous fn/2 in Ash.Engine.run_iteration/1 (ash 2.13.3) lib/ash/engine/engine.ex:558: anonymous fn/4 in Ash.Engine.async/2 (elixir 1.15.4) lib/task/supervised.ex:101: Task.Supervised.invoke_mfa/2 (elixir 1.15.4) lib/task/supervised.ex:36: Task.Supervised.reply/4 (ash 2.13.3) lib/ash/engine/engine.ex:552: Ash.Engine.async/2 (elixir 1.15.4) lib/enum.ex:1693: Enum."-map/2-lists^map/1-1-"/2 (elixir 1.15.4) lib/enum.ex:1693: Enum."-map/2-lists^map/1-1-"/2 (ash 2.13.3) lib/ash/engine/engine.ex:702: Ash.Engine.start_pending_tasks/1 (ash 2.13.3) lib/ash/engine/engine.ex:323: Ash.Engine.run_to_completion/1 (ash 2.13.3) lib/ash/engine/engine.ex:252: Ash.Engine.do_run/2 (ash 2.13.3) lib/ash/engine/engine.ex:148: Ash.Engine.run/2 (ash 2.13.3) lib/ash/actions/read.ex:173: Ash.Actions.Read.do_run/3 (ash 2.13.3) lib/ash/actions/read.ex:96: Ash.Actions.Read.run/3 (ash 2.13.3) lib/ash/api/api.ex:1733: Ash.Api.load/4 (ash 2.13.3) lib/ash/api/api.ex:1707: Ash.Api.load!/4 test/complex_calculations_test.exs:55: (test)
This commit is contained in:
parent
c570d5f60e
commit
bac2e01b54
11 changed files with 487 additions and 1 deletions
|
@ -44,7 +44,11 @@ if Mix.env() == :test do
|
|||
|
||||
config :ash_postgres,
|
||||
ecto_repos: [AshPostgres.TestRepo, AshPostgres.TestNoSandboxRepo],
|
||||
ash_apis: [AshPostgres.Test.Api, AshPostgres.MultitenancyTest.Api]
|
||||
ash_apis: [
|
||||
AshPostgres.Test.Api,
|
||||
AshPostgres.MultitenancyTest.Api,
|
||||
AshPostgres.Test.ComplexCalculations.Api
|
||||
]
|
||||
|
||||
config :logger, level: :warning
|
||||
end
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"default": "fragment(\"uuid_generate_v4()\")",
|
||||
"size": null,
|
||||
"type": "uuid",
|
||||
"source": "id",
|
||||
"references": null,
|
||||
"allow_nil?": false,
|
||||
"primary_key?": true,
|
||||
"generated?": false
|
||||
}
|
||||
],
|
||||
"table": "complex_calculations_certifications",
|
||||
"hash": "A4D8129693BDC95C72E91842B17BB1B44951D91A87DC166A3371D052E4D27C1F",
|
||||
"repo": "Elixir.AshPostgres.TestRepo",
|
||||
"schema": null,
|
||||
"check_constraints": [],
|
||||
"identities": [],
|
||||
"custom_indexes": [],
|
||||
"multitenancy": {
|
||||
"global": null,
|
||||
"attribute": null,
|
||||
"strategy": null
|
||||
},
|
||||
"base_filter": null,
|
||||
"custom_statements": [],
|
||||
"has_create_action": true
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"default": "fragment(\"uuid_generate_v4()\")",
|
||||
"size": null,
|
||||
"type": "uuid",
|
||||
"source": "id",
|
||||
"references": null,
|
||||
"allow_nil?": false,
|
||||
"primary_key?": true,
|
||||
"generated?": false
|
||||
},
|
||||
{
|
||||
"default": "nil",
|
||||
"size": null,
|
||||
"type": "text",
|
||||
"source": "status",
|
||||
"references": null,
|
||||
"allow_nil?": false,
|
||||
"primary_key?": false,
|
||||
"generated?": false
|
||||
},
|
||||
{
|
||||
"default": "nil",
|
||||
"size": null,
|
||||
"type": "utc_datetime_usec",
|
||||
"source": "documented_at",
|
||||
"references": null,
|
||||
"allow_nil?": true,
|
||||
"primary_key?": false,
|
||||
"generated?": false
|
||||
},
|
||||
{
|
||||
"default": "fragment(\"now()\")",
|
||||
"size": null,
|
||||
"type": "utc_datetime_usec",
|
||||
"source": "inserted_at",
|
||||
"references": null,
|
||||
"allow_nil?": false,
|
||||
"primary_key?": false,
|
||||
"generated?": false
|
||||
},
|
||||
{
|
||||
"default": "fragment(\"now()\")",
|
||||
"size": null,
|
||||
"type": "utc_datetime_usec",
|
||||
"source": "updated_at",
|
||||
"references": null,
|
||||
"allow_nil?": false,
|
||||
"primary_key?": false,
|
||||
"generated?": false
|
||||
},
|
||||
{
|
||||
"default": "nil",
|
||||
"size": null,
|
||||
"type": "uuid",
|
||||
"source": "skill_id",
|
||||
"references": {
|
||||
"name": "complex_calculations_documentations_skill_id_fkey",
|
||||
"table": "complex_calculations_skills",
|
||||
"primary_key?": true,
|
||||
"schema": "public",
|
||||
"multitenancy": {
|
||||
"global": null,
|
||||
"attribute": null,
|
||||
"strategy": null
|
||||
},
|
||||
"destination_attribute": "id",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"deferrable": false,
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null
|
||||
},
|
||||
"allow_nil?": true,
|
||||
"primary_key?": false,
|
||||
"generated?": false
|
||||
}
|
||||
],
|
||||
"table": "complex_calculations_documentations",
|
||||
"hash": "26FCE27CAB6B3B67C7E099831352AF89AFD352CBD6E30043C4354B0400F09FBD",
|
||||
"repo": "Elixir.AshPostgres.TestRepo",
|
||||
"schema": null,
|
||||
"check_constraints": [],
|
||||
"identities": [],
|
||||
"custom_indexes": [],
|
||||
"multitenancy": {
|
||||
"global": null,
|
||||
"attribute": null,
|
||||
"strategy": null
|
||||
},
|
||||
"base_filter": null,
|
||||
"custom_statements": [],
|
||||
"has_create_action": true
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"attributes": [
|
||||
{
|
||||
"default": "fragment(\"uuid_generate_v4()\")",
|
||||
"size": null,
|
||||
"type": "uuid",
|
||||
"source": "id",
|
||||
"references": null,
|
||||
"allow_nil?": false,
|
||||
"primary_key?": true,
|
||||
"generated?": false
|
||||
},
|
||||
{
|
||||
"default": "false",
|
||||
"size": null,
|
||||
"type": "boolean",
|
||||
"source": "removed",
|
||||
"references": null,
|
||||
"allow_nil?": false,
|
||||
"primary_key?": false,
|
||||
"generated?": false
|
||||
},
|
||||
{
|
||||
"default": "nil",
|
||||
"size": null,
|
||||
"type": "uuid",
|
||||
"source": "certification_id",
|
||||
"references": {
|
||||
"name": "complex_calculations_skills_certification_id_fkey",
|
||||
"table": "complex_calculations_certifications",
|
||||
"primary_key?": true,
|
||||
"schema": "public",
|
||||
"multitenancy": {
|
||||
"global": null,
|
||||
"attribute": null,
|
||||
"strategy": null
|
||||
},
|
||||
"destination_attribute": "id",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"deferrable": false,
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null
|
||||
},
|
||||
"allow_nil?": true,
|
||||
"primary_key?": false,
|
||||
"generated?": false
|
||||
}
|
||||
],
|
||||
"table": "complex_calculations_skills",
|
||||
"hash": "D2569EE39E2C9C58AAA3EB9E03A5EE726C5CD2F43D7387DA213F2C2D539F7606",
|
||||
"repo": "Elixir.AshPostgres.TestRepo",
|
||||
"schema": null,
|
||||
"check_constraints": [],
|
||||
"identities": [],
|
||||
"custom_indexes": [],
|
||||
"multitenancy": {
|
||||
"global": null,
|
||||
"attribute": null,
|
||||
"strategy": null
|
||||
},
|
||||
"base_filter": null,
|
||||
"custom_statements": [],
|
||||
"has_create_action": true
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationTables 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
|
||||
create table(:complex_calculations_skills, primary_key: false) do
|
||||
add :id, :uuid, null: false, default: fragment("uuid_generate_v4()"), primary_key: true
|
||||
add :removed, :boolean, null: false, default: false
|
||||
add :certification_id, :uuid
|
||||
end
|
||||
|
||||
create table(:complex_calculations_documentations, primary_key: false) do
|
||||
add :id, :uuid, null: false, default: fragment("uuid_generate_v4()"), primary_key: true
|
||||
add :status, :text, null: false
|
||||
add :documented_at, :utc_datetime_usec
|
||||
add :inserted_at, :utc_datetime_usec, null: false, default: fragment("now()")
|
||||
add :updated_at, :utc_datetime_usec, null: false, default: fragment("now()")
|
||||
|
||||
add :skill_id,
|
||||
references(:complex_calculations_skills,
|
||||
column: :id,
|
||||
name: "complex_calculations_documentations_skill_id_fkey",
|
||||
type: :uuid,
|
||||
prefix: "public"
|
||||
)
|
||||
end
|
||||
|
||||
create table(:complex_calculations_certifications, primary_key: false) do
|
||||
add :id, :uuid, null: false, default: fragment("uuid_generate_v4()"), primary_key: true
|
||||
end
|
||||
|
||||
alter table(:complex_calculations_skills) do
|
||||
modify :certification_id,
|
||||
references(:complex_calculations_certifications,
|
||||
column: :id,
|
||||
name: "complex_calculations_skills_certification_id_fkey",
|
||||
type: :uuid,
|
||||
prefix: "public"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def down do
|
||||
drop constraint(
|
||||
:complex_calculations_skills,
|
||||
"complex_calculations_skills_certification_id_fkey"
|
||||
)
|
||||
|
||||
alter table(:complex_calculations_skills) do
|
||||
modify :certification_id, :uuid
|
||||
end
|
||||
|
||||
drop table(:complex_calculations_certifications)
|
||||
|
||||
drop constraint(
|
||||
:complex_calculations_documentations,
|
||||
"complex_calculations_documentations_skill_id_fkey"
|
||||
)
|
||||
|
||||
drop table(:complex_calculations_documentations)
|
||||
|
||||
drop table(:complex_calculations_skills)
|
||||
end
|
||||
end
|
60
test/complex_calculations_test.exs
Normal file
60
test/complex_calculations_test.exs
Normal file
|
@ -0,0 +1,60 @@
|
|||
defmodule AshPostgres.Test.ComplexCalculationsTest do
|
||||
use AshPostgres.RepoCase, async: false
|
||||
|
||||
test "complex calculation" do
|
||||
certification =
|
||||
AshPostgres.Test.ComplexCalculations.Certification
|
||||
|> Ash.Changeset.new()
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.create!()
|
||||
|
||||
skill =
|
||||
AshPostgres.Test.ComplexCalculations.Skill
|
||||
|> Ash.Changeset.new()
|
||||
|> Ash.Changeset.manage_relationship(:certification, certification, type: :append)
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.create!()
|
||||
|
||||
_documentation =
|
||||
AshPostgres.Test.ComplexCalculations.Documentation
|
||||
|> Ash.Changeset.new(%{status: :demonstrated})
|
||||
|> Ash.Changeset.manage_relationship(:skill, skill, type: :append)
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.create!()
|
||||
|
||||
skill =
|
||||
skill
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.load!([:latest_documentation_status])
|
||||
|
||||
assert skill.latest_documentation_status == :demonstrated
|
||||
|
||||
certification =
|
||||
certification
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.load!([
|
||||
:count_of_skills
|
||||
])
|
||||
|
||||
assert certification.count_of_skills == 1
|
||||
|
||||
certification =
|
||||
certification
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.load!([
|
||||
:count_of_approved_skills
|
||||
])
|
||||
|
||||
assert certification.count_of_approved_skills == 0
|
||||
|
||||
certification =
|
||||
certification
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.load!([
|
||||
:count_of_documented_skills
|
||||
])
|
||||
|
||||
assert certification.count_of_documented_skills == 1
|
||||
|
||||
certification =
|
||||
certification
|
||||
|> AshPostgres.Test.ComplexCalculations.Api.load!([
|
||||
:some_documentation_created
|
||||
])
|
||||
|
||||
refute certification.some_documentation_created
|
||||
end
|
||||
end
|
8
test/support/complex_calculations/api.ex
Normal file
8
test/support/complex_calculations/api.ex
Normal file
|
@ -0,0 +1,8 @@
|
|||
defmodule AshPostgres.Test.ComplexCalculations.Api do
|
||||
@moduledoc false
|
||||
use Ash.Api
|
||||
|
||||
resources do
|
||||
registry(AshPostgres.Test.ComplexCalculations.Registry)
|
||||
end
|
||||
end
|
10
test/support/complex_calculations/registry.ex
Normal file
10
test/support/complex_calculations/registry.ex
Normal file
|
@ -0,0 +1,10 @@
|
|||
defmodule AshPostgres.Test.ComplexCalculations.Registry do
|
||||
@moduledoc false
|
||||
use Ash.Registry
|
||||
|
||||
entries do
|
||||
entry(AshPostgres.Test.ComplexCalculations.Certification)
|
||||
entry(AshPostgres.Test.ComplexCalculations.Skill)
|
||||
entry(AshPostgres.Test.ComplexCalculations.Documentation)
|
||||
end
|
||||
end
|
48
test/support/complex_calculations/resources/certification.ex
Normal file
48
test/support/complex_calculations/resources/certification.ex
Normal file
|
@ -0,0 +1,48 @@
|
|||
defmodule AshPostgres.Test.ComplexCalculations.Certification do
|
||||
@moduledoc false
|
||||
use Ash.Resource, data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
defaults([:create, :read, :update, :destroy])
|
||||
end
|
||||
|
||||
aggregates do
|
||||
count :count_of_documented_skills, :skills do
|
||||
filter(expr(removed == false and status != :pending))
|
||||
end
|
||||
|
||||
count :count_of_approved_skills, :skills do
|
||||
filter(expr(removed == false and status == :approved))
|
||||
end
|
||||
|
||||
count :count_of_skills, :skills do
|
||||
filter(expr(removed == false))
|
||||
end
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
end
|
||||
|
||||
calculations do
|
||||
calculate :all_documentation_approved, :boolean do
|
||||
calculation(expr(count_of_skills == count_of_approved_skills))
|
||||
load([:count_of_skills, :count_of_approved_skills])
|
||||
end
|
||||
|
||||
calculate :some_documentation_created, :boolean do
|
||||
calculation(expr(count_of_documented_skills > 0 && all_documentation_approved == false))
|
||||
|
||||
load([:count_of_documented_skills, :all_documentation_approved])
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
table "complex_calculations_certifications"
|
||||
repo(AshPostgres.TestRepo)
|
||||
end
|
||||
|
||||
relationships do
|
||||
has_many(:skills, AshPostgres.Test.ComplexCalculations.Skill)
|
||||
end
|
||||
end
|
48
test/support/complex_calculations/resources/documentation.ex
Normal file
48
test/support/complex_calculations/resources/documentation.ex
Normal file
|
@ -0,0 +1,48 @@
|
|||
defmodule AshPostgres.Test.ComplexCalculations.Documentation do
|
||||
@moduledoc false
|
||||
use Ash.Resource, data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
defaults([:create, :read, :update, :destroy])
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
|
||||
attribute(
|
||||
:status,
|
||||
:atom,
|
||||
constraints: [
|
||||
one_of: [:demonstrated, :performed, :approved, :reopened]
|
||||
],
|
||||
allow_nil?: false
|
||||
)
|
||||
|
||||
attribute(:documented_at, :utc_datetime_usec)
|
||||
create_timestamp(:inserted_at, private?: false)
|
||||
update_timestamp(:updated_at, private?: false)
|
||||
end
|
||||
|
||||
calculations do
|
||||
calculate(
|
||||
:timestamp,
|
||||
:utc_datetime_usec,
|
||||
expr(
|
||||
if is_nil(documented_at) do
|
||||
inserted_at
|
||||
else
|
||||
documented_at
|
||||
end
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
postgres do
|
||||
table "complex_calculations_documentations"
|
||||
repo(AshPostgres.TestRepo)
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to(:skill, AshPostgres.Test.ComplexCalculations.Skill)
|
||||
end
|
||||
end
|
50
test/support/complex_calculations/resources/skill.ex
Normal file
50
test/support/complex_calculations/resources/skill.ex
Normal file
|
@ -0,0 +1,50 @@
|
|||
defmodule AshPostgres.Test.ComplexCalculations.Skill do
|
||||
@moduledoc false
|
||||
use Ash.Resource, data_layer: AshPostgres.DataLayer
|
||||
|
||||
actions do
|
||||
defaults([:create, :read, :update, :destroy])
|
||||
end
|
||||
|
||||
aggregates do
|
||||
first :latest_documentation_status, [:documentations], :status do
|
||||
sort(timestamp: :desc)
|
||||
end
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
attribute(:removed, :boolean, default: false, allow_nil?: false)
|
||||
end
|
||||
|
||||
calculations do
|
||||
calculate :status, :atom do
|
||||
calculation(
|
||||
expr(
|
||||
if is_nil(latest_documentation_status) do
|
||||
:pending
|
||||
else
|
||||
latest_documentation_status
|
||||
end
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
table "complex_calculations_skills"
|
||||
repo(AshPostgres.TestRepo)
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to(:certification, AshPostgres.Test.ComplexCalculations.Certification)
|
||||
|
||||
has_many :documentations, AshPostgres.Test.ComplexCalculations.Documentation do
|
||||
sort(timestamp: :desc, inserted_at: :desc)
|
||||
end
|
||||
|
||||
has_one :latest_documentation, AshPostgres.Test.ComplexCalculations.Documentation do
|
||||
sort(timestamp: :desc, inserted_at: :desc)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue