# JFaster patterns: how do I…?

Common modeling tasks in the JFaster language, each with a complete, minimal answer. The full definitions are in
the [language specification](language-spec.md).

---

## How do I define an entity with required fields?

```
Customer @Sales order="name"
   name d r
   taxId r "Tax_ID"
   email
   phone
```

`@Sales` puts it in the Sales menu, `d` makes `name` its description, `r` marks required fields and `order` sets
the default sort. `email` and `phone` get their types from their names.

## How do I reference another entity?

```
Order @Sales order="orderDate desc"
   customer Customer d r
   orderDate date ds r default="now"
```

A PascalCase token after the name (`Customer`) makes the property a reference. Users choose a customer from a
selector.

## How do I make a master/detail form (an invoice with lines)?

```
Invoice @Billing order="issueDate desc"
   customer Customer d r
   issueDate date ds r default="now"
   lines InvoiceLine set ei x childproperty="invoice"
   total double ds calculated="sum(lines[*].amount)"

InvoiceLine @
   invoice Invoice
   product Product r
   quantity integer r
   unitPrice double r
   amount double calculated="quantity * unitPrice"
```

`set ei x` edits the lines inline and lets users add rows; `childproperty` names the back-reference in the line.
`InvoiceLine @` has no menu entry because lines only exist inside an invoice.

## How do I make cascading selectors (country → province → city)?

```
Province @Configuration order="name"
   <subset name="forCountry" order="name">
   <param name="country" entity="Country" />
   <condition field="country" value="country" />
   </subset>
   name d r
   country Country r

City @Configuration order="name"
   <subset name="forProvince" order="name">
   <param name="province" entity="Province" />
   <condition field="province" value="province" />
   </subset>
   name d r
   province Province r

Address @
   country Country r
   province Province r subset="forCountry" subsetparams="country"
   city City r subset="forProvince" subsetparams="province"
```

Each selector is restricted to a parameterized subset, and `subsetparams` names the field that feeds it. When the
country changes, the provinces are recomputed.

## How do I restrict a selector to active records?

```
Supplier @Purchasing order="name"
   <subset name="active" order="name">
   <condition field="active" value="true" />
   </subset>
   name d r
   active boolean default="true"

PurchaseOrder @Purchasing order="id desc"
   supplier Supplier d r subset="active"
```

## How do I add search filters to a listing?

```
Product @Catalog order="name"
   <filter name="category" property="category" display="primary" />
   <filter name="search" label="Search" display="primary">
   <or>
   <condition field="name" like="concat('%', search, '%')" />
   <condition field="code" like="concat('%', search, '%')" />
   </or>
   </filter>
   code d r
   name d r
   category Category
```

## How do I split a listing into tabs by state?

```
<enumset name="TicketState">
<enum value="open">Open</enum>
<enum value="closed">Closed</enum>
</enumset>

Ticket @Support order="id desc" defaultlisting="main"
   <subset name="open" order="id desc">
   <condition field="state" value="'open'" />
   </subset>
   <subset name="closed" order="id desc">
   <condition field="state" value="'closed'" />
   </subset>
   <listing name="main">
   <tab name="open" label="Open" subset="open" displayactions="close" />
   <tab name="closed" label="Closed" subset="closed" />
   <tab name="all" label="All" />
   </listing>
   <action name="close" label="Close" type="relatedentity" entity="CloseTicket" location="local" defaultset="forTicket" />
   subject d r
   state enum enumset="TicketState" default="open" fixed

CloseTicket @ transient
   <defaultset name="forTicket">
   <param name="ticket" entity="Ticket" />
   <default name="ticket" value="ticket" />
   </defaultset>
   ticket Ticket fixed
   resolution text r
```

Each tab is a subset with its own actions. Strings in conditions go in single quotes (`'open'`).

## How do I model an operation (approve, send, import)?

With a **transient** entity: a form whose submission performs the operation. Open it with an action and prefill it
with a defaultset.

```
Quote @Sales order="id desc"
   <action name="send" label="Send to customer" type="relatedentity" entity="SendQuote" location="form" defaultset="forQuote" />
   customer Customer d r
   amount double ds r

SendQuote @ transient
   <defaultset name="forQuote">
   <param name="quote" entity="Quote" />
   <default name="quote" value="quote" />
   <default name="recipient" value="quote.customer.email" />
   </defaultset>
   quote Quote fixed
   recipient email r
   message text
```

