@hubert.legec/firestore-storage-nest 0.0.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.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/core.d.ts +14 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +36 -0
- package/dist/core.js.map +1 -0
- package/dist/entity-repository.d.ts +27 -0
- package/dist/entity-repository.d.ts.map +1 -0
- package/dist/entity-repository.js +67 -0
- package/dist/entity-repository.js.map +1 -0
- package/dist/firestore-memory.d.ts +7 -0
- package/dist/firestore-memory.d.ts.map +1 -0
- package/dist/firestore-memory.js +9 -0
- package/dist/firestore-memory.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/model-transformer.d.ts +6 -0
- package/dist/model-transformer.d.ts.map +1 -0
- package/dist/model-transformer.js +3 -0
- package/dist/model-transformer.js.map +1 -0
- package/dist/module-with-memory.d.ts +6 -0
- package/dist/module-with-memory.d.ts.map +1 -0
- package/dist/module-with-memory.js +16 -0
- package/dist/module-with-memory.js.map +1 -0
- package/dist/path-ids.d.ts +13 -0
- package/dist/path-ids.d.ts.map +1 -0
- package/dist/path-ids.js +26 -0
- package/dist/path-ids.js.map +1 -0
- package/dist/testing.d.ts +20 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +56 -0
- package/dist/testing.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hubert Legęć
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# firestore-storage-nest
|
|
2
|
+
|
|
3
|
+
A **NestJS module** for easy integration with [Firestore](https://cloud.google.com/firestore) in NestJS applications, built for use with [firestore-storage](https://www.npmjs.com/package/firestore-storage) v7. It provides a shared Firestore instance via dependency injection and, for tests, an **in-memory Firestore** so you can run tests without the Firebase Emulator.
|
|
4
|
+
|
|
5
|
+
Published on [npm](https://www.npmjs.com/package/firestore-storage-nest).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Production**: Register Firestore once with `forRootAsync` and inject it anywhere with `@Inject(FIRESTORE)`.
|
|
10
|
+
- **Testing**: Use `withMemoryStorage()` for an in-memory Firestore (powered by [@firebase-bridge/firestore-admin](https://www.npmjs.com/package/@firebase-bridge/firestore-admin), Apache-2.0). No emulator required.
|
|
11
|
+
- **Repository helpers**: `EntityRepository`, `ModelTransformer`, and path helpers (`pathToDocumentIds`, `pathToCollectionIds`) for building repositories on top of firestore-storage v7.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add firestore-storage-nest firestore-storage firestore-storage-core @google-cloud/firestore
|
|
17
|
+
# or
|
|
18
|
+
npm i firestore-storage-nest firestore-storage firestore-storage-core @google-cloud/firestore
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
For tests using the built-in in-memory Firestore, also install the optional dependency:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add -D @firebase-bridge/firestore-admin
|
|
25
|
+
# or rely on the package’s optional dependency
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Peer dependencies:** `@nestjs/common` (≥10), `@google-cloud/firestore` (≥6), `firestore-storage` (≥7), `firestore-storage-core` (≥7).
|
|
29
|
+
|
|
30
|
+
## Production usage
|
|
31
|
+
|
|
32
|
+
Register the module with your Firestore instance (e.g. from `firebase-admin`):
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { Module } from "@nestjs/common";
|
|
36
|
+
import { FirestoreStorageNestModule, FIRESTORE } from "firestore-storage-nest";
|
|
37
|
+
import { getFirestore } from "firebase-admin/firestore";
|
|
38
|
+
|
|
39
|
+
@Module({
|
|
40
|
+
imports: [
|
|
41
|
+
{
|
|
42
|
+
...FirestoreStorageNestModule.forRootAsync({
|
|
43
|
+
useFactory: () => getFirestore(),
|
|
44
|
+
}),
|
|
45
|
+
global: true,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
export class AppModule {}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Inject the Firestore instance where needed:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
56
|
+
import { FIRESTORE } from "firestore-storage-nest";
|
|
57
|
+
import type { Firestore } from "@google-cloud/firestore";
|
|
58
|
+
|
|
59
|
+
@Injectable()
|
|
60
|
+
export class MyService {
|
|
61
|
+
constructor(@Inject(FIRESTORE) private readonly firestore: Firestore) {}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Testing with in-memory Firestore
|
|
66
|
+
|
|
67
|
+
Use the built-in in-memory Firestore so tests don’t need the Firebase Emulator:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { Test } from "@nestjs/testing";
|
|
71
|
+
import {
|
|
72
|
+
FirestoreStorageNestModule,
|
|
73
|
+
TestFirestoreClearService,
|
|
74
|
+
} from "firestore-storage-nest";
|
|
75
|
+
|
|
76
|
+
const module = await Test.createTestingModule({
|
|
77
|
+
imports: [FirestoreStorageNestModule.withMemoryStorage()],
|
|
78
|
+
// ... your providers
|
|
79
|
+
}).compile();
|
|
80
|
+
|
|
81
|
+
// In beforeEach: clear collections between tests
|
|
82
|
+
const clearService = module.get(TestFirestoreClearService);
|
|
83
|
+
await clearService.clear("users");
|
|
84
|
+
await clearService.clear("posts");
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For a custom in-memory instance, use:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
FirestoreStorageNestModule.withMemoryStorage({
|
|
91
|
+
useFactory: () => yourCustomFirestore,
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`createMemoryFirestore()` from this package returns a real Firestore-compatible instance (from `@firebase-bridge/firestore-admin`).
|
|
96
|
+
|
|
97
|
+
### Running tests against the Firebase Emulator
|
|
98
|
+
|
|
99
|
+
To confirm compatibility with real Firestore, run the same test suite against the [Firestore emulator](https://firebase.google.com/docs/emulator_suite/connect_firestore):
|
|
100
|
+
|
|
101
|
+
1. Start the emulator: `firebase emulators:start --only firestore` (default port 8080).
|
|
102
|
+
2. Run tests with the emulator: `FIRESTORE_EMULATOR_HOST=localhost:8080 pnpm test` (or `npm run test:emulator` if you add that script).
|
|
103
|
+
|
|
104
|
+
The package’s integration tests use a helper that switches to the emulator when `FIRESTORE_EMULATOR_HOST` is set, so the same tests run with in-memory Firestore by default and with the emulator when that env var is set.
|
|
105
|
+
|
|
106
|
+
## Repository helpers
|
|
107
|
+
|
|
108
|
+
- **`EntityRepository<E, M>`** – Abstract base for entity repositories (varargs API over firestore-storage v7).
|
|
109
|
+
- **`ModelTransformer<E, M>`** – Interface for converting between entity `E` and firestore-storage model `M`.
|
|
110
|
+
- **`pathToDocumentIds(path, ids)`** / **`pathToCollectionIds(path, ids)`** – Build v7 `DocumentIds` / `CollectionIds` from an ordered list of ids.
|
|
111
|
+
- **`Id`** – Type alias for entity id (string).
|
|
112
|
+
|
|
113
|
+
## API summary
|
|
114
|
+
|
|
115
|
+
| Export | Description |
|
|
116
|
+
|--------|-------------|
|
|
117
|
+
| `FIRESTORE` | Injection token for the Firestore instance |
|
|
118
|
+
| `FirestoreStorageNestModule` | Module with `forRootAsync(options)` and `withMemoryStorage(options?)` |
|
|
119
|
+
| `TestFirestoreClearService` | Service to clear collections in tests |
|
|
120
|
+
| `createMemoryFirestore()` | Returns an in-memory Firestore instance |
|
|
121
|
+
| `EntityRepository`, `ModelTransformer`, `pathToDocumentIds`, `pathToCollectionIds`, `Id` | Repository and path helpers |
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
From the repo:
|
|
126
|
+
|
|
127
|
+
- `pnpm test` – run tests (in-memory Firestore).
|
|
128
|
+
- `pnpm test:emulator` – run the same tests against the Firestore emulator (set `FIRESTORE_EMULATOR_HOST=localhost:8080`; start the emulator first).
|
|
129
|
+
|
|
130
|
+
The tests in `test/` demonstrate root and nested entity CRUD (create, update, fetch, list, delete) using `EntityRepository`, `withMemoryStorage`, and `TestFirestoreClearService`.
|
|
131
|
+
|
|
132
|
+
### Releasing
|
|
133
|
+
|
|
134
|
+
Releases are automated via GitHub Actions (`.github/workflows/release.yml`). To publish:
|
|
135
|
+
|
|
136
|
+
1. Set the version in `package.json` (e.g. `0.0.2`).
|
|
137
|
+
2. Commit, push to `main`, then create and push a tag matching that version: `git tag v0.0.2 && git push origin v0.0.2`.
|
|
138
|
+
|
|
139
|
+
The workflow will: publish the package to npm (using the version in `package.json`), create a GitHub Release from the tag with generated release notes, then bump the version on `main` (patch increment) and push the commit.
|
|
140
|
+
|
|
141
|
+
**Required:** Add an `NPM_TOKEN` repository secret (Settings → Secrets and variables → Actions). Use an npm [automation token](https://docs.npmjs.com/creating-and-viewing-access-tokens) or granular access token with “Publish packages” permission.
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
MIT
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core NestJS module for Firestore (production).
|
|
3
|
+
*/
|
|
4
|
+
import { DynamicModule } from "@nestjs/common";
|
|
5
|
+
import type { Firestore } from "@google-cloud/firestore";
|
|
6
|
+
export declare const FIRESTORE: unique symbol;
|
|
7
|
+
export interface FirestoreStorageModuleAsyncOptions {
|
|
8
|
+
useFactory: () => Firestore;
|
|
9
|
+
inject?: unknown[];
|
|
10
|
+
}
|
|
11
|
+
export declare class FirestoreStorageNestModule {
|
|
12
|
+
static forRootAsync(options: FirestoreStorageModuleAsyncOptions): DynamicModule;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAA0B,MAAM,gBAAgB,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,eAAO,MAAM,SAAS,eAAsB,CAAC;AAE7C,MAAM,WAAW,kCAAkC;IACjD,UAAU,EAAE,MAAM,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,qBACa,0BAA0B;IACrC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,kCAAkC,GAAG,aAAa;CAchF"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var FirestoreStorageNestModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.FirestoreStorageNestModule = exports.FIRESTORE = void 0;
|
|
11
|
+
/**
|
|
12
|
+
* Core NestJS module for Firestore (production).
|
|
13
|
+
*/
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
exports.FIRESTORE = Symbol("FIRESTORE");
|
|
16
|
+
let FirestoreStorageNestModule = FirestoreStorageNestModule_1 = class FirestoreStorageNestModule {
|
|
17
|
+
static forRootAsync(options) {
|
|
18
|
+
return {
|
|
19
|
+
module: FirestoreStorageNestModule_1,
|
|
20
|
+
global: false,
|
|
21
|
+
providers: [
|
|
22
|
+
{
|
|
23
|
+
provide: exports.FIRESTORE,
|
|
24
|
+
useFactory: options.useFactory,
|
|
25
|
+
inject: (options.inject ?? []),
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
exports: [exports.FIRESTORE],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.FirestoreStorageNestModule = FirestoreStorageNestModule;
|
|
33
|
+
exports.FirestoreStorageNestModule = FirestoreStorageNestModule = FirestoreStorageNestModule_1 = __decorate([
|
|
34
|
+
(0, common_1.Module)({})
|
|
35
|
+
], FirestoreStorageNestModule);
|
|
36
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":";;;;;;;;;;AAAA;;GAEG;AACH,2CAAuE;AAG1D,QAAA,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;AAQtC,IAAM,0BAA0B,kCAAhC,MAAM,0BAA0B;IACrC,MAAM,CAAC,YAAY,CAAC,OAA2C;QAC7D,OAAO;YACL,MAAM,EAAE,4BAA0B;YAClC,MAAM,EAAE,KAAK;YACb,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,iBAAS;oBAClB,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAqB;iBACnD;aACF;YACD,OAAO,EAAE,CAAC,iBAAS,CAAC;SACrB,CAAC;IACJ,CAAC;CACF,CAAA;AAfY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,0BAA0B,CAetC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BaseRepository, Query } from "firestore-storage";
|
|
2
|
+
import type { BaseModel, CollectionPath, ModelQuery } from "firestore-storage-core";
|
|
3
|
+
import type { ModelTransformer } from "./model-transformer";
|
|
4
|
+
type Path = CollectionPath<string, string, void | object>;
|
|
5
|
+
/**
|
|
6
|
+
* Entity id type (string).
|
|
7
|
+
* Public API of EntityRepository (save, delete, findById, findAllById, list, query, generateId)
|
|
8
|
+
* is unchanged from master: same method names and signatures for all classes extending it.
|
|
9
|
+
*/
|
|
10
|
+
export type Id = string;
|
|
11
|
+
export declare abstract class EntityRepository<E, M extends BaseModel> {
|
|
12
|
+
protected readonly modelRepository: BaseRepository<M, Path>;
|
|
13
|
+
protected readonly modelTransformer: ModelTransformer<E, M>;
|
|
14
|
+
protected constructor(modelRepository: BaseRepository<M, Path>, modelTransformer: ModelTransformer<E, M>);
|
|
15
|
+
protected getPath(): Path;
|
|
16
|
+
save(value: E, ...ids: Id[]): Promise<E>;
|
|
17
|
+
delete(id: Id, ...ids: Id[]): Promise<void>;
|
|
18
|
+
findById(id: Id, subcollectionId?: Id): Promise<E | null>;
|
|
19
|
+
findAllById(ids: Id[]): Promise<E[]>;
|
|
20
|
+
list(attributes?: ModelQuery<M>, ...ids: Id[]): Promise<E[]>;
|
|
21
|
+
query(cb: (qb: Query<M>) => Query<M>, ...ids: Id[]): Promise<E[]>;
|
|
22
|
+
generateId(): string;
|
|
23
|
+
/** Override in subclasses to filter out models (e.g. deleted). */
|
|
24
|
+
protected modelCustomFilter(_model: M): boolean;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=entity-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-repository.d.ts","sourceRoot":"","sources":["../src/entity-repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,KAAK,IAAI,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;AAE1D;;;;GAIG;AACH,MAAM,MAAM,EAAE,GAAG,MAAM,CAAC;AAExB,8BAAsB,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,SAAS;IAEzD,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC;IAC3D,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC;IAF7D,SAAS,aACY,eAAe,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,EACxC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC;IAG7D,SAAS,CAAC,OAAO,IAAI,IAAI;IAInB,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;IAO9C,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IASzD,WAAW,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAYpC,IAAI,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAM5D,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IASvE,UAAU;IAIV,kEAAkE;IAElE,SAAS,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO;CAGhD"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntityRepository = void 0;
|
|
4
|
+
const path_ids_1 = require("./path-ids");
|
|
5
|
+
class EntityRepository {
|
|
6
|
+
modelRepository;
|
|
7
|
+
modelTransformer;
|
|
8
|
+
constructor(modelRepository, modelTransformer) {
|
|
9
|
+
this.modelRepository = modelRepository;
|
|
10
|
+
this.modelTransformer = modelTransformer;
|
|
11
|
+
}
|
|
12
|
+
getPath() {
|
|
13
|
+
return this.modelRepository.getPath();
|
|
14
|
+
}
|
|
15
|
+
async save(value, ...ids) {
|
|
16
|
+
const model = this.modelTransformer.toModel(value);
|
|
17
|
+
const collectionIds = (0, path_ids_1.pathToCollectionIds)(this.getPath(), ids);
|
|
18
|
+
const saved = await this.modelRepository.write(model, collectionIds);
|
|
19
|
+
return this.modelTransformer.fromModel(saved);
|
|
20
|
+
}
|
|
21
|
+
delete(id, ...ids) {
|
|
22
|
+
const documentIds = (0, path_ids_1.pathToDocumentIds)(this.getPath(), [...ids, id]);
|
|
23
|
+
return this.modelRepository.delete(documentIds);
|
|
24
|
+
}
|
|
25
|
+
async findById(id, subcollectionId) {
|
|
26
|
+
const documentIds = (0, path_ids_1.pathToDocumentIds)(this.getPath(), subcollectionId !== undefined ? [subcollectionId, id] : [id]);
|
|
27
|
+
const model = await this.modelRepository.findById(documentIds);
|
|
28
|
+
if (!model || !this.modelCustomFilter(model)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return this.modelTransformer.fromModel(model);
|
|
32
|
+
}
|
|
33
|
+
async findAllById(ids) {
|
|
34
|
+
if (ids.length === 0) {
|
|
35
|
+
return Promise.resolve([]);
|
|
36
|
+
}
|
|
37
|
+
const collectionIds = (0, path_ids_1.pathToCollectionIds)(this.getPath(), []);
|
|
38
|
+
const result = await this.modelRepository.findAll(ids, collectionIds);
|
|
39
|
+
return result
|
|
40
|
+
.filter((m) => !!m)
|
|
41
|
+
.filter((m) => this.modelCustomFilter(m))
|
|
42
|
+
.map((m) => this.modelTransformer.fromModel(m));
|
|
43
|
+
}
|
|
44
|
+
async list(attributes, ...ids) {
|
|
45
|
+
const collectionIds = (0, path_ids_1.pathToCollectionIds)(this.getPath(), ids);
|
|
46
|
+
const result = await this.modelRepository.list(attributes ?? null, collectionIds);
|
|
47
|
+
return result.filter((o) => this.modelCustomFilter(o)).map((m) => this.modelTransformer.fromModel(m));
|
|
48
|
+
}
|
|
49
|
+
async query(cb, ...ids) {
|
|
50
|
+
const collectionIds = (0, path_ids_1.pathToCollectionIds)(this.getPath(), ids);
|
|
51
|
+
const result = await this.modelRepository.query(cb, collectionIds);
|
|
52
|
+
return result
|
|
53
|
+
.filter((m) => !!m)
|
|
54
|
+
.filter((m) => this.modelCustomFilter(m))
|
|
55
|
+
.map((m) => this.modelTransformer.fromModel(m));
|
|
56
|
+
}
|
|
57
|
+
generateId() {
|
|
58
|
+
return this.modelRepository.generateId();
|
|
59
|
+
}
|
|
60
|
+
/** Override in subclasses to filter out models (e.g. deleted). */
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
62
|
+
modelCustomFilter(_model) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.EntityRepository = EntityRepository;
|
|
67
|
+
//# sourceMappingURL=entity-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-repository.js","sourceRoot":"","sources":["../src/entity-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory Firestore for tests. Uses @firebase-bridge/firestore-admin (Apache-2.0).
|
|
3
|
+
* Returns a real Firestore instance compatible with firebase-admin.
|
|
4
|
+
*/
|
|
5
|
+
import type { Firestore } from "@google-cloud/firestore";
|
|
6
|
+
export declare function createMemoryFirestore(): Firestore;
|
|
7
|
+
//# sourceMappingURL=firestore-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firestore-memory.d.ts","sourceRoot":"","sources":["../src/firestore-memory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGzD,wBAAgB,qBAAqB,IAAI,SAAS,CAGjD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMemoryFirestore = createMemoryFirestore;
|
|
4
|
+
const firestore_admin_1 = require("@firebase-bridge/firestore-admin");
|
|
5
|
+
function createMemoryFirestore() {
|
|
6
|
+
const env = new firestore_admin_1.FirestoreMock();
|
|
7
|
+
return env.createDatabase().firestore();
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=firestore-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firestore-memory.js","sourceRoot":"","sources":["../src/firestore-memory.ts"],"names":[],"mappings":";;AAOA,sDAGC;AALD,sEAAiE;AAEjE,SAAgB,qBAAqB;IACnC,MAAM,GAAG,GAAG,IAAI,+BAAa,EAAE,CAAC;IAChC,OAAO,GAAG,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE,CAAC;AAC1C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NestJS module for Firestore (firestore-storage v7 compatible).
|
|
3
|
+
* Production: forRootAsync, FIRESTORE. Testing: withMemoryStorage, TestFirestoreClearService, createMemoryFirestore.
|
|
4
|
+
* Repository helpers: EntityRepository, path-ids, ModelTransformer.
|
|
5
|
+
*/
|
|
6
|
+
export { FIRESTORE, type FirestoreStorageModuleAsyncOptions } from "./core";
|
|
7
|
+
export { EntityRepository, type Id } from "./entity-repository";
|
|
8
|
+
export { createMemoryFirestore } from "./firestore-memory";
|
|
9
|
+
export type { ModelTransformer } from "./model-transformer";
|
|
10
|
+
export { FirestoreStorageNestModule } from "./module-with-memory";
|
|
11
|
+
export { pathToCollectionIds, pathToDocumentIds } from "./path-ids";
|
|
12
|
+
export { TestFirestoreClearService, withMemoryStorage, type TestFirestoreClear, type WithMemoryStorageOptions, } from "./testing";
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,KAAK,kCAAkC,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withMemoryStorage = exports.TestFirestoreClearService = exports.pathToDocumentIds = exports.pathToCollectionIds = exports.FirestoreStorageNestModule = exports.createMemoryFirestore = exports.EntityRepository = exports.FIRESTORE = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* NestJS module for Firestore (firestore-storage v7 compatible).
|
|
6
|
+
* Production: forRootAsync, FIRESTORE. Testing: withMemoryStorage, TestFirestoreClearService, createMemoryFirestore.
|
|
7
|
+
* Repository helpers: EntityRepository, path-ids, ModelTransformer.
|
|
8
|
+
*/
|
|
9
|
+
var core_1 = require("./core");
|
|
10
|
+
Object.defineProperty(exports, "FIRESTORE", { enumerable: true, get: function () { return core_1.FIRESTORE; } });
|
|
11
|
+
var entity_repository_1 = require("./entity-repository");
|
|
12
|
+
Object.defineProperty(exports, "EntityRepository", { enumerable: true, get: function () { return entity_repository_1.EntityRepository; } });
|
|
13
|
+
var firestore_memory_1 = require("./firestore-memory");
|
|
14
|
+
Object.defineProperty(exports, "createMemoryFirestore", { enumerable: true, get: function () { return firestore_memory_1.createMemoryFirestore; } });
|
|
15
|
+
var module_with_memory_1 = require("./module-with-memory");
|
|
16
|
+
Object.defineProperty(exports, "FirestoreStorageNestModule", { enumerable: true, get: function () { return module_with_memory_1.FirestoreStorageNestModule; } });
|
|
17
|
+
var path_ids_1 = require("./path-ids");
|
|
18
|
+
Object.defineProperty(exports, "pathToCollectionIds", { enumerable: true, get: function () { return path_ids_1.pathToCollectionIds; } });
|
|
19
|
+
Object.defineProperty(exports, "pathToDocumentIds", { enumerable: true, get: function () { return path_ids_1.pathToDocumentIds; } });
|
|
20
|
+
var testing_1 = require("./testing");
|
|
21
|
+
Object.defineProperty(exports, "TestFirestoreClearService", { enumerable: true, get: function () { return testing_1.TestFirestoreClearService; } });
|
|
22
|
+
Object.defineProperty(exports, "withMemoryStorage", { enumerable: true, get: function () { return testing_1.withMemoryStorage; } });
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACH,+BAA4E;AAAnE,iGAAA,SAAS,OAAA;AAClB,yDAAgE;AAAvD,qHAAA,gBAAgB,OAAA;AACzB,uDAA2D;AAAlD,yHAAA,qBAAqB,OAAA;AAE9B,2DAAkE;AAAzD,gIAAA,0BAA0B,OAAA;AACnC,uCAAoE;AAA3D,+GAAA,mBAAmB,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AAC/C,qCAKmB;AAJjB,oHAAA,yBAAyB,OAAA;AACzB,4GAAA,iBAAiB,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-transformer.d.ts","sourceRoot":"","sources":["../src/model-transformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,SAAS;IACtD,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACvB,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-transformer.js","sourceRoot":"","sources":["../src/model-transformer.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { FirestoreStorageNestModule as BaseModule } from "./core";
|
|
2
|
+
export declare class FirestoreStorageNestModule extends BaseModule {
|
|
3
|
+
/** In-memory Firestore for tests; uses @firebase-bridge/firestore-admin. No emulator required. */
|
|
4
|
+
static withMemoryStorage(): import("@nestjs/common").DynamicModule;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=module-with-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-with-memory.d.ts","sourceRoot":"","sources":["../src/module-with-memory.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,0BAA0B,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAIlE,qBAAa,0BAA2B,SAAQ,UAAU;IACxD,kGAAkG;IAClG,MAAM,CAAC,iBAAiB;CAKzB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FirestoreStorageNestModule = void 0;
|
|
4
|
+
const core_1 = require("./core");
|
|
5
|
+
const firestore_memory_1 = require("./firestore-memory");
|
|
6
|
+
const testing_1 = require("./testing");
|
|
7
|
+
class FirestoreStorageNestModule extends core_1.FirestoreStorageNestModule {
|
|
8
|
+
/** In-memory Firestore for tests; uses @firebase-bridge/firestore-admin. No emulator required. */
|
|
9
|
+
static withMemoryStorage() {
|
|
10
|
+
return (0, testing_1.withMemoryStorage)({
|
|
11
|
+
useFactory: () => (0, firestore_memory_1.createMemoryFirestore)(),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.FirestoreStorageNestModule = FirestoreStorageNestModule;
|
|
16
|
+
//# sourceMappingURL=module-with-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-with-memory.js","sourceRoot":"","sources":["../src/module-with-memory.ts"],"names":[],"mappings":";;;AAKA,iCAAkE;AAClE,yDAA2D;AAC3D,uCAA8C;AAE9C,MAAa,0BAA2B,SAAQ,iCAAU;IACxD,kGAAkG;IAClG,MAAM,CAAC,iBAAiB;QACtB,OAAO,IAAA,2BAAiB,EAAC;YACvB,UAAU,EAAE,GAAc,EAAE,CAAC,IAAA,wCAAqB,GAAE;SACrD,CAAC,CAAC;IACL,CAAC;CACF;AAPD,gEAOC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CollectionPath } from "firestore-storage-core";
|
|
2
|
+
type Path = CollectionPath<string, string, void | object>;
|
|
3
|
+
/**
|
|
4
|
+
* Build DocumentIds object from path and ordered id values (root to leaf).
|
|
5
|
+
* Depends on firestore-storage-core CollectionPath shape (idKey, parent); see getOrderedIdKeys.
|
|
6
|
+
*/
|
|
7
|
+
export declare function pathToDocumentIds(path: Path, ids: string[]): Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Build CollectionIds object from path and parent id values (no document id).
|
|
10
|
+
*/
|
|
11
|
+
export declare function pathToCollectionIds(path: Path, ids: string[]): Record<string, string>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=path-ids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-ids.d.ts","sourceRoot":"","sources":["../src/path-ids.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,KAAK,IAAI,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGnF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGrF"}
|
package/dist/path-ids.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pathToDocumentIds = pathToDocumentIds;
|
|
4
|
+
exports.pathToCollectionIds = pathToCollectionIds;
|
|
5
|
+
/**
|
|
6
|
+
* Build DocumentIds object from path and ordered id values (root to leaf).
|
|
7
|
+
* Depends on firestore-storage-core CollectionPath shape (idKey, parent); see getOrderedIdKeys.
|
|
8
|
+
*/
|
|
9
|
+
function pathToDocumentIds(path, ids) {
|
|
10
|
+
const keys = getOrderedIdKeys(path);
|
|
11
|
+
return Object.fromEntries(keys.map((k, i) => [k, ids[i] ?? ""]));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build CollectionIds object from path and parent id values (no document id).
|
|
15
|
+
*/
|
|
16
|
+
function pathToCollectionIds(path, ids) {
|
|
17
|
+
const p = path;
|
|
18
|
+
return pathToDocumentIds(p.parent, ids);
|
|
19
|
+
}
|
|
20
|
+
function getOrderedIdKeys(path) {
|
|
21
|
+
if (!path)
|
|
22
|
+
return [];
|
|
23
|
+
const p = path;
|
|
24
|
+
return [...getOrderedIdKeys(p.parent), p.idKey];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=path-ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-ids.js","sourceRoot":"","sources":["../src/path-ids.ts"],"names":[],"mappings":";;AAQA,8CAGC;AAKD,kDAGC;AAfD;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,IAAU,EAAE,GAAa;IACzD,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB,CAAC,IAAU,EAAE,GAAa;IAC3D,MAAM,CAAC,GAAG,IAAoC,CAAC;IAC/C,OAAO,iBAAiB,CAAC,CAAC,CAAC,MAAc,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAsB;IAC9C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,CAAC,GAAG,IAAmD,CAAC;IAC9D,OAAO,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Testing utilities for FirestoreStorageNestModule.
|
|
3
|
+
* Consumers pass useFactory that returns in-memory Firestore.
|
|
4
|
+
*/
|
|
5
|
+
import type { Firestore } from "@google-cloud/firestore";
|
|
6
|
+
import { DynamicModule } from "@nestjs/common";
|
|
7
|
+
/** Interface for test helper that clears a collection by path. */
|
|
8
|
+
export interface TestFirestoreClear {
|
|
9
|
+
clear(path: string): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare class TestFirestoreClearService implements TestFirestoreClear {
|
|
12
|
+
private readonly firestore;
|
|
13
|
+
constructor(firestore: Firestore);
|
|
14
|
+
clear(path: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export interface WithMemoryStorageOptions {
|
|
17
|
+
useFactory: () => Firestore;
|
|
18
|
+
}
|
|
19
|
+
export declare function withMemoryStorage(options: WithMemoryStorageOptions): DynamicModule;
|
|
20
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,SAAS,EAAyB,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAsB,MAAM,gBAAgB,CAAC;AAGnE,kEAAkE;AAClE,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,qBACa,yBAA0B,YAAW,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAE9D,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAgBzC;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,SAAS,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,aAAa,CAOlF"}
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.TestFirestoreClearService = void 0;
|
|
16
|
+
exports.withMemoryStorage = withMemoryStorage;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const core_1 = require("./core");
|
|
19
|
+
let TestFirestoreClearService = class TestFirestoreClearService {
|
|
20
|
+
firestore;
|
|
21
|
+
constructor(firestore) {
|
|
22
|
+
this.firestore = firestore;
|
|
23
|
+
}
|
|
24
|
+
async clear(path) {
|
|
25
|
+
const col = this.firestore.collection(path);
|
|
26
|
+
let docs = [];
|
|
27
|
+
try {
|
|
28
|
+
const snapshot = await col.get();
|
|
29
|
+
docs = snapshot.docs ?? [];
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (err instanceof TypeError && String(err.message).includes("undefined or null")) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
for (const doc of docs) {
|
|
38
|
+
await doc.ref.delete();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
exports.TestFirestoreClearService = TestFirestoreClearService;
|
|
43
|
+
exports.TestFirestoreClearService = TestFirestoreClearService = __decorate([
|
|
44
|
+
(0, common_1.Injectable)(),
|
|
45
|
+
__param(0, (0, common_1.Inject)(core_1.FIRESTORE)),
|
|
46
|
+
__metadata("design:paramtypes", [Function])
|
|
47
|
+
], TestFirestoreClearService);
|
|
48
|
+
function withMemoryStorage(options) {
|
|
49
|
+
return {
|
|
50
|
+
module: core_1.FirestoreStorageNestModule,
|
|
51
|
+
global: false,
|
|
52
|
+
providers: [{ provide: core_1.FIRESTORE, useFactory: options.useFactory }, TestFirestoreClearService],
|
|
53
|
+
exports: [core_1.FIRESTORE, TestFirestoreClearService],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAuCA,8CAOC;AAzCD,2CAAmE;AACnE,iCAA+D;AAQxD,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;IACY;IAAhD,YAAgD,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAExE,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,IAAI,GAAiC,EAAE,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;YACjC,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,SAAS,IAAI,MAAM,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBAC7F,OAAO;YACT,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;CACF,CAAA;AAnBY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,mBAAU,GAAE;IAEE,WAAA,IAAA,eAAM,EAAC,gBAAS,CAAC,CAAA;;GADnB,yBAAyB,CAmBrC;AAMD,SAAgB,iBAAiB,CAAC,OAAiC;IACjE,OAAO;QACL,MAAM,EAAE,iCAA0B;QAClC,MAAM,EAAE,KAAK;QACb,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAS,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,yBAAyB,CAAC;QAC9F,OAAO,EAAE,CAAC,gBAAS,EAAE,yBAAyB,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hubert.legec/firestore-storage-nest",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A NestJS module that simplifies integration with Firestore database and makes testing easier",
|
|
5
|
+
"author": "Hubert Legęć",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/hubertlegec/firestore-storage-nest.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.build.json",
|
|
15
|
+
"prepare": "tsc -p tsconfig.build.json",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:emulator": "FIRESTORE_EMULATOR_HOST=localhost:8080 vitest run",
|
|
18
|
+
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
19
|
+
"lint:fix": "eslint \"src/**/*.ts\" \"test/**/*.ts\" --fix"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@google-cloud/firestore": ">=6.0.0",
|
|
23
|
+
"@nestjs/common": ">=10.0.0",
|
|
24
|
+
"firestore-storage": ">=7.0.0",
|
|
25
|
+
"firestore-storage-core": ">=7.0.0"
|
|
26
|
+
},
|
|
27
|
+
"optionalDependencies": {
|
|
28
|
+
"@firebase-bridge/firestore-admin": "^0.0.9"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"nestjs",
|
|
32
|
+
"firestore",
|
|
33
|
+
"firebase",
|
|
34
|
+
"firestore-storage",
|
|
35
|
+
"testing",
|
|
36
|
+
"in-memory"
|
|
37
|
+
],
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
40
|
+
"@eslint/js": "^9.17.0",
|
|
41
|
+
"@firebase-bridge/firestore-admin": "^0.0.9",
|
|
42
|
+
"@google-cloud/firestore": "^7.0.0",
|
|
43
|
+
"@nestjs/common": "^11.1.14",
|
|
44
|
+
"@nestjs/core": "^11.1.14",
|
|
45
|
+
"@nestjs/testing": "^11.1.14",
|
|
46
|
+
"reflect-metadata": "^0.2.2",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
48
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
49
|
+
"@vitest/eslint-plugin": "^1.6.0",
|
|
50
|
+
"eslint": "^10.0.2",
|
|
51
|
+
"eslint-config-prettier": "^10.1.8",
|
|
52
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
53
|
+
"globals": "^15.14.0",
|
|
54
|
+
"firebase-admin": "^13.0.0",
|
|
55
|
+
"firestore-storage": "^7.2.1",
|
|
56
|
+
"firestore-storage-core": "^7.0.5",
|
|
57
|
+
"prettier": "^3.8.1",
|
|
58
|
+
"typescript": "^5.9.3",
|
|
59
|
+
"vitest": "^4.1.0"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist"
|
|
63
|
+
],
|
|
64
|
+
"private": false
|
|
65
|
+
}
|