-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathorm.remarkup
More file actions
275 lines (213 loc) · 6.55 KB
/
Copy pathorm.remarkup
File metadata and controls
275 lines (213 loc) · 6.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# ORM-style database access
Each Sealious collection has simple Promise-based accessor methods.
## Getting a single item
```
lang=typescript
const item = await app.collections.tasks.getByID(context, some_id);
```
If you want to skip any access policy checks, you can pass `SuperContext` as the first argument:
```
lang=typescript
await app.collections.tasks.getByID(new app.SuperContext(), some_id);
```
A shorthand for that, as with many other collection methods, is to add a `su` prefix to the method name, and skip the context:
```
lang=typescript
await app.collections.tasks.suGetByID(some_id);
```
If you want to use `.attach` or `.filter` or any other list-based methods on a single item, you can use
```
lang=typescript
const {
items: [item],
} = await app.collectionst.tasks
.list(context)
.ids([some_id])
.attach({ author: true })
.fetch();
```
## Listing items
To query a collection, first create an `ItemList`:
```
lang=typescript
app.collections.tasks.list(context)
```
The above code returns an instance of `ItemList`. It supports chainable methods
that allow you to specify which items you want to fetch before any database
query is ran. Those methods are described below.
Remember that in order to actually run the database query and get the items you
want, you have to call the `.fetch()` method of the ItemList object.
### Filtering the list
You can narrow down the items that will be returned by field values. For that,
use the `.filter` chain method:
```
lang=typescript
const { items: matching_animals } = await app.collections.animals
.list(context)
.filter({ name: "Reksio" })
.fetch();
```
You can specify multiple field names and values:
```
lang=typescript
const { items: matching_animals } = await app.collections.animals
.list(context)
.filter({ name: "Reksio", species: "dog" })
.fetch();
```
Some field types support more complex filter values. Refer to each of the field
type's specification for details.
```
lang=typescript
const { items: matching_animals } = await app.collections.animals
.list(context)
.filter({ name: "Reksio", species: "dog", age: { ">": 3, "<": 5 } })
.fetch();
```
### Setting field format
Some fields' output varies depending on the specified format. While querying the
database usint `ItemList`, you can specify different formats for each field.
Refer to each of the field types' specification for details.
```
lang=typescript
const { items: messages } = await app.collections.messages.list().fetch();
console.log(messages[0].get("content")); // foo & bar
const original_messages = await app.collections.messages
.list(context)
.format({ content: "original" })
.fetch();
console.log(messages[0].get("content")); // foo & bar
```
### Pagination
You can use pagination to limit the amount of returned entries. Think of it as
LIMIT/SKIP from SQL, but within Sealious' context.
```
lang=typescript
const { items: logs } = await app.collections.logs
.list(context)
.paginate({ page: 2, items: 10 })
.fetch(); // returns items 11-20
```
### Turning on attachments
```
lang=typescript
const { items: users } = await app.collections.users
.list(context)
.attach({ field1: true })
.fetch();
```
After turning on attachments for certain field/fields, you can access their full
values (e.g. `CollectionItem` instances) with `getAttachments`:
```
lang=typescript
items[0].getAttachments("field1");
```
`.attach` is very useful, because you can load all resources related
to a given item in one command chain. If you want to for example load
all Images linked to a Gallery item, make sure that the Gallery
collection has an `images` field that is a `ReverseSingleReference`
and do:
```
const { items: users } = await app.collections.galleries
.list(context)
.attach({ images: true })
.fetch();
```
You can nest the attachments, as well:
```
const { items: users } = await app.collections.galleries
.list(context)
.attach({ images: {author: true} })
.fetch();
```
### Sorting
```
lang=typescript
const { items: users } = await app.collections.users
.list(context)
.sort({ price: "asc" }) // "asc" or "desc"
.fetch();
```
### Listing many items by a list of IDs
If you have a list of IDs, you can get all of the items for that ids with a single query like this:
```
lang=typescript
const { items } = await app.collections.tasks
.list(context)
.ids([id1, id2, id3, ...])
.fetch();
```
### Combining the chain methods
You can combine the `filter`, `paginate`, `format`, `sort`, `ids` and `attach` methods into one elegant chain, like so:
```
const { items } = await app.collections.items
.list(context)
.filter({ name: "Reksio" })
.format({content: "original"})
.attach({ field1: true })
.sort({name: "asc"})
.paginate({ page: 2, items: 10 })
.fetch();
```
The order of the methods in chain is not significant, aside from the fact that
`fetch` has to be at the end of the chain.
### Listing one item
Comparable to `fetch` method you can use `fetchOne` which returns exactly one item, or null if value is not found:
```
const item = await app.collections.numbers
.suList()
.filter({ item: { "<": 10 } })
.sort({ item: "desc" })
.fetchOne();
```
## Creating an item in a database
```
lang=typescript
const new_task = app.collections.tasks.make();
new_task.set("title", "Write sealious docs");
new_task.set("done", false);
await item.save(context);
```
Alternatively, you can use `setMultiple` to set multiple fields with one call:
```
lang=typescript
const new_task = app.collections.tasks.make();
new_task.setMultiple({ title: "Write sealious docs", done: false });
await item.save(context);
```
## Editing an item
```
lang=typescript
const item = await app.collections.tasks.getByID(context, "Xi3am-29");
item.set("done", true);
await item.save(context);
```
## Removing an item from database
```
lang=typescript
const item = await app.collections.tasks.getByID(context, "Xi3am-29");
item.set("done", true);
await item.remove(context);
```
## Upserting
You can use the upsert method to add or update an existing item in the
database based on some identifying field:
```
lang=typescript
await app.collections.patrons.upsert(
new app.SuperContext(),
"email",
[
{
email: "adam@example.com",
end_date: "2024-12-24",
},
]
);
```
## Custom methods
Some collections have custom methods attached to them, so it's easier
to perform certain repetitive tasks. Developers are encouraged to add
all custom logic related to a given collection to the class
representing that collection.
[Custom methods in Users class](https://hub.sealcode.org/source/sealious/browse/dev/src/app/collections/users.remarkup)