@roit/roit-data-firestore 1.2.42 → 1.2.44

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.
Files changed (37) hide show
  1. package/README.md +107 -0
  2. package/dist/archive/ArchivePluginRegistry.d.ts +78 -0
  3. package/dist/archive/ArchivePluginRegistry.js +135 -0
  4. package/dist/archive/ArchiveService.d.ts +61 -11
  5. package/dist/archive/ArchiveService.js +138 -120
  6. package/dist/archive/IArchivePlugin.d.ts +102 -0
  7. package/dist/archive/IArchivePlugin.js +12 -0
  8. package/dist/archive/index.d.ts +2 -0
  9. package/dist/archive/index.js +11 -0
  10. package/dist/cache/CacheResolver.js +6 -5
  11. package/dist/config/ArchiveConfig.d.ts +17 -12
  12. package/dist/config/ArchiveConfig.js +25 -41
  13. package/dist/config/BaseRepository.js +1 -1
  14. package/dist/config/ReadonlyRepository.js +1 -1
  15. package/dist/exception/RepositoryException.js +1 -1
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.js +10 -1
  18. package/dist/model/CacheProviders.d.ts +1 -2
  19. package/dist/model/CacheProviders.js +1 -2
  20. package/dist/query/ManualQueryHelper.js +0 -1
  21. package/dist/query/QueryPredicateFunctionTransform.js +4 -1
  22. package/dist/template/FunctionAggregationTemplate.txt +1 -1
  23. package/dist/template/FunctionAverageTemplate.txt +1 -1
  24. package/dist/template/FunctionCountTemplate.txt +20 -25
  25. package/dist/template/FunctionCreateOrUpdateTemplate.txt +69 -20
  26. package/dist/template/FunctionCreateTemplate.txt +15 -13
  27. package/dist/template/FunctionDeleteTemplate.txt +45 -13
  28. package/dist/template/FunctionFindAllTemplate.txt +39 -23
  29. package/dist/template/FunctionFindByIdTemplate.txt +24 -14
  30. package/dist/template/FunctionQueryTemplate.txt +67 -41
  31. package/dist/template/FunctionSumTemplate.txt +48 -32
  32. package/dist/template/FunctionUpdatePartialTemplate.txt +76 -21
  33. package/dist/template/FunctionUpdateTemplate.txt +64 -17
  34. package/dist/tsconfig.build.tsbuildinfo +1 -1
  35. package/package.json +1 -1
  36. package/dist/cache/providers/RedisCacheArchiveProvider.d.ts +0 -19
  37. package/dist/cache/providers/RedisCacheArchiveProvider.js +0 -115
