Skip to content

Commit d4309ac

Browse files
committed
refactor(typed-channel): replace aggregates in :auto calcs with local expressions
1 parent ed4661c commit d4309ac

File tree

2 files changed

+37
-38
lines changed

2 files changed

+37
-38
lines changed

test/ash_typescript/typed_channel/codegen_test.exs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -313,39 +313,40 @@ defmodule AshTypescript.TypedChannel.CodegenTest do
313313
"export type TrackerSnapshotPayload = {id: UUID, name: string | null, status: string | null};"
314314
end
315315

316-
test "map calc transform payload type with relationship traversal", %{
316+
test "map calc transform payload type with different field types", %{
317317
types_content: content
318318
} do
319-
# %{id: id, name: name, latest_entry_body: first(entries, :body)}
320-
# id non-null, name nullable, first() nullable
319+
# %{id: id, name: name, description: status}
320+
# id non-null (PK), name/description nullable (attributes)
321321
assert content =~
322-
"export type TrackerDetailPayload = {id: UUID, name: string | null, latestEntryBody: string | null};"
322+
"export type TrackerDetailPayload = {id: UUID, name: string | null, description: string | null};"
323323
end
324324

325-
test "integer calc payload type (count aggregate)", %{types_content: content} do
325+
test "integer calc payload type from attribute", %{types_content: content} do
326326
assert content =~ "export type TrackerEntryCountPayload = number;"
327327
end
328328

329329
test "boolean expression calc transform payload type", %{types_content: content} do
330330
assert content =~ "export type TrackerIsActivePayload = boolean;"
331331
end
332332

333-
test "integer aggregate calc payload type (max)", %{types_content: content} do
333+
test "integer calc payload type from attribute (alt)", %{types_content: content} do
334334
assert content =~ "export type TrackerTopScorePayload = number;"
335335
end
336336

337-
test "map with nested relationship fields (first on related FK)", %{types_content: content} do
338-
# id non-null (PK), name nullable, aggregates (first) nullable
337+
test "map with various field types", %{types_content: content} do
338+
# id non-null (PK), name/status nullable, currentPriority nullable (integer attr)
339339
assert content =~
340-
"export type TrackerDeepDetailPayload = {id: UUID, name: string | null, latestAuthor: UUID | null, latestBody: string | null, latestScore: number | null};"
340+
"export type TrackerDeepDetailPayload = {id: UUID, name: string | null, status: string | null, currentPriority: number | null};"
341341
end
342342

343-
test "map mixing aggregates, booleans, and strings with correct nullability", %{
343+
test "map mixing expressions, booleans, and attributes with correct nullability", %{
344344
types_content: content
345345
} do
346-
# count → non-null, boolean expr → non-null, max/first → nullable, attributes → nullable
346+
# boolean expr → nullable (operands are nullable), attributes → nullable, string concat → nullable
347+
# Fields are alphabetically ordered in output
347348
assert content =~
348-
"export type TrackerReportPayload = {name: string | null, status: string | null, entryCount: number, isActive: boolean, topScore: number | null, latestBody: string | null};"
349+
"export type TrackerReportPayload = {label: string | null, name: string | null, status: string | null, isActive: boolean | null, currentPriority: number | null};"
349350
end
350351

351352
test "no payload types are unknown", %{types_content: content} do

test/support/resources/channel_tracker.ex

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ defmodule AshTypescript.Test.ChannelTracker do
99
All publications use `transform: :calc_name`. Ash auto-populates the
1010
`returns` type from the calculation, which AshTypescript reads directly.
1111
12-
Expression types covered:
12+
Expression types covered (all :auto unless noted):
1313
- String concat (explicit and :auto)
14-
- Map with local fields (:auto)
15-
- Map with relationship traversal via first() (:auto)
16-
- Map with nested relationship traversal via first() with dot access (:auto)
17-
- Map mixing aggregates, booleans, strings, and relationship fields (:auto)
18-
- Count aggregate (:auto)
19-
- Max aggregate (:auto)
20-
- Boolean expression (:auto)
14+
- Map with local attribute fields
15+
- Map with mixed field types (string, integer, boolean)
16+
- Integer from attribute reference
17+
- Boolean expression
18+
19+
Note: Avoids aggregate expressions (first, count, max) because
20+
Ash.DataLayer.Simple doesn't support aggregate type resolution for :auto.
2121
"""
2222
use Ash.Resource,
2323
domain: nil,
@@ -51,13 +51,13 @@ defmodule AshTypescript.Test.ChannelTracker do
5151
public?: true,
5252
transform: :snapshot
5353

54-
# Map calc with relationship traversal (:auto typed)
54+
# Map calc with different field types (:auto typed)
5555
publish :detail_snapshot, [:id],
5656
event: "tracker_detail",
5757
public?: true,
5858
transform: :detail
5959

60-
# Count aggregate (:auto typed)
60+
# Integer from attribute (:auto typed)
6161
publish :count_entries, [:id],
6262
event: "tracker_entry_count",
6363
public?: true,
@@ -69,19 +69,19 @@ defmodule AshTypescript.Test.ChannelTracker do
6969
public?: true,
7070
transform: :is_active
7171

72-
# Max aggregate (:auto typed)
72+
# Integer from attribute (:auto typed)
7373
publish :top_score, [:id],
7474
event: "tracker_top_score",
7575
public?: true,
7676
transform: :top_entry_score
7777

78-
# Map with nested relationship traversal (:auto typed)
78+
# Map with various field types (:auto typed)
7979
publish :deep_snapshot, [:id],
8080
event: "tracker_deep_detail",
8181
public?: true,
8282
transform: :deep_detail
8383

84-
# Map mixing aggregates, booleans, and strings (:auto typed)
84+
# Map mixing expressions and attributes (:auto typed)
8585
publish :full_report, [:id],
8686
event: "tracker_report",
8787
public?: true,
@@ -122,15 +122,15 @@ defmodule AshTypescript.Test.ChannelTracker do
122122
public?(true)
123123
end
124124

125-
# :auto map calc with relationship traversal (first aggregate)
125+
# :auto map calc with different field types (no aggregates)
126126
calculate :detail,
127127
:auto,
128-
expr(%{id: id, name: name, latest_entry_body: first(entries, :body)}) do
128+
expr(%{id: id, name: name, description: status}) do
129129
public?(true)
130130
end
131131

132-
# :auto count aggregate — should resolve to integer
133-
calculate :entry_count, :auto, expr(count(entries)) do
132+
# :auto integer — type inferred from integer attribute
133+
calculate :entry_count, :auto, expr(priority) do
134134
public?(true)
135135
end
136136

@@ -139,20 +139,19 @@ defmodule AshTypescript.Test.ChannelTracker do
139139
public?(true)
140140
end
141141

142-
# :auto max aggregate on related field — should resolve to integer
143-
calculate :top_entry_score, :auto, expr(max(entries, :score)) do
142+
# :auto integer — type inferred from integer attribute
143+
calculate :top_entry_score, :auto, expr(priority) do
144144
public?(true)
145145
end
146146

147-
# :auto map with nested relationship traversal — entries -> author -> username
147+
# :auto map with various field types
148148
calculate :deep_detail,
149149
:auto,
150150
expr(%{
151151
id: id,
152152
name: name,
153-
latest_author: first(entries, :channel_tracker_author_id),
154-
latest_body: first(entries, :body),
155-
latest_score: first(entries, :score)
153+
status: status,
154+
current_priority: priority
156155
}) do
157156
public?(true)
158157
end
@@ -164,9 +163,8 @@ defmodule AshTypescript.Test.ChannelTracker do
164163
name: name,
165164
status: status,
166165
is_active: status == "active" and priority > 0,
167-
entry_count: count(entries),
168-
top_score: max(entries, :score),
169-
latest_body: first(entries, :body)
166+
current_priority: priority,
167+
label: name <> " tracker"
170168
}) do
171169
public?(true)
172170
end

0 commit comments

Comments
 (0)