@visiolab/effect-firebase 0.0.0-stage → 0.3.0
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.
- package/LICENSE +21 -0
- package/README.md +81 -2
- package/dist/_virtual/_rolldown/runtime.mjs +12 -0
- package/dist/app/App.d.mts +27 -0
- package/dist/app/App.mjs +27 -0
- package/dist/app/index.d.mts +2 -0
- package/dist/app/index.mjs +1 -0
- package/dist/firestore/Collection.d.mts +423 -0
- package/dist/firestore/Collection.mjs +133 -0
- package/dist/firestore/CollectionGroup.d.mts +164 -0
- package/dist/firestore/CollectionGroup.mjs +84 -0
- package/dist/firestore/DocumentPath.d.mts +95 -0
- package/dist/firestore/DocumentPath.mjs +71 -0
- package/dist/firestore/DocumentSnapshot.d.mts +239 -0
- package/dist/firestore/DocumentSnapshot.mjs +134 -0
- package/dist/firestore/FieldValue.d.mts +332 -0
- package/dist/firestore/FieldValue.mjs +256 -0
- package/dist/firestore/Firestore.d.mts +1165 -0
- package/dist/firestore/Firestore.mjs +274 -0
- package/dist/firestore/FirestoreModel.d.mts +1232 -0
- package/dist/firestore/FirestoreModel.mjs +586 -0
- package/dist/firestore/FirestoreSchema.d.mts +567 -0
- package/dist/firestore/FirestoreSchema.mjs +419 -0
- package/dist/firestore/FirestoreValue.d.mts +145 -0
- package/dist/firestore/FirestoreValue.mjs +87 -0
- package/dist/firestore/GeoPoint.d.mts +90 -0
- package/dist/firestore/GeoPoint.mjs +75 -0
- package/dist/firestore/Patch.d.mts +73 -0
- package/dist/firestore/Patch.mjs +57 -0
- package/dist/firestore/QuerySnapshot.d.mts +107 -0
- package/dist/firestore/QuerySnapshot.mjs +43 -0
- package/dist/firestore/Timestamp.d.mts +273 -0
- package/dist/firestore/Timestamp.mjs +255 -0
- package/dist/firestore/index.d.mts +14 -0
- package/dist/firestore/index.mjs +14 -0
- package/dist/firestore/internal/collection.mjs +156 -0
- package/dist/firestore/internal/collectionGroup.mjs +64 -0
- package/dist/firestore/internal/documentPath.d.mts +4 -0
- package/dist/firestore/internal/documentPath.mjs +42 -0
- package/dist/firestore/internal/documentSnapshot.mjs +63 -0
- package/dist/firestore/internal/fieldValue.d.mts +11 -0
- package/dist/firestore/internal/fieldValue.mjs +88 -0
- package/dist/firestore/internal/firestore.mjs +145 -0
- package/dist/firestore/internal/firestoreError.d.mts +29 -0
- package/dist/firestore/internal/firestoreError.mjs +30 -0
- package/dist/firestore/internal/firestoreModel.mjs +719 -0
- package/dist/firestore/internal/firestoreSchema.mjs +123 -0
- package/dist/firestore/internal/firestoreValue.mjs +108 -0
- package/dist/firestore/internal/firestoreValueWalk.d.mts +58 -0
- package/dist/firestore/internal/firestoreValueWalk.mjs +223 -0
- package/dist/firestore/internal/geoPoint.d.mts +4 -0
- package/dist/firestore/internal/geoPoint.mjs +39 -0
- package/dist/firestore/internal/patch.mjs +19 -0
- package/dist/firestore/internal/querySnapshot.mjs +24 -0
- package/dist/firestore/internal/schemaAST.mjs +35 -0
- package/dist/firestore/internal/snapshotExtra.mjs +35 -0
- package/dist/firestore/internal/streamFromListener.mjs +12 -0
- package/dist/firestore/internal/timestamp.d.mts +4 -0
- package/dist/firestore/internal/timestamp.mjs +66 -0
- package/dist/firestore/internal/timestampSchema.mjs +31 -0
- package/dist/firestore/internal/transactionFromCallback.mjs +66 -0
- package/dist/functions/Callable.d.mts +654 -0
- package/dist/functions/Callable.mjs +450 -0
- package/dist/functions/CallableError.d.mts +297 -0
- package/dist/functions/CallableError.mjs +256 -0
- package/dist/functions/CallableMiddleware.d.mts +213 -0
- package/dist/functions/CallableMiddleware.mjs +52 -0
- package/dist/functions/CallableRequest.d.mts +166 -0
- package/dist/functions/CallableRequest.mjs +18 -0
- package/dist/functions/Caller.d.mts +103 -0
- package/dist/functions/Caller.mjs +115 -0
- package/dist/functions/DocumentTrigger.d.mts +795 -0
- package/dist/functions/DocumentTrigger.mjs +566 -0
- package/dist/functions/FirebaseFunction.d.mts +79 -0
- package/dist/functions/FirebaseFunction.mjs +4 -0
- package/dist/functions/FunctionGroup.d.mts +175 -0
- package/dist/functions/FunctionGroup.mjs +64 -0
- package/dist/functions/index.d.mts +9 -0
- package/dist/functions/index.mjs +9 -0
- package/dist/functions/internal/callable.mjs +167 -0
- package/dist/functions/internal/callableMiddleware.d.mts +19 -0
- package/dist/functions/internal/callableMiddleware.mjs +15 -0
- package/dist/functions/internal/callableRequest.mjs +6 -0
- package/dist/functions/internal/documentTrigger.d.mts +10 -0
- package/dist/functions/internal/documentTrigger.mjs +73 -0
- package/dist/functions/internal/firebaseFunction.d.mts +5 -0
- package/dist/functions/internal/firebaseFunction.mjs +24 -0
- package/dist/functions/internal/functionGroup.mjs +36 -0
- package/package.json +66 -3
- package/src/app/App.ts +24 -0
- package/src/app/index.ts +7 -0
- package/src/firestore/Collection.ts +520 -0
- package/src/firestore/CollectionGroup.ts +245 -0
- package/src/firestore/DocumentPath.ts +114 -0
- package/src/firestore/DocumentSnapshot.ts +308 -0
- package/src/firestore/FieldValue.ts +375 -0
- package/src/firestore/Firestore.ts +1432 -0
- package/src/firestore/FirestoreModel.ts +1884 -0
- package/src/firestore/FirestoreSchema.ts +643 -0
- package/src/firestore/FirestoreValue.ts +207 -0
- package/src/firestore/GeoPoint.ts +105 -0
- package/src/firestore/Patch.ts +117 -0
- package/src/firestore/QuerySnapshot.ts +150 -0
- package/src/firestore/Timestamp.ts +302 -0
- package/src/firestore/index.ts +67 -0
- package/src/firestore/internal/collection.ts +246 -0
- package/src/firestore/internal/collectionGroup.ts +81 -0
- package/src/firestore/internal/documentPath.ts +53 -0
- package/src/firestore/internal/documentSnapshot.ts +117 -0
- package/src/firestore/internal/fieldValue.ts +119 -0
- package/src/firestore/internal/firestore.ts +322 -0
- package/src/firestore/internal/firestoreError.ts +36 -0
- package/src/firestore/internal/firestoreModel.ts +1242 -0
- package/src/firestore/internal/firestoreSchema.ts +218 -0
- package/src/firestore/internal/firestoreValue.ts +202 -0
- package/src/firestore/internal/firestoreValueWalk.ts +349 -0
- package/src/firestore/internal/geoPoint.ts +59 -0
- package/src/firestore/internal/patch.ts +21 -0
- package/src/firestore/internal/querySnapshot.ts +39 -0
- package/src/firestore/internal/schemaAST.ts +83 -0
- package/src/firestore/internal/snapshotExtra.ts +47 -0
- package/src/firestore/internal/streamFromListener.ts +27 -0
- package/src/firestore/internal/timestamp.ts +119 -0
- package/src/firestore/internal/timestampSchema.ts +42 -0
- package/src/firestore/internal/transactionFromCallback.ts +106 -0
- package/src/functions/Callable.ts +855 -0
- package/src/functions/CallableError.ts +348 -0
- package/src/functions/CallableMiddleware.ts +279 -0
- package/src/functions/CallableRequest.ts +207 -0
- package/src/functions/Caller.ts +141 -0
- package/src/functions/DocumentTrigger.ts +927 -0
- package/src/functions/FirebaseFunction.ts +96 -0
- package/src/functions/FunctionGroup.ts +225 -0
- package/src/functions/index.ts +62 -0
- package/src/functions/internal/callable.ts +272 -0
- package/src/functions/internal/callableMiddleware.ts +54 -0
- package/src/functions/internal/callableRequest.ts +8 -0
- package/src/functions/internal/documentTrigger.ts +143 -0
- package/src/functions/internal/firebaseFunction.ts +58 -0
- package/src/functions/internal/functionGroup.ts +47 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { isDocumentPath, makeUnchecked } from "./documentPath.mjs";
|
|
2
|
+
import { arrayRemove, arrayUnion, isArrayRemove, isArrayUnion, isDeleteField, isIncrement, isServerTimestamp, serverTimestamp } from "./fieldValue.mjs";
|
|
3
|
+
import { isGeoPoint } from "./geoPoint.mjs";
|
|
4
|
+
import { Timestamp as Timestamp$1 } from "./timestampSchema.mjs";
|
|
5
|
+
import { toCodecFirestore } from "./firestoreValue.mjs";
|
|
6
|
+
import { fromPath, isDocumentReference, pattern } from "./collection.mjs";
|
|
7
|
+
import { Array, Effect, Equal, Schema, SchemaGetter, SchemaIssue, SchemaParser, SchemaTransformation } from "effect";
|
|
8
|
+
// src/firestore/internal/firestoreSchema.ts
|
|
9
|
+
/** @internal */
|
|
10
|
+
const Timestamp = Timestamp$1;
|
|
11
|
+
/** @internal */
|
|
12
|
+
const GeoPoint = Schema.declare(isGeoPoint, {
|
|
13
|
+
representation: {
|
|
14
|
+
id: "@visiolab/effect-firebase/firestore/GeoPoint",
|
|
15
|
+
payload: null
|
|
16
|
+
},
|
|
17
|
+
expected: "a Firestore GeoPoint",
|
|
18
|
+
toEquivalence: () => Equal.equals,
|
|
19
|
+
toCodecFirestore: () => void 0
|
|
20
|
+
});
|
|
21
|
+
/** @internal */
|
|
22
|
+
const DocumentPath = Schema.declare(isDocumentPath, {
|
|
23
|
+
representation: {
|
|
24
|
+
id: "@visiolab/effect-firebase/firestore/DocumentPath",
|
|
25
|
+
payload: null
|
|
26
|
+
},
|
|
27
|
+
expected: "a Firestore document path",
|
|
28
|
+
toEquivalence: () => Equal.equals,
|
|
29
|
+
toCodecFirestore: () => void 0
|
|
30
|
+
});
|
|
31
|
+
/** @internal */
|
|
32
|
+
const DocumentReference = (collection) => {
|
|
33
|
+
const pattern$1 = pattern(collection);
|
|
34
|
+
return Schema.declare((u) => isDocumentReference(u) && u.collection === collection, {
|
|
35
|
+
representation: {
|
|
36
|
+
id: "@visiolab/effect-firebase/firestore/DocumentReference",
|
|
37
|
+
payload: null
|
|
38
|
+
},
|
|
39
|
+
expected: `a reference to a document in ${pattern$1}`,
|
|
40
|
+
toEquivalence: () => Equal.equals,
|
|
41
|
+
toCodecFirestore: () => Schema.link()(DocumentPath.annotate({ expected: `a reference to a document in ${pattern$1}` }), {
|
|
42
|
+
decode: SchemaGetter.transformEffect((value, options) => Effect.fromOption(fromPath(collection, value.path)).pipe(Effect.mapError(() => new SchemaIssue.InvalidValue({ message: `Expected a document in ${pattern$1}, got "${value.path}"` }, value, options)))),
|
|
43
|
+
encode: SchemaGetter.transform((ref) => makeUnchecked(ref.path))
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
/** @internal */
|
|
48
|
+
const ServerTimestamp = Schema.declare(isServerTimestamp, {
|
|
49
|
+
representation: {
|
|
50
|
+
id: "@visiolab/effect-firebase/firestore/FieldValue/ServerTimestamp",
|
|
51
|
+
payload: null
|
|
52
|
+
},
|
|
53
|
+
expected: "a server timestamp",
|
|
54
|
+
toCodecFirestore: () => void 0
|
|
55
|
+
}).pipe(Schema.withConstructorDefault(Effect.succeed(serverTimestamp)));
|
|
56
|
+
/** @internal */
|
|
57
|
+
const ServerTimestampOr = (schema) => Schema.Union([schema, ServerTimestamp]);
|
|
58
|
+
/** @internal */
|
|
59
|
+
const Increment = Schema.declare(isIncrement, {
|
|
60
|
+
representation: {
|
|
61
|
+
id: "@visiolab/effect-firebase/firestore/FieldValue/Increment",
|
|
62
|
+
payload: null
|
|
63
|
+
},
|
|
64
|
+
expected: "an increment",
|
|
65
|
+
toEquivalence: () => Equal.equals,
|
|
66
|
+
toCodecFirestore: () => void 0
|
|
67
|
+
});
|
|
68
|
+
/** @internal */
|
|
69
|
+
const IncrementOr = (schema) => Schema.Union([schema, Increment]);
|
|
70
|
+
/** @internal */
|
|
71
|
+
const DeleteField = Schema.declare(isDeleteField, {
|
|
72
|
+
representation: {
|
|
73
|
+
id: "@visiolab/effect-firebase/firestore/FieldValue/DeleteField",
|
|
74
|
+
payload: null
|
|
75
|
+
},
|
|
76
|
+
expected: "a field deletion",
|
|
77
|
+
toCodecFirestore: () => void 0
|
|
78
|
+
});
|
|
79
|
+
/** @internal */
|
|
80
|
+
const DeleteFieldOr = (schema) => Schema.Union([DeleteField, schema]);
|
|
81
|
+
/**
|
|
82
|
+
* Declares a sentinel that carries elements, each of them run through `item` -
|
|
83
|
+
* decoded on the way in and encoded on the way out, as `Schema.Option` does
|
|
84
|
+
* with what it holds.
|
|
85
|
+
*
|
|
86
|
+
* Its Firestore form is the same sentinel, holding the elements in their own
|
|
87
|
+
* Firestore form: `toCodecFirestore` links it to a sentinel of `item`'s derived
|
|
88
|
+
* codec, so a `DateTimeUtc` among them is stored as a timestamp.
|
|
89
|
+
*/
|
|
90
|
+
const elementsSentinel = (name, is, make) => {
|
|
91
|
+
const declareSentinel = (item, toCodecFirestore) => Schema.declareConstructor()([item], ([item]) => {
|
|
92
|
+
const elements = Schema.Array(item);
|
|
93
|
+
return (input, ast, options) => is(input) ? SchemaParser.decodeEffect(elements)(input.elements, options).pipe(Effect.mapBothEager({
|
|
94
|
+
onSuccess: (decoded) => make(...decoded),
|
|
95
|
+
onFailure: (issue) => new SchemaIssue.Pointer(["elements"], issue)
|
|
96
|
+
})) : Effect.fail(new SchemaIssue.InvalidType(ast, input, options));
|
|
97
|
+
}, {
|
|
98
|
+
representation: {
|
|
99
|
+
id: `@visiolab/effect-firebase/firestore/FieldValue/${name}`,
|
|
100
|
+
payload: null
|
|
101
|
+
},
|
|
102
|
+
expected: `an ${name}`,
|
|
103
|
+
toCodecFirestore,
|
|
104
|
+
toEquivalence: ([item]) => {
|
|
105
|
+
const elements = Array.makeEquivalence(item);
|
|
106
|
+
return (self, that) => elements(self.elements, that.elements);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
return (item) => declareSentinel(item, ([encoded]) => Schema.link()(declareSentinel(toCodecFirestore(encoded), () => void 0), SchemaTransformation.passthrough()));
|
|
110
|
+
};
|
|
111
|
+
const ArrayUnionSentinel = elementsSentinel("ArrayUnion", isArrayUnion, arrayUnion);
|
|
112
|
+
/** @internal */
|
|
113
|
+
const ArrayUnion = (item) => ArrayUnionSentinel(item);
|
|
114
|
+
const ArrayRemoveSentinel = elementsSentinel("ArrayRemove", isArrayRemove, arrayRemove);
|
|
115
|
+
/** @internal */
|
|
116
|
+
const ArrayRemove = (item) => ArrayRemoveSentinel(item);
|
|
117
|
+
/** @internal */
|
|
118
|
+
const ArrayOr = (item) => Schema.Union([
|
|
119
|
+
Schema.Array(item),
|
|
120
|
+
ArrayUnion(item),
|
|
121
|
+
ArrayRemove(item)
|
|
122
|
+
]);
|
|
123
|
+
export { ArrayOr, ArrayRemove, ArrayUnion, DeleteField, DeleteFieldOr, DocumentPath, DocumentReference, GeoPoint, Increment, IncrementOr, ServerTimestamp, ServerTimestampOr, Timestamp };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { fromMillis, toDateTime, toMillis } from "./timestamp.mjs";
|
|
2
|
+
import { isFirestoreValue as isFirestoreValue$1 } from "./firestoreValueWalk.mjs";
|
|
3
|
+
import { applyToSelfOrLastLinkEncodingIdempotent, keywordToCodecJson, keywordToCodecStringTree, mapLink, parameterFromString, recur, replaceContextLastLink, replaceEncoding } from "./schemaAST.mjs";
|
|
4
|
+
import { Timestamp } from "./timestampSchema.mjs";
|
|
5
|
+
import { DateTime, Effect, Predicate, Schema, SchemaAST, SchemaGetter, SchemaIssue, SchemaTransformation } from "effect";
|
|
6
|
+
// src/firestore/internal/firestoreValue.ts
|
|
7
|
+
/** @internal */
|
|
8
|
+
const isFirestoreValue = isFirestoreValue$1;
|
|
9
|
+
/**
|
|
10
|
+
* Accepts only Firestore Values. A declaration with no link to any canonical
|
|
11
|
+
* format falls back to this, so a value Firestore cannot store fails at its own
|
|
12
|
+
* path instead of being stored as a map.
|
|
13
|
+
*/
|
|
14
|
+
const FirestoreValueSchema = Schema.declare(isFirestoreValue, {
|
|
15
|
+
expected: "a Firestore value",
|
|
16
|
+
toCodecFirestore: () => void 0
|
|
17
|
+
});
|
|
18
|
+
/** @internal */
|
|
19
|
+
const unknownToFirestore = new SchemaAST.Link(FirestoreValueSchema.ast, SchemaTransformation.passthrough());
|
|
20
|
+
const timestampFromMillis = (millis, options) => {
|
|
21
|
+
const out = fromMillis(millis);
|
|
22
|
+
return out._tag === "Some" ? Effect.succeed(out.value) : Effect.fail(new SchemaIssue.InvalidValue({ message: "Expected an instant Firestore can store, between the years 1 and 9999" }, millis, options));
|
|
23
|
+
};
|
|
24
|
+
const dateToTimestamp = Schema.link()(Timestamp, {
|
|
25
|
+
decode: SchemaGetter.transform((ts) => new Date(toMillis(ts))),
|
|
26
|
+
encode: SchemaGetter.transformEffect((date, options) => timestampFromMillis(date.getTime(), options))
|
|
27
|
+
});
|
|
28
|
+
const dateTimeUtcToTimestamp = Schema.link()(Timestamp, {
|
|
29
|
+
decode: SchemaGetter.transform(toDateTime),
|
|
30
|
+
encode: SchemaGetter.transformEffect((dateTime, options) => timestampFromMillis(DateTime.toEpochMillis(dateTime), options))
|
|
31
|
+
});
|
|
32
|
+
const representationId = (ast) => {
|
|
33
|
+
const representation = ast.annotations?.representation;
|
|
34
|
+
return Predicate.hasProperty(representation, "id") ? representation.id : void 0;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Firestore's own types come first, so these win over the declaration's
|
|
38
|
+
* `toCodecJson`, which would write a string.
|
|
39
|
+
*/
|
|
40
|
+
const nativeLink = (ast) => {
|
|
41
|
+
switch (representationId(ast)) {
|
|
42
|
+
case "effect/schema/Date": return dateToTimestamp;
|
|
43
|
+
case "effect/schema/DateTimeUtc": return dateTimeUtcToTimestamp;
|
|
44
|
+
case "effect/schema/Uint8Array": return null;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const declarationStep = (ast, recur) => {
|
|
48
|
+
const native = nativeLink(ast);
|
|
49
|
+
if (native === null) return ast;
|
|
50
|
+
if (native !== void 0) return replaceEncoding(ast, [native]);
|
|
51
|
+
const annotations = ast.annotations;
|
|
52
|
+
const getLink = [
|
|
53
|
+
annotations?.toCodecFirestore,
|
|
54
|
+
annotations?.toCodecJson,
|
|
55
|
+
annotations?.toCodec
|
|
56
|
+
].find(Predicate.isFunction);
|
|
57
|
+
if (getLink === void 0) return replaceEncoding(ast, [unknownToFirestore]);
|
|
58
|
+
const link = getLink(ast.typeParameters.map((tp) => Schema.make(SchemaAST.toEncoded(tp))));
|
|
59
|
+
return link === void 0 ? ast : replaceEncoding(ast, [mapLink(link, recur)]);
|
|
60
|
+
};
|
|
61
|
+
const reorderUnion = (types) => {
|
|
62
|
+
const priority = (ast) => {
|
|
63
|
+
switch (SchemaAST.toEncoded(ast)._tag) {
|
|
64
|
+
case "BigInt":
|
|
65
|
+
case "Symbol":
|
|
66
|
+
case "UniqueSymbol": return 0;
|
|
67
|
+
default: return 1;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const sorted = [...types].sort((a, b) => priority(a) - priority(b));
|
|
71
|
+
return sorted.some((ast, i) => ast !== types[i]) ? sorted : types;
|
|
72
|
+
};
|
|
73
|
+
const step = (ast, recur$1) => {
|
|
74
|
+
switch (ast._tag) {
|
|
75
|
+
case "Declaration": return declarationStep(ast, recur$1);
|
|
76
|
+
case "Any":
|
|
77
|
+
case "Unknown":
|
|
78
|
+
case "ObjectKeyword": return replaceEncoding(ast, [unknownToFirestore]);
|
|
79
|
+
case "Undefined":
|
|
80
|
+
case "Void":
|
|
81
|
+
case "Literal": return keywordToCodecJson(ast);
|
|
82
|
+
case "UniqueSymbol":
|
|
83
|
+
case "Symbol":
|
|
84
|
+
case "BigInt": return keywordToCodecStringTree(ast);
|
|
85
|
+
case "Objects":
|
|
86
|
+
if (ast.propertySignatures.some((ps) => typeof ps.name !== "string")) return replaceEncoding(ast, [unknownToFirestore]);
|
|
87
|
+
return recur(ast, recur$1, parameterFromString);
|
|
88
|
+
case "Union": {
|
|
89
|
+
const types = reorderUnion(ast.types);
|
|
90
|
+
const union = types === ast.types ? ast : new SchemaAST.Union(types, ast.options, ast.annotations, ast.checks, ast.encoding, ast.context, ast.encodingChecks);
|
|
91
|
+
return recur(union, recur$1);
|
|
92
|
+
}
|
|
93
|
+
case "Arrays":
|
|
94
|
+
case "Suspend": return recur(ast, recur$1);
|
|
95
|
+
}
|
|
96
|
+
return ast;
|
|
97
|
+
};
|
|
98
|
+
const withoutConstructorDefault = (context) => context.constructorDefault === void 0 ? context : new SchemaAST.Context(context.isOptional, context.isMutable, void 0, context.annotations);
|
|
99
|
+
/** @internal */
|
|
100
|
+
const toCodecFirestoreAST = applyToSelfOrLastLinkEncodingIdempotent((ast) => {
|
|
101
|
+
const out = step(ast, toCodecFirestoreAST);
|
|
102
|
+
const context = ast.context;
|
|
103
|
+
if (out === ast || context === void 0) return out;
|
|
104
|
+
return replaceContextLastLink(out, withoutConstructorDefault(context));
|
|
105
|
+
});
|
|
106
|
+
/** @internal */
|
|
107
|
+
const toCodecFirestore = (schema) => Schema.make(toCodecFirestoreAST(schema.ast), { schema });
|
|
108
|
+
export { isFirestoreValue, toCodecFirestore, toCodecFirestoreAST, unknownToFirestore };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import "./firestoreError.mjs";
|
|
2
|
+
import { isDocumentPath } from "./documentPath.mjs";
|
|
3
|
+
import { isArrayRemove, isArrayUnion, isDeleteField, isIncrement, isServerTimestamp } from "./fieldValue.mjs";
|
|
4
|
+
import { isGeoPoint } from "./geoPoint.mjs";
|
|
5
|
+
import { isTimestamp } from "./timestamp.mjs";
|
|
6
|
+
import { FirestoreValue } from "../FirestoreValue.mjs";
|
|
7
|
+
import { Result } from "effect";
|
|
8
|
+
/** @internal */
|
|
9
|
+
export type FieldPath = ReadonlyArray<string | number>;
|
|
10
|
+
/**
|
|
11
|
+
* The kinds of Firestore Value other than scalars, arrays and maps, each with
|
|
12
|
+
* the guard that recognises it. Adding a kind here makes every SDK's
|
|
13
|
+
* {@link Writer} name it too.
|
|
14
|
+
*/
|
|
15
|
+
declare const kinds: {
|
|
16
|
+
readonly bytes: (u: unknown) => u is Uint8Array;
|
|
17
|
+
readonly timestamp: typeof isTimestamp;
|
|
18
|
+
readonly geoPoint: typeof isGeoPoint;
|
|
19
|
+
readonly documentPath: typeof isDocumentPath;
|
|
20
|
+
readonly serverTimestamp: typeof isServerTimestamp;
|
|
21
|
+
readonly increment: typeof isIncrement;
|
|
22
|
+
readonly deleteField: typeof isDeleteField;
|
|
23
|
+
readonly arrayUnion: typeof isArrayUnion;
|
|
24
|
+
readonly arrayRemove: typeof isArrayRemove;
|
|
25
|
+
};
|
|
26
|
+
type Guarded<F> = F extends ((u: unknown) => u is infer A) ? A : never;
|
|
27
|
+
/**
|
|
28
|
+
* Each kind of Firestore Value that is not a scalar, array or map, by name.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export type Kinds = { readonly [K in keyof typeof kinds]: Guarded<(typeof kinds)[K]>; };
|
|
33
|
+
/**
|
|
34
|
+
* Walks the value a kind holds, such as an array union's elements: `key` is
|
|
35
|
+
* where `child` sits within it.
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export type Walk = (child: unknown, key: string | number) => unknown;
|
|
40
|
+
/**
|
|
41
|
+
* How one SDK writes each kind of Firestore Value that is not a scalar, array
|
|
42
|
+
* or map.
|
|
43
|
+
*
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
export type Writer = { readonly [K in keyof Kinds]: (value: Kinds[K], walk: Walk) => unknown; };
|
|
47
|
+
/**
|
|
48
|
+
* How one SDK's values read back as Firestore Values. It hands back
|
|
49
|
+
* `undefined` for a value it leaves to the walk - a scalar, array or map -
|
|
50
|
+
* and calls `fail` for one of its own it cannot read.
|
|
51
|
+
*
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export type Reader = (value: object, context: {
|
|
55
|
+
readonly walk: (child: unknown, key: string | number) => FirestoreValue;
|
|
56
|
+
readonly fail: (kind: string) => never;
|
|
57
|
+
}) => FirestoreValue | undefined;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { FirestoreError } from "./firestoreError.mjs";
|
|
2
|
+
import { isDocumentPath } from "./documentPath.mjs";
|
|
3
|
+
import { isArrayRemove, isArrayUnion, isDeleteField, isIncrement, isServerTimestamp } from "./fieldValue.mjs";
|
|
4
|
+
import { isGeoPoint } from "./geoPoint.mjs";
|
|
5
|
+
import { isTimestamp } from "./timestamp.mjs";
|
|
6
|
+
import { Equal, Result } from "effect";
|
|
7
|
+
// src/firestore/internal/firestoreValueWalk.ts
|
|
8
|
+
/**
|
|
9
|
+
* The one walk over Firestore Values that the guard and both SDK mappings
|
|
10
|
+
* share: the path to each value, the scalars, arrays and maps, and how a
|
|
11
|
+
* value outside the union is reported. What differs per SDK is only how each
|
|
12
|
+
* kind of value in {@link kinds} becomes the SDK's own, and back.
|
|
13
|
+
*/
|
|
14
|
+
/** @internal */
|
|
15
|
+
const formatFieldPath = (path) => path.length === 0 ? "the document" : `"${path.map((key, i) => typeof key === "number" ? `[${key}]` : i === 0 ? key : `.${key}`).join("")}"`;
|
|
16
|
+
/**
|
|
17
|
+
* The kinds of Firestore Value other than scalars, arrays and maps, each with
|
|
18
|
+
* the guard that recognises it. Adding a kind here makes every SDK's
|
|
19
|
+
* {@link Writer} name it too.
|
|
20
|
+
*/
|
|
21
|
+
const kinds = {
|
|
22
|
+
bytes: (u) => u instanceof Uint8Array,
|
|
23
|
+
timestamp: isTimestamp,
|
|
24
|
+
geoPoint: isGeoPoint,
|
|
25
|
+
documentPath: isDocumentPath,
|
|
26
|
+
serverTimestamp: isServerTimestamp,
|
|
27
|
+
increment: isIncrement,
|
|
28
|
+
deleteField: isDeleteField,
|
|
29
|
+
arrayUnion: isArrayUnion,
|
|
30
|
+
arrayRemove: isArrayRemove
|
|
31
|
+
};
|
|
32
|
+
const kindNames = Object.keys(kinds);
|
|
33
|
+
const kindOf = (u) => kindNames.find((kind) => kinds[kind](u));
|
|
34
|
+
/** A map: a plain object whose keys are all strings. */
|
|
35
|
+
const isMap = (u) => {
|
|
36
|
+
const proto = Object.getPrototypeOf(u);
|
|
37
|
+
return (proto === Object.prototype || proto === null) && Object.getOwnPropertySymbols(u).length === 0;
|
|
38
|
+
};
|
|
39
|
+
const describe = (u) => {
|
|
40
|
+
const name = u.constructor?.name;
|
|
41
|
+
return name === void 0 ? "an object with no prototype" : `a ${name}`;
|
|
42
|
+
};
|
|
43
|
+
/** A value outside the Firestore Value union, at `path`. */
|
|
44
|
+
var Outside = class {
|
|
45
|
+
kind;
|
|
46
|
+
value;
|
|
47
|
+
path;
|
|
48
|
+
constructor(kind, value, path) {
|
|
49
|
+
this.kind = kind;
|
|
50
|
+
this.value = value;
|
|
51
|
+
this.path = path;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const unhandled = Symbol("unhandled");
|
|
55
|
+
/**
|
|
56
|
+
* Walks `value`, handing every object to `visit` first and then walking
|
|
57
|
+
* arrays and maps itself. Throws {@link Outside} at the first value that is
|
|
58
|
+
* none of these, or that contains itself.
|
|
59
|
+
*/
|
|
60
|
+
const walk = (value, visit) => {
|
|
61
|
+
const path = [];
|
|
62
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
63
|
+
const within = (child, key) => {
|
|
64
|
+
path.push(key);
|
|
65
|
+
try {
|
|
66
|
+
return go(child);
|
|
67
|
+
} finally {
|
|
68
|
+
path.pop();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const go = (u) => {
|
|
72
|
+
switch (typeof u) {
|
|
73
|
+
case "boolean":
|
|
74
|
+
case "number":
|
|
75
|
+
case "string": return u;
|
|
76
|
+
case "object": break;
|
|
77
|
+
default: throw new Outside(`a value of type ${typeof u}`, u, [...path]);
|
|
78
|
+
}
|
|
79
|
+
if (u === null) return u;
|
|
80
|
+
const fail = (kind) => {
|
|
81
|
+
throw new Outside(kind, u, [...path]);
|
|
82
|
+
};
|
|
83
|
+
if (ancestors.has(u)) return fail("a value that contains itself");
|
|
84
|
+
ancestors.add(u);
|
|
85
|
+
try {
|
|
86
|
+
const out = visit(u, within, fail);
|
|
87
|
+
if (out !== unhandled) return out;
|
|
88
|
+
if (Array.isArray(u)) return u.map((e, i) => within(e, i));
|
|
89
|
+
if (isMap(u)) {
|
|
90
|
+
const map = {};
|
|
91
|
+
for (const key of Object.keys(u)) map[key] = within(u[key], key);
|
|
92
|
+
return map;
|
|
93
|
+
}
|
|
94
|
+
return fail(describe(u));
|
|
95
|
+
} finally {
|
|
96
|
+
ancestors.delete(u);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
return go(value);
|
|
100
|
+
};
|
|
101
|
+
const write = (value, writer) => walk(value, (u, within) => {
|
|
102
|
+
const kind = kindOf(u);
|
|
103
|
+
return kind === void 0 ? unhandled : writer[kind](u, within);
|
|
104
|
+
});
|
|
105
|
+
const keep = (value) => value;
|
|
106
|
+
/** Builds nothing: walking with it only checks a value is a Firestore Value. */
|
|
107
|
+
const checker = {
|
|
108
|
+
bytes: keep,
|
|
109
|
+
timestamp: keep,
|
|
110
|
+
geoPoint: keep,
|
|
111
|
+
documentPath: keep,
|
|
112
|
+
serverTimestamp: keep,
|
|
113
|
+
increment: keep,
|
|
114
|
+
deleteField: keep,
|
|
115
|
+
arrayUnion: (u, within) => u.elements.forEach(within),
|
|
116
|
+
arrayRemove: (u, within) => u.elements.forEach(within)
|
|
117
|
+
};
|
|
118
|
+
/** @internal */
|
|
119
|
+
const isFirestoreValue = (u) => {
|
|
120
|
+
try {
|
|
121
|
+
write(u, checker);
|
|
122
|
+
return true;
|
|
123
|
+
} catch (e) {
|
|
124
|
+
if (e instanceof Outside) return false;
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Whether two Firestore Values are the same, as Firestore would store them:
|
|
130
|
+
* scalars by value, arrays and maps element by element and key by key, bytes
|
|
131
|
+
* byte by byte, and every other kind as that kind tells its values apart.
|
|
132
|
+
*
|
|
133
|
+
* @internal
|
|
134
|
+
*/
|
|
135
|
+
const equals = (self, that) => {
|
|
136
|
+
if (Object.is(self, that)) return true;
|
|
137
|
+
if (typeof self !== "object" || typeof that !== "object" || self === null || that === null) return false;
|
|
138
|
+
if (Array.isArray(self) || Array.isArray(that)) return Array.isArray(self) && Array.isArray(that) && self.length === that.length && self.every((element, i) => equals(element, that[i]));
|
|
139
|
+
const kind = kindOf(self);
|
|
140
|
+
if (kind !== kindOf(that)) return false;
|
|
141
|
+
switch (kind) {
|
|
142
|
+
case void 0: return isMap(self) && isMap(that) && Object.keys(self).length === Object.keys(that).length && Object.keys(self).every((key) => Object.hasOwn(that, key) && equals(self[key], that[key]));
|
|
143
|
+
case "bytes": {
|
|
144
|
+
const a = self;
|
|
145
|
+
const b = that;
|
|
146
|
+
return a.length === b.length && a.every((byte, i) => byte === b[i]);
|
|
147
|
+
}
|
|
148
|
+
case "arrayUnion":
|
|
149
|
+
case "arrayRemove": return equals(self.elements, that.elements);
|
|
150
|
+
default: return Equal.equals(self, that);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Turns a Firestore Value into an SDK's own value through `writer`. A value
|
|
155
|
+
* outside the union is a defect, since `toCodecFirestore` only ever encodes
|
|
156
|
+
* Firestore Values.
|
|
157
|
+
*
|
|
158
|
+
* @internal
|
|
159
|
+
*/
|
|
160
|
+
const toSdk = (value, writer) => {
|
|
161
|
+
try {
|
|
162
|
+
return write(value, writer);
|
|
163
|
+
} catch (e) {
|
|
164
|
+
if (!(e instanceof Outside)) throw e;
|
|
165
|
+
throw new globalThis.Error(`Cannot write ${e.kind} at ${formatFieldPath(e.path)}, which is not a Firestore Value`, { cause: e.value });
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Turns what an SDK read into a Firestore Value through `reader`, failing on
|
|
170
|
+
* a value outside the union, such as a vector, and naming the field that
|
|
171
|
+
* holds it.
|
|
172
|
+
*
|
|
173
|
+
* @internal
|
|
174
|
+
*/
|
|
175
|
+
const fromSdk = (value, reader) => {
|
|
176
|
+
try {
|
|
177
|
+
return Result.succeed(walk(value, (u, within, fail) => {
|
|
178
|
+
const out = reader(u, {
|
|
179
|
+
walk: within,
|
|
180
|
+
fail
|
|
181
|
+
});
|
|
182
|
+
return out === void 0 ? unhandled : out;
|
|
183
|
+
}));
|
|
184
|
+
} catch (e) {
|
|
185
|
+
if (!(e instanceof Outside)) throw e;
|
|
186
|
+
return Result.fail(new FirestoreError({
|
|
187
|
+
message: `Firestore holds ${e.kind} at ${formatFieldPath(e.path)}, which is not a Firestore Value`,
|
|
188
|
+
code: void 0,
|
|
189
|
+
cause: e.value
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Reads what an SDK holds for the document at `path` as Firestore Values
|
|
195
|
+
* through `reader`, keeping `undefined` - a document that is not there - as
|
|
196
|
+
* it is.
|
|
197
|
+
*
|
|
198
|
+
* @internal
|
|
199
|
+
*/
|
|
200
|
+
const readDocument = (path, data, reader) => data === void 0 ? Result.succeed(void 0) : Result.mapError(fromSdk(data, reader), (error) => new FirestoreError({
|
|
201
|
+
message: `Failed to read the document "${path}": ${error.message}`,
|
|
202
|
+
code: void 0,
|
|
203
|
+
cause: error.cause
|
|
204
|
+
}));
|
|
205
|
+
/**
|
|
206
|
+
* Reads Firestore Values as they are, walking into the values a kind holds,
|
|
207
|
+
* so that only a value outside the union fails.
|
|
208
|
+
*/
|
|
209
|
+
const asIs = (u, { walk }) => {
|
|
210
|
+
const kind = kindOf(u);
|
|
211
|
+
if (kind === "arrayUnion" || kind === "arrayRemove") u.elements.forEach((element, i) => walk(element, i));
|
|
212
|
+
return kind === void 0 ? void 0 : u;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Checks that what a backend read for the document at `path` is made of
|
|
216
|
+
* Firestore Values, failing as {@link readDocument} does on one that is not.
|
|
217
|
+
* It hands back `data` itself, so `undefined` - a document that is not there -
|
|
218
|
+
* stays as it is.
|
|
219
|
+
*
|
|
220
|
+
* @internal
|
|
221
|
+
*/
|
|
222
|
+
const checkDocument = (path, data) => Result.map(readDocument(path, data, asIs), () => data);
|
|
223
|
+
export { checkDocument, equals, formatFieldPath, fromSdk, isFirestoreValue, readDocument, toSdk };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Equal, Hash, Inspectable, Option, Predicate } from "effect";
|
|
2
|
+
// src/firestore/internal/geoPoint.ts
|
|
3
|
+
/** @internal */
|
|
4
|
+
const TypeId = "~@visiolab/effect-firebase/firestore/GeoPoint";
|
|
5
|
+
/** Kept apart from the guards below, which narrow a `number` to `never`. */
|
|
6
|
+
const inLatitudeRange = (n) => Number.isFinite(n) && n >= -90 && n <= 90;
|
|
7
|
+
const inLongitudeRange = (n) => Number.isFinite(n) && n >= -180 && n <= 180;
|
|
8
|
+
/** @internal */
|
|
9
|
+
const isGeoPoint = (u) => Predicate.hasProperty(u, "~@visiolab/effect-firebase/firestore/GeoPoint") && u["~@visiolab/effect-firebase/firestore/GeoPoint"] === "~@visiolab/effect-firebase/firestore/GeoPoint" && Predicate.hasProperty(u, "latitude") && Predicate.hasProperty(u, "longitude") && Predicate.isNumber(u.latitude) && Predicate.isNumber(u.longitude) && inLatitudeRange(u.latitude) && inLongitudeRange(u.longitude);
|
|
10
|
+
const Proto = {
|
|
11
|
+
...Inspectable.BaseProto,
|
|
12
|
+
[TypeId]: TypeId,
|
|
13
|
+
toJSON() {
|
|
14
|
+
return {
|
|
15
|
+
_id: "GeoPoint",
|
|
16
|
+
latitude: this.latitude,
|
|
17
|
+
longitude: this.longitude
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
[Equal.symbol](that) {
|
|
21
|
+
return isGeoPoint(that) && this.latitude === that.latitude && this.longitude === that.longitude;
|
|
22
|
+
},
|
|
23
|
+
[Hash.symbol]() {
|
|
24
|
+
return Hash.combine(Hash.number(this.latitude), Hash.number(this.longitude));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const makeUnchecked = (latitude, longitude) => Object.assign(Object.create(Proto), {
|
|
28
|
+
latitude,
|
|
29
|
+
longitude
|
|
30
|
+
});
|
|
31
|
+
/** @internal */
|
|
32
|
+
const makeUnsafe = (latitude, longitude) => {
|
|
33
|
+
if (!inLatitudeRange(latitude)) throw new Error(`Invalid Firestore geopoint: latitude must be a number between -90 and 90, got ${latitude}`);
|
|
34
|
+
if (!inLongitudeRange(longitude)) throw new Error(`Invalid Firestore geopoint: longitude must be a number between -180 and 180, got ${longitude}`);
|
|
35
|
+
return makeUnchecked(latitude, longitude);
|
|
36
|
+
};
|
|
37
|
+
/** @internal */
|
|
38
|
+
const make = (latitude, longitude) => inLatitudeRange(latitude) && inLongitudeRange(longitude) ? Option.some(makeUnchecked(latitude, longitude)) : Option.none();
|
|
39
|
+
export { TypeId, isGeoPoint, make, makeUnsafe };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Inspectable, Predicate } from "effect";
|
|
2
|
+
// src/firestore/internal/patch.ts
|
|
3
|
+
/** @internal */
|
|
4
|
+
const ReplaceTypeId = "~@visiolab/effect-firebase/firestore/Patch/Replace";
|
|
5
|
+
const ReplaceProto = {
|
|
6
|
+
...Inspectable.BaseProto,
|
|
7
|
+
[ReplaceTypeId]: ReplaceTypeId,
|
|
8
|
+
toJSON() {
|
|
9
|
+
return {
|
|
10
|
+
_id: "Replace",
|
|
11
|
+
value: Inspectable.toJson(this.value)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
/** @internal */
|
|
16
|
+
const isReplace = (u) => Predicate.hasProperty(u, ReplaceTypeId);
|
|
17
|
+
/** @internal */
|
|
18
|
+
const replace = (value) => Object.assign(Object.create(ReplaceProto), { value });
|
|
19
|
+
export { ReplaceTypeId, isReplace, replace };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { attach, extraToJson } from "./snapshotExtra.mjs";
|
|
2
|
+
import { Inspectable, Predicate } from "effect";
|
|
3
|
+
// src/firestore/internal/querySnapshot.ts
|
|
4
|
+
/** @internal */
|
|
5
|
+
const TypeId = "~@visiolab/effect-firebase/firestore/QuerySnapshot";
|
|
6
|
+
/** @internal */
|
|
7
|
+
const isQuerySnapshot = (u) => Predicate.hasProperty(u, TypeId);
|
|
8
|
+
const QuerySnapshotProto = {
|
|
9
|
+
...Inspectable.BaseProto,
|
|
10
|
+
[TypeId]: TypeId,
|
|
11
|
+
toJSON() {
|
|
12
|
+
return {
|
|
13
|
+
_id: "QuerySnapshot",
|
|
14
|
+
docs: this.docs.map((doc) => doc.toJSON()),
|
|
15
|
+
...extraToJson(this)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/** @internal */
|
|
20
|
+
const make = (docs, extra) => {
|
|
21
|
+
const self = Object.assign(Object.create(QuerySnapshotProto), { docs });
|
|
22
|
+
return attach(self, extra);
|
|
23
|
+
};
|
|
24
|
+
export { TypeId, isQuerySnapshot, make };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SchemaAST } from "effect";
|
|
2
|
+
// src/firestore/internal/schemaAST.ts
|
|
3
|
+
/**
|
|
4
|
+
* The one place this package reaches into Effect's `@internal` `SchemaAST`
|
|
5
|
+
* helpers.
|
|
6
|
+
*
|
|
7
|
+
* Effect has no public way to define a canonical format, so deriving
|
|
8
|
+
* `toCodecFirestore` the way `toCodecJson` is derived needs the same internal
|
|
9
|
+
* helpers Effect uses for it (ADR 0002). They exist at runtime but are stripped
|
|
10
|
+
* from Effect's type declarations, so each is typed here by hand, against the
|
|
11
|
+
* pinned `effect` version. Keeping them together means a future public API for
|
|
12
|
+
* canonical formats is a swap of this module only.
|
|
13
|
+
*/
|
|
14
|
+
const internals = SchemaAST;
|
|
15
|
+
/** Replaces the encoding chain of `ast`, leaving `ast` alone when it is the same. */
|
|
16
|
+
const replaceEncoding = internals.replaceEncoding;
|
|
17
|
+
/** Maps the target of `link`, leaving `link` alone when the target is unchanged. */
|
|
18
|
+
const mapLink = internals.mapLink;
|
|
19
|
+
/** Replaces the context of the last link's target. */
|
|
20
|
+
const replaceContextLastLink = internals.replaceContextLastLink;
|
|
21
|
+
/**
|
|
22
|
+
* Applies `f` to the node itself when it has no encoding, or to the target of
|
|
23
|
+
* its last encoding link otherwise, so user transformations run first. The
|
|
24
|
+
* result is memoized per node.
|
|
25
|
+
*/
|
|
26
|
+
const applyToSelfOrLastLinkEncodingIdempotent = internals.applyToSelfOrLastLinkEncodingIdempotent;
|
|
27
|
+
/** How a canonical format reads index-signature and property keys back from strings. */
|
|
28
|
+
const parameterFromString = internals.parameterFromString;
|
|
29
|
+
/** The keyword's own canonical JSON codec, as `toCodecJson` derives it. */
|
|
30
|
+
const keywordToCodecJson = (ast) => ast.toCodecJson();
|
|
31
|
+
/** The keyword's own canonical StringTree codec, as `toCodecStringTree` derives it. */
|
|
32
|
+
const keywordToCodecStringTree = (ast) => ast.toCodecStringTree();
|
|
33
|
+
/** Recurs into the members of a composite node. */
|
|
34
|
+
const recur = (ast, f, onKey) => ast.recur(f, onKey);
|
|
35
|
+
export { applyToSelfOrLastLinkEncodingIdempotent, keywordToCodecJson, keywordToCodecStringTree, mapLink, parameterFromString, recur, replaceContextLastLink, replaceEncoding };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Inspectable } from "effect";
|
|
2
|
+
// src/firestore/internal/snapshotExtra.ts
|
|
3
|
+
/**
|
|
4
|
+
* Where a snapshot keeps the extra an SDK built it with, so that it can show
|
|
5
|
+
* that extra when it prints without telling the extra's fields from its own.
|
|
6
|
+
*/
|
|
7
|
+
const ExtraKey = "~@visiolab/effect-firebase/firestore/SnapshotExtra";
|
|
8
|
+
/**
|
|
9
|
+
* `self` with the fields of `extra` on it, remembered as its extra so that
|
|
10
|
+
* {@link extraToJson} shows them.
|
|
11
|
+
*
|
|
12
|
+
* The extra itself is held on a key that is not enumerable, so that it does
|
|
13
|
+
* not show up twice: its fields are already on the snapshot.
|
|
14
|
+
*
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
const attach = (self, extra) => {
|
|
18
|
+
if (extra === void 0) return self;
|
|
19
|
+
Object.defineProperty(self, ExtraKey, { value: extra });
|
|
20
|
+
return Object.assign(self, extra);
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* How the extra `self` was built with prints: each of its fields as it would
|
|
24
|
+
* print on its own, or nothing when it was built without one.
|
|
25
|
+
*
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
const extraToJson = (self) => {
|
|
29
|
+
const extra = self[ExtraKey];
|
|
30
|
+
if (extra === void 0) return {};
|
|
31
|
+
const json = {};
|
|
32
|
+
for (const [key, value] of Object.entries(extra)) json[key] = Inspectable.toJson(value);
|
|
33
|
+
return json;
|
|
34
|
+
};
|
|
35
|
+
export { attach, extraToJson };
|