@data-weave/backend-firestore 0.4.2 → 0.4.3

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.
@@ -0,0 +1,48 @@
1
+ import { Cache } from '@data-weave/datamanager/lib/Cache';
2
+ import { DataManager, WithMetadata } from '@data-weave/datamanager/lib/DataManager';
3
+ import { List, ListPaginationParams } from '@data-weave/datamanager/lib/List';
4
+ import { IdentifiableReference, WithoutId } from '@data-weave/datamanager/lib/Reference';
5
+ import { FirestoreList, FirestoreListContext } from './FirestoreList';
6
+ import { FirestoreSerializedMetadata } from './FirestoreMetadata';
7
+ import { FirestoreReference, FirestoreReferenceContext } from './FirestoreReference';
8
+ import { FilterBy, FirebaseCreateOptions, Firestore, FirestoreDataConverter, FirestoreReadMode, FirestoreReadOptions, FirestoreTypes, FirestoreWriteOptions, OrderBy, WithFieldValue } from './firestoreTypes';
9
+ export type FirebaseDataManagerDeleteMode = 'soft' | 'hard';
10
+ export interface FirebaseDataManagerOptions {
11
+ readonly idResolver?: () => string;
12
+ readonly deleteMode?: FirebaseDataManagerDeleteMode;
13
+ readonly readMode?: FirestoreReadMode;
14
+ readonly preventOverwriteOnCreate?: boolean;
15
+ readonly errorInterceptor?: (error: unknown, ctx: FirestoreReferenceContext | FirestoreListContext) => void;
16
+ readonly snapshotOptions?: FirestoreTypes.SnapshotOptions;
17
+ readonly Reference?: typeof FirestoreReference;
18
+ readonly List?: typeof FirestoreList;
19
+ readonly listCache?: Cache;
20
+ readonly refCache?: Cache;
21
+ }
22
+ export interface QueryParams<T extends FirestoreTypes.DocumentData> {
23
+ readonly filters?: Array<FilterBy<T & FirestoreSerializedMetadata>>;
24
+ readonly orderBy?: Array<OrderBy<T & FirestoreSerializedMetadata>>;
25
+ }
26
+ export declare class FirestoreDataManager<T extends FirestoreTypes.DocumentData, SerializedT extends FirestoreTypes.DocumentData = T> implements DataManager<T> {
27
+ private readonly firestore;
28
+ private readonly collectionPath;
29
+ private readonly converter;
30
+ private readonly opts?;
31
+ private mergedConverter;
32
+ private collection;
33
+ private collectionQuery;
34
+ private managerOptions;
35
+ private refCache;
36
+ private listCache;
37
+ constructor(firestore: Firestore, collectionPath: string, converter: FirestoreDataConverter<T, SerializedT>, opts?: FirebaseDataManagerOptions | undefined);
38
+ read(id: string, options?: FirestoreReadOptions): Promise<WithMetadata<T> | undefined>;
39
+ create(data: WithFieldValue<WithoutId<T>>, options?: FirebaseCreateOptions): Promise<IdentifiableReference<WithMetadata<T>>>;
40
+ private _update;
41
+ update(id: string, data: WithoutId<Partial<WithFieldValue<T>>>, options?: FirestoreWriteOptions): Promise<void>;
42
+ upsert(id: string, data: WithFieldValue<WithoutId<T>>, options?: FirestoreWriteOptions): Promise<void>;
43
+ delete(id: string, options?: FirestoreWriteOptions): Promise<void>;
44
+ getRef(id: string): IdentifiableReference<WithMetadata<T>>;
45
+ private _getFilteredQuery;
46
+ getList(params?: QueryParams<SerializedT> & ListPaginationParams): List<WithMetadata<T>>;
47
+ private preventOverwriteOnCreate;
48
+ }
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.FirestoreDataManager = void 0;
51
+ const inversify_1 = require("inversify");
52
+ const Cache_1 = require("@data-weave/datamanager/lib/Cache");
53
+ const FirestoreList_1 = require("./FirestoreList");
54
+ const FirestoreMetadata_1 = require("./FirestoreMetadata");
55
+ const FirestoreReference_1 = require("./FirestoreReference");
56
+ const utils_1 = require("./utils");
57
+ const defaultFirebaseDataManagerOptions = {
58
+ deleteMode: 'soft',
59
+ preventOverwriteOnCreate: true,
60
+ readMode: 'static',
61
+ Reference: FirestoreReference_1.FirestoreReference,
62
+ List: FirestoreList_1.FirestoreList,
63
+ };
64
+ let FirestoreDataManager = (() => {
65
+ let _classDecorators = [(0, inversify_1.injectable)()];
66
+ let _classDescriptor;
67
+ let _classExtraInitializers = [];
68
+ let _classThis;
69
+ var FirestoreDataManager = _classThis = class {
70
+ constructor(firestore, collectionPath, converter, opts) {
71
+ this.firestore = firestore;
72
+ this.collectionPath = collectionPath;
73
+ this.converter = converter;
74
+ this.opts = opts;
75
+ // @ts-expect-error - Force merge FirestoreDataConverter and InternalFirestoreDataConverter
76
+ this.mergedConverter = new utils_1.MergeConverters(this.converter, new FirestoreMetadata_1.FirestoreMetadataConverter());
77
+ this.managerOptions = Object.assign(defaultFirebaseDataManagerOptions, this.opts);
78
+ this.refCache = this.managerOptions.refCache || new Cache_1.MapCache(100);
79
+ this.listCache = this.managerOptions.listCache || new Cache_1.MapCache(100);
80
+ this.collection = this.firestore
81
+ .collection(this.firestore.app, this.collectionPath)
82
+ .withConverter(this.mergedConverter);
83
+ this.collectionQuery =
84
+ this.managerOptions.deleteMode === 'soft'
85
+ ? (0, FirestoreMetadata_1.queryNotDeleted)(this.collection, this.firestore.query, this.firestore.where)
86
+ : this.collection;
87
+ }
88
+ read(id, options) {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ var _a;
91
+ if (!((_a = this.managerOptions) === null || _a === void 0 ? void 0 : _a.Reference))
92
+ throw new Error('ReferenceClass not defined');
93
+ const ref = this.getRef(id);
94
+ if (options === null || options === void 0 ? void 0 : options.transaction) {
95
+ const snapshot = yield options.transaction.get(this.firestore.doc(this.collection, id));
96
+ if (!(0, utils_1.checkIfReferenceExists)(snapshot))
97
+ return undefined;
98
+ return snapshot.data();
99
+ }
100
+ return yield ref.resolve();
101
+ });
102
+ }
103
+ create(data, options) {
104
+ return __awaiter(this, void 0, void 0, function* () {
105
+ var _a;
106
+ let id = undefined;
107
+ if (options === null || options === void 0 ? void 0 : options.id) {
108
+ id = options === null || options === void 0 ? void 0 : options.id;
109
+ }
110
+ else if ((_a = this.managerOptions) === null || _a === void 0 ? void 0 : _a.idResolver) {
111
+ id = this.managerOptions.idResolver();
112
+ }
113
+ let docRef;
114
+ let docExists = false;
115
+ if (id) {
116
+ docRef = this.firestore.doc(this.collection, id);
117
+ docExists = yield this.preventOverwriteOnCreate(docRef, options);
118
+ }
119
+ else {
120
+ docRef = this.firestore.doc(this.collection);
121
+ }
122
+ const docDataWithMetadata = Object.assign(Object.assign({}, data), { [FirestoreMetadata_1.FIRESTORE_KEYS.CREATED_AT]: docExists ? undefined : this.firestore.serverTimestamp(), [FirestoreMetadata_1.FIRESTORE_KEYS.UPDATED_AT]: this.firestore.serverTimestamp(), [FirestoreMetadata_1.FIRESTORE_KEYS.DELETED]: false });
123
+ const firebaseOptions = { merge: options === null || options === void 0 ? void 0 : options.merge };
124
+ if (options === null || options === void 0 ? void 0 : options.transaction) {
125
+ options === null || options === void 0 ? void 0 : options.transaction.set(docRef, docDataWithMetadata, firebaseOptions);
126
+ }
127
+ else {
128
+ yield this.firestore.setDoc(docRef, docDataWithMetadata, firebaseOptions);
129
+ }
130
+ return this.getRef(docRef.id);
131
+ });
132
+ }
133
+ _update(id, data, options) {
134
+ return __awaiter(this, void 0, void 0, function* () {
135
+ const extendedData = Object.assign(Object.assign({}, data), { [FirestoreMetadata_1.FIRESTORE_KEYS.UPDATED_AT]: this.firestore.serverTimestamp() });
136
+ // Firestore update method doesn't call converter like setDoc does, so we need to serialize the data manually.
137
+ const serializedData = this.mergedConverter.toFirestore(extendedData);
138
+ const ref = this.firestore.doc(this.collection, id);
139
+ if (options === null || options === void 0 ? void 0 : options.transaction) {
140
+ return options.transaction.update(ref, serializedData);
141
+ }
142
+ return this.firestore.updateDoc(ref, serializedData);
143
+ });
144
+ }
145
+ update(id, data, options) {
146
+ return __awaiter(this, void 0, void 0, function* () {
147
+ yield this._update(id, data, options);
148
+ });
149
+ }
150
+ upsert(id, data, options) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ this.create(data, Object.assign(Object.assign({}, options), { id, merge: true }));
153
+ });
154
+ }
155
+ delete(id, options) {
156
+ return __awaiter(this, void 0, void 0, function* () {
157
+ if (this.managerOptions.deleteMode === 'soft') {
158
+ yield this._update(id, Object.assign(Object.assign({}, {}), { [FirestoreMetadata_1.FIRESTORE_KEYS.DELETED]: true }), options);
159
+ return;
160
+ }
161
+ return this.firestore.deleteDoc(this.firestore.doc(this.collection, id));
162
+ });
163
+ }
164
+ getRef(id) {
165
+ var _a;
166
+ if (!((_a = this.managerOptions) === null || _a === void 0 ? void 0 : _a.Reference))
167
+ throw new Error('ReferenceClass not defined');
168
+ if (this.refCache.has(id)) {
169
+ return this.refCache.get(id);
170
+ }
171
+ const newRef = new this.managerOptions.Reference(this.firestore, this.firestore.doc(this.collection, id), {
172
+ readMode: this.managerOptions.readMode,
173
+ errorInterceptor: this.managerOptions.errorInterceptor,
174
+ snapshotOptions: this.managerOptions.snapshotOptions,
175
+ });
176
+ this.refCache.set(id, newRef);
177
+ return newRef;
178
+ }
179
+ _getFilteredQuery(params) {
180
+ var _a, _b;
181
+ let compoundQuery = this.collectionQuery;
182
+ (_a = params === null || params === void 0 ? void 0 : params.filters) === null || _a === void 0 ? void 0 : _a.forEach(filter => {
183
+ compoundQuery = this.firestore.query(compoundQuery, this.firestore.where(filter[0], filter[1], filter[2]));
184
+ });
185
+ (_b = params === null || params === void 0 ? void 0 : params.orderBy) === null || _b === void 0 ? void 0 : _b.forEach(orderBy => {
186
+ compoundQuery = this.firestore.query(compoundQuery, this.firestore.orderBy(orderBy[0], orderBy[1]));
187
+ });
188
+ return compoundQuery;
189
+ }
190
+ getList(params) {
191
+ if (!this.managerOptions.List)
192
+ throw new Error('ListClass not defined');
193
+ const compoundQuery = this._getFilteredQuery(params);
194
+ const key = JSON.stringify(params || {});
195
+ if (this.listCache.has(key)) {
196
+ return this.listCache.get(key);
197
+ }
198
+ const newList = new this.managerOptions.List(this.firestore, compoundQuery, Object.assign({ readMode: this.managerOptions.readMode, errorInterceptor: this.managerOptions.errorInterceptor }, params));
199
+ this.listCache.set(key, newList);
200
+ return newList;
201
+ }
202
+ preventOverwriteOnCreate(docRef, createOptions) {
203
+ return __awaiter(this, void 0, void 0, function* () {
204
+ const doc = yield this.firestore.getDoc(docRef);
205
+ const docExists = (0, utils_1.checkIfReferenceExists)(doc);
206
+ if (docExists && this.managerOptions.preventOverwriteOnCreate && (createOptions === null || createOptions === void 0 ? void 0 : createOptions.merge) !== true) {
207
+ throw new Error(`Document already exists - ${doc.ref.path}`);
208
+ }
209
+ return docExists;
210
+ });
211
+ }
212
+ };
213
+ __setFunctionName(_classThis, "FirestoreDataManager");
214
+ (() => {
215
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
216
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
217
+ FirestoreDataManager = _classThis = _classDescriptor.value;
218
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
219
+ __runInitializers(_classThis, _classExtraInitializers);
220
+ })();
221
+ return FirestoreDataManager = _classThis;
222
+ })();
223
+ exports.FirestoreDataManager = FirestoreDataManager;
@@ -0,0 +1,23 @@
1
+ import { ListPaginationParams, LiveList, LiveListOptions } from '@data-weave/datamanager';
2
+ import { DocumentData, Firestore, FirestoreReadMode, FirestoreTypes } from './firestoreTypes';
3
+ export interface FirestoreListContext {
4
+ query: FirestoreTypes.Query<unknown>;
5
+ readMode?: FirestoreReadMode;
6
+ type: 'list';
7
+ }
8
+ export interface FirestoreListOptions<T> extends LiveListOptions<T> {
9
+ readMode?: FirestoreReadMode;
10
+ errorInterceptor?: (error: unknown, ctx: FirestoreListContext) => void;
11
+ }
12
+ export declare class FirestoreList<T extends DocumentData, S extends DocumentData> extends LiveList<T> {
13
+ private readonly firestore;
14
+ private readonly query;
15
+ private readonly options;
16
+ private unsubscribeFromSnapshot;
17
+ constructor(firestore: Firestore, query: FirestoreTypes.Query<T, S>, options: FirestoreListOptions<T> & ListPaginationParams);
18
+ resolve(): Promise<T[]>;
19
+ protected handleInitialDataChange(values: FirestoreTypes.QueryDocumentSnapshot<T, S>[]): void;
20
+ protected handleSubsequentDataChanges(changes: FirestoreTypes.DocumentChange<T, S>[]): void;
21
+ unSubscribe(): void;
22
+ protected onError(error: unknown): void;
23
+ }
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FirestoreList = void 0;
13
+ const datamanager_1 = require("@data-weave/datamanager");
14
+ class FirestoreList extends datamanager_1.LiveList {
15
+ constructor(firestore, query, options) {
16
+ super(options);
17
+ this.firestore = firestore;
18
+ this.query = query;
19
+ this.options = options;
20
+ }
21
+ resolve() {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ var _a;
24
+ if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.readMode) === 'realtime') {
25
+ let initialLoad = true;
26
+ return new Promise((resolve, reject) => {
27
+ this.unsubscribeFromSnapshot = this.firestore.onSnapshot(this.query, querySnapshot => {
28
+ try {
29
+ if (initialLoad) {
30
+ initialLoad = false;
31
+ this.handleInitialDataChange(querySnapshot.docs);
32
+ }
33
+ else {
34
+ this.handleSubsequentDataChanges(querySnapshot.docChanges());
35
+ }
36
+ // TODO: When calling ".resolve()" with realtime listener,
37
+ // the snapshot data might be stale from cache.
38
+ resolve(this.values);
39
+ }
40
+ catch (error) {
41
+ this.onError(error);
42
+ reject(error);
43
+ }
44
+ }, error => {
45
+ this.onError(error);
46
+ reject(error);
47
+ });
48
+ });
49
+ }
50
+ else {
51
+ const snapshot = yield this.firestore.getDocs(this.query);
52
+ this.handleInitialDataChange(snapshot.docs);
53
+ return this.values;
54
+ }
55
+ });
56
+ }
57
+ handleInitialDataChange(values) {
58
+ const newValues = values.map(v => v.data());
59
+ this.onUpdateAll(newValues);
60
+ }
61
+ handleSubsequentDataChanges(changes) {
62
+ changes.forEach(change => {
63
+ if (change.type === 'added') {
64
+ this.onAddAtIndex(change.newIndex, change.doc.data());
65
+ }
66
+ else if (change.type === 'modified') {
67
+ this.onUpdateAtIndex(change.newIndex, change.doc.data());
68
+ }
69
+ else if (change.type === 'removed') {
70
+ this.onRemoveAtIndex(change.oldIndex);
71
+ }
72
+ });
73
+ // TODO: handle onUpdate in the parent class - make sure it's only called once after all changes are processed
74
+ this.onUpdate();
75
+ }
76
+ unSubscribe() {
77
+ var _a;
78
+ (_a = this.unsubscribeFromSnapshot) === null || _a === void 0 ? void 0 : _a.call(this);
79
+ this.setStale();
80
+ }
81
+ onError(error) {
82
+ var _a, _b, _c, _d, _e;
83
+ // Try to provide useful collection details using internal properties
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ console.error(`FirestoreList Collection: ${(_b = (_a = this.query) === null || _a === void 0 ? void 0 : _a._collectionPath) === null || _b === void 0 ? void 0 : _b.id} error`, error);
86
+ (_d = (_c = this.options) === null || _c === void 0 ? void 0 : _c.errorInterceptor) === null || _d === void 0 ? void 0 : _d.call(_c, error, {
87
+ query: this.query,
88
+ readMode: (_e = this.options) === null || _e === void 0 ? void 0 : _e.readMode,
89
+ type: 'list',
90
+ });
91
+ super.onError(error);
92
+ }
93
+ }
94
+ exports.FirestoreList = FirestoreList;
@@ -0,0 +1,32 @@
1
+ import { Metadata, WithoutId } from '@data-weave/datamanager';
2
+ import { DocumentData, FirestoreQuery, FirestoreTypes, FirestoreWhere, InternalFirestoreDataConverter, WithFieldValue } from './firestoreTypes';
3
+ declare enum FIRESTORE_INTERAL_KEYS {
4
+ DELETED = "__deleted",
5
+ CREATED_AT = "__createdAt",
6
+ UPDATED_AT = "__updatedAt"
7
+ }
8
+ export declare enum FIRESTORE_KEYS {
9
+ DELETED = "deleted",
10
+ CREATED_AT = "createdAt",
11
+ UPDATED_AT = "updatedAt"
12
+ }
13
+ export type FirestoreSerializedMetadata = {
14
+ [FIRESTORE_INTERAL_KEYS.DELETED]: boolean;
15
+ [FIRESTORE_INTERAL_KEYS.CREATED_AT]: FirestoreTypes.Timestamp;
16
+ [FIRESTORE_INTERAL_KEYS.UPDATED_AT]: FirestoreTypes.Timestamp;
17
+ };
18
+ export declare class FirestoreMetadataConverter implements InternalFirestoreDataConverter<Metadata, FirestoreSerializedMetadata> {
19
+ toFirestore(data: WithFieldValue<WithoutId<Metadata>>): {
20
+ __deleted: FirestoreTypes.FieldValue | FirestoreTypes.WithFieldValue<boolean>;
21
+ __createdAt: FirestoreTypes.Timestamp;
22
+ __updatedAt: FirestoreTypes.Timestamp;
23
+ };
24
+ fromFirestore(snapshot: FirestoreTypes.QueryDocumentSnapshot<DocumentData, DocumentData>, options: FirestoreTypes.SnapshotOptions): {
25
+ id: string;
26
+ createdAt: Date;
27
+ updatedAt: Date;
28
+ deleted: boolean;
29
+ };
30
+ }
31
+ export declare const queryNotDeleted: <T extends DocumentData, SerializedT extends DocumentData>(query: FirestoreTypes.Query<T, SerializedT>, firestoreQuery: FirestoreQuery<T, SerializedT>, firestoreWhere: FirestoreWhere) => FirestoreTypes.Query<T, SerializedT>;
32
+ export {};
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryNotDeleted = exports.FirestoreMetadataConverter = exports.FIRESTORE_KEYS = void 0;
4
+ var FIRESTORE_INTERAL_KEYS;
5
+ (function (FIRESTORE_INTERAL_KEYS) {
6
+ FIRESTORE_INTERAL_KEYS["DELETED"] = "__deleted";
7
+ FIRESTORE_INTERAL_KEYS["CREATED_AT"] = "__createdAt";
8
+ FIRESTORE_INTERAL_KEYS["UPDATED_AT"] = "__updatedAt";
9
+ })(FIRESTORE_INTERAL_KEYS || (FIRESTORE_INTERAL_KEYS = {}));
10
+ var FIRESTORE_KEYS;
11
+ (function (FIRESTORE_KEYS) {
12
+ FIRESTORE_KEYS["DELETED"] = "deleted";
13
+ FIRESTORE_KEYS["CREATED_AT"] = "createdAt";
14
+ FIRESTORE_KEYS["UPDATED_AT"] = "updatedAt";
15
+ })(FIRESTORE_KEYS || (exports.FIRESTORE_KEYS = FIRESTORE_KEYS = {}));
16
+ class FirestoreMetadataConverter {
17
+ toFirestore(data) {
18
+ return {
19
+ [FIRESTORE_INTERAL_KEYS.DELETED]: data[FIRESTORE_KEYS.DELETED],
20
+ // Cast: Firestore handles conversion from Date to Timestamp internally
21
+ [FIRESTORE_INTERAL_KEYS.CREATED_AT]: data[FIRESTORE_KEYS.CREATED_AT],
22
+ [FIRESTORE_INTERAL_KEYS.UPDATED_AT]: data[FIRESTORE_KEYS.UPDATED_AT],
23
+ };
24
+ }
25
+ fromFirestore(snapshot, options) {
26
+ var _a, _b;
27
+ const data = snapshot.data(options);
28
+ return {
29
+ id: snapshot.ref.id,
30
+ // TODO: add warning in case data type is not as expected
31
+ createdAt: (_a = data[FIRESTORE_INTERAL_KEYS.CREATED_AT]) === null || _a === void 0 ? void 0 : _a.toDate(),
32
+ updatedAt: (_b = data[FIRESTORE_INTERAL_KEYS.UPDATED_AT]) === null || _b === void 0 ? void 0 : _b.toDate(),
33
+ deleted: data[FIRESTORE_INTERAL_KEYS.DELETED],
34
+ };
35
+ }
36
+ }
37
+ exports.FirestoreMetadataConverter = FirestoreMetadataConverter;
38
+ const queryNotDeleted = (query, firestoreQuery, firestoreWhere) => firestoreQuery(query, firestoreWhere(FIRESTORE_INTERAL_KEYS.DELETED, '==', false));
39
+ exports.queryNotDeleted = queryNotDeleted;
@@ -0,0 +1,27 @@
1
+ import { LiveReference, LiveReferenceOptions } from '@data-weave/datamanager';
2
+ import { DocumentData, Firestore, FirestoreReadMode, FirestoreTypes } from './firestoreTypes';
3
+ export interface FirestoreReferenceContext {
4
+ path: string;
5
+ id: string;
6
+ readMode?: FirestoreReadMode;
7
+ snapshotOptions?: FirestoreTypes.SnapshotOptions;
8
+ type: 'reference';
9
+ }
10
+ export interface FirestoreReferenceOptions<T> extends LiveReferenceOptions<T> {
11
+ readMode?: FirestoreReadMode;
12
+ snapshotOptions?: FirestoreTypes.SnapshotOptions;
13
+ errorInterceptor?: (error: unknown, ctx: FirestoreReferenceContext) => void;
14
+ }
15
+ export declare class FirestoreReference<T extends DocumentData, S extends DocumentData> extends LiveReference<T> {
16
+ private readonly firestore;
17
+ private readonly docRef;
18
+ readonly options: FirestoreReferenceOptions<T>;
19
+ private unsubscribeFromSnapshot;
20
+ constructor(firestore: Firestore, docRef: FirestoreTypes.DocumentReference<T, S>, options: FirestoreReferenceOptions<T>);
21
+ resolve(): Promise<T | undefined>;
22
+ get id(): string;
23
+ get path(): string;
24
+ protected onError(error: unknown): void;
25
+ unSubscribe(): void;
26
+ private parseDocumentSnapshot;
27
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FirestoreReference = void 0;
13
+ const datamanager_1 = require("@data-weave/datamanager");
14
+ const utils_1 = require("./utils");
15
+ class FirestoreReference extends datamanager_1.LiveReference {
16
+ constructor(firestore, docRef, options) {
17
+ super(options);
18
+ this.firestore = firestore;
19
+ this.docRef = docRef;
20
+ this.options = options;
21
+ }
22
+ resolve() {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ var _a;
25
+ if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.readMode) === 'realtime') {
26
+ return new Promise((res, reject) => {
27
+ this.unsubscribeFromSnapshot = this.firestore.onSnapshot(this.docRef, documentSnapshot => {
28
+ try {
29
+ this.onUpdate(this.parseDocumentSnapshot(documentSnapshot));
30
+ // TODO: When calling ".resolve()" with realtime listener,
31
+ // the snapshot data might be stale from cache.
32
+ res(this.value);
33
+ }
34
+ catch (error) {
35
+ this.onError(error);
36
+ reject(error);
37
+ }
38
+ }, error => {
39
+ this.onError(error);
40
+ reject(error);
41
+ });
42
+ });
43
+ }
44
+ try {
45
+ const doc = yield this.firestore.getDoc(this.docRef);
46
+ this.onUpdate(this.parseDocumentSnapshot(doc));
47
+ }
48
+ catch (error) {
49
+ this.onError(error);
50
+ throw error;
51
+ }
52
+ return this.value;
53
+ });
54
+ }
55
+ get id() {
56
+ return this.docRef.id;
57
+ }
58
+ get path() {
59
+ return this.docRef.path;
60
+ }
61
+ onError(error) {
62
+ var _a, _b, _c, _d;
63
+ console.error(`FirestoreReference error ${this.docRef.path}`, error);
64
+ (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.errorInterceptor) === null || _b === void 0 ? void 0 : _b.call(_a, error, {
65
+ path: this.docRef.path,
66
+ id: this.docRef.id,
67
+ readMode: (_c = this.options) === null || _c === void 0 ? void 0 : _c.readMode,
68
+ snapshotOptions: (_d = this.options) === null || _d === void 0 ? void 0 : _d.snapshotOptions,
69
+ type: 'reference',
70
+ });
71
+ super.onError(error);
72
+ }
73
+ unSubscribe() {
74
+ var _a;
75
+ (_a = this.unsubscribeFromSnapshot) === null || _a === void 0 ? void 0 : _a.call(this);
76
+ this.setStale();
77
+ }
78
+ parseDocumentSnapshot(docSnapshot) {
79
+ var _a;
80
+ if (!(0, utils_1.checkIfReferenceExists)(docSnapshot))
81
+ throw new Error(`Document does not exist ${this.docRef.path}`);
82
+ return docSnapshot.data((_a = this.options) === null || _a === void 0 ? void 0 : _a.snapshotOptions);
83
+ }
84
+ }
85
+ exports.FirestoreReference = FirestoreReference;