@sneat/api 0.27.14 → 0.27.16

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.
@@ -1,7 +1,7 @@
1
1
  import { runInInjectionContext } from '@angular/core';
2
2
  import { doc, getDoc, query, where, onSnapshot, limit, } from 'firebase/firestore';
3
3
  import { SneatUrlOperationBlocker, } from '@sneat/core';
4
- import { from, map, NEVER, Subject } from 'rxjs';
4
+ import { from, map, NEVER, Observable } from 'rxjs';
5
5
  export class SneatFirestoreService {
6
6
  constructor(injector,
7
7
  // private readonly afs: AngularFirestore,
@@ -27,20 +27,11 @@ export class SneatFirestoreService {
27
27
  if (this.operationBlocker.isBlocked('server-requests')) {
28
28
  return NEVER;
29
29
  }
30
- return runInInjectionContext(this.injector, () => {
31
- const subj = new Subject();
32
- // const snapshots = docSnapshots<Dbo2>(docRef);
33
- onSnapshot(docRef, (snapshot) => subj.next(snapshot), (err) => subj.error(err), () => subj.complete());
34
- // const snapshots = from(getDoc<Dbo2>(docRef));
35
- return subj.asObservable().pipe(
36
- // tap((snapshot) =>
37
- // console.log(
38
- // `SneatFirestoreService.watchByDocRef(${docRef.path}): snapshot:`,
39
- // snapshot,
40
- // ),
41
- // ),
42
- map((changes) => docSnapshotToDto(docRef.id, this.dto2brief, changes)));
43
- });
30
+ return new Observable((subscriber) => runInInjectionContext(this.injector, () => {
31
+ if (this.operationBlocker.isBlocked('server-requests'))
32
+ return;
33
+ return onSnapshot(docRef, (snapshot) => subscriber.next(snapshot), (err) => subscriber.error(err), () => subscriber.complete());
34
+ })).pipe(map((changes) => docSnapshotToDto(docRef.id, this.dto2brief, changes)));
44
35
  }
45
36
  getByDocRef(docRef) {
46
37
  if (this.operationBlocker.isBlocked('server-requests')) {
@@ -54,9 +45,11 @@ export class SneatFirestoreService {
54
45
  }
55
46
  const operator = (f) => f.field.endsWith('IDs') ? 'array-contains' : f.operator;
56
47
  const q = query(collectionRef, ...(queryArgs?.filter || []).map((f) => where(f.field, operator(f), f.value)), ...(queryArgs?.orderBy || []), ...(queryArgs?.limit ? [limit(queryArgs.limit)] : []));
57
- const subj = new Subject();
58
- onSnapshot(q, subj);
59
- return subj;
48
+ return new Observable((subscriber) => {
49
+ if (this.operationBlocker.isBlocked('server-requests'))
50
+ return;
51
+ return onSnapshot(q, subscriber);
52
+ });
60
53
  }
61
54
  watchByFilter(collectionRef, queryArgs) {
62
55
  return this.watchSnapshotsByFilter(collectionRef, queryArgs).pipe(map((querySnapshot) => {
@@ -72,15 +65,18 @@ export class SneatFirestoreService {
72
65
  const { id } = doc;
73
66
  const dto = doc.data();
74
67
  const brief = dto && this.dto2brief(id, dto);
75
- return {
68
+ const context = {
76
69
  id,
70
+ dbo: dto,
71
+ // Preserve the legacy runtime alias while satisfying the declared contract.
77
72
  dto,
78
73
  brief,
79
- }; // TODO: try to remove this cast
74
+ };
75
+ return context;
80
76
  }
81
77
  }
82
78
  export function docSnapshotToDto(id, dto2brief, docSnapshot) {
83
- if (!docSnapshot.exists) {
79
+ if (!docSnapshot.exists()) {
84
80
  return { id, brief: null, dbo: null };
85
81
  }
86
82
  const dto = docSnapshot.data();
@@ -1 +1 @@
1
- {"version":3,"file":"sneat-firestore.service.js","sourceRoot":"","sources":["../../../../../libs/api/src/lib/sneat-firestore.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injector, runInInjectionContext } from '@angular/core';\nimport {\n doc,\n getDoc,\n CollectionReference,\n DocumentReference,\n DocumentSnapshot,\n query,\n where,\n onSnapshot,\n limit,\n QuerySnapshot,\n QueryOrderByConstraint,\n} from 'firebase/firestore';\nimport {\n IIdAndOptionalBriefAndOptionalDbo,\n SneatUrlOperationBlocker,\n} from '@sneat/core';\nimport { WhereFilterOp } from '@firebase/firestore-types';\nimport { INavContext } from '@sneat/core';\nimport { from, map, NEVER, Observable, Subject } from 'rxjs';\n\nexport interface IFilter {\n readonly field: string;\n readonly operator: WhereFilterOp;\n readonly value: unknown;\n}\n\nexport interface IQueryArgs {\n readonly limit?: number;\n readonly filter?: readonly IFilter[];\n readonly orderBy?: readonly QueryOrderByConstraint[];\n}\n\nexport class SneatFirestoreService<Brief, Dbo extends Brief> {\n private readonly operationBlocker: SneatUrlOperationBlocker;\n\n constructor(\n private readonly injector: Injector,\n // private readonly afs: AngularFirestore,\n private readonly dto2brief: (id: string, dto: Dbo) => Brief = (\n id: string,\n dto: Dbo,\n ) => ({\n ...(dto as unknown as Brief),\n id,\n }),\n ) {\n if (!dto2brief) {\n throw new Error('dto2brief is required');\n }\n this.operationBlocker = injector.get(SneatUrlOperationBlocker);\n }\n\n watchByID<Dbo2 extends Dbo>(\n collection: CollectionReference<Dbo2>,\n id: string,\n ): Observable<IIdAndOptionalBriefAndOptionalDbo<Brief, Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n const docRef = runInInjectionContext(this.injector, () =>\n doc(collection, id),\n );\n return this.watchByDocRef(docRef);\n }\n\n watchByDocRef<Dbo2 extends Dbo>(\n docRef: DocumentReference<Dbo2>,\n ): Observable<IIdAndOptionalBriefAndOptionalDbo<Brief, Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n return runInInjectionContext(this.injector, () => {\n const subj = new Subject<DocumentSnapshot<Dbo2>>();\n // const snapshots = docSnapshots<Dbo2>(docRef);\n onSnapshot(\n docRef,\n (snapshot) => subj.next(snapshot),\n (err) => subj.error(err),\n () => subj.complete(),\n );\n // const snapshots = from(getDoc<Dbo2>(docRef));\n return subj.asObservable().pipe(\n // tap((snapshot) =>\n // \tconsole.log(\n // \t\t`SneatFirestoreService.watchByDocRef(${docRef.path}): snapshot:`,\n // \t\tsnapshot,\n // \t),\n // ),\n map((changes) =>\n docSnapshotToDto<Brief, Dbo2>(docRef.id, this.dto2brief, changes),\n ),\n );\n });\n }\n\n getByDocRef<Dbo2 extends Dbo>(\n docRef: DocumentReference<Dbo2>,\n ): Observable<INavContext<Brief, Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n return from(getDoc(docRef)).pipe(\n map((changes) =>\n docSnapshotToDto<Brief, Dbo2>(docRef.id, this.dto2brief, changes),\n ),\n );\n }\n\n watchSnapshotsByFilter<Dbo2 extends Dbo>(\n collectionRef: CollectionReference<Dbo2>,\n queryArgs?: IQueryArgs,\n ): Observable<QuerySnapshot<Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n const operator = (f: IFilter) =>\n f.field.endsWith('IDs') ? 'array-contains' : f.operator;\n const q = query(\n collectionRef,\n ...(queryArgs?.filter || []).map((f) =>\n where(f.field, operator(f), f.value),\n ),\n ...(queryArgs?.orderBy || []),\n ...(queryArgs?.limit ? [limit(queryArgs.limit)] : []),\n );\n const subj = new Subject<QuerySnapshot<Dbo2>>();\n onSnapshot(q, subj);\n return subj;\n }\n\n watchByFilter<Dbo2 extends Dbo>(\n collectionRef: CollectionReference<Dbo2>,\n queryArgs?: IQueryArgs,\n ): Observable<INavContext<Brief, Dbo2>[]> {\n return this.watchSnapshotsByFilter(collectionRef, queryArgs).pipe(\n map((querySnapshot) => {\n return querySnapshot.docs.map(this.docSnapshotToContext.bind(this));\n }),\n );\n }\n\n docSnapshotsToContext<Dbo2 extends Dbo>(\n docSnapshots: DocumentSnapshot<Dbo2>[],\n ): INavContext<Brief, Dbo2>[] {\n return docSnapshots.map((doc) => {\n return this.docSnapshotToContext(doc);\n });\n }\n\n docSnapshotToContext<Dbo2 extends Dbo>(\n doc: DocumentSnapshot<Dbo2>,\n ): INavContext<Brief, Dbo2> {\n const { id } = doc;\n const dto: Dbo2 | undefined = doc.data();\n const brief = dto && this.dto2brief(id, dto);\n return {\n id,\n dto,\n brief,\n } as unknown as INavContext<Brief, Dbo2>; // TODO: try to remove this cast\n }\n}\n\nexport function docSnapshotToDto<Brief, Dbo extends Brief>(\n id: string,\n dto2brief: (id: string, dto: Dbo) => Brief,\n docSnapshot: DocumentSnapshot<Dbo>,\n): INavContext<Brief, Dbo> {\n if (!docSnapshot.exists) {\n return { id, brief: null, dbo: null };\n }\n const dto: Dbo | undefined = docSnapshot.data();\n return { id, dbo: dto, brief: dto ? dto2brief(id, dto) : undefined };\n}\n"]}
1
+ {"version":3,"file":"sneat-firestore.service.js","sourceRoot":"","sources":["../../../../../libs/api/src/lib/sneat-firestore.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injector, runInInjectionContext } from '@angular/core';\nimport {\n doc,\n getDoc,\n CollectionReference,\n DocumentReference,\n DocumentSnapshot,\n query,\n where,\n onSnapshot,\n limit,\n QuerySnapshot,\n QueryOrderByConstraint,\n} from 'firebase/firestore';\nimport {\n IIdAndOptionalBriefAndOptionalDbo,\n SneatUrlOperationBlocker,\n} from '@sneat/core';\nimport { WhereFilterOp } from '@firebase/firestore-types';\nimport { INavContext } from '@sneat/core';\nimport { from, map, NEVER, Observable } from 'rxjs';\n\nexport interface IFilter {\n readonly field: string;\n readonly operator: WhereFilterOp;\n readonly value: unknown;\n}\n\nexport interface IQueryArgs {\n readonly limit?: number;\n readonly filter?: readonly IFilter[];\n readonly orderBy?: readonly QueryOrderByConstraint[];\n}\n\nexport class SneatFirestoreService<Brief, Dbo extends Brief> {\n private readonly operationBlocker: SneatUrlOperationBlocker;\n\n constructor(\n private readonly injector: Injector,\n // private readonly afs: AngularFirestore,\n private readonly dto2brief: (id: string, dto: Dbo) => Brief = (\n id: string,\n dto: Dbo,\n ) => ({\n ...(dto as unknown as Brief),\n id,\n }),\n ) {\n if (!dto2brief) {\n throw new Error('dto2brief is required');\n }\n this.operationBlocker = injector.get(SneatUrlOperationBlocker);\n }\n\n watchByID<Dbo2 extends Dbo>(\n collection: CollectionReference<Dbo2>,\n id: string,\n ): Observable<IIdAndOptionalBriefAndOptionalDbo<Brief, Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n const docRef = runInInjectionContext(this.injector, () =>\n doc(collection, id),\n );\n return this.watchByDocRef(docRef);\n }\n\n watchByDocRef<Dbo2 extends Dbo>(\n docRef: DocumentReference<Dbo2>,\n ): Observable<IIdAndOptionalBriefAndOptionalDbo<Brief, Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n return new Observable<DocumentSnapshot<Dbo2>>((subscriber) =>\n runInInjectionContext(this.injector, () => {\n if (this.operationBlocker.isBlocked('server-requests')) return;\n return onSnapshot(\n docRef,\n (snapshot) => subscriber.next(snapshot),\n (err) => subscriber.error(err),\n () => subscriber.complete(),\n );\n }),\n ).pipe(\n map((changes) =>\n docSnapshotToDto<Brief, Dbo2>(docRef.id, this.dto2brief, changes),\n ),\n );\n }\n\n getByDocRef<Dbo2 extends Dbo>(\n docRef: DocumentReference<Dbo2>,\n ): Observable<INavContext<Brief, Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n return from(getDoc(docRef)).pipe(\n map((changes) =>\n docSnapshotToDto<Brief, Dbo2>(docRef.id, this.dto2brief, changes),\n ),\n );\n }\n\n watchSnapshotsByFilter<Dbo2 extends Dbo>(\n collectionRef: CollectionReference<Dbo2>,\n queryArgs?: IQueryArgs,\n ): Observable<QuerySnapshot<Dbo2>> {\n if (this.operationBlocker.isBlocked('server-requests')) {\n return NEVER;\n }\n const operator = (f: IFilter) =>\n f.field.endsWith('IDs') ? 'array-contains' : f.operator;\n const q = query(\n collectionRef,\n ...(queryArgs?.filter || []).map((f) =>\n where(f.field, operator(f), f.value),\n ),\n ...(queryArgs?.orderBy || []),\n ...(queryArgs?.limit ? [limit(queryArgs.limit)] : []),\n );\n return new Observable<QuerySnapshot<Dbo2>>((subscriber) => {\n if (this.operationBlocker.isBlocked('server-requests')) return;\n return onSnapshot(q, subscriber);\n });\n }\n\n watchByFilter<Dbo2 extends Dbo>(\n collectionRef: CollectionReference<Dbo2>,\n queryArgs?: IQueryArgs,\n ): Observable<INavContext<Brief, Dbo2>[]> {\n return this.watchSnapshotsByFilter(collectionRef, queryArgs).pipe(\n map((querySnapshot) => {\n return querySnapshot.docs.map(this.docSnapshotToContext.bind(this));\n }),\n );\n }\n\n docSnapshotsToContext<Dbo2 extends Dbo>(\n docSnapshots: DocumentSnapshot<Dbo2>[],\n ): INavContext<Brief, Dbo2>[] {\n return docSnapshots.map((doc) => {\n return this.docSnapshotToContext(doc);\n });\n }\n\n docSnapshotToContext<Dbo2 extends Dbo>(\n doc: DocumentSnapshot<Dbo2>,\n ): INavContext<Brief, Dbo2> {\n const { id } = doc;\n const dto: Dbo2 | undefined = doc.data();\n const brief = dto && this.dto2brief(id, dto);\n const context = {\n id,\n dbo: dto,\n // Preserve the legacy runtime alias while satisfying the declared contract.\n dto,\n brief,\n };\n return context;\n }\n}\n\nexport function docSnapshotToDto<Brief, Dbo extends Brief>(\n id: string,\n dto2brief: (id: string, dto: Dbo) => Brief,\n docSnapshot: DocumentSnapshot<Dbo>,\n): INavContext<Brief, Dbo> {\n if (!docSnapshot.exists()) {\n return { id, brief: null, dbo: null };\n }\n const dto: Dbo | undefined = docSnapshot.data();\n return { id, dbo: dto, brief: dto ? dto2brief(id, dto) : undefined };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sneat/api",
3
- "version": "0.27.14",
3
+ "version": "0.27.16",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },