@visiolab/effect-firebase 0.0.0-stage → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -2
  3. package/dist/_virtual/_rolldown/runtime.mjs +12 -0
  4. package/dist/app/App.d.mts +27 -0
  5. package/dist/app/App.mjs +27 -0
  6. package/dist/app/index.d.mts +2 -0
  7. package/dist/app/index.mjs +1 -0
  8. package/dist/firestore/Collection.d.mts +423 -0
  9. package/dist/firestore/Collection.mjs +133 -0
  10. package/dist/firestore/CollectionGroup.d.mts +164 -0
  11. package/dist/firestore/CollectionGroup.mjs +84 -0
  12. package/dist/firestore/DocumentPath.d.mts +95 -0
  13. package/dist/firestore/DocumentPath.mjs +71 -0
  14. package/dist/firestore/DocumentSnapshot.d.mts +239 -0
  15. package/dist/firestore/DocumentSnapshot.mjs +134 -0
  16. package/dist/firestore/FieldValue.d.mts +332 -0
  17. package/dist/firestore/FieldValue.mjs +256 -0
  18. package/dist/firestore/Firestore.d.mts +1165 -0
  19. package/dist/firestore/Firestore.mjs +274 -0
  20. package/dist/firestore/FirestoreModel.d.mts +1232 -0
  21. package/dist/firestore/FirestoreModel.mjs +586 -0
  22. package/dist/firestore/FirestoreSchema.d.mts +567 -0
  23. package/dist/firestore/FirestoreSchema.mjs +419 -0
  24. package/dist/firestore/FirestoreValue.d.mts +145 -0
  25. package/dist/firestore/FirestoreValue.mjs +87 -0
  26. package/dist/firestore/GeoPoint.d.mts +90 -0
  27. package/dist/firestore/GeoPoint.mjs +75 -0
  28. package/dist/firestore/Patch.d.mts +73 -0
  29. package/dist/firestore/Patch.mjs +57 -0
  30. package/dist/firestore/QuerySnapshot.d.mts +107 -0
  31. package/dist/firestore/QuerySnapshot.mjs +43 -0
  32. package/dist/firestore/Timestamp.d.mts +273 -0
  33. package/dist/firestore/Timestamp.mjs +255 -0
  34. package/dist/firestore/index.d.mts +14 -0
  35. package/dist/firestore/index.mjs +14 -0
  36. package/dist/firestore/internal/collection.mjs +156 -0
  37. package/dist/firestore/internal/collectionGroup.mjs +64 -0
  38. package/dist/firestore/internal/documentPath.d.mts +4 -0
  39. package/dist/firestore/internal/documentPath.mjs +42 -0
  40. package/dist/firestore/internal/documentSnapshot.mjs +63 -0
  41. package/dist/firestore/internal/fieldValue.d.mts +11 -0
  42. package/dist/firestore/internal/fieldValue.mjs +88 -0
  43. package/dist/firestore/internal/firestore.mjs +145 -0
  44. package/dist/firestore/internal/firestoreError.d.mts +29 -0
  45. package/dist/firestore/internal/firestoreError.mjs +30 -0
  46. package/dist/firestore/internal/firestoreModel.mjs +719 -0
  47. package/dist/firestore/internal/firestoreSchema.mjs +123 -0
  48. package/dist/firestore/internal/firestoreValue.mjs +108 -0
  49. package/dist/firestore/internal/firestoreValueWalk.d.mts +58 -0
  50. package/dist/firestore/internal/firestoreValueWalk.mjs +223 -0
  51. package/dist/firestore/internal/geoPoint.d.mts +4 -0
  52. package/dist/firestore/internal/geoPoint.mjs +39 -0
  53. package/dist/firestore/internal/patch.mjs +19 -0
  54. package/dist/firestore/internal/querySnapshot.mjs +24 -0
  55. package/dist/firestore/internal/schemaAST.mjs +35 -0
  56. package/dist/firestore/internal/snapshotExtra.mjs +35 -0
  57. package/dist/firestore/internal/streamFromListener.mjs +12 -0
  58. package/dist/firestore/internal/timestamp.d.mts +4 -0
  59. package/dist/firestore/internal/timestamp.mjs +66 -0
  60. package/dist/firestore/internal/timestampSchema.mjs +31 -0
  61. package/dist/firestore/internal/transactionFromCallback.mjs +66 -0
  62. package/dist/functions/Callable.d.mts +654 -0
  63. package/dist/functions/Callable.mjs +450 -0
  64. package/dist/functions/CallableError.d.mts +297 -0
  65. package/dist/functions/CallableError.mjs +256 -0
  66. package/dist/functions/CallableMiddleware.d.mts +213 -0
  67. package/dist/functions/CallableMiddleware.mjs +52 -0
  68. package/dist/functions/CallableRequest.d.mts +166 -0
  69. package/dist/functions/CallableRequest.mjs +18 -0
  70. package/dist/functions/Caller.d.mts +103 -0
  71. package/dist/functions/Caller.mjs +115 -0
  72. package/dist/functions/DocumentTrigger.d.mts +795 -0
  73. package/dist/functions/DocumentTrigger.mjs +566 -0
  74. package/dist/functions/FirebaseFunction.d.mts +79 -0
  75. package/dist/functions/FirebaseFunction.mjs +4 -0
  76. package/dist/functions/FunctionGroup.d.mts +175 -0
  77. package/dist/functions/FunctionGroup.mjs +64 -0
  78. package/dist/functions/index.d.mts +9 -0
  79. package/dist/functions/index.mjs +9 -0
  80. package/dist/functions/internal/callable.mjs +167 -0
  81. package/dist/functions/internal/callableMiddleware.d.mts +19 -0
  82. package/dist/functions/internal/callableMiddleware.mjs +15 -0
  83. package/dist/functions/internal/callableRequest.mjs +6 -0
  84. package/dist/functions/internal/documentTrigger.d.mts +10 -0
  85. package/dist/functions/internal/documentTrigger.mjs +73 -0
  86. package/dist/functions/internal/firebaseFunction.d.mts +5 -0
  87. package/dist/functions/internal/firebaseFunction.mjs +24 -0
  88. package/dist/functions/internal/functionGroup.mjs +36 -0
  89. package/package.json +72 -3
  90. package/src/app/App.ts +24 -0
  91. package/src/app/index.ts +7 -0
  92. package/src/firestore/Collection.ts +520 -0
  93. package/src/firestore/CollectionGroup.ts +245 -0
  94. package/src/firestore/DocumentPath.ts +114 -0
  95. package/src/firestore/DocumentSnapshot.ts +308 -0
  96. package/src/firestore/FieldValue.ts +375 -0
  97. package/src/firestore/Firestore.ts +1432 -0
  98. package/src/firestore/FirestoreModel.ts +1884 -0
  99. package/src/firestore/FirestoreSchema.ts +643 -0
  100. package/src/firestore/FirestoreValue.ts +207 -0
  101. package/src/firestore/GeoPoint.ts +105 -0
  102. package/src/firestore/Patch.ts +117 -0
  103. package/src/firestore/QuerySnapshot.ts +150 -0
  104. package/src/firestore/Timestamp.ts +302 -0
  105. package/src/firestore/index.ts +67 -0
  106. package/src/firestore/internal/collection.ts +246 -0
  107. package/src/firestore/internal/collectionGroup.ts +81 -0
  108. package/src/firestore/internal/documentPath.ts +53 -0
  109. package/src/firestore/internal/documentSnapshot.ts +117 -0
  110. package/src/firestore/internal/fieldValue.ts +119 -0
  111. package/src/firestore/internal/firestore.ts +322 -0
  112. package/src/firestore/internal/firestoreError.ts +36 -0
  113. package/src/firestore/internal/firestoreModel.ts +1242 -0
  114. package/src/firestore/internal/firestoreSchema.ts +218 -0
  115. package/src/firestore/internal/firestoreValue.ts +202 -0
  116. package/src/firestore/internal/firestoreValueWalk.ts +349 -0
  117. package/src/firestore/internal/geoPoint.ts +59 -0
  118. package/src/firestore/internal/patch.ts +21 -0
  119. package/src/firestore/internal/querySnapshot.ts +39 -0
  120. package/src/firestore/internal/schemaAST.ts +83 -0
  121. package/src/firestore/internal/snapshotExtra.ts +47 -0
  122. package/src/firestore/internal/streamFromListener.ts +27 -0
  123. package/src/firestore/internal/timestamp.ts +119 -0
  124. package/src/firestore/internal/timestampSchema.ts +42 -0
  125. package/src/firestore/internal/transactionFromCallback.ts +106 -0
  126. package/src/functions/Callable.ts +855 -0
  127. package/src/functions/CallableError.ts +348 -0
  128. package/src/functions/CallableMiddleware.ts +279 -0
  129. package/src/functions/CallableRequest.ts +207 -0
  130. package/src/functions/Caller.ts +141 -0
  131. package/src/functions/DocumentTrigger.ts +927 -0
  132. package/src/functions/FirebaseFunction.ts +96 -0
  133. package/src/functions/FunctionGroup.ts +225 -0
  134. package/src/functions/index.ts +62 -0
  135. package/src/functions/internal/callable.ts +272 -0
  136. package/src/functions/internal/callableMiddleware.ts +54 -0
  137. package/src/functions/internal/callableRequest.ts +8 -0
  138. package/src/functions/internal/documentTrigger.ts +143 -0
  139. package/src/functions/internal/firebaseFunction.ts +58 -0
  140. package/src/functions/internal/functionGroup.ts +47 -0
