Skip to content

Commit 6b3628b

Browse files
docs: document includeCalculated finder argument for select=false SQL properties
Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
1 parent a5b58ea commit 6b3628b

3 files changed

Lines changed: 33 additions & 1 deletion

File tree

.ai/wheels/snippets/model-snippets.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,18 @@ function recent(days=30) {
151151
## Calculated Properties
152152
```cfm
153153
function config() {
154-
// SQL-based calculated property
154+
// SQL-based calculated property — included in every SELECT by default
155155
property(name="orderTotal", sql="(SELECT SUM(amount) FROM order_items WHERE order_id = orders.id)");
156+
157+
// Keep off the hot path with select=false; opt in per-call with includeCalculated
158+
property(name="fullName", sql="firstName || ' ' || lastName", select=false);
156159
}
157160
161+
// Opt a select=false property back into one finder (additive — base columns still selected)
162+
user = model("User").findOne(includeCalculated="fullName");
163+
order = model("Order").findAll(includeCalculated="orderTotal,shippingCost");
164+
```
165+
158166
// Method-based calculated property
159167
function displayName() {
160168
if (Len(this.nickName)) {

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ component extends="Model" {
280280
// Callbacks
281281
beforeSave("sanitizeInput");
282282
283+
// Calculated SQL properties — select=false keeps them off the default SELECT (hot path)
284+
property(name="fullName", sql="firstName || ' ' || lastName", select=false);
285+
283286
// Query scopes — reusable, composable query fragments
284287
scope(name="active", where="status = 'active'");
285288
scope(name="recent", order="createdAt DESC");
@@ -299,6 +302,7 @@ component extends="Model" {
299302
Finders: `model("User").findAll()`, `findOne(where="...")`, `findByKey(params.key)`.
300303
Create: `model("User").new(params.user).save()`, or `model("User").create(params.user)`.
301304
Include associations: `findAll(include="role,orders")`. Pagination: `findAll(page=params.page, perPage=25)`.
305+
Opt a `select=false` calculated property into one call (additive): `findAll(includeCalculated="fullName")`. Unknown names throw `Wheels.CalculatedPropertyNotFound` in dev/testing.
302306

303307
### Scopes / Enums / Builder / Batch
304308

web/sites/guides/src/content/docs/v4-0-0/basics/models-and-the-orm.mdx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,26 @@ component extends="Model" {
6565

6666
Composite keys are also supported — pass a comma-separated list to `setPrimaryKey("tenantId,entryId")`. Most apps never need them.
6767

68+
## Calculated SQL properties
69+
70+
A `property()` declaration can carry a `sql` expression that Wheels evaluates as a computed `SELECT` column. Pass `select=false` to keep the property off the default `SELECT` (reducing hot-path cost), then opt it back into a specific finder with `includeCalculated`:
71+
72+
```cfm
73+
component extends="Model" {
74+
function config() {
75+
property(name="fullName", sql="firstName || ' ' || lastName", select=false);
76+
}
77+
}
78+
79+
// Additive — all base columns are still selected; fullName is merged on top
80+
user = model("User").findOne(includeCalculated="fullName");
81+
82+
// Comma-list for multiple properties; composes with other finder arguments
83+
users = model("User").active().findAll(include="role", includeCalculated="fullName", page=1, perPage=25);
84+
```
85+
86+
Unknown names passed to `includeCalculated` throw `Wheels.CalculatedPropertyNotFound` in `development` and `testing`, and are silently ignored in `production`.
87+
6888
## Finders
6989

7090
The finders read from the database. Every finder below is a method on the class, called via `model("Name")`. The calls return different shapes depending on whether you're loading many, one, or just asking a question.

0 commit comments

Comments
 (0)