-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocument.html
More file actions
453 lines (406 loc) · 21.7 KB
/
Copy pathdocument.html
File metadata and controls
453 lines (406 loc) · 21.7 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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
---
layout: default
---
<div class="content">
<h1>Document</h1>
<div class="desc">
<p>
Documents are instances of <a href="collection">Collections</a>.
</p>
</div>
<div class="note">
Document fields usually start with a "<u>$</u>" so that the Tyranid fields do not conflict with the underlying data being modeled.
</div>
<article id="$">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$: TaggedTemplateLiteral => any</span>
<p>This is a short-cut for <a href="#$get"><u>$get()</u></a> using
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals">tagged template literals</a>.</p>
<p>For example:</p>
<pre><code class="js">myDoc.$`organization.name`</code></pre>
<p>is equivalent to:</p>
<pre><code class="js">myDoc.$get('organization.name')</code></pre>
</article>
<article id="$access">
<b class="property"></b>
<b class="server"></b>
<span class="sig">$access: <a href="secure#accessResult">AccessResult</a></span>
<p>This contains the result of a <a href="#$checkAccess"><u>$checkAccess()</u></a> call.</p>
</article>
<article id="$asOf">
<b class="method"></b>
<b class="server"></b>
<b class="async"></b>
<span class="sig">$asOf(<i>date</i>, fields: object?): void</span>
<p>This rolls back the object in-place to the given date if its collection supports <a href="/#historical">historical data</a>.</p>
<p><u>date</u> can be either an instance of Date or the number of UTC milliseconds (<u><i>Date</i>.getTime()</u>).</p>
<p>Note that once a document is rolled back to an earlier date the document is essentially read-only as updating it in the past
does not make sense. Tyranid will mark the document as <a href="document#$historical"><u>$historical</u></a> which will prevent calls like
<a href="#$save"><u>$save</u></a> from being used on it.</p>
<p>If the <u>fields</u> object is present, it indicates that only changes for the listed properties should be applied (by default
all properties are patched). For example:</p>
<p>Note that if using <a href="/#historical_patch"><u>patch</u></a> historical storage, then this method is not asynchronous.</p>
<pre><code class="js">const fields = { name: 1, age: 1 };
const myUser = User.byId(myId, { fields });
doc.$asOf(new Date(...), fields);
</code></pre>
<p>Be sure to include the <a href="#_history"><u>_history</u></a> in your projection on any object you plan to use <u>$asOf()</u> on.</p>
</article>
<article id="$cache">
<b class="method"></b>
<b class="client"></b>
<span class="sig">$cache(): this</span>
<p>This updates the local client-side database cache with the contents of this document.</p>
</article>
<article id="$checkAccess">
<b class="async"></b>
<b class="method"></b>
<b class="server"></b>
<span class="sig">$checkAccess(opts: <a href="collection#options">Options</a>): <i>MongoDB query object</i></span>
<p><u>opts</u> should contain a <u>perm</u> and <u>auth</u> option otherwise this method is likely a no-op (depending on how the <a href="secure"><u>Secure</u></a>
is written).</p>
<p>If a <u>Secure</u> component is registered with Tyranid, Tyranid will invoke its <a href="secure#checkAccess"><u>checkAccess()</u></a> method to
populate the <a href="#$access"><u>$access</u></a> object on this document.</p>
<p>Use <a href="#$redact"><u>$redact()</u></a> to process the <u>$access</u> object and remove fields that users do not have access to. <u>$redact()</u>
is separate from <u>$checkAccess</u> so that server methods can access hidden properties to create computed visible data.</p>
<p><u>$checkAccess()</u> is invoked automatically by <u>find*()</u> and <u>byId*</u> methods automatically if an <u>auth</u> is passed in. Furthermore,
<u>toClient</u> methods also automatically invoke <a href="#$redact"><u>$redact()</u></a>. So you usually do not need to manually invoke either method.</p>
</article>
<article id="$clone">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$clone(): <a href="document">Document</a></span>
<p>This performs a shallow in-memory clone of the current document that also retains the class into the cloned document.</p>
<p>See also <a href="#$cloneDeep"><u>$cloneDeep()</u></a>.
</article>
<article id="$cloneDeep">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$cloneDeep(): <a href="document">Document</a></span>
<p>This performs a deep in-memory clone of the current document that also retains the class into the cloned document.</p>
<p>See also <a href="#$clone"><u>$clone()</u></a>.
</article>
<article id="$copy">
<b class="method"></b>
<b class="server"></b>
<span class="sig">$copy(obj, keys: (string[] | Tyr.$all)?): void</span>
<p>This copies values from <u>obj</u> into the current object. If the target object has <a href="/#historical">historical</a> properties like
<a href="#_history"><u>_history</u></a> or <a href="#$orig"><u>$orig</u></a> these will not be copied.</p>
<p>If the <u>keys</u> parameter is:
<ul>
<li><b>a string array</b>, then only the properties specified in the array will be copied. If a key is specified that exists
in the current document but not in <u>obj</u>, then it will be deleted from the current document.</p>
<li><b><u>Tyr.$all</u></b>, then all properties of this collection are expected to be contained in <u>obj</u>. Any missing
will be deleted. This is effectively a replace. Also see <a href="#$replace"><u>$replace()</u></a>.
</article>
<article id="$get">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$get(path: string): any</span>
<p>This method returns a value from the current object according to the given path.</p>
<p>This is shorthand for:</p>
<pre><code class="js">return this.$model.parsePath(path).get(this);</code></pre>
<p>This method is analogous to <a href="https://lodash.com">Lodash</a>'s <u>_.get()</u>.</p>
<p>Because this method uses <a href="path"><u>Path</u></a> to parse the data, it will also deal with embedded arrays and populated/denormalized
values. For example, if <u>organization</u> is a link, then:</p>
<pre><code class="js">$get('myDoc.organization.name')</code></pre>
<p>is equivalent to</p>
<pre><code class="js">$get('myDoc.$organization.name')</code></pre>
<p>Like Lodash's <u>_.get</u>, <u>$get()</u> handles the case where <u>organization$</u> is <u>undefined</u>.</p>
<p>A tagged template literal short-cut for this method is available as <a href="#$"><u>$</u></a>.</p>
</article>
<article id="$historical">
<b class="property"></b>
<b class="server"></b>
<span class="sig">$historical: boolean</span>
<p>This indicates that this is a read-only document that is a <a href="/#historical">historical</a> version of another document
created using <a href="document#$asOf"><u>$asOf</u></a>.</p>
</article>
<article id="_history">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">_history: <a href="#snapshot">snapshot</a>[]</span>
<p>If <a href="/#historical">historical data</a> is enabled for this collection, then this field will contain an array of historical snapshots
for this document.</p>
<p id="snapshot">
The format of each <i>snapshot</i> document is:
<table class="def">
<thead>
<tr><th>Object Structure<th>Note<th>Type<th>Notes
</thead>
<tr><td>{</td>
<tr><td> a:<td>Author<td><a href="/#uids">UID</a><td>A UID referencing the author of the change.
<tr><td> c:<td>Comment<td>String<td>An optional comment about the change.
<tr><td> o:<td>On<td><i>Date in UTC ms</i><td>The date this snapshot was taken (from <i>Date</i>.getTime()).
<tr><td> p:<td><a href="diff#patchFormat">Patch</a><td><i>patch</i><td>The <a href="diff#patchFormat">patch object</a> containing the differences.
<tr><td>}</td>
</table>
</p>
<p>Users of Tyranid do not usually need to work with this history property directly.</p>
<p>Also, if you are using historical data, do not have a field named "history" as Tyranid will overwrite it with this array.</p>
</article>
<article id="$id">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$id: <i>id type</i></span>
<p>This returns the id for this document. This is usually (but not always) the contents of <u>_id</u>.
</article>
<article id="$insert">
<b class="method"></b>
<b class="server"></b>
<b class="async"></b>
<span class="sig">$insert(options: <a href="collection#options">Options</a>?): <a href="document">Document</a></span>
</article>
<article id="$isNew">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$isNew: boolean</span>
<p>This returns true if this is a new document that has not been saved to the database yet.
</article>
<article id="$label">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$label: string</span>
<p>This returns the label for this document. See <a href="/#labels">labels</a>.
</article>
<article id="$metaType">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$metaType: 'document'</span>
<p>This returns 'document'.</p>
</article>
<article id="$model">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$model: <a href="collection">Collection</a></span>
<p>This is a reference to the collection of this document. <u>this.$model</u> is equivalent to <u>this.constructor</u>.
</article>
<article id="$options">
<b class="property"></b>
<b class="server"></b>
<span class="sig">$options: object</span>
<p>This read-only property contains a reference to the <a href="collection#options">Options</a> instance that was used to find this object.</p>
</article>
<article id="$orig">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$orig: object</span>
<p>This will contain all of the original values for the document if <a href="/#historical">historical data</a> is enabled for this collection
or if the <a href="collection#def"><u>preserveInitialValues</u></a> property is set for the collection.</p>
<p>This property is also available on the client if <a href="#$snapshot"><u>$snapshot()</u></a> has been called.<p>
</article>
<article id="$parsePath">
<b class="method"></b>
<b class="server"></b>
<b class="async"></b>
<span class="sig">$parsePath(path: string): <a href="path"><u>Path</u></a></span>
<p>
This is equivalent to <a href="collection#parsePath"><u><i>Collection</i>.parsePath()</u></a> except that it also finds
<a href="/#dynamicSchemas">dynamic schema</a> paths using the current document as match criteria.
</p>
</article>
<article id="$populate">
<b class="method"></b>
<b class="server"></b>
<b class="async"></b>
<span class="sig">$populate(fields, <a href="/#denormalization">denormal</a>: boolean): this</span>
<p>
This is equivalent to <u>doc.$model.<a href="collection#populate">populate(fields, doc, denormal)</a></u>.
</p>
<p>
Also see <a href="/#population">Population</a> for more information and examples.
</p>
</article>
<article id="$redact">
<b class="method"></b>
<b class="server"></b>
<span class="sig">$redact(): void</span>
<p>If an <a href="#$access"><u>$access</u></a> property is present on this document, <u>$redact()</u> will process that object and remove
fields that the end-user does not have access to.</p>
<p><u>$redact</u> is called automatically by <a href="#$toClient"><u>$toClient()</u></a> and <a href="collection#toClient"><u>Collection.toClient()</u></a>.
</article>
<article id="$remove">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<b class="async"></b>
<span class="sig">$remove(options?: <a href="collection#options">Options</a>): void</span>
<p>This removes the current document from the database.</p>
</article>
<article id="$replace">
<b class="method"></b>
<b class="server"></b>
<span class="sig">$replace(obj): void</span>
<p>This is a short-cut for <a href="#$copy"><u>$copy(obj, Tyr.$all)</u></a>.
</article>
<article id="$revert">
<b class="method"></b>
<b class="client"></b>
<span class="sig">$revert(): void</span>
<p>If an object has an <a href="#$orig"><u>$orig</u></a> property available then this method will revert the
contents of this document to those values.</p>
</article>
<article id="$save">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<b class="async"></b>
<span class="sig">$save(options?: <a href="collection#options">Options</a>): <a href="document">Document</a></span>
<p>This method will either update or insert the object based on whether it has an _id.
<p>When updating, the entire object is <b>replaced</b>. See <a href="document#$update"><u>$update()</u></a> to only update instead of replace.
<p>If the document ends up being inserted, the document returned by this method will have its <u>_id</u> set.
<p>This method will use <a href="#$options"><u>$options()</u></a> as a default set of options.
</article>
<article id="$set">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$set(path: string, value: any): any</span>
<p>This method sets a value on the current object according to the given path.</p>
<p>This is shorthand for:</p>
<pre><code class="js">return this.$model.parsePath(path).set(this, value, { create: true });</code></pre>
<p>This method is analogous to <a href="https://lodash.com">Lodash</a>'s <u>_.set()</u>.</p>
</article>
<article id="$slice">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<b class="async"></b>
<span class="sig">$slice(path, options): void</span>
<p>
<p>This reads in a slice of values into an embedded array. This can be useful if a document contains large arrays
and you want to read in the array values separately and/or page them down to the client.</p>
<p><u>options</u> are:</p>
<table class="def">
<thead>
<tr><th>Option<th>Type<th>Notes
<tbody>
<tr><td>{</td>
<tr><td> limit:<td>integer<td>How many elements to slice.
<tr><td> where:<td>any => boolean<td>A predicate function that can be used to filter the array. Is applied before skip/limit.
<tr><td> populate:<td><i>population object</i><td>A <a href="index#population">population</a> object.
<tr><td> skip:<td>integer<td>Where to start slicing the array.
<tr><td> sort:<td><i>MongoDB-style sort object</i><td>Specifies how to sort the array. Is applied before skip/limit.
<tr><td>}</td>
</table>
<p>The array values are stored in the local object's array at the given <u>skip</u> and <u>offset</u> positions
in the given <u>sort</u> order. For this reason, do not call <u>$slice()</u> multiple times with different
<u>sort</u> values.
</p>
<p>Example:</p>
<pre><code class="js">const myDoc = Tyr.byId(myKey, { fields: { hugeArray: 0 } });
myDoc.$slice('hugeArray', {
where: v => v.myActiveField,
population: { myLinkPropInHugeArray: $all, myOtherPropInHugeArray: 1 },
skip: 10,
limit: 10,
sort: { myField: -1, myOtherField: 1 }
});
</code></pre>
</article>
<article id="$snapshot">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$snapshot(updateHistory: boolean, options?: <a href="collection#options">Options</a>): <a href="#snapshot">snapshot</a></span>
<p>This <a href="/#historical">historical data</a> method compares the <a href="#$orig"><u>$orig</u></a> property and the current
state of the object and returns a <a href="#snapshot">snapshot</a> record.</p>
<p>If <u>updateHistory</u> is true, the <a href="#_history"><u>_history</u></a> property is expected to be present it will be updated in memory.
Otherwise you are expected to insert the <a href="#snapshot">snapshot</a> returned into the <u>_history</u> property yourself.</p>
<p>After the snapshot is taken, the object's current <u>$orig</u> property is updated to the current values of the object (so you can make
more changes and then do another <u>$snapshot()</u>.</p>
<p>Historical options like <a href="collection#options"><u>author</u></a> and <a href="collection#options"><u>comment</u></a> are supported.</p>
<p>This method does not update the database.</p>
<p>This method can be useful if you want to make a number of snapshots in memory and write them out at once (bulk updates for many documents,
single updates when importing history from another source, and so on).</p>
<p>This method is also available in the client-side API but the client-side API does not take any arguments.</p>
</article>
<article id="$toClient">
<b class="method"></b>
<b class="server"></b>
<span class="sig">$toClient(opts?: object): object</span>
<p>This creates a new POJO out of this document. Values are copied by reference (not deep-cloned!).</p>
<p>This method passes through to <a href="collection#toClient"><u><i>Collection</i>.toClient()</u></a>, so see that method for a description of
<u>opts</u> and a more detailed explanation of how this method works.</p>
</article>
<article id="$toRaw">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$toPlain(): object</span>
<p>This creates a new Plain 'ole JavaScript Object (POJO) out of this document. Values are copied by reference (not deep-cloned!).</p>
<p>Unlike <a href="#$toClient"><u>$toClient()</u></a>, client processing is not performed. This version is also available on the client.</p>
</article>
<article id="$tyr">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$tyr: <a href="tyr">Tyr</a></span>
<p>This is a reference to the tyranid namespace object <a href="tyr"><u>Tyr</u></a>.
<p>This property can be essential if you are writing isomorphic properties or methods inside tyranid since this
value will not be name-mangled. For example, if your code is being uglified (or some equivalent), then in a
production build the "Tyr" <i>inside the getter</i> will get name mangled:
<pre><code class="js"><i>...</i> = new Tyr.Collection({
<i>...</i>,
fields: {
<i>...</i>,
myPredicateProperty: {
is: 'boolean',
get() { return this.myStatus === Tyr.byName.myEnum.MY_VALUE._id; }
},
<i>...</i>
},
<i>...</i>
</code></pre>
<p>The following getter will be fine even under name-mangling:</p>
<pre><code class="js"><i>...</i> = new Tyr.Collection({
<i>...</i>,
fields: {
<i>...</i>,
myPredicateProperty: {
is: 'boolean',
get() { return this.myStatus === this.$tyr.byName.myEnum.MY_VALUE._id; }
},
<i>...</i>
},
<i>...</i>
</code></pre>
</article>
<article id="$uid">
<b class="property"></b>
<b class="server"></b>
<b class="client"></b>
<span class="sig">$uid: string</span>
<p>This returns the <a href="/#uids">UID</a> for this document.</p>
</article>
<article id="$update">
<b class="method"></b>
<b class="server"></b>
<b class="client"></b>
<b class="async"></b>
<span class="sig">$update(options?: <a href="collection#options">Options</a>): <a href="document"><u>Document</u></a></span>
<p>This updates the server document with the values in this object. Note that the document is <i>not</i> replaced. See
<a href="document#$save"><u>$save()</u></a> if you want to do a full replace.</p>
<p>This method is a short-cut for <a href="collection#updateDoc"><u><i>Collection</i>.updateDoc()</u></a>.</p>
<p>If the document is new (it does not have an <u>_id</u>) then an exception will be thrown unless the <u>upsert</u> option is set to <u>true</u>.</p>
<p>This method will use <a href="#$options"><u>$options()</u></a> as a default set of options.
</article>
<article id="$validate">
<b class="method"></b>
<b class="server"></b>
<span class="sig">$validate(): <a href="userError">UserError</a>[]</span>
<p>This validates the current document according to the validation rules specified by the metadata for this collection.</p>
</article>
</div>