@@ -0,0 +1,643 @@
1
+ /**
2
+ * Schemas for the Firestore Values that Effect has no schema for.
3
+ *
4
+ * - Values: {@link Timestamp}, {@link GeoPoint}, {@link DocumentPath}, and
5
+ * typed references with {@link DocumentReference}.
6
+ * - Sentinels, for writes only: {@link ServerTimestamp}, {@link Increment},
7
+ * {@link DeleteField}, {@link ArrayUnion} and {@link ArrayRemove}.
8
+ * - A field's write side, combining a value with the sentinels it accepts:
9
+ * {@link ServerTimestampOr}, {@link IncrementOr}, {@link DeleteFieldOr} and
10
+ * {@link ArrayOr}.
11
+ *
12
+ * Each schema holds a portable value this library owns, so a document schema
13
+ * reads the same under the Admin SDK and the client SDK. Each SDK package turns
14
+ * those values into its own SDK's on the way out, and back on the way in.
15
+ *
16
+ * Most models use these through the {@link FirestoreModel} field helpers,
17
+ * which pair a field's read schema with the write schemas here.
18
+ *
19
+ * @stability unstable
20
+ * @since 0.2.0
21
+ */
22
+ import type { DateTime, Schema } from "effect";
23
+ import type * as Collection from "./Collection.ts";
24
+ import type * as DocumentPath_ from "./DocumentPath.ts";
25
+ import type * as FieldValue from "./FieldValue.ts";
26
+ import type * as GeoPoint_ from "./GeoPoint.ts";
27
+ import * as firestoreSchema from "./internal/firestoreSchema.ts";
28
+ import type * as Timestamp_ from "./Timestamp.ts";
29
+
30
+ /**
31
+ * Type-level representation of {@link Timestamp}.
32
+ *
33
+ * @stability unstable
34
+ * @category models
35
+ * @since 0.2.0
36
+ */
37
+ export interface Timestamp extends Schema.declare<Timestamp_.Timestamp> {
38
+ readonly Rebuild: Timestamp;
39
+ }
40
+
41
+ /**
42
+ * Schema for a Firestore timestamp, held as the portable
43
+ * {@link Timestamp.Timestamp}.
44
+ *
45
+ * **When to use**
46
+ *
47
+ * Use when a document is read, written back, and has to come out unchanged.
48
+ * Use `Schema.DateTimeUtc` or `Schema.Date` when a millisecond is precise
49
+ * enough and that value is easier to work with: Firestore stores both as a
50
+ * timestamp too, but they drop the digits finer than a millisecond.
51
+ *
52
+ * **Details**
53
+ *
54
+ * It serializes with `Schema.toCodecJson` as `{ seconds, nanoseconds }`, so the
55
+ * same model can be sent over HTTP.
56
+ *
57
+ * @example Storing a timestamp at full precision
58
+ * ```ts
59
+ * import { Schema } from "effect";
60
+ * import { FirestoreSchema } from "@visiolab/effect-firebase/firestore";
61
+ *
62
+ * const Event = Schema.Struct({ at: FirestoreSchema.Timestamp });
63
+ * ```
64
+ *
65
+ * @see {@link FirestoreModel.Timestamp} for a timestamp field the server may also fill in
66
+ * @see {@link ServerTimestampOr} for the write side of such a field
67
+ * @see {@link TimeSchema} for every schema Firestore stores as a timestamp
68
+ *
69
+ * @stability unstable
70
+ * @category schemas
71
+ * @since 0.2.0
72
+ */
73
+ export const Timestamp: Timestamp = firestoreSchema.Timestamp;
74
+
75
+ /**
76
+ * A schema Firestore stores as a timestamp: {@link Timestamp},
77
+ * `Schema.DateTimeUtc`, `Schema.Date`, or any schema transformed into one of
78
+ * them.
79
+ *
80
+ * **Details**
81
+ *
82
+ * The check is on the encoded type alone, so it accepts any schema whose
83
+ * encoded side is a {@link Timestamp.Timestamp}, a `DateTime.Utc` or a `Date`.
84
+ * A declaration of your own, such as `Schema.declare<Date>(...)`, type-checks
85
+ * but is not stored as a timestamp: {@link FirestoreValue.toCodecFirestore}
86
+ * only stores `Schema.Date` and `Schema.DateTimeUtc` as one, so it fails to
87
+ * encode, or is written through its own `toCodecJson`. The types cannot tell
88
+ * the two apart, since `Schema.Date` has the same type as any
89
+ * `Schema.declare<Date>`.
90
+ *
91
+ * @see {@link ServerTimestampOr} for a timestamp the server may fill in
92
+ * @see {@link FirestoreModel.Timestamp} for the matching model field
93
+ *
94
+ * @stability unstable
95
+ * @category models
96
+ * @since 0.2.0
97
+ */
98
+ export type TimeSchema = Schema.Codec<
99
+ unknown,
100
+ Timestamp_.Timestamp | DateTime.Utc | globalThis.Date,
101
+ unknown,
102
+ unknown
103
+ >;
104
+
105
+ /**
106
+ * Type-level representation of {@link GeoPoint}.
107
+ *
108
+ * @stability unstable
109
+ * @category models
110
+ * @since 0.2.0
111
+ */
112
+ export interface GeoPoint extends Schema.declare<GeoPoint_.GeoPoint> {
113
+ readonly Rebuild: GeoPoint;
114
+ }
115
+
116
+ /**
117
+ * Schema for a Firestore geopoint, held as the portable
118
+ * {@link GeoPoint.GeoPoint}.
119
+ *
120
+ * **When to use**
121
+ *
122
+ * Use for a location field. A hand-written struct of `latitude` and
123
+ * `longitude` would be stored as a map; this schema is stored as Firestore's
124
+ * own geopoint.
125
+ *
126
+ * @example Storing a location
127
+ * ```ts
128
+ * import { Schema } from "effect";
129
+ * import { FirestoreSchema } from "@visiolab/effect-firebase/firestore";
130
+ *
131
+ * const Place = Schema.Struct({ name: Schema.String, location: FirestoreSchema.GeoPoint });
132
+ * ```
133
+ *
134
+ * @see {@link GeoPoint.make} for building a geopoint
135
+ *
136
+ * @stability unstable
137
+ * @category schemas
138
+ * @since 0.2.0
139
+ */
140
+ export const GeoPoint: GeoPoint = firestoreSchema.GeoPoint;
141
+
142
+ /**
143
+ * Type-level representation of {@link DocumentPath}.
144
+ *
145
+ * @stability unstable
146
+ * @category models
147
+ * @since 0.2.0
148
+ */
149
+ export interface DocumentPath extends Schema.declare<DocumentPath_.DocumentPath> {
150
+ readonly Rebuild: DocumentPath;
151
+ }
152
+
153
+ /**
154
+ * Schema for an untyped reference to a document, held as the portable
155
+ * {@link DocumentPath.DocumentPath}.
156
+ *
157
+ * **When to use**
158
+ *
159
+ * Use for a reference whose target collection the model does not know. Use
160
+ * {@link DocumentReference} when the field always points into a known
161
+ * collection.
162
+ *
163
+ * **Details**
164
+ *
165
+ * It is stored as the SDK's own reference, built against the database the
166
+ * document is written to.
167
+ *
168
+ * @see {@link DocumentReference} for a reference typed by its collection
169
+ *
170
+ * @stability unstable
171
+ * @category schemas
172
+ * @since 0.2.0
173
+ */
174
+ export const DocumentPath: DocumentPath = firestoreSchema.DocumentPath;
175
+
176
+ /**
177
+ * Type-level representation of {@link DocumentReference}.
178
+ *
179
+ * @stability unstable
180
+ * @category models
181
+ * @since 0.2.0
182
+ */
183
+ export interface DocumentReference<C extends Collection.Any> extends Schema.declare<
184
+ Collection.DocumentReference<C>
185
+ > {
186
+ readonly Rebuild: DocumentReference<C>;
187
+ }
188
+
189
+ /**
190
+ * Schema for a reference to a document in `collection`, held as a typed
191
+ * {@link Collection.DocumentReference}.
192
+ *
193
+ * **When to use**
194
+ *
195
+ * Use for a field that points to a document in a known collection, so the
196
+ * reference keeps its ids and model typed. For a field that may point into
197
+ * several collections, use a `Schema.Union` of one of these per collection.
198
+ * Use {@link DocumentPath} when the target collection is unknown.
199
+ *
200
+ * **Details**
201
+ *
202
+ * Firestore stores a reference as the document's path alone, so it is written
203
+ * as a {@link DocumentPath.DocumentPath}. Reading it back checks the path
204
+ * against the collection's segments and rebuilds the collection's own
205
+ * reference, equal to one built from `collection`. A path into any other
206
+ * collection, even one with the same last segment, fails to decode.
207
+ * `Schema.is` only accepts references built from `collection`.
208
+ *
209
+ * @example Referencing the author of a post
210
+ * ```ts
211
+ * import { Schema } from "effect";
212
+ * import { Collection, FirestoreModel, FirestoreSchema } from "@visiolab/effect-firebase/firestore";
213
+ *
214
+ * class User extends FirestoreModel.Class<User>("User")({ name: Schema.String }) {}
215
+ * const Users = Collection.make("users", User);
216
+ *
217
+ * class Post extends FirestoreModel.Class<Post>("Post")({
218
+ * author: FirestoreSchema.DocumentReference(Users),
219
+ * }) {}
220
+ * ```
221
+ *
222
+ * @see {@link DocumentPath} for an untyped reference
223
+ *
224
+ * @stability unstable
225
+ * @category schemas
226
+ * @since 0.2.0
227
+ */
228
+ export const DocumentReference: <C extends Collection.Any>(collection: C) => DocumentReference<C> =
229
+ firestoreSchema.DocumentReference;
230
+
231
+ interface ServerTimestampSentinel extends Schema.declare<FieldValue.ServerTimestamp> {
232
+ readonly Rebuild: ServerTimestampSentinel;
233
+ }
234
+
235
+ /**
236
+ * Type-level representation of {@link ServerTimestamp}.
237
+ *
238
+ * @stability unstable
239
+ * @category models
240
+ * @since 0.2.0
241
+ */
242
+ export interface ServerTimestamp extends Schema.withConstructorDefault<ServerTimestampSentinel> {
243
+ readonly Rebuild: ServerTimestamp;
244
+ }
245
+
246
+ /**
247
+ * Schema that always writes the {@link FieldValue.serverTimestamp} sentinel,
248
+ * and fills it in when the value is constructed.
249
+ *
250
+ * **When to use**
251
+ *
252
+ * Use in a write-only schema for a field that is always the server's time,
253
+ * such as `updatedAt` on every update. Use {@link ServerTimestampOr} when the
254
+ * field may also be written with a time of your own.
255
+ *
256
+ * **Details**
257
+ *
258
+ * It accepts only the sentinel, and its constructor default fills it in, the
259
+ * way `Schema.tag` fills in a tag, so a call site never names the field. A
260
+ * document never holds the sentinel: the field reads back as the timestamp the
261
+ * server wrote, so the read side is a timestamp schema.
262
+ *
263
+ * @example Stamping every update with the server's time
264
+ * ```ts
265
+ * import { Schema } from "effect";
266
+ * import { FirestoreSchema } from "@visiolab/effect-firebase/firestore";
267
+ *
268
+ * const Touch = Schema.Struct({ updatedAt: FirestoreSchema.ServerTimestamp });
269
+ *
270
+ * const update = Touch.make({}); // { updatedAt: FieldValue.serverTimestamp }
271
+ * ```
272
+ *
273
+ * @see {@link ServerTimestampOr} for a field that may also take a time of your own
274
+ * @see {@link FirestoreModel.Timestamp} for the matching model field
275
+ *
276
+ * @stability unstable
277
+ * @category schemas
278
+ * @since 0.2.0
279
+ */
280
+ export const ServerTimestamp: ServerTimestamp = firestoreSchema.ServerTimestamp;
281
+
282
+ /**
283
+ * Type-level representation of {@link ServerTimestampOr}.
284
+ *
285
+ * @stability unstable
286
+ * @category models
287
+ * @since 0.2.0
288
+ */
289
+ export interface ServerTimestampOr<S extends TimeSchema> extends Schema.Union<
290
+ readonly [S, ServerTimestamp]
291
+ > {
292
+ readonly Rebuild: ServerTimestampOr<S>;
293
+ }
294
+
295
+ /**
296
+ * Schema for a timestamp field written either as a time of your own or as
297
+ * {@link FieldValue.serverTimestamp}.
298
+ *
299
+ * **When to use**
300
+ *
301
+ * Use as the write side of a timestamp field when building model variants by
302
+ * hand. Most models use {@link FirestoreModel.Timestamp}, which pairs this with
303
+ * the read side for you.
304
+ *
305
+ * **Details**
306
+ *
307
+ * `schema` is the read side: {@link Timestamp} to keep digits finer than a
308
+ * millisecond, or `Schema.DateTimeUtc` or `Schema.Date` (see
309
+ * {@link TimeSchema}). A read never sees the sentinel, so the read variant
310
+ * uses `schema` alone.
311
+ *
312
+ * @example A timestamp the server may fill in
313
+ * ```ts
314
+ * import { Schema } from "effect";
315
+ * import { FieldValue, FirestoreSchema } from "@visiolab/effect-firebase/firestore";
316
+ *
317
+ * const UpdatedAt = FirestoreSchema.ServerTimestampOr(Schema.DateTimeUtc);
318
+ *
319
+ * Schema.is(UpdatedAt)(FieldValue.serverTimestamp); // true
320
+ * ```
321
+ *
322
+ * @see {@link FirestoreModel.Timestamp} for the model field built on it
323
+ * @see {@link ServerTimestamp} for a field that always writes the sentinel
324
+ * @see {@link FieldValue.serverTimestamp} for the sentinel itself
325
+ *
326
+ * @stability unstable
327
+ * @category schemas
328
+ * @since 0.2.0
329
+ */
330
+ export const ServerTimestampOr: <S extends TimeSchema>(schema: S) => ServerTimestampOr<S> =
331
+ firestoreSchema.ServerTimestampOr;
332
+
333
+ /**
334
+ * Type-level representation of {@link Increment}.
335
+ *
336
+ * @stability unstable
337
+ * @category models
338
+ * @since 0.2.0
339
+ */
340
+ export interface Increment extends Schema.declare<FieldValue.Increment> {
341
+ readonly Rebuild: Increment;
342
+ }
343
+
344
+ /**
345
+ * Schema for the {@link FieldValue.Increment} sentinel, as built by
346
+ * {@link FieldValue.increment} and {@link FieldValue.decrement}.
347
+ *
348
+ * **When to use**
349
+ *
350
+ * Use in a write-only schema for a field that is only ever moved, never set.
351
+ * Use {@link IncrementOr} for a field that may be set outright too.
352
+ *
353
+ * **Details**
354
+ *
355
+ * A document holds the sum the server wrote, so the read side of the same
356
+ * field is a plain number.
357
+ *
358
+ * @see {@link IncrementOr} for a number that may also be set outright
359
+ * @see {@link FirestoreModel.Number} for the matching model field
360
+ *
361
+ * @stability unstable
362
+ * @category schemas
363
+ * @since 0.2.0
364
+ */
365
+ export const Increment: Increment = firestoreSchema.Increment;
366
+
367
+ /**
368
+ * Type-level representation of {@link IncrementOr}.
369
+ *
370
+ * @stability unstable
371
+ * @category models
372
+ * @since 0.2.0
373
+ */
374
+ export interface IncrementOr<
375
+ S extends Schema.Codec<unknown, number, unknown, unknown>,
376
+ > extends Schema.Union<readonly [S, Increment]> {
377
+ readonly Rebuild: IncrementOr<S>;
378
+ }
379
+
380
+ /**
381
+ * Schema for a number field written either as a number or as an
382
+ * {@link FieldValue.increment} or {@link FieldValue.decrement}.
383
+ *
384
+ * **When to use**
385
+ *
386
+ * Use as the write side of a counter when building model variants by hand.
387
+ * Most models use {@link FirestoreModel.Number}, which pairs this with the
388
+ * read side for you.
389
+ *
390
+ * **Details**
391
+ *
392
+ * `schema` is the read side and says what the number may be: `Schema.Finite`,
393
+ * `Schema.Int` for whole steps, or either with further checks. It must be
394
+ * stored as a number, since that is what the server adds to. A read never sees
395
+ * the sentinel, so the read variant uses `schema` alone.
396
+ *
397
+ * @example A counter the server may move
398
+ * ```ts
399
+ * import { Schema } from "effect";
400
+ * import { FieldValue, FirestoreSchema } from "@visiolab/effect-firebase/firestore";
401
+ *
402
+ * const Visits = FirestoreSchema.IncrementOr(Schema.Int);
403
+ *
404
+ * Schema.is(Visits)(FieldValue.increment(1)); // true
405
+ * ```
406
+ *
407
+ * @see {@link FirestoreModel.Number} for the model field built on it
408
+ * @see {@link Increment} for a field that is only ever moved
409
+ * @see {@link FieldValue.increment} for the sentinel itself
410
+ *
411
+ * @stability unstable
412
+ * @category schemas
413
+ * @since 0.2.0
414
+ */
415
+ export const IncrementOr: <S extends Schema.Codec<unknown, number, unknown, unknown>>(
416
+ schema: S,
417
+ ) => IncrementOr<S> = firestoreSchema.IncrementOr;
418
+
419
+ /**
420
+ * Type-level representation of {@link DeleteField}.
421
+ *
422
+ * @stability unstable
423
+ * @category models
424
+ * @since 0.2.0
425
+ */
426
+ export interface DeleteField extends Schema.declare<FieldValue.DeleteField> {
427
+ readonly Rebuild: DeleteField;
428
+ }
429
+
430
+ /**
431
+ * Schema for the {@link FieldValue.deleteField} sentinel.
432
+ *
433
+ * **When to use**
434
+ *
435
+ * Use when building an update schema by hand. Most models get it through
436
+ * {@link DeleteFieldOr}, or through {@link FirestoreModel.Optional}.
437
+ *
438
+ * **Details**
439
+ *
440
+ * Unlike {@link ServerTimestamp}, it has no constructor default: a field is
441
+ * only removed when you ask for it. A removed field is not there to read, so
442
+ * the read side of the same field is an optional key.
443
+ *
444
+ * @see {@link DeleteFieldOr} for a field an update may write or remove
445
+ * @see {@link FirestoreModel.Optional} for the matching model field
446
+ *
447
+ * @stability unstable
448
+ * @category schemas
449
+ * @since 0.2.0
450
+ */
451
+ export const DeleteField: DeleteField = firestoreSchema.DeleteField;
452
+
453
+ /**
454
+ * Type-level representation of {@link DeleteFieldOr}.
455
+ *
456
+ * @stability unstable
457
+ * @category models
458
+ * @since 0.2.0
459
+ */
460
+ export interface DeleteFieldOr<S extends Schema.Top> extends Schema.Union<
461
+ readonly [DeleteField, S]
462
+ > {
463
+ readonly Rebuild: DeleteFieldOr<S>;
464
+ }
465
+
466
+ /**
467
+ * Schema for a field an update either writes or removes with
468
+ * {@link FieldValue.deleteField}.
469
+ *
470
+ * **When to use**
471
+ *
472
+ * Use as the update side of an optional field when building model variants by
473
+ * hand. Most models use {@link FirestoreModel.Optional}, which does this for
474
+ * you.
475
+ *
476
+ * **Details**
477
+ *
478
+ * `schema` is what the field holds while it is there. Only an update accepts
479
+ * it: a read never holds the sentinel, and Firestore refuses it in a document
480
+ * written whole.
481
+ *
482
+ * The sentinel is tried first, since a schema that accepts any object, such
483
+ * as a struct whose keys are all optional, would accept it too and strip it to
484
+ * `{}`.
485
+ *
486
+ * @example An optional field an update may remove
487
+ * ```ts
488
+ * import { Schema } from "effect";
489
+ * import { FieldValue, FirestoreSchema } from "@visiolab/effect-firebase/firestore";
490
+ *
491
+ * const Nickname = FirestoreSchema.DeleteFieldOr(Schema.String);
492
+ *
493
+ * Schema.is(Nickname)(FieldValue.deleteField); // true
494
+ * ```
495
+ *
496
+ * @see {@link FirestoreModel.Optional} for the model field built on it
497
+ * @see {@link FieldValue.deleteField} for the sentinel itself
498
+ *
499
+ * @stability unstable
500
+ * @category schemas
501
+ * @since 0.2.0
502
+ */
503
+ export const DeleteFieldOr: <S extends Schema.Top>(schema: S) => DeleteFieldOr<S> =
504
+ firestoreSchema.DeleteFieldOr;
505
+
506
+ /**
507
+ * Type-level representation of {@link ArrayUnion}.
508
+ *
509
+ * @stability unstable
510
+ * @category models
511
+ * @since 0.2.0
512
+ */
513
+ export interface ArrayUnion<S extends Schema.Top> extends Schema.declareConstructor<
514
+ FieldValue.ArrayUnion<S["Type"]>,
515
+ FieldValue.ArrayUnion<S["Encoded"]>,
516
+ readonly [S]
517
+ > {
518
+ readonly Rebuild: ArrayUnion<S>;
519
+ }
520
+
521
+ /**
522
+ * Schema for the {@link FieldValue.arrayUnion} sentinel, with each element
523
+ * encoded through `item`.
524
+ *
525
+ * **When to use**
526
+ *
527
+ * Use when building an update schema by hand. Most models get it through
528
+ * {@link ArrayOr}, or through {@link FirestoreModel.Array}.
529
+ *
530
+ * **Details**
531
+ *
532
+ * Each element is encoded through `item`, then stored the way
533
+ * {@link FirestoreValue.toCodecFirestore} stores `item`, so a `DateTimeUtc`
534
+ * among them is stored as a timestamp, and an element `item` rejects is
535
+ * rejected here too.
536
+ *
537
+ * Firestore requires two things of `item`: it is not an array itself, since
538
+ * arrays may not nest, and it does not write a sentinel, since one may not sit
539
+ * inside an array.
540
+ *
541
+ * A document holds the array the server wrote, so the read side of the same
542
+ * field is the array.
543
+ *
544
+ * @see {@link ArrayRemove} for removing elements
545
+ * @see {@link ArrayOr} for an array field written whole, grown or shrunk
546
+ *
547
+ * @stability unstable
548
+ * @category schemas
549
+ * @since 0.2.0
550
+ */
551
+ export const ArrayUnion: <S extends Schema.Top>(item: S) => ArrayUnion<S> =
552
+ firestoreSchema.ArrayUnion;
553
+
554
+ /**
555
+ * Type-level representation of {@link ArrayRemove}.
556
+ *
557
+ * @stability unstable
558
+ * @category models
559
+ * @since 0.2.0
560
+ */
561
+ export interface ArrayRemove<S extends Schema.Top> extends Schema.declareConstructor<
562
+ FieldValue.ArrayRemove<S["Type"]>,
563
+ FieldValue.ArrayRemove<S["Encoded"]>,
564
+ readonly [S]
565
+ > {
566
+ readonly Rebuild: ArrayRemove<S>;
567
+ }
568
+
569
+ /**
570
+ * Schema for the {@link FieldValue.arrayRemove} sentinel, with each element
571
+ * encoded through `item`.
572
+ *
573
+ * **When to use**
574
+ *
575
+ * Use when building an update schema by hand. Most models get it through
576
+ * {@link ArrayOr}, or through {@link FirestoreModel.Array}.
577
+ *
578
+ * **Details**
579
+ *
580
+ * Each element is encoded through `item`, as for {@link ArrayUnion}. Encode
581
+ * through the same schema the array was written with: the server only removes
582
+ * elements that match exactly.
583
+ *
584
+ * @see {@link ArrayUnion} for adding elements
585
+ * @see {@link ArrayOr} for an array field written whole, grown or shrunk
586
+ *
587
+ * @stability unstable
588
+ * @category schemas
589
+ * @since 0.2.0
590
+ */
591
+ export const ArrayRemove: <S extends Schema.Top>(item: S) => ArrayRemove<S> =
592
+ firestoreSchema.ArrayRemove;
593
+
594
+ /**
595
+ * Type-level representation of {@link ArrayOr}.
596
+ *
597
+ * @stability unstable
598
+ * @category models
599
+ * @since 0.2.0
600
+ */
601
+ export interface ArrayOr<S extends Schema.Top> extends Schema.Union<
602
+ readonly [Schema.$Array<S>, ArrayUnion<S>, ArrayRemove<S>]
603
+ > {
604
+ readonly Rebuild: ArrayOr<S>;
605
+ }
606
+
607
+ /**
608
+ * Schema for an array field written whole, or grown or shrunk by the server
609
+ * with {@link FieldValue.arrayUnion} and {@link FieldValue.arrayRemove}.
610
+ *
611
+ * **When to use**
612
+ *
613
+ * Use as the update side of an array of `item` when building model variants by
614
+ * hand, against a read of `Schema.Array(item)`. Most models use
615
+ * {@link FirestoreModel.Array}, which pairs the two for you.
616
+ *
617
+ * **Details**
618
+ *
619
+ * Writing the array whole replaces what the server holds, so a client that
620
+ * read it, added an element and wrote it back loses whatever another client
621
+ * added in between. Growing or shrinking it does not. A read never sees the
622
+ * sentinels, so the read variant is the array alone.
623
+ *
624
+ * @example An array the server may grow or shrink
625
+ * ```ts
626
+ * import { Schema } from "effect";
627
+ * import { FieldValue, FirestoreSchema } from "@visiolab/effect-firebase/firestore";
628
+ *
629
+ * const Tags = FirestoreSchema.ArrayOr(Schema.String);
630
+ *
631
+ * Schema.is(Tags)(["news"]); // true
632
+ * Schema.is(Tags)(FieldValue.arrayUnion("news")); // true
633
+ * ```
634
+ *
635
+ * @see {@link FirestoreModel.Array} for the model field built on it
636
+ * @see {@link ArrayUnion} for the growing sentinel's schema
637
+ * @see {@link ArrayRemove} for the shrinking sentinel's schema
638
+ *
639
+ * @stability unstable
640
+ * @category schemas
641
+ * @since 0.2.0
642
+ */
643
+ export const ArrayOr: <S extends Schema.Top>(item: S) => ArrayOr<S> = firestoreSchema.ArrayOr;