@roit/roit-data-firestore 1.2.33 → 1.2.36
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/dist/archive/ArchiveService.d.ts +41 -0
- package/dist/archive/ArchiveService.js +229 -0
- package/dist/cache/CacheResolver.d.ts +2 -0
- package/dist/cache/CacheResolver.js +66 -0
- package/dist/cache/providers/RedisCacheArchiveProvider.d.ts +20 -0
- package/dist/cache/providers/RedisCacheArchiveProvider.js +137 -0
- package/dist/config/ArchiveConfig.d.ts +16 -0
- package/dist/config/ArchiveConfig.js +30 -0
- package/dist/config/BaseRepository.d.ts +6 -0
- package/dist/config/BaseRepository.js +12 -0
- package/dist/emulator/FirestoreEmuator.js +5 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -2
- package/dist/model/Aggregate.d.ts +1 -1
- package/dist/model/CacheProviders.d.ts +2 -1
- package/dist/model/CacheProviders.js +1 -0
- package/dist/model/Paging.d.ts +1 -1
- package/dist/model/PersistFirestoreReadProps.d.ts +2 -2
- package/dist/model/RepositoryOptions.d.ts +1 -1
- package/dist/model/index.js +5 -1
- package/dist/platform/PlatformTools.js +5 -1
- package/dist/query/ManualQueryHelper.d.ts +4 -0
- package/dist/query/ManualQueryHelper.js +46 -2
- package/dist/query/QueryPredicateFunctionTransform.js +8 -2
- package/dist/template/FunctionFindAllTemplate.txt +19 -0
- package/dist/template/FunctionFindByIdTemplate.txt +11 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/util/TemplateLoading.js +5 -1
- package/package.json +3 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare class ArchiveService {
|
|
2
|
+
private static instance;
|
|
3
|
+
private static readonly lock;
|
|
4
|
+
private static isInitializing;
|
|
5
|
+
private storage;
|
|
6
|
+
private bucketName;
|
|
7
|
+
private config;
|
|
8
|
+
private cacheResolver;
|
|
9
|
+
private projectId;
|
|
10
|
+
private firestore;
|
|
11
|
+
private isInitialized;
|
|
12
|
+
private isDebug;
|
|
13
|
+
/**
|
|
14
|
+
* Construtor privado para prevenir instanciação direta
|
|
15
|
+
*/
|
|
16
|
+
private constructor();
|
|
17
|
+
static getInstance(): Promise<ArchiveService>;
|
|
18
|
+
private initialize;
|
|
19
|
+
static resetInstance(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Verifica se o arquivamento está habilitado
|
|
22
|
+
*/
|
|
23
|
+
isEnabled(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Verifica se um documento está arquivado
|
|
26
|
+
*/
|
|
27
|
+
isDocumentArchived(documentData: any): boolean;
|
|
28
|
+
private pipeline;
|
|
29
|
+
/**
|
|
30
|
+
* Recupera documento arquivado em formato JSON
|
|
31
|
+
*/
|
|
32
|
+
private retrieveJsonDocument;
|
|
33
|
+
/**
|
|
34
|
+
* Verifica se um documento está arquivado e recupera seus dados completos
|
|
35
|
+
*/
|
|
36
|
+
getArchivedDocument(collectionName: string, doc: any): Promise<Record<string, any> | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Limpa o cache de documentos arquivados
|
|
39
|
+
*/
|
|
40
|
+
clearArchivedCache(collectionName?: string, docId?: string): Promise<void>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.ArchiveService = void 0;
|
|
36
|
+
const storage_1 = require("@google-cloud/storage");
|
|
37
|
+
const zlib = __importStar(require("zlib"));
|
|
38
|
+
const stream_1 = require("stream");
|
|
39
|
+
const ArchiveConfig_1 = require("../config/ArchiveConfig");
|
|
40
|
+
const CacheResolver_1 = require("../cache/CacheResolver");
|
|
41
|
+
const CacheProviders_1 = require("../model/CacheProviders");
|
|
42
|
+
const firestore_1 = require("@google-cloud/firestore");
|
|
43
|
+
class ArchiveService {
|
|
44
|
+
/**
|
|
45
|
+
* Construtor privado para prevenir instanciação direta
|
|
46
|
+
*/
|
|
47
|
+
constructor() {
|
|
48
|
+
this.isInitialized = false;
|
|
49
|
+
this.isDebug = Boolean(ArchiveConfig_1.ArchiveConfig.getConfig().debug);
|
|
50
|
+
// Construtor vazio - inicialização será feita em initialize()
|
|
51
|
+
}
|
|
52
|
+
static getInstance() {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
// Se já existe uma instância, retorna ela
|
|
55
|
+
if (ArchiveService.instance && ArchiveService.instance.isInitialized) {
|
|
56
|
+
return ArchiveService.instance;
|
|
57
|
+
}
|
|
58
|
+
// Se está inicializando, aguarda
|
|
59
|
+
if (ArchiveService.isInitializing) {
|
|
60
|
+
yield ArchiveService.lock;
|
|
61
|
+
return ArchiveService.instance;
|
|
62
|
+
}
|
|
63
|
+
// Inicializa a instância
|
|
64
|
+
ArchiveService.isInitializing = true;
|
|
65
|
+
try {
|
|
66
|
+
if (!ArchiveService.instance) {
|
|
67
|
+
ArchiveService.instance = new ArchiveService();
|
|
68
|
+
}
|
|
69
|
+
yield ArchiveService.instance.initialize();
|
|
70
|
+
return ArchiveService.instance;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
ArchiveService.isInitializing = false;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
initialize() {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
if (this.isInitialized) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.config = ArchiveConfig_1.ArchiveConfig.getConfig();
|
|
83
|
+
this.cacheResolver = CacheResolver_1.CacheResolver.getInstance();
|
|
84
|
+
this.projectId = this.config.projectId;
|
|
85
|
+
if (this.isDebug) {
|
|
86
|
+
console.log(`[ARCHIVE SERVICE] Configuração: ${JSON.stringify(this.config)}`);
|
|
87
|
+
}
|
|
88
|
+
if (!this.firestore) {
|
|
89
|
+
this.firestore = new firestore_1.Firestore({
|
|
90
|
+
projectId: 'roit-intern-infra'
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// REGISTRAR O ARCHIVESERVICE COMO REPOSITORY
|
|
94
|
+
this.cacheResolver.addRepository('ArchiveService', {
|
|
95
|
+
cacheExpiresInSeconds: 3600,
|
|
96
|
+
cacheProvider: CacheProviders_1.CacheProviders.REDIS_ARCHIVE
|
|
97
|
+
});
|
|
98
|
+
if (!this.config.enabled) {
|
|
99
|
+
console.log('ArchiveService: Arquivamento desabilitado');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this.storage = new storage_1.Storage();
|
|
103
|
+
this.bucketName = this.config.bucketName;
|
|
104
|
+
if (!this.bucketName) {
|
|
105
|
+
console.warn('ArchiveService: bucket_name não configurado');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
static resetInstance() {
|
|
110
|
+
ArchiveService.instance = null;
|
|
111
|
+
ArchiveService.isInitializing = false;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Verifica se o arquivamento está habilitado
|
|
115
|
+
*/
|
|
116
|
+
isEnabled() {
|
|
117
|
+
return this.config.enabled;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Verifica se um documento está arquivado
|
|
121
|
+
*/
|
|
122
|
+
isDocumentArchived(documentData) {
|
|
123
|
+
return true;
|
|
124
|
+
if (!this.isEnabled()) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return documentData && documentData.fbArchivedAt;
|
|
128
|
+
}
|
|
129
|
+
pipeline(readStream, gunzip, writable) {
|
|
130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
readStream.pipe(gunzip).pipe(writable);
|
|
133
|
+
writable.on('finish', resolve);
|
|
134
|
+
writable.on('error', reject);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Recupera documento arquivado em formato JSON
|
|
140
|
+
*/
|
|
141
|
+
retrieveJsonDocument(collectionName, docId) {
|
|
142
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
143
|
+
try {
|
|
144
|
+
const filePath = `${this.projectId}/${collectionName}/${docId}.json.gz`;
|
|
145
|
+
const bucket = this.storage.bucket(this.bucketName);
|
|
146
|
+
const file = bucket.file(filePath);
|
|
147
|
+
const [exists] = yield file.exists();
|
|
148
|
+
if (!exists) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const readStream = file.createReadStream();
|
|
152
|
+
const gunzip = zlib.createGunzip();
|
|
153
|
+
const chunks = [];
|
|
154
|
+
yield this.pipeline(readStream, gunzip, new stream_1.Writable({
|
|
155
|
+
write(chunk, _enc, cb) {
|
|
156
|
+
chunks.push(chunk);
|
|
157
|
+
cb();
|
|
158
|
+
}
|
|
159
|
+
}));
|
|
160
|
+
const result = Buffer.concat(chunks).toString('utf-8');
|
|
161
|
+
return JSON.parse(result);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
console.warn(`Erro ao recuperar documento JSON arquivado ${collectionName}/${docId}:`, error);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Verifica se um documento está arquivado e recupera seus dados completos
|
|
171
|
+
*/
|
|
172
|
+
getArchivedDocument(collectionName, doc) {
|
|
173
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
if (!this.isEnabled()) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
if (!this.bucketName) {
|
|
178
|
+
console.warn('ArchiveService: bucket_name não configurado, não é possível recuperar documentos arquivados');
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const docId = doc.id;
|
|
182
|
+
// Verificar cache se habilitado
|
|
183
|
+
if (this.config.cache.enabled) {
|
|
184
|
+
const cacheKey = `archived_${collectionName}_${docId}`;
|
|
185
|
+
const cachedData = yield this.cacheResolver.getCacheResult('ArchiveService', 'getArchivedDocument', cacheKey);
|
|
186
|
+
if (cachedData) {
|
|
187
|
+
if (this.isDebug) {
|
|
188
|
+
console.log(`Cache hit para documento arquivado: ${collectionName}/${docId}`);
|
|
189
|
+
}
|
|
190
|
+
return cachedData;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const archivedData = yield this.retrieveJsonDocument(collectionName, docId);
|
|
195
|
+
if (archivedData) {
|
|
196
|
+
// Salvar no cache se habilitado
|
|
197
|
+
if (this.config.cache.enabled) {
|
|
198
|
+
const cacheKey = `archived_${collectionName}_${docId}`;
|
|
199
|
+
yield this.cacheResolver.cacheResult('ArchiveService', 'getArchivedDocument', archivedData, cacheKey);
|
|
200
|
+
if (this.isDebug) {
|
|
201
|
+
console.log(`Documento arquivado cacheado: ${collectionName}/${docId}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return archivedData;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
console.warn(`Erro ao recuperar documento arquivado ${collectionName}/${docId}:`, error);
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Limpa o cache de documentos arquivados
|
|
215
|
+
*/
|
|
216
|
+
clearArchivedCache(collectionName, docId) {
|
|
217
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
+
if (!this.config.cache.enabled) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
yield this.cacheResolver.revokeArchiveCache(collectionName, docId);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.ArchiveService = ArchiveService;
|
|
226
|
+
// Singleton instance
|
|
227
|
+
ArchiveService.instance = null;
|
|
228
|
+
ArchiveService.lock = new Promise((resolve) => resolve());
|
|
229
|
+
ArchiveService.isInitializing = false;
|
|
@@ -12,4 +12,6 @@ export declare class CacheResolver {
|
|
|
12
12
|
getCacheResult(repositoryClassName: string, methodSignature: string, ...paramValue: any[]): Promise<any | null | any[]>;
|
|
13
13
|
revokeCacheFromRepository(repositoryClassName: string): Promise<void>;
|
|
14
14
|
cacheResult(repositoryClassName: string, methodSignature: string, valueToCache: any, ...paramValue: any[]): Promise<boolean>;
|
|
15
|
+
revokeArchiveCache(collectionName?: string, docId?: string): Promise<void>;
|
|
16
|
+
private revokeArchiveCacheForRepository;
|
|
15
17
|
}
|
|
@@ -16,12 +16,16 @@ const RedisCacheProvider_1 = require("./providers/RedisCacheProvider");
|
|
|
16
16
|
const CacheProviders_1 = require("../model/CacheProviders");
|
|
17
17
|
const CurrentEnv_1 = require("../util/CurrentEnv");
|
|
18
18
|
const IsDebug_1 = require("../util/IsDebug");
|
|
19
|
+
const QueryPredicateFunctionTransform_1 = require("../query/QueryPredicateFunctionTransform");
|
|
20
|
+
const RedisCacheArchiveProvider_1 = require("./providers/RedisCacheArchiveProvider");
|
|
21
|
+
const ArchiveConfig_1 = require("../config/ArchiveConfig");
|
|
19
22
|
class CacheResolver {
|
|
20
23
|
constructor() {
|
|
21
24
|
this.repositorys = new Map;
|
|
22
25
|
this.providersImplMap = new Map;
|
|
23
26
|
this.providersImplMap.set(CacheProviders_1.CacheProviders.LOCAL, providers_1.InMemoryCacheProvider);
|
|
24
27
|
this.providersImplMap.set(CacheProviders_1.CacheProviders.REDIS, RedisCacheProvider_1.RedisCacheProvider);
|
|
28
|
+
this.providersImplMap.set(CacheProviders_1.CacheProviders.REDIS_ARCHIVE, RedisCacheArchiveProvider_1.RedisCacheArchiveProvider);
|
|
25
29
|
}
|
|
26
30
|
static getInstance() {
|
|
27
31
|
return this.instance;
|
|
@@ -64,6 +68,8 @@ class CacheResolver {
|
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
yield this.cacheProvider.delete(key);
|
|
71
|
+
// REVOGAR CACHE DO ARCHIVE PARA A MESMA COLLECTION
|
|
72
|
+
yield this.revokeArchiveCacheForRepository(repositoryClassName);
|
|
67
73
|
});
|
|
68
74
|
}
|
|
69
75
|
cacheResult(repositoryClassName, methodSignature, valueToCache, ...paramValue) {
|
|
@@ -84,6 +90,66 @@ class CacheResolver {
|
|
|
84
90
|
return false;
|
|
85
91
|
});
|
|
86
92
|
}
|
|
93
|
+
revokeArchiveCache(collectionName, docId) {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
const repositoryKey = this.buildRepositoryKey('ArchiveService');
|
|
96
|
+
if (!this.repositorys.get('ArchiveService')) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const keys = yield this.cacheProvider.getKeys(`${repositoryKey}`);
|
|
100
|
+
if (!keys || !Array.isArray(keys)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
for (const key of keys) {
|
|
104
|
+
let shouldDelete = false;
|
|
105
|
+
if (collectionName && docId) {
|
|
106
|
+
// Limpar cache de documento específico
|
|
107
|
+
const cacheKey = `archived_${collectionName}_${docId}`;
|
|
108
|
+
shouldDelete = key.includes(`getArchivedDocument:${cacheKey}`);
|
|
109
|
+
}
|
|
110
|
+
else if (collectionName) {
|
|
111
|
+
// Limpar cache de collection específica
|
|
112
|
+
shouldDelete = key.includes(`getArchivedDocument:archived_${collectionName}`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Limpar todo o cache de arquivamento
|
|
116
|
+
shouldDelete = key.includes('getArchivedDocument');
|
|
117
|
+
}
|
|
118
|
+
if (shouldDelete) {
|
|
119
|
+
if (Boolean(ArchiveConfig_1.ArchiveConfig.getConfig().debug)) {
|
|
120
|
+
console.debug('[DEBUG] Archive Cache >', `Removing key: ${key}`);
|
|
121
|
+
}
|
|
122
|
+
yield this.cacheProvider.delete(key);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
revokeArchiveCacheForRepository(repositoryClassName) {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
// Verificar se ArchiveService está registrado
|
|
130
|
+
if (!this.repositorys.get('ArchiveService')) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Obter a collection do repositório que está sendo revogado
|
|
134
|
+
const repositoryOptions = QueryPredicateFunctionTransform_1.QueryPredicateFunctionTransform.classConfig.get(repositoryClassName);
|
|
135
|
+
if (!repositoryOptions || !repositoryOptions.collection) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const collectionName = repositoryOptions.collection;
|
|
139
|
+
// Revogar cache do archive para essa collection
|
|
140
|
+
const archiveKeys = yield this.cacheProvider.getKeys(`${CurrentEnv_1.currentEnv}:ArchiveService`);
|
|
141
|
+
if (archiveKeys && Array.isArray(archiveKeys)) {
|
|
142
|
+
for (const key of archiveKeys) {
|
|
143
|
+
if (key.includes(`getArchivedDocument:archived_${collectionName}`)) {
|
|
144
|
+
if (Boolean(ArchiveConfig_1.ArchiveConfig.getConfig().debug)) {
|
|
145
|
+
console.debug('[DEBUG] Archive Cache >', `Removing archive key: ${key}`);
|
|
146
|
+
}
|
|
147
|
+
yield this.cacheProvider.delete(key);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
87
153
|
}
|
|
88
154
|
exports.CacheResolver = CacheResolver;
|
|
89
155
|
CacheResolver.instance = new CacheResolver;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CacheProvider } from "./CacheProvider";
|
|
2
|
+
export declare class RedisCacheArchiveProvider implements CacheProvider {
|
|
3
|
+
/**
|
|
4
|
+
* Redis module instance loaded dynamically.
|
|
5
|
+
*/
|
|
6
|
+
private redis;
|
|
7
|
+
/**
|
|
8
|
+
* Connected redis client.
|
|
9
|
+
*/
|
|
10
|
+
private client;
|
|
11
|
+
private isRedisReady;
|
|
12
|
+
private isDebug;
|
|
13
|
+
constructor();
|
|
14
|
+
private handleTimeoutError;
|
|
15
|
+
getKeys(query: string): Promise<string[]>;
|
|
16
|
+
getCacheResult(key: string): Promise<any | null>;
|
|
17
|
+
saveCacheResult(key: string, valueToCache: any, ttl: number | undefined): Promise<void>;
|
|
18
|
+
delete(key: string): Promise<void>;
|
|
19
|
+
private loadRedis;
|
|
20
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
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.RedisCacheArchiveProvider = void 0;
|
|
13
|
+
const PlatformTools_1 = require("../../platform/PlatformTools");
|
|
14
|
+
const promise_timeout_1 = require("promise-timeout");
|
|
15
|
+
const ArchiveConfig_1 = require("../../config/ArchiveConfig");
|
|
16
|
+
const REDIS_TIMEOUT = ArchiveConfig_1.ArchiveConfig.getConfig().cache.timeout;
|
|
17
|
+
const REDIS_RECONNECT = ArchiveConfig_1.ArchiveConfig.getConfig().cache.reconnectInSecondsAfterTimeout;
|
|
18
|
+
class RedisCacheArchiveProvider {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.isRedisReady = false;
|
|
21
|
+
this.isDebug = Boolean(ArchiveConfig_1.ArchiveConfig.getConfig().debug);
|
|
22
|
+
if (!this.redis) {
|
|
23
|
+
const url = ArchiveConfig_1.ArchiveConfig.getConfig().cache.redisUrl;
|
|
24
|
+
if (!url) {
|
|
25
|
+
console.error(`[ERROR] Redis Caching > environtment variable "firestore.cache.archive.redisUrl" was not found!`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (process.env.JEST_WORKER_ID !== undefined) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.redis = this.loadRedis();
|
|
32
|
+
this.client = this.redis.createClient({ url });
|
|
33
|
+
this.client.on('error', (err) => {
|
|
34
|
+
this.isRedisReady = false;
|
|
35
|
+
if (this.isDebug) {
|
|
36
|
+
console.warn('[WARN] Redis error', err);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
this.client.on('ready', () => {
|
|
40
|
+
this.isRedisReady = true;
|
|
41
|
+
if (this.isDebug) {
|
|
42
|
+
console.log('[DEBUG] Redis Caching Archive > Redis is ready');
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
this.client.connect();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
handleTimeoutError(error) {
|
|
49
|
+
if (error.message === 'Timeout' && this.isRedisReady) {
|
|
50
|
+
console.log('Setting isRedisReady as false');
|
|
51
|
+
this.isRedisReady = false;
|
|
52
|
+
// Stop everything for a while to unburden Redis
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
console.log('Setting isRedisReady as true');
|
|
55
|
+
this.isRedisReady = true;
|
|
56
|
+
}, REDIS_RECONNECT * 1000);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
getKeys(query) {
|
|
60
|
+
try {
|
|
61
|
+
if (this.isRedisReady) {
|
|
62
|
+
return (0, promise_timeout_1.timeout)(this.client.KEYS(`*${query}*`), REDIS_TIMEOUT);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
this.handleTimeoutError(error);
|
|
67
|
+
console.log(`[DEBUG] Redis Caching > Error when getting KEYS with query: ${query}, error: ${error}`);
|
|
68
|
+
}
|
|
69
|
+
return Promise.resolve([]);
|
|
70
|
+
}
|
|
71
|
+
getCacheResult(key) {
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
try {
|
|
74
|
+
if (this.isRedisReady) {
|
|
75
|
+
const result = yield (0, promise_timeout_1.timeout)(this.client.get(key), REDIS_TIMEOUT);
|
|
76
|
+
if (this.isDebug) {
|
|
77
|
+
if (result) {
|
|
78
|
+
console.debug('[DEBUG] Redis Caching >', `Return value in cache from key: ${key}`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log("[DEBUG] Redis Caching > ", `Key [${key}] is not found in the cache`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (result) {
|
|
85
|
+
return JSON.parse(result);
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
this.handleTimeoutError(error);
|
|
92
|
+
console.log(`[DEBUG] Redis Caching > Error when getting key from redis. ${key}`, { error });
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
saveCacheResult(key, valueToCache, ttl) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
if (this.isRedisReady) {
|
|
100
|
+
try {
|
|
101
|
+
yield (0, promise_timeout_1.timeout)(this.client.set(key, JSON.stringify(valueToCache), {
|
|
102
|
+
EX: ttl || ArchiveConfig_1.ArchiveConfig.getConfig().cache.expiresInSeconds
|
|
103
|
+
}), REDIS_TIMEOUT);
|
|
104
|
+
if (this.isDebug) {
|
|
105
|
+
console.debug('[DEBUG] Redis Caching >', `Storage cache from key: ${key}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
this.handleTimeoutError(error);
|
|
110
|
+
console.log(`[DEBUG] Redis Caching > Error when saving cache. Key: ${key}, value: ${valueToCache}, error: ${error}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
delete(key) {
|
|
116
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
try {
|
|
118
|
+
if (this.isRedisReady) {
|
|
119
|
+
yield (0, promise_timeout_1.timeout)(this.client.del(key), REDIS_TIMEOUT);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
this.handleTimeoutError(error);
|
|
124
|
+
console.log(`[DEBUG] Redis Caching > Error when deleting key from redis. ${key}`);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
loadRedis() {
|
|
129
|
+
try {
|
|
130
|
+
return PlatformTools_1.PlatformTools.load("redis");
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
throw new Error(`Cannot use cache because redis is not installed. Please run "npm i redis@4.0.6 --save-exact".`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.RedisCacheArchiveProvider = RedisCacheArchiveProvider;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ArchiveConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
bucketName: string;
|
|
4
|
+
debug: boolean;
|
|
5
|
+
projectId: string;
|
|
6
|
+
cache: {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
redisUrl: string;
|
|
9
|
+
timeout: number;
|
|
10
|
+
reconnectInSecondsAfterTimeout: number;
|
|
11
|
+
expiresInSeconds: number;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare class ArchiveConfig {
|
|
15
|
+
static getConfig(): ArchiveConfig;
|
|
16
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ArchiveConfig = void 0;
|
|
4
|
+
const FIRESTORE_PROJECT_ID = process.env.FIRESTORE_PROJECTID || '';
|
|
5
|
+
const FIRESTORE_ARCHIVE_DEBUG = process.env.FIRESTORE_ARCHIVE_DEBUG || false;
|
|
6
|
+
const FIRESTORE_ARCHIVE_ENABLED = process.env.FIRESTORE_ARCHIVE_ENABLED || false;
|
|
7
|
+
const FIRESTORE_ARCHIVE_BUCKET_NAME = process.env.FIRESTORE_ARCHIVE_BUCKET_NAME || "firestore-archive-roit";
|
|
8
|
+
const FIRESTORE_ARCHIVE_CACHE_ENABLED = process.env.FIRESTORE_ARCHIVE_CACHE_ENABLED || false;
|
|
9
|
+
const FIRESTORE_ARCHIVE_CACHE_REDIS_URL = process.env.FIRESTORE_ARCHIVE_CACHE_REDISURL || '';
|
|
10
|
+
const FIRESTORE_ARCHIVE_CACHE_REDIS_TIMEOUT = process.env.FIRESTORE_ARCHIVE_CACHE_REDIS_TIMEOUT || 2000;
|
|
11
|
+
const FIRESTORE_ARCHIVE_CACHE_REDIS_RECONNECT_IN_SECONDS_AFTER_TIMEOUT = process.env.FIRESTORE_ARCHIVE_CACHE_REDIS_RECONNECT_IN_SECONDS_AFTER_TIMEOUT || 30;
|
|
12
|
+
const FIRESTORE_ARCHIVE_CACHE_EXPIRES_IN_SECONDS = process.env.FIRESTORE_ARCHIVE_CACHE_EXPIRESINSECONDS || 3600;
|
|
13
|
+
class ArchiveConfig {
|
|
14
|
+
static getConfig() {
|
|
15
|
+
return {
|
|
16
|
+
debug: ['true', true].includes(FIRESTORE_ARCHIVE_DEBUG),
|
|
17
|
+
enabled: ['true', true].includes(FIRESTORE_ARCHIVE_ENABLED),
|
|
18
|
+
bucketName: FIRESTORE_ARCHIVE_BUCKET_NAME,
|
|
19
|
+
projectId: FIRESTORE_PROJECT_ID,
|
|
20
|
+
cache: {
|
|
21
|
+
enabled: ['true', true].includes(FIRESTORE_ARCHIVE_CACHE_ENABLED),
|
|
22
|
+
redisUrl: FIRESTORE_ARCHIVE_CACHE_REDIS_URL,
|
|
23
|
+
timeout: FIRESTORE_ARCHIVE_CACHE_REDIS_TIMEOUT,
|
|
24
|
+
reconnectInSecondsAfterTimeout: FIRESTORE_ARCHIVE_CACHE_REDIS_RECONNECT_IN_SECONDS_AFTER_TIMEOUT,
|
|
25
|
+
expiresInSeconds: FIRESTORE_ARCHIVE_CACHE_EXPIRES_IN_SECONDS
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.ArchiveConfig = ArchiveConfig;
|
|
@@ -55,4 +55,10 @@ export declare abstract class BaseRepository<T> {
|
|
|
55
55
|
}) => Promise<{
|
|
56
56
|
[k: string]: string | number;
|
|
57
57
|
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Limpa o cache de documentos arquivados
|
|
60
|
+
* @param collectionName Nome da collection (opcional)
|
|
61
|
+
* @param docId ID do documento (opcional)
|
|
62
|
+
*/
|
|
63
|
+
clearArchivedCache(collectionName?: string, docId?: string): Promise<void>;
|
|
58
64
|
}
|
|
@@ -19,6 +19,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.BaseRepository = void 0;
|
|
22
|
+
const ArchiveService_1 = require("../archive/ArchiveService");
|
|
22
23
|
const Query_1 = require("../decorators/Query");
|
|
23
24
|
const ManualQueryHelper_1 = require("../query/ManualQueryHelper");
|
|
24
25
|
class BaseRepository {
|
|
@@ -40,6 +41,17 @@ class BaseRepository {
|
|
|
40
41
|
return ManualQueryHelper_1.ManualQueryHelper.executeQueryManualPaginated(className, config);
|
|
41
42
|
});
|
|
42
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Limpa o cache de documentos arquivados
|
|
46
|
+
* @param collectionName Nome da collection (opcional)
|
|
47
|
+
* @param docId ID do documento (opcional)
|
|
48
|
+
*/
|
|
49
|
+
clearArchivedCache(collectionName, docId) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const archiveService = yield ArchiveService_1.ArchiveService.getInstance();
|
|
52
|
+
yield archiveService.clearArchivedCache(collectionName, docId);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
43
55
|
}
|
|
44
56
|
__decorate([
|
|
45
57
|
(0, Query_1.Query)(),
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { Cacheable } from "./decorators/Cacheable";
|
|
|
11
11
|
export { BaseRepository } from "./config/BaseRepository";
|
|
12
12
|
export { ReadonlyRepository } from "./config/ReadonlyRepository";
|
|
13
13
|
export { GenericRepository } from "./config/GenericRepository";
|
|
14
|
+
export { ArchiveConfig } from "./config/ArchiveConfig";
|
|
14
15
|
export { CacheProviders } from "./model/CacheProviders";
|
|
15
16
|
export { FirestoreInstance } from "./config/FirestoreInstance";
|
|
16
17
|
export * from "./model";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -10,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
10
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
15
|
};
|
|
12
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.FirestoreInstance = exports.CacheProviders = exports.GenericRepository = exports.ReadonlyRepository = exports.BaseRepository = exports.Cacheable = exports.Query = exports.Repository = void 0;
|
|
17
|
+
exports.FirestoreInstance = exports.CacheProviders = exports.ArchiveConfig = exports.GenericRepository = exports.ReadonlyRepository = exports.BaseRepository = exports.Cacheable = exports.Query = exports.Repository = void 0;
|
|
14
18
|
require("reflect-metadata");
|
|
15
19
|
/**
|
|
16
20
|
* decorators
|
|
@@ -30,6 +34,8 @@ var ReadonlyRepository_1 = require("./config/ReadonlyRepository");
|
|
|
30
34
|
Object.defineProperty(exports, "ReadonlyRepository", { enumerable: true, get: function () { return ReadonlyRepository_1.ReadonlyRepository; } });
|
|
31
35
|
var GenericRepository_1 = require("./config/GenericRepository");
|
|
32
36
|
Object.defineProperty(exports, "GenericRepository", { enumerable: true, get: function () { return GenericRepository_1.GenericRepository; } });
|
|
37
|
+
var ArchiveConfig_1 = require("./config/ArchiveConfig");
|
|
38
|
+
Object.defineProperty(exports, "ArchiveConfig", { enumerable: true, get: function () { return ArchiveConfig_1.ArchiveConfig; } });
|
|
33
39
|
var CacheProviders_1 = require("./model/CacheProviders");
|
|
34
40
|
Object.defineProperty(exports, "CacheProviders", { enumerable: true, get: function () { return CacheProviders_1.CacheProviders; } });
|
|
35
41
|
var FirestoreInstance_1 = require("./config/FirestoreInstance");
|