@@ -1,74 +1,100 @@
1
- async function(<params_replace>) {
1
+ async function(<params_replace>) {
2
2
  return __awaiter(this, void 0, void 0, function* () {
3
3
  return yield global.instances.startTracer('firestore.query', async (span) => {
4
4
  try {
5
- if(<params_validator_replace>) throw new Error('All parameters required, ref..: <params_replace>')
6
-
7
- let repositoryClassName = '<repositoryClassName_value>'
8
- let methodSignature = '<methodSignature_value>'
5
+ if (<params_validator_replace>) {
6
+ throw new Error('All parameters required, ref..: <params_replace>');
7
+ }
9
8
 
10
- const db = global.instances.globalDbFile.FirestoreInstance.getInstance()
11
- const cacheResolver = global.instances.cacheResolver
12
- const firestoreReadAuditResolver = global.instances.firestoreReadAuditResolver
9
+ const repositoryClassName = '<repositoryClassName_value>';
10
+ const methodSignature = '<methodSignature_value>';
13
11
 
14
- const environmentUtil = global.instances.environmentUtil
15
- if(environmentUtil.areWeTesting()) {
16
- console.log('It was decreed that it is being executed try, no operation or effective transaction will be performed')
17
- return []
12
+ const db = global.instances.globalDbFile.FirestoreInstance.getInstance();
13
+ const cacheResolver = global.instances.cacheResolver;
14
+ const firestoreReadAuditResolver = global.instances.firestoreReadAuditResolver;
15
+ const environmentUtil = global.instances.environmentUtil;
16
+ const archiveService = await global.instances.archiveService;
17
+
18
+ if (environmentUtil.areWeTesting()) {
19
+ console.log('It was decreed that it is being executed try, no operation or effective transaction will be performed');
20
+ return [];
18
21
  }
19
22
 
20
- const result = await cacheResolver.getCacheResult(repositoryClassName, methodSignature, <params_replace>)
23
+ const result = await cacheResolver.getCacheResult(repositoryClassName, methodSignature, <params_replace>);
21
24
 
22
- if(result) {
23
- return result
25
+ if (result) {
26
+ return result;
24
27
  }
25
28
 
26
- const collection = db.collection('<collection_name_replace>')
29
+ const collection = db.collection('<collection_name_replace>');
30
+
31
+ if (Number(process.env.FIRESTORE_DEBUG)) {
32
+ console.debug('[DEBUG] Executing query >', "<query_predicate_replace>");
33
+ }
27
34
 
28
- if(Number(process.env.FIRESTORE_DEBUG)) { console.debug('[DEBUG] Executing query >', "<query_predicate_replace>") }
35
+ const collectionRef = collection<query_predicate_replace>;
36
+ const { documentRef } = await global.instances.queryCreatorConfig.buildPaging(collectionRef, paging, { showCount: false });
37
+ const snapshot = await documentRef.get();
29
38
 
30
- let collectionRef = collection<query_predicate_replace>
31
- let { documentRef } = await global.instances.queryCreatorConfig.buildPaging(collectionRef, paging, { showCount: false })
32
- const snapshot = await documentRef.get()
39
+ let items = [];
40
+ snapshot.forEach(doc => {
41
+ items.push({ ...doc.data(), id: doc.id });
42
+ });
33
43
 
34
- let items = []
35
- snapshot.forEach(doc => {
36
- let element = { ...doc.data() }
37
- element.id = doc.id
38
- items.push(element)
39
- })
44
+ // VERIFICAÇÃO DE ARQUIVAMENTO PARA DOCUMENTOS RETORNADOS
45
+ if (archiveService.isEnabled()) {
46
+ const archivedItems = items.filter(item => archiveService.isDocumentArchived(item));
47
+
48
+ if (archivedItems.length > 0) {
49
+ const recoveryPromises = archivedItems.map(item => {
50
+ return archiveService.getArchivedDocument('<collection_name_replace>', item)
51
+ .then(archivedData => archivedData ? { ...item, ...archivedData } : item)
52
+ .catch(() => item); // Fallback para stub se falhar
53
+ });
54
+
55
+ const recoveredItems = await Promise.all(recoveryPromises);
56
+
57
+ // Substituir itens arquivados pelos recuperados
58
+ const recoveredMap = new Map(recoveredItems.map(item => [item.id, item]));
59
+ items = items.map(item => {
60
+ if (archiveService.isDocumentArchived(item)) {
61
+ return recoveredMap.get(item.id) || item;
62
+ }
63
+ return item;
64
+ });
65
+ }
66
+ }
40
67
 
41
- await cacheResolver.cacheResult(repositoryClassName, methodSignature, items, <params_replace>)
68
+ await cacheResolver.cacheResult(repositoryClassName, methodSignature, items, <params_replace>);
42
69
 
43
70
  await firestoreReadAuditResolver.persistFirestoreRead({
44
71
  collection: '<collection_name_replace>',
45
- repositoryClassName: repositoryClassName,
72
+ repositoryClassName,
46
73
  functionSignature: methodSignature,
47
74
  params: <params_replace>,
48
75
  queryResult: items
49
- })
76
+ });
50
77
 
51
78
  span.setAttributes({
52
79
  'firestore.operation.name': 'query',
53
80
  'firestore.operation.query': "<query_predicate_replace>",
54
81
  'firestore.collection.name': '<collection_name_replace>',
55
82
  'firestore.operation.size': items.length
56
- })
83
+ });
57
84
 
58
- if(<is_one_row>) {
59
- return items[0]
60
- }
61
-
62
- return items
85
+ if (<is_one_row>) {
86
+ return items[0];
87
+ }
63
88
 
89
+ return items;
64
90
  } catch (error) {
65
91
  span.setStatus({
66
92
  code: 2,
67
93
  message: error.message
68
- })
69
- span.recordException(error)
70
- throw error
94
+ });
95
+ span.recordException(error);
96
+ throw error;
71
97
  }
72
- })
73
- })
74
- }
98
+ });
99
+ });
100
+ }
@@ -1,37 +1,53 @@
1
1
  sum(config) {
2
2
  return __awaiter(this, void 0, void 0, function* () {
3
- const db = global.instances.globalDbFile.FirestoreInstance.getInstance();
4
- const environmentUtil = global.instances.environmentUtil;
5
- const convertToMQuery = global.instances.convertToMQuery;
6
- const aggregateSum = global.instances.aggregateSum;
7
- if (environmentUtil.areWeTesting()) {
8
- console.log('It was decreed that it is being executed try, no operation or effective transaction will be performed');
9
- return 0;
10
- }
11
- const collection = db.collection('<COLLECTION_REPLACE>');
12
- let queryList;
13
- let queryExecute;
14
- if ((config === null || config === void 0 ? void 0 : config.query) && config.query.length > 0) {
15
- queryList = config.query.map(query => {
16
- if (Object.keys(query).length === 1) {
17
- return convertToMQuery(query);
3
+ return yield global.instances.startTracer('firestore.sum', async (span) => {
4
+ try {
5
+ const db = global.instances.globalDbFile.FirestoreInstance.getInstance();
6
+ const environmentUtil = global.instances.environmentUtil;
7
+ const convertToMQuery = global.instances.convertToMQuery;
8
+ const aggregateSum = global.instances.aggregateSum;
9
+
10
+ if (environmentUtil.areWeTesting()) {
11
+ console.log('It was decreed that it is being executed try, no operation or effective transaction will be performed');
12
+ return 0;
18
13
  }
19
- return query;
20
- });
21
- const queryInit = queryList[0];
22
- queryExecute = collection.where(queryInit.field, queryInit.operator, queryInit.value);
23
- queryList.shift();
24
- queryList.forEach(que => {
25
- queryExecute = queryExecute.where(que.field, que.operator, que.value);
26
- });
27
- }
28
- else {
29
- queryExecute = collection;
30
- }
31
- const sumAggregateQuery = queryExecute.aggregate({
32
- sum: aggregateSum(config.attributeSum),
14
+
15
+ const collection = db.collection('<COLLECTION_REPLACE>');
16
+ let queryExecute = collection;
17
+
18
+ if (config?.query && config.query.length > 0) {
19
+ const queryList = config.query.map(query => {
20
+ if (Object.keys(query).length === 1) {
21
+ return convertToMQuery(query);
22
+ }
23
+ return query;
24
+ });
25
+
26
+ for (const query of queryList) {
27
+ queryExecute = queryExecute.where(query.field, query.operator, query.value);
28
+ }
29
+ }
30
+
31
+ const sumAggregateQuery = queryExecute.aggregate({
32
+ sum: aggregateSum(config.attributeSum),
33
+ });
34
+ const snapshot = yield sumAggregateQuery.get();
35
+
36
+ span.setAttributes({
37
+ 'firestore.operation.name': 'sum',
38
+ 'firestore.collection.name': '<COLLECTION_REPLACE>',
39
+ 'firestore.aggregate.attribute': config.attributeSum
40
+ });
41
+
42
+ return snapshot.data().sum;
43
+ } catch (error) {
44
+ span.setStatus({
45
+ code: 2,
46
+ message: error.message
47
+ });
48
+ span.recordException(error);
49
+ throw error;
50
+ }
33
51
  });
34
- const snapshot = yield sumAggregateQuery.get();
35
- return snapshot.data().sum;
36
52
  });
37
- }
53
+ }
@@ -1,25 +1,80 @@
1
1
  updatePartial(id, item) {
2
2
  return __awaiter(this, void 0, void 0, function* () {
3
- const db = global.instances.globalDbFile.FirestoreInstance.getInstance();
4
- const { newDate } = global.instances.dateRef;
5
- const lastServiceModify = process.env.SERVICE || 'PROJECT_UNDEFINED';
6
- const updateAt = newDate();
7
- const updateTimestampAt = new Date(updateAt).getTime();
8
- const environmentUtil = global.instances.environmentUtil;
9
- const document = db.collection('<COLLECTION_REPLACE>').doc(id);
10
- try {
11
- if (!environmentUtil.areWeTesting()) {
12
- yield document.set(Object.assign({ lastServiceModify,
13
- updateAt,
14
- updateTimestampAt }, item), { merge: true });
15
- yield this.revokeCache();
3
+ return yield global.instances.startTracer('firestore.updatePartial', async (span) => {
4
+ try {
5
+ const db = global.instances.globalDbFile.FirestoreInstance.getInstance();
6
+ const { newDate } = global.instances.dateRef;
7
+ const lastServiceModify = process.env.SERVICE || 'PROJECT_UNDEFINED';
8
+ const updateAt = newDate();
9
+ const updateTimestampAt = new Date(updateAt).getTime();
10
+ const environmentUtil = global.instances.environmentUtil;
11
+ const archiveService = yield global.instances.archiveService;
12
+ const document = db.collection('<COLLECTION_REPLACE>').doc(id);
13
+
14
+ let shouldUnarchive = false;
15
+
16
+ // VERIFICAÇÃO DE DOCUMENTO ARQUIVADO
17
+ if (archiveService.isEnabled()) {
18
+ const currentDoc = yield document.get();
19
+
20
+ if (currentDoc.exists) {
21
+ const currentData = currentDoc.data();
22
+
23
+ if (currentData && archiveService.isDocumentArchived(currentData)) {
24
+ const archivePath = currentData.fbArchivePath;
25
+ const updateResult = yield archiveService.updateArchivedDocument(
26
+ '<COLLECTION_REPLACE>',
27
+ id,
28
+ item,
29
+ archivePath,
30
+ { unarchive: true }
31
+ );
32
+
33
+ if (!(updateResult && updateResult.result && updateResult.result.success && updateResult.mergedData)) {
34
+ throw new Error('Failed to update archived document; aborting partial update to prevent inconsistent state and stale archive overwriting user changes.');
35
+ }
36
+ const originalItem = Object.assign({}, item);
37
+ Object.assign(item, updateResult.mergedData, originalItem);
38
+ shouldUnarchive = true;
39
+ }
40
+ }
41
+ }
42
+
43
+ if (!environmentUtil.areWeTesting()) {
44
+ const itemData = {
45
+ ...item,
46
+ lastServiceModify,
47
+ updateAt,
48
+ updateTimestampAt
49
+ };
50
+
51
+ if (shouldUnarchive) {
52
+ const FieldValue = global.instances.FieldValue;
53
+ const ARCHIVE_FIELDS = global.instances.ARCHIVE_FIELDS;
54
+ itemData[ARCHIVE_FIELDS.ARCHIVED_AT] = FieldValue.delete();
55
+ itemData[ARCHIVE_FIELDS.ARCHIVE_PATH] = FieldValue.delete();
56
+ itemData[ARCHIVE_FIELDS.ARCHIVE_HASH] = FieldValue.delete();
57
+ }
58
+
59
+ yield document.set(itemData, { merge: true });
60
+ yield this.revokeCache();
61
+ } else {
62
+ console.log('It was decreed that it is being executed try, no operation or effective transaction will be performed');
63
+ }
64
+
65
+ span.setAttributes({
66
+ 'firestore.operation.name': 'updatePartial',
67
+ 'firestore.collection.name': '<COLLECTION_REPLACE>',
68
+ 'firestore.document.id': id,
69
+ });
70
+ } catch (error) {
71
+ span.setStatus({
72
+ code: 2,
73
+ message: error.message
74
+ });
75
+ span.recordException(error);
76
+ throw error;
16
77
  }
17
- else {
18
- console.log('It was decreed that it is being executed try, no operation or effective transaction will be performed');
19
- }
20
- }
21
- catch (e) {
22
- console.error(e === null || e === void 0 ? void 0 : e.details);
23
- }
78
+ });
24
79
  });
25
- }
80
+ }
@@ -19,48 +19,95 @@ update(items) {
19
19
  const getTtlTimestamp = global.instances.getTtlTimestamp;
20
20
  const collection = db.collection('<COLLECTION_REPLACE>');
21
21
  const validatorDataHandle = global.instances.validatorDataHandle;
22
+ const archiveService = yield global.instances.archiveService;
22
23
  const batch = db.batch();
24
+
25
+ // Validar IDs antes de processar
23
26
  for (const item of items) {
24
- yield validatorDataHandle.validateModel(modelName, item, validatorOptions);
25
27
  if (!item.id) {
26
28
  throw new RepositoryBusinessException_1.RepositoryBusinessException(`Id is required`, []);
27
29
  }
30
+ }
31
+
32
+ // Buscar documentos existentes em lote (otimização)
33
+ const docRefs = items.map(item => collection.doc(item.id));
34
+ const existingDocs = (archiveService.isEnabled() && docRefs.length > 0)
35
+ ? yield db.getAll(...docRefs)
36
+ : [];
37
+
38
+ for (let i = 0; i < items.length; i++) {
39
+ const item = items[i];
40
+ yield validatorDataHandle.validateModel(modelName, item, validatorOptions);
41
+
42
+ const docRef = docRefs[i];
43
+ let shouldUnarchive = false;
44
+
45
+ // VERIFICAÇÃO DE DOCUMENTO ARQUIVADO
46
+ if (archiveService.isEnabled() && existingDocs[i]?.exists) {
47
+ const currentData = existingDocs[i].data();
48
+
49
+ if (currentData && archiveService.isDocumentArchived(currentData)) {
50
+ const archivePath = currentData.fbArchivePath;
51
+ const updateResult = yield archiveService.updateArchivedDocument(
52
+ '<COLLECTION_REPLACE>',
53
+ item.id,
54
+ item,
55
+ archivePath,
56
+ { unarchive: true }
57
+ );
58
+
59
+ if (updateResult.result.success && updateResult.mergedData) {
60
+ const originalItem = Object.assign({}, item);
61
+ Object.assign(item, updateResult.mergedData, originalItem);
62
+ shouldUnarchive = true;
63
+ } else {
64
+ throw new Error('Failed to update archived document; aborting update to prevent inconsistent state and stale archive overwriting user changes.');
65
+ }
66
+ }
67
+ }
68
+
28
69
  item.updateAt = newDate();
29
70
  item.updateTimestampAt = new Date(item.updateAt).getTime();
30
71
  item.lastServiceModify = process.env.SERVICE || 'PROJECT_UNDEFINED';
31
- const docRef = collection.doc(item.id);
32
- if (ttlExpirationIn && item?.ttlExpirationAt) {
33
- delete item.ttlExpirationAt;
34
- }
35
- batch.set(docRef, JSON.parse(JSON.stringify(item)), { merge: true });
72
+
73
+ // Preparar dados para persistir (consolidado)
74
+ const itemData = JSON.parse(JSON.stringify(item));
36
75
  if (ttlExpirationIn && ttlUnit && ttlUpdate) {
37
- const ttl = getTtlTimestamp(ttlExpirationIn, ttlUnit);
38
- batch.set(docRef, {
39
- ttlExpirationAt: ttl,
40
- }, { merge: true });
76
+ itemData.ttlExpirationAt = getTtlTimestamp(ttlExpirationIn, ttlUnit);
77
+ }
78
+
79
+ if (shouldUnarchive) {
80
+ const FieldValue = global.instances.FieldValue;
81
+ const ARCHIVE_FIELDS = global.instances.ARCHIVE_FIELDS;
82
+ itemData[ARCHIVE_FIELDS.ARCHIVED_AT] = FieldValue.delete();
83
+ itemData[ARCHIVE_FIELDS.ARCHIVE_PATH] = FieldValue.delete();
84
+ itemData[ARCHIVE_FIELDS.ARCHIVE_HASH] = FieldValue.delete();
41
85
  }
86
+
87
+ batch.set(docRef, itemData, { merge: true });
42
88
  }
89
+
43
90
  if (!environmentUtil.areWeTesting()) {
44
91
  yield batch.commit();
45
92
  yield this.revokeCache();
46
- }
47
- else {
93
+ } else {
48
94
  console.log('It was decreed that it is being executed try, no operation or effective transaction will be performed');
49
95
  }
96
+
50
97
  span.setAttributes({
51
98
  'firestore.operation.name': 'update',
52
99
  'firestore.collection.name': '<COLLECTION_REPLACE>',
53
100
  'firestore.operation.size': items.length,
54
- })
101
+ });
55
102
  return items;
56
103
  } catch (error) {
57
104
  span.setStatus({
58
105
  code: 2,
59
106
  message: error.message
60
- })
61
- span.recordException(error)
62
- throw error
107
+ });
108
+ span.recordException(error);
109
+ throw error;
63
110
  }
64
- })
111
+ });
65
112
  });
66
113
  }