What the operation does when submitted (sending the email) is business logic, written in the implementation's
extension point for `SendQuote`.

## How do I run an operation on many selected records?

```
Invoice @Billing order="id desc"
   <action name="markPaid" label="Mark as paid" type="relatedentity" entity="MarkInvoicesPaid" location="listing" defaultset="forInvoices" />
   number d r
   paid boolean ds

MarkInvoicesPaid @ transient
   <defaultset name="forInvoices">
   <param name="invoices" entity="Invoice" collection="set" />
   <default name="invoices" value="invoices" />
   </defaultset>
   invoices Invoice set fixed
   paymentDate date r default="now"
```

`location="listing"` puts the action on the listing and passes the selected rows as a collection parameter.

## How do I show related records inside a form?

```
Person @CRM order="lastName"
   <subset name="forCompany" order="lastName">
   <param name="company" entity="Company" />
   <condition field="company" value="company" />
   </subset>
   <defaultset name="newForCompany">
   <param name="company" entity="Company" />
   <default name="company" value="company" />
   </defaultset>
   firstName d r / lastName d r
   company Company r

Company @CRM order="name"
   name d r
   <embeddedlisting name="people" entity="Person" subset="forCompany" subsetparams="." defaultset="newForCompany" defaultsetparams="." />
```

People added from the company's form get the company prefilled.

## How do I show a field only in some cases?

```
<enumset name="PaymentMethod">
<enum value="cash">Cash</enum>
<enum value="card">Card</enum>
<enum value="transfer">Bank transfer</enum>
</enumset>

Payment @Finance order="id desc"
   method enum enumset="PaymentMethod" r
   cardNumber displayif="method = 'card'"
   bankAccount displayif="method = 'transfer'"
   reference disabledif="method = 'cash'"
```

## How do I compute a field?

From fields of the same form, use `calculated`:

```
OrderLine @
   quantity integer r
   unitPrice double r
   discountPct double default="0"
   amount double calculated="quantity * unitPrice * (1 - discountPct div 100)"
```

From other records, use a dynamic value:

```
OrderLine @
   product Product r
   unitPrice double disabled \
   <dynamicvalue expr="product.price">
   <param name="product" entity="Product" value="product" />
   </dynamicvalue>
   quantity integer r
```

From the database, for display in listings, use `formula`:

```
Company @CRM order="name"
   name d r
   employeeCount integer ds formula="(SELECT COUNT(*) FROM person WHERE person.company = id)"
```

## How do I set default values?

```
<enumset name="Priority">
<enum value="low">Low</enum>
<enum value="normal">Normal</enum>
<enum value="high">High</enum>
</enumset>

Task @Tasks order="dueDate"
   title d r
   dueDate date
   createdOn datetime fixed default="now"
   owner User fixed default="User:find(userId)"
   priority enum enumset="Priority" default="normal"
   done boolean default="false"
```

## How do I show each user only their own records?

`userId` is the id of the logged-in user, and `User` is the model's user entity.

```
Request @Requests order="id desc" defaultlisting="mine"
   <subset name="mine" order="id desc">
   <condition field="requester" value="User:find(userId)" />
   </subset>
   <listing name="mine">
   <tab name="mine" label="My requests" subset="mine" />
   </listing>
   requester User fixed default="User:find(userId)"
   subject d r
```

## How do I organize a long form?

```
Employee @HR order="lastName"
   #tab Personal
   firstName d r / lastName d r
   birthDate date
   personalEmail email
   #tab Job
   department Department r
   position r
   startDate date r
```

## How do I define a list of fixed values?

```
<enumset name="Priority">
<enum value="low">Low</enum>
<enum value="normal">Normal</enum>
<enum value="high">High</enum>
</enumset>

Task @Tasks order="title"
   title d r
   priority enum enumset="Priority" default="normal"
```

## How do I model a many-to-many relationship?

For a plain association, use a collection of references:

```
Article @Content order="title"
   title d r
   tags Tag set
```

When the relationship has its own data (a grade, a date, a role), make it an entity and name it by its meaning:

```
Enrollment @Academic order="id desc"
   student Student d r
   course Course d r
   enrolledOn date r default="now"
   grade double
```

## How do I prevent records from being created or removed by hand?

```
AuditEntry @System noadd="noadd" noremove="noremove" order="timestamp desc"
   timestamp datetime d fixed
   user User ds fixed
   description fixed
```

Records are then created only by operations or by code.
