Skip to content

Commit 88810a7

Browse files
author
David Lastrucci
committed
Docs
1 parent 36621c7 commit 88810a7

42 files changed

Lines changed: 5497 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/settings.local.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(for f:*)",
5+
"Bash(do test:*)",
6+
"Bash(echo \"EXISTS: $f\")",
7+
"Bash(echo \"MISSING: $f\")",
8+
"Bash(done)"
9+
]
10+
}
11+
}

.github/workflows/docs.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Deploy Documentation
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
paths:
8+
- 'docs/**'
9+
- 'mkdocs.yml'
10+
workflow_dispatch:
11+
12+
permissions:
13+
contents: write
14+
15+
jobs:
16+
deploy:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
- uses: actions/setup-python@v5
21+
with:
22+
python-version: 3.x
23+
- run: pip install mkdocs-material
24+
- run: mkdocs gh-deploy --force

Docs/api-reference/attributes.md

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
# Attributes
2+
3+
Complete reference of all Trysil attributes.
4+
5+
## Entity Mapping
6+
7+
Unit: `Trysil.Attributes`
8+
9+
| Attribute | Target | Description |
10+
|---|---|---|
11+
| `TTable(name)` | Class | Maps class to database table |
12+
| `TSequence(name)` | Class | Sequence for ID generation |
13+
| `TPrimaryKey` | Field | Marks primary key field |
14+
| `TColumn(name)` | Field | Maps field to database column |
15+
| `TDetailColumn(fk, name)` | Field | Maps a detail/lookup column |
16+
| `TVersionColumn` | Field | Enables optimistic locking |
17+
| `TRelation(table, fk, cascade)` | Class | Declares child relationship |
18+
| `TWhereClause(sql)` | Class | Adds fixed WHERE clause to all queries |
19+
| `TWhereClauseParameter(name, value)` | Class | Parameter for `TWhereClause` |
20+
21+
### TTable
22+
23+
```pascal
24+
[TTable('Persons')]
25+
TPerson = class
26+
```
27+
28+
Maps the entity class to a database table. Required on every entity.
29+
30+
### TSequence
31+
32+
```pascal
33+
[TSequence('PersonsID')]
34+
TPerson = class
35+
```
36+
37+
Names the database sequence used for ID generation. Behavior varies by database:
38+
39+
- **SQL Server**: `NEXT VALUE FOR [dbo].[PersonsID]`
40+
- **PostgreSQL**: `nextval('PersonsID')`
41+
- **Firebird**: `NEXT VALUE FOR PersonsID`
42+
- **SQLite**: `AUTOINCREMENT` (sequence name used as reference)
43+
44+
### TPrimaryKey
45+
46+
```pascal
47+
[TPrimaryKey]
48+
[TColumn('ID')]
49+
FID: TTPrimaryKey;
50+
```
51+
52+
Marks the primary key field. Must be `TTPrimaryKey` (`Int32`). One per entity.
53+
54+
### TColumn
55+
56+
```pascal
57+
[TColumn('Firstname')]
58+
FFirstname: String;
59+
```
60+
61+
Maps a field to a database column by name. The field must be `strict private`.
62+
63+
### TDetailColumn
64+
65+
```pascal
66+
[TDetailColumn('CompanyID', 'CompanyName')]
67+
FCompanyName: String;
68+
```
69+
70+
Maps a read-only column from a related table. First parameter is the foreign key column, second is the detail column name.
71+
72+
### TVersionColumn
73+
74+
```pascal
75+
[TVersionColumn]
76+
[TColumn('VersionID')]
77+
FVersionID: TTVersion;
78+
```
79+
80+
Enables optimistic locking. The version is incremented on each update. If another transaction has modified the record (version mismatch), `ETConcurrentUpdateException` is raised.
81+
82+
### TRelation
83+
84+
```pascal
85+
[TRelation('Employees', 'CompanyID', False)]
86+
TCompany = class
87+
```
88+
89+
Parameters:
90+
91+
1. **Child table name** — the table that references this entity
92+
2. **Foreign key column** — the column in the child table
93+
3. **Cascade delete**`True`: auto-delete children; `False`: block delete if children exist (raises `ETDataIntegrityException`)
94+
95+
Multiple `TRelation` attributes can be applied to the same class.
96+
97+
### TWhereClause / TWhereClauseParameter
98+
99+
```pascal
100+
[TTable('Users')]
101+
[TWhereClause('Active = :Active AND Role = :Role')]
102+
[TWhereClauseParameter('Active', True)]
103+
[TWhereClauseParameter('Role', 'admin')]
104+
TActiveAdmin = class
105+
```
106+
107+
Adds a fixed WHERE clause to every query on this entity. Parameters are **compile-time constants only**. For dynamic filtering, use [`TTFilterBuilder<T>`](../guide/filtering.md).
108+
109+
`TWhereClauseParameter` constructors accept: `String`, `Integer`, `Int64`, `Double`, `Boolean`, `TDateTime`.
110+
111+
---
112+
113+
## Validation
114+
115+
Unit: `Trysil.Validation.Attributes`
116+
117+
| Attribute | Description | Signature |
118+
|---|---|---|
119+
| `TRequired` | Not empty, null, or zero | `Create` or `Create(errorMsg)` |
120+
| `TMaxLength(n)` | Maximum string length | `Create(length)` or `Create(length, errorMsg)` |
121+
| `TMinLength(n)` | Minimum string length | `Create(length)` or `Create(length, errorMsg)` |
122+
| `TMaxValue(n)` | Maximum numeric value | `Create(Integer\|Double)` or with `errorMsg` |
123+
| `TMinValue(n)` | Minimum numeric value | `Create(Integer\|Double)` or with `errorMsg` |
124+
| `TGreater(n)` | Greater than n | `Create(Integer\|Double)` or with `errorMsg` |
125+
| `TLess(n)` | Less than n | `Create(Integer\|Double)` or with `errorMsg` |
126+
| `TRange(min, max)` | Value in range | `Create(min, max)` or with `errorMsg` |
127+
| `TRegex(pattern)` | Matches regex pattern | `Create(regex)` or `Create(regex, errorMsg)` |
128+
| `TEmail` | Valid email format | `Create` or `Create(errorMsg)` |
129+
| `TDisplayName(name)` | Human-readable field name for errors | `Create(displayName)` |
130+
| `TValidator` | Marks custom validator method | Marker attribute |
131+
132+
### Examples
133+
134+
```pascal
135+
[TRequired]
136+
[TMaxLength(50)]
137+
[TColumn('Firstname')]
138+
FFirstname: String;
139+
140+
[TMinValue(0)]
141+
[TMaxValue(100)]
142+
[TColumn('Score')]
143+
FScore: Integer;
144+
145+
[TEmail('Please enter a valid email')]
146+
[TColumn('Email')]
147+
FEmail: String;
148+
149+
[TRange(1, 999)]
150+
[TDisplayName('Order Number')]
151+
[TColumn('OrderNo')]
152+
FOrderNo: Integer;
153+
154+
[TRegex('^\+?[0-9\s\-]+$', 'Invalid phone number')]
155+
[TColumn('Phone')]
156+
FPhone: String;
157+
```
158+
159+
All validation attributes optionally accept a custom error message as the last parameter. If omitted, a default message is generated using the `TDisplayName` (if present) or the column name.
160+
161+
---
162+
163+
## Events
164+
165+
Unit: `Trysil.Events.Attributes`
166+
167+
### Class-Level Event Attributes
168+
169+
Register an event class for an entity:
170+
171+
| Attribute | Description |
172+
|---|---|
173+
| `TInsertEvent(eventClass)` | Event class for insert operations |
174+
| `TUpdateEvent(eventClass)` | Event class for update operations |
175+
| `TDeleteEvent(eventClass)` | Event class for delete operations |
176+
177+
```pascal
178+
[TInsertEvent(TPersonInsertEvent)]
179+
[TUpdateEvent(TPersonUpdateEvent)]
180+
[TDeleteEvent(TPersonDeleteEvent)]
181+
TPerson = class
182+
```
183+
184+
### Method-Level Event Attributes
185+
186+
Declare event methods directly on the entity:
187+
188+
| Attribute | Description |
189+
|---|---|
190+
| `TBeforeInsert` | Method called before insert |
191+
| `TAfterInsert` | Method called after insert |
192+
| `TBeforeUpdate` | Method called before update |
193+
| `TAfterUpdate` | Method called after update |
194+
| `TBeforeDelete` | Method called before delete |
195+
| `TAfterDelete` | Method called after delete |
196+
197+
```pascal
198+
TPerson = class
199+
strict private
200+
[TBeforeInsert]
201+
procedure OnBeforeInsert;
202+
[TAfterUpdate]
203+
procedure OnAfterUpdate;
204+
end;
205+
```
206+
207+
See [Events](../guide/events.md) for detailed usage.
208+
209+
---
210+
211+
## JSON
212+
213+
Unit: `Trysil.JSon.Attributes`
214+
215+
| Attribute | Description |
216+
|---|---|
217+
| `TJSonIgnore` | Exclude field from JSON serialization/deserialization |
218+
219+
```pascal
220+
[TJSonIgnore]
221+
[TColumn('InternalHash')]
222+
FInternalHash: String;
223+
```
224+
225+
See [JSON Module](../json/index.md) for serialization documentation.
226+
227+
---
228+
229+
## HTTP
230+
231+
Unit: `Trysil.Http.Attributes`
232+
233+
### Routing
234+
235+
| Attribute | Description |
236+
|---|---|
237+
| `TUri(path)` | Controller base URI |
238+
| `TGet` / `TGet(path)` | GET endpoint |
239+
| `TPost` / `TPost(path)` | POST endpoint |
240+
| `TPut` / `TPut(path)` | PUT endpoint |
241+
| `TDelete` / `TDelete(path)` | DELETE endpoint |
242+
243+
URL parameters use `?` as placeholder:
244+
245+
```pascal
246+
[TUri('/api/persons')]
247+
TPersonController = class(TTHttpController<TAPIContext>)
248+
public
249+
[TGet] // GET /api/persons
250+
procedure GetAll;
251+
252+
[TGet('/?')] // GET /api/persons/123
253+
procedure GetById(const AID: TTPrimaryKey);
254+
255+
[TPost] // POST /api/persons
256+
procedure Insert;
257+
258+
[TPut] // PUT /api/persons
259+
procedure Update;
260+
261+
[TDelete('/?/?')] // DELETE /api/persons/123/1
262+
procedure Delete(const AID: TTPrimaryKey; const AVersionID: TTVersion);
263+
end;
264+
```
265+
266+
### Authentication & Authorization
267+
268+
| Attribute | Description |
269+
|---|---|
270+
| `TAuthorizationType(type)` | Authentication requirement for controller |
271+
| `TArea(name)` | Required authorization area for method |
272+
273+
```pascal
274+
// No authentication required
275+
[TAuthorizationType(TTHttpAuthorizationType.None)]
276+
TLogonController = class(TTHttpController<TAPIContext>)
277+
278+
// Require 'admin' area
279+
[TGet]
280+
[TArea('admin')]
281+
procedure GetSettings;
282+
```
283+
284+
`TTHttpAuthorizationType` values:
285+
286+
- `None` — no authentication required
287+
- `Authentication` — authentication required (default)
288+
289+
See [HTTP Module](../http/index.md) for full documentation.

0 commit comments

Comments
 (0)