@natlibfi/melinda-rest-api-commons 6.1.0-alpha.0 → 6.2.0-alpha.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.
Files changed (92) hide show
  1. package/.github/workflows/melinda-node-tests-and-publish.yml +4 -2
  2. package/README.md +211 -14
  3. package/dist/amqp.d.ts +41 -0
  4. package/dist/amqp.d.ts.map +1 -0
  5. package/dist/amqp.js +251 -235
  6. package/dist/amqp.js.map +1 -7
  7. package/dist/constants.d.ts +49 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +38 -38
  10. package/dist/constants.js.map +1 -7
  11. package/dist/helpers/conversion.d.ts +8 -0
  12. package/dist/helpers/conversion.d.ts.map +1 -0
  13. package/dist/helpers/conversion.js +70 -64
  14. package/dist/helpers/conversion.js.map +1 -7
  15. package/dist/helpers/fix-constants.d.ts +76 -0
  16. package/dist/helpers/fix-constants.d.ts.map +1 -0
  17. package/dist/helpers/fix-constants.js +41 -41
  18. package/dist/helpers/fix-constants.js.map +1 -7
  19. package/dist/helpers/fix-handle-tempurns.d.ts +3 -0
  20. package/dist/helpers/fix-handle-tempurns.d.ts.map +1 -0
  21. package/dist/helpers/fix-handle-tempurns.js +73 -71
  22. package/dist/helpers/fix-handle-tempurns.js.map +1 -7
  23. package/dist/helpers/fix-strip-f884s.d.ts +10 -0
  24. package/dist/helpers/fix-strip-f884s.d.ts.map +1 -0
  25. package/dist/helpers/fix-strip-f884s.js +161 -163
  26. package/dist/helpers/fix-strip-f884s.js.map +1 -7
  27. package/dist/helpers/fix.d.ts +6 -0
  28. package/dist/helpers/fix.d.ts.map +1 -0
  29. package/dist/helpers/fix.js +133 -121
  30. package/dist/helpers/fix.js.map +1 -7
  31. package/dist/helpers/validation.d.ts +9 -0
  32. package/dist/helpers/validation.d.ts.map +1 -0
  33. package/dist/helpers/validation.js +14 -16
  34. package/dist/helpers/validation.js.map +1 -7
  35. package/dist/index.d.ts +13 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -7
  39. package/dist/mongo.d.ts +165 -0
  40. package/dist/mongo.d.ts.map +1 -0
  41. package/dist/mongo.js +595 -547
  42. package/dist/mongo.js.map +1 -7
  43. package/dist/mongoError.d.ts +2 -0
  44. package/dist/mongoError.d.ts.map +1 -0
  45. package/dist/mongoError.js +19 -0
  46. package/dist/mongoError.js.map +1 -0
  47. package/dist/mongoLog.d.ts +50 -0
  48. package/dist/mongoLog.d.ts.map +1 -0
  49. package/dist/mongoLog.js +274 -242
  50. package/dist/mongoLog.js.map +1 -7
  51. package/dist/utils.d.ts +36 -0
  52. package/dist/utils.d.ts.map +1 -0
  53. package/dist/utils.js +112 -110
  54. package/dist/utils.js.map +1 -7
  55. package/eslint.config.ts +66 -0
  56. package/package.json +17 -11
  57. package/{tests/amqp-error-branches.test.js → test/amqp-error-branches.test.ts} +135 -61
  58. package/{tests/amqp.healthtest.js → test/amqp.healthtest.ts} +19 -11
  59. package/{tests/amqp.tests.localtest.js → test/amqp.tests.localtest.ts} +54 -35
  60. package/{tests/helpers/conversion.test.js → test/helpers/conversion.test.ts} +26 -14
  61. package/{tests/helpers/fix-edge.test.js → test/helpers/fix-edge.test.ts} +16 -12
  62. package/{tests/helpers/fix.test.js → test/helpers/fix.test.ts} +14 -8
  63. package/{tests/helpers/validation.test.js → test/helpers/validation.test.ts} +7 -6
  64. package/{tests/mongo-add-blob-size.test.js → test/mongo-add-blob-size.test.ts} +14 -15
  65. package/{tests/mongo-check-and-check-state.test.js → test/mongo-check-and-check-state.test.ts} +6 -8
  66. package/{tests/mongo-check-and-set-import-job-state.test.js → test/mongo-check-and-set-import-job-state.test.ts} +6 -9
  67. package/{tests/mongo-check-timeout.test.js → test/mongo-check-timeout.test.ts} +6 -9
  68. package/{tests/mongo-create-bulk.test.js → test/mongo-create-bulk.test.ts} +6 -7
  69. package/{tests/mongo-create-prio.test.js → test/mongo-create-prio.test.ts} +6 -6
  70. package/{tests/mongo-error-branches.test.js → test/mongo-error-branches.test.ts} +166 -65
  71. package/{tests/mongo-get-one.test.js → test/mongo-get-one.test.ts} +6 -6
  72. package/{tests/mongo-get-stream.test.js → test/mongo-get-stream.test.ts} +6 -8
  73. package/{tests/mongo-push-ids.test.js → test/mongo-push-ids.test.ts} +6 -6
  74. package/{tests/mongo-push-messages.test.js → test/mongo-push-messages.test.ts} +6 -6
  75. package/{tests/mongo-query-by-id.test.js → test/mongo-query-by-id.test.ts} +6 -9
  76. package/{tests/mongo-query.test.js → test/mongo-query.test.ts} +6 -7
  77. package/{tests/mongo-read-content.test.js → test/mongo-read-content.test.ts} +6 -9
  78. package/{tests/mongo-remove.test.js → test/mongo-remove.test.ts} +6 -8
  79. package/{tests/mongo-set-blob-size.test.js → test/mongo-set-blob-size.test.ts} +6 -6
  80. package/{tests/mongo-set-import-job-state.test.js → test/mongo-set-import-job-state.test.ts} +6 -6
  81. package/{tests/mongo-set-operation.test.js → test/mongo-set-operation.test.ts} +6 -6
  82. package/{tests/mongo-set-operations.test.js → test/mongo-set-operations.test.ts} +6 -6
  83. package/{tests/mongo-set-state.test.js → test/mongo-set-state.test.ts} +6 -6
  84. package/{tests/mongoLog-protect.test.js → test/mongoLog-protect.test.ts} +18 -17
  85. package/{tests/mongoLog.test.js → test/mongoLog.test.ts} +8 -8
  86. package/{tests/testUtils.js → test/testUtils.ts} +49 -15
  87. package/{tests/utils.test.js → test/utils.test.ts} +5 -5
  88. package/tsconfig.json +62 -0
  89. package/tsconfig.test.json +17 -0
  90. package/dist/helpers/fix-utils.js +0 -39
  91. package/dist/helpers/fix-utils.js.map +0 -7
  92. package/eslint.config.js +0 -53
package/dist/mongoLog.js CHANGED
@@ -1,262 +1,294 @@
1
- import { MongoClient } from "mongodb";
2
- import httpStatus from "http-status";
3
- import { createLogger, Error as ApiError } from "@natlibfi/melinda-commons";
1
+ import { MongoClient } from 'mongodb';
2
+ import httpStatus from 'http-status';
3
+ import { createLogger, Error as ApiError } from '@natlibfi/melinda-commons';
4
4
  import { logError, assertString } from "./utils.js";
5
+ import { withMongoError } from "./mongoError.js";
5
6
  import { LOG_ITEM_TYPE } from "./constants.js";
6
- export default async function(MONGO_URI, dbName = "rest-api", deps = {}) {
7
- const logger = createLogger();
8
- function buildBlobSequenceFilter(correlationId, blobSequence) {
9
- if (!blobSequence) {
10
- return { correlationId };
11
- }
12
- if (typeof blobSequence === "number") {
13
- return { correlationId, blobSequence: parseInt(blobSequence, 10) };
7
+ export default async function (MONGO_URI, dbName = 'rest-api', deps = {}) {
8
+ const logger = createLogger();
9
+ const collection = 'logs';
10
+ function buildBlobSequenceFilter(correlationId, blobSequence) {
11
+ if (!blobSequence) {
12
+ return { correlationId };
13
+ }
14
+ if (typeof blobSequence === 'number') {
15
+ return { correlationId, blobSequence: parseInt(String(blobSequence), 10) };
16
+ }
17
+ if (typeof blobSequence === 'string') {
18
+ const parsed = parseInt(blobSequence, 10);
19
+ if (!Number.isNaN(parsed)) {
20
+ return { correlationId, blobSequence: parsed };
21
+ }
22
+ }
23
+ throw new ApiError(httpStatus.BAD_REQUEST, 'blobSequence must be a number or a numeric string');
14
24
  }
15
- if (typeof blobSequence === "string") {
16
- const parsed = parseInt(blobSequence, 10);
17
- if (!Number.isNaN(parsed)) {
18
- return { correlationId, blobSequence: parsed };
19
- }
25
+ let logCollection = deps.collection;
26
+ if (!deps.collection) {
27
+ const client = await MongoClient.connect(MONGO_URI);
28
+ logCollection = client.db(dbName).collection(collection);
20
29
  }
21
- throw new ApiError(httpStatus.BAD_REQUEST, "blobSequence must be a number or a numeric string");
22
- }
23
- const collection = "logs";
24
- let db;
25
- if (deps.collection) {
26
- db = { collection: () => deps.collection };
27
- } else {
28
- const client = await MongoClient.connect(MONGO_URI);
29
- db = client.db(dbName);
30
- }
31
- return { addLogItem, query, queryById, getListOfLogs, getListOfCatalogers, getListOfCorrelationIds, getExpandedListOfLogs, protect, unprotect, remove, removeBySequences };
32
- async function addLogItem(logItem) {
33
- const time = /* @__PURE__ */ new Date();
34
- const newLogItem = {
35
- ...logItem,
36
- creationTime: time,
37
- protected: false
30
+ return {
31
+ addLogItem,
32
+ query: (params) => withMongoError(() => query(params)),
33
+ queryById: (correlationId, logItemType, skip, limit) => withMongoError(() => queryById(correlationId, logItemType, skip, limit)),
34
+ getListOfLogs: (logItemType) => withMongoError(() => getListOfLogs(logItemType)),
35
+ getListOfCatalogers: () => withMongoError(() => getListOfCatalogers()),
36
+ getListOfCorrelationIds: () => withMongoError(() => getListOfCorrelationIds()),
37
+ getExpandedListOfLogs: (params) => withMongoError(() => getExpandedListOfLogs(params)),
38
+ protect,
39
+ unprotect,
40
+ remove,
41
+ removeBySequences
38
42
  };
39
- try {
40
- checkLogItemType(logItem.logItemType, false);
41
- const result = await db.collection(collection).insertOne(newLogItem);
42
- if (result.acknowledged) {
43
- const { blobSequence, blobSequenceStart, blobSequenceEnd } = logItem;
44
- const itemString = blobSequenceStart && blobSequenceEnd ? `${blobSequenceStart} - ${blobSequenceEnd}` : `${blobSequence}`;
45
- logger.info(`*** New ${logItem.logItemType} added for ${logItem.correlationId}, blobSequence(s): ${itemString}. ***`);
46
- return;
47
- }
48
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR);
49
- } catch (error) {
50
- const errorMessage = error.payload || error.message || "";
51
- logError(error);
52
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
43
+ function isKnownLogItemType(value) {
44
+ const knownLogItemTypes = Object.values(LOG_ITEM_TYPE);
45
+ return knownLogItemTypes.includes(value);
53
46
  }
54
- }
55
- async function query({ limit = 5, skip = 0, ...rest }) {
56
- logger.debug(`Query params: ${JSON.stringify(rest)}`);
57
- logger.debug(`Limit and skip params: ${limit} | ${skip}`);
58
- checkLogItemType(rest.logItemType, false);
59
- const result = await db.collection(collection).find(rest).sort({ creationTime: 1 }).skip(parseInt(skip, 10)).limit(parseInt(limit, 10)).toArray();
60
- logger.debug(`Query result: ${result.length > 0 ? `Found ${result.length} log items! (skip: ${skip} limit: ${limit})` : "Not found!"}`);
61
- return result;
62
- }
63
- async function queryById(correlationId, logItemType = LOG_ITEM_TYPE.MERGE_LOG, skip = 0, limit = 1) {
64
- assertString(correlationId, "correlationId");
65
- logger.debug(`QueryById: ${correlationId}, logItemType: ${logItemType}, skip: ${skip}, limit: ${limit}`);
66
- const result = await db.collection(collection).find({ correlationId, logItemType }).sort({ blobSequence: 1 }).skip(parseInt(skip, 10)).limit(parseInt(limit, 10)).toArray();
67
- logger.debug(`Query result: ${result.length > 0 ? `Found ${result.length} log items!` : "Not found!"}`);
68
- return result;
69
- }
70
- async function getListOfLogs(logItemType = LOG_ITEM_TYPE.MERGE_LOG) {
71
- checkLogItemType(logItemType, true);
72
- const result = await db.collection(collection).distinct("correlationId", { logItemType });
73
- logger.debug(`Query result for getListOfLogs: ${result.length > 0 ? `Found ${result.length} correlationIds for ${logItemType}!` : "Not found!"}`);
74
- return result;
75
- }
76
- async function getListOfCatalogers() {
77
- logger.debug(`Getting list of Catalogers`);
78
- const result = await db.collection(collection).distinct("cataloger");
79
- return result;
80
- }
81
- async function getListOfCorrelationIds() {
82
- logger.debug(`Getting list of CorrelationIds`);
83
- const result = await db.collection(collection).distinct("correlationId");
84
- return result;
85
- }
86
- async function getExpandedListOfLogs({ logItemTypes, catalogers = [], dateBefore = /* @__PURE__ */ new Date(), dateAfter = "1970-01-01", test = false }) {
87
- const wantedLogItemTypes = logItemTypes === void 0 ? [LOG_ITEM_TYPE.MERGE_LOG, LOG_ITEM_TYPE.MATCH_LOG] : logItemTypes;
88
- if (!Array.isArray(wantedLogItemTypes)) {
89
- throw new ApiError(httpStatus.BAD_REQUEST, `logItemTypes must be an array: ${logItemTypes}`);
47
+ async function addLogItem(logItem) {
48
+ const time = new Date();
49
+ const newLogItem = {
50
+ ...logItem,
51
+ creationTime: time,
52
+ protected: false
53
+ };
54
+ try {
55
+ checkLogItemType(logItem.logItemType, false);
56
+ const result = await logCollection.insertOne(newLogItem);
57
+ if (result.acknowledged) {
58
+ const { blobSequence, blobSequenceStart, blobSequenceEnd } = logItem;
59
+ const itemString = blobSequenceStart && blobSequenceEnd ? `${blobSequenceStart} - ${blobSequenceEnd}` : `${blobSequence}`;
60
+ logger.info(`*** New ${logItem.logItemType} added for ${logItem.correlationId}, blobSequence(s): ${itemString}. ***`);
61
+ return;
62
+ }
63
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, undefined);
64
+ }
65
+ catch (error) {
66
+ const apiError = error;
67
+ const errorMessage = apiError.payload || apiError.message || '';
68
+ logError(error);
69
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
70
+ }
71
+ }
72
+ async function query({ limit = 5, skip = 0, ...rest }) {
73
+ logger.debug(`Query params: ${JSON.stringify(rest)}`);
74
+ logger.debug(`Limit and skip params: ${limit} | ${skip}`);
75
+ checkLogItemType(rest['logItemType'], false);
76
+ const result = await logCollection
77
+ .find(rest)
78
+ .sort({ creationTime: 1 })
79
+ .skip(parseInt(String(skip), 10))
80
+ .limit(parseInt(String(limit), 10))
81
+ .toArray();
82
+ logger.debug(`Query result: ${result.length > 0 ? `Found ${result.length} log items! (skip: ${skip} limit: ${limit})` : 'Not found!'}`);
83
+ return result;
84
+ }
85
+ async function queryById(correlationId, logItemType = LOG_ITEM_TYPE.MERGE_LOG, skip = 0, limit = 1) {
86
+ assertString(correlationId, 'correlationId');
87
+ logger.debug(`QueryById: ${correlationId}, logItemType: ${logItemType}, skip: ${skip}, limit: ${limit}`);
88
+ const result = await logCollection
89
+ .find({ correlationId, logItemType })
90
+ .sort({ blobSequence: 1 })
91
+ .skip(parseInt(String(skip), 10))
92
+ .limit(parseInt(String(limit), 10))
93
+ .toArray();
94
+ logger.debug(`Query result: ${result.length > 0 ? `Found ${result.length} log items!` : 'Not found!'}`);
95
+ return result;
96
+ }
97
+ async function getListOfLogs(logItemType = LOG_ITEM_TYPE.MERGE_LOG) {
98
+ checkLogItemType(logItemType, true);
99
+ const result = await logCollection
100
+ .distinct('correlationId', { logItemType: logItemType });
101
+ logger.debug(`Query result for getListOfLogs: ${result.length > 0 ? `Found ${result.length} correlationIds for ${logItemType}!` : 'Not found!'}`);
102
+ return result;
103
+ }
104
+ async function getListOfCatalogers() {
105
+ logger.debug(`Getting list of Catalogers`);
106
+ const result = await logCollection
107
+ .distinct('cataloger');
108
+ return result;
109
+ }
110
+ async function getListOfCorrelationIds() {
111
+ logger.debug(`Getting list of CorrelationIds`);
112
+ const result = await logCollection
113
+ .distinct('correlationId');
114
+ return result;
115
+ }
116
+ async function getExpandedListOfLogs({ logItemTypes, catalogers = [], dateBefore = new Date(), dateAfter = '1970-01-01', test: _test = false }) {
117
+ const wantedLogItemTypes = logItemTypes === undefined
118
+ ? [LOG_ITEM_TYPE.MERGE_LOG, LOG_ITEM_TYPE.MATCH_LOG]
119
+ : logItemTypes;
120
+ if (!Array.isArray(wantedLogItemTypes)) {
121
+ throw new ApiError(httpStatus.BAD_REQUEST, `logItemTypes must be an array: ${logItemTypes}`);
122
+ }
123
+ if (logItemTypes !== undefined) {
124
+ wantedLogItemTypes.forEach(logItemType => {
125
+ if (isKnownLogItemType(logItemType)) {
126
+ return;
127
+ }
128
+ throw new ApiError(httpStatus.BAD_REQUEST, `Unknown logItemType: ${logItemType}`);
129
+ });
130
+ }
131
+ logger.debug(`commons/getExpandedListOfLogs: logItemTypes: ${JSON.stringify(wantedLogItemTypes)}, dateAfter: ${dateAfter}, dateBefore: ${dateBefore}, catalogers: ${JSON.stringify(catalogers)}`);
132
+ logger.silly(JSON.stringify(generateMatchObject({ logItemTypes: wantedLogItemTypes, catalogers, dateBefore, dateAfter })));
133
+ const pipeline = [
134
+ generateMatchObject({ logItemTypes: wantedLogItemTypes, catalogers, dateBefore, dateAfter }),
135
+ {
136
+ '$sort': { 'correlationId': 1, 'logItemType': 1, 'creationTime': 1 }
137
+ },
138
+ {
139
+ '$group': {
140
+ '_id': { 'correlationId': '$correlationId', 'logItemType': '$logItemType' },
141
+ 'creationTime': { '$first': '$creationTime' },
142
+ 'cataloger': { '$first': '$cataloger' },
143
+ 'logCount': { '$sum': 1 }
144
+ }
145
+ },
146
+ {
147
+ '$sort': { '_id.correlationId': 1, '_id.logItemType': 1, 'creationTime': 1 }
148
+ }
149
+ ];
150
+ const result = await logCollection
151
+ .aggregate(pipeline)
152
+ .toArray();
153
+ const fixedResult = result.map(logListing => {
154
+ const { correlationId, logItemType } = logListing['_id'];
155
+ const { cataloger, creationTime, logCount } = logListing;
156
+ return { correlationId, logItemType, cataloger, creationTime, logCount };
157
+ });
158
+ logger.silly(`Query result: ${JSON.stringify(result)}`);
159
+ logger.silly(`Query result: ${JSON.stringify(fixedResult)}`);
160
+ logger.debug(`Query result: ${fixedResult.length > 0 ? `Found ${fixedResult.length} log items!` : 'Not found!'}`);
161
+ return fixedResult;
162
+ function generateMatchObject({ logItemTypes, catalogers, dateBefore, dateAfter }) {
163
+ const matchOptions = {
164
+ '$match': {
165
+ 'logItemType': logItemTypes.length > 0 ? { '$in': logItemTypes } : /.*/ui,
166
+ 'cataloger': catalogers.length > 0 ? { '$in': catalogers } : /.*/ui,
167
+ 'creationTime': {
168
+ '$gte': dateToUtcStartOfDay(dateAfter),
169
+ '$lt': dateToUtcExclusiveUpperBound(dateBefore)
170
+ }
171
+ }
172
+ };
173
+ return matchOptions;
174
+ function dateToUtcStartOfDay(value) {
175
+ if (value instanceof Date) {
176
+ return value;
177
+ }
178
+ const parts = String(value).slice(0, 10).split('-');
179
+ if (parts.length === 3) {
180
+ return new Date(Date.UTC(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2])));
181
+ }
182
+ return new Date(value);
183
+ }
184
+ function dateToUtcExclusiveUpperBound(value) {
185
+ if (value instanceof Date) {
186
+ return value;
187
+ }
188
+ const parts = String(value).slice(0, 10).split('-');
189
+ if (parts.length === 3) {
190
+ return new Date(Date.UTC(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2])) + 86400000);
191
+ }
192
+ return new Date(value);
193
+ }
194
+ }
90
195
  }
91
- if (logItemTypes !== void 0) {
92
- logItemTypes.forEach((logItemType) => {
93
- if (Object.values(LOG_ITEM_TYPE).includes(logItemType)) {
94
- return;
196
+ async function protect(correlationId, blobSequence) {
197
+ logger.info(`Protecting in Mongo (${collection}) correlationId: ${correlationId}, blobSequence: ${blobSequence}`);
198
+ assertString(correlationId, 'correlationId');
199
+ const filter = buildBlobSequenceFilter(correlationId, blobSequence);
200
+ try {
201
+ const result = await logCollection.updateMany(filter, [
202
+ {
203
+ $set: {
204
+ modificationTime: new Date(),
205
+ protected: true
206
+ }
207
+ }
208
+ ]);
209
+ return result;
210
+ }
211
+ catch (error) {
212
+ const apiError = error;
213
+ const errorMessage = apiError.payload || apiError.message || '';
214
+ logError(error);
215
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
95
216
  }
96
- throw new ApiError(httpStatus.BAD_REQUEST, `Unknown logItemType: ${logItemType}`);
97
- });
98
217
  }
99
- logger.debug(`commons/getExpandedListOfLogs: logItemTypes: ${JSON.stringify(wantedLogItemTypes)}, dateAfter: ${dateAfter}, dateBefore: ${dateBefore}}, catalogers: ${JSON.stringify(catalogers)}`);
100
- logger.silly(JSON.stringify(generateMatchObject({ logItemTypes: wantedLogItemTypes, catalogers, dateBefore, dateAfter })));
101
- const pipeline = [
102
- // currently return only MERGE_LOG and MATCH_LOG
103
- generateMatchObject({ logItemTypes: wantedLogItemTypes, catalogers, dateBefore, dateAfter }),
104
- {
105
- "$sort": { "correlationId": 1, "logItemType": 1, "creationTime": 1 }
106
- },
107
- {
108
- "$group": {
109
- "_id": { "correlationId": "$correlationId", "logItemType": "$logItemType" },
110
- "creationTime": { "$first": "$creationTime" },
111
- "cataloger": { "$first": "$cataloger" },
112
- "logCount": { "$sum": 1 }
218
+ async function unprotect(correlationId, blobSequence) {
219
+ logger.info(`Unprotecting in Mongo (${collection}) correlationId: ${correlationId}, blobSequence: ${blobSequence}`);
220
+ assertString(correlationId, 'correlationId');
221
+ const filter = buildBlobSequenceFilter(correlationId, blobSequence);
222
+ try {
223
+ const result = await logCollection.updateMany(filter, [
224
+ {
225
+ $set: {
226
+ modificationTime: new Date(),
227
+ protected: false
228
+ }
229
+ }
230
+ ]);
231
+ return result;
113
232
  }
114
- },
115
- // after $group the output has no top-level correlationId /
116
- // logItemType, so the sort must address them via _id
117
- {
118
- "$sort": { "_id.correlationId": 1, "_id.logItemType": 1, "creationTime": 1 }
119
- }
120
- ];
121
- const result = await db.collection(collection).aggregate(pipeline).toArray();
122
- const fixedResult = result.map((logListing) => {
123
- const { correlationId, logItemType } = logListing._id;
124
- const { cataloger, creationTime, logCount } = logListing;
125
- return { correlationId, logItemType, cataloger, creationTime, logCount };
126
- });
127
- logger.silly(`Query result: ${JSON.stringify(result)}`);
128
- logger.silly(`Query result: ${JSON.stringify(fixedResult)}`);
129
- logger.debug(`Query result: ${fixedResult.length > 0 ? `Found ${fixedResult.length} log items!` : "Not found!"}`);
130
- return fixedResult;
131
- function generateMatchObject({ logItemTypes: logItemTypes2, catalogers: catalogers2, dateBefore: dateBefore2, dateAfter: dateAfter2 }) {
132
- const matchOptions = {
133
- "$match": {
134
- "logItemType": logItemTypes2.length > 0 ? { "$in": logItemTypes2 } : /.*/ui,
135
- "cataloger": catalogers2.length > 0 ? { "$in": catalogers2 } : /.*/ui,
136
- // creationTime is stored as a Date, so the bounds must be
137
- // Dates too (the old test=true branch compared against ISO strings
138
- // and never matched; the old non-test branch relied on
139
- // local-timezone parsing of new Date('YYYY-MM-DD')). Date strings
140
- // are anchored at UTC midnight so the result is deterministic
141
- // regardless of the server timezone.
142
- "creationTime": {
143
- "$gte": dateToUtcStartOfDay(dateAfter2),
144
- "$lt": dateToUtcExclusiveUpperBound(dateBefore2)
145
- }
233
+ catch (error) {
234
+ const apiError = error;
235
+ const errorMessage = apiError.payload || apiError.message || '';
236
+ logError(error);
237
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
146
238
  }
147
- };
148
- return matchOptions;
149
- function dateToUtcStartOfDay(value) {
150
- if (value instanceof Date) {
151
- return value;
239
+ }
240
+ async function remove(correlationId, force = false) {
241
+ logger.info(`Removing from Mongo (${collection}) correlationId: ${correlationId}`);
242
+ assertString(correlationId, 'correlationId');
243
+ const filter = force ? { correlationId } : { correlationId, protected: { $ne: true } };
244
+ try {
245
+ const result = await logCollection.deleteMany(filter);
246
+ return result;
152
247
  }
153
- const parts = String(value).slice(0, 10).split("-");
154
- if (parts.length === 3) {
155
- return new Date(Date.UTC(parts[0], parts[1] - 1, parts[2]));
248
+ catch (error) {
249
+ const apiError = error;
250
+ const errorMessage = apiError.payload || apiError.message || '';
251
+ logError(error);
252
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
156
253
  }
157
- return new Date(value);
158
- }
159
- function dateToUtcExclusiveUpperBound(value) {
160
- if (value instanceof Date) {
161
- return value;
254
+ }
255
+ async function removeBySequences(correlationId, sequences = [], force = false) {
256
+ logger.info(`Removing from Mongo (${collection}) correlationId: ${correlationId}, sequences: ${sequences.length}`);
257
+ assertString(correlationId, 'correlationId');
258
+ const cleanSequences = sequences
259
+ .map(sequence => Number(sequence))
260
+ .filter(sequence => Number.isInteger(sequence) && sequence > 0);
261
+ if (sequences.length !== cleanSequences.length) {
262
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Invalid sequences in removeBySequences. Sequences should be positive integers`);
162
263
  }
163
- const parts = String(value).slice(0, 10).split("-");
164
- if (parts.length === 3) {
165
- return new Date(Date.UTC(parts[0], parts[1] - 1, parts[2]) + 864e5);
264
+ const filter = force
265
+ ? { correlationId, blobSequence: { $in: cleanSequences } }
266
+ : { correlationId, blobSequence: { $in: cleanSequences }, protected: { $ne: true } };
267
+ try {
268
+ const result = await logCollection.deleteMany(filter);
269
+ return result;
270
+ }
271
+ catch (error) {
272
+ const apiError = error;
273
+ const errorMessage = apiError.payload || apiError.message || '';
274
+ logError(error);
275
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
166
276
  }
167
- return new Date(value);
168
- }
169
277
  }
170
- }
171
- async function protect(correlationId, blobSequence) {
172
- logger.info(`Protecting in Mongo (${collection}) correlationId: ${correlationId}, blobSequence: ${blobSequence}`);
173
- assertString(correlationId, "correlationId");
174
- const filter = buildBlobSequenceFilter(correlationId, blobSequence);
175
- try {
176
- const result = await db.collection(collection).updateMany(
177
- filter,
178
- [
179
- {
180
- $set: {
181
- modificationTime: /* @__PURE__ */ new Date(),
182
- // plain true, not a $not toggle: protect must be idempotent
183
- protected: true
278
+ function checkLogItemType(logItemType, errorUnknown = false) {
279
+ if (logItemType) {
280
+ const typeInLogItemTypes = isKnownLogItemType(logItemType);
281
+ if (typeInLogItemTypes) {
282
+ logger.debug(`Valid logItemType: ${logItemType}`);
283
+ return;
184
284
  }
185
- }
186
- ]
187
- );
188
- return result;
189
- } catch (error) {
190
- const errorMessage = error.payload || error.message || "";
191
- logError(error);
192
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
193
- }
194
- }
195
- async function unprotect(correlationId, blobSequence) {
196
- logger.info(`Unprotecting in Mongo (${collection}) correlationId: ${correlationId}, blobSequence: ${blobSequence}`);
197
- assertString(correlationId, "correlationId");
198
- const filter = buildBlobSequenceFilter(correlationId, blobSequence);
199
- try {
200
- const result = await db.collection(collection).updateMany(
201
- filter,
202
- [
203
- {
204
- $set: {
205
- modificationTime: /* @__PURE__ */ new Date(),
206
- protected: false
285
+ if (errorUnknown) {
286
+ throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Unknown logItemType: ${logItemType}`);
207
287
  }
208
- }
209
- ]
210
- );
211
- return result;
212
- } catch (error) {
213
- const errorMessage = error.payload || error.message || "";
214
- logError(error);
215
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
216
- }
217
- }
218
- async function remove(correlationId, force = false) {
219
- logger.info(`Removing from Mongo (${collection}) correlationId: ${correlationId}`);
220
- assertString(correlationId, "correlationId");
221
- const filter = force ? { correlationId } : { correlationId, protected: { $ne: true } };
222
- try {
223
- const result = await db.collection(collection).deleteMany(filter);
224
- return result;
225
- } catch (error) {
226
- const errorMessage = error.payload || error.message || "";
227
- logError(error);
228
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
229
- }
230
- }
231
- async function removeBySequences(correlationId, sequences = [], force = false) {
232
- logger.info(`Removing from Mongo (${collection}) correlationId: ${correlationId}, sequences: ${sequences.length}`);
233
- assertString(correlationId, "correlationId");
234
- const cleanSequences = sequences.map((sequence) => Number(sequence)).filter((sequence) => Number.isInteger(sequence) && sequence > 0);
235
- if (sequences.length !== cleanSequences.length) {
236
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Invalid sequences in removeBySequences. Sequences should be positive integers`);
237
- }
238
- const filter = force ? { correlationId, blobSequence: { $in: cleanSequences } } : { correlationId, blobSequence: { $in: cleanSequences }, protected: { $ne: true } };
239
- try {
240
- const result = await db.collection(collection).deleteMany(filter);
241
- return result;
242
- } catch (error) {
243
- const errorMessage = error.payload || error.message || "";
244
- logError(error);
245
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
246
- }
247
- }
248
- function checkLogItemType(logItemType, errorUnknown = false) {
249
- if (logItemType) {
250
- const typeInLogItemTypes = Object.values(LOG_ITEM_TYPE).indexOf(logItemType) > -1;
251
- if (typeInLogItemTypes) {
252
- return logger.debug(`Valid logItemType: ${logItemType}`);
253
- }
254
- if (errorUnknown) {
255
- throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Unknown logItemType: ${logItemType}`);
256
- }
257
- return logger.debug(`WARN: We have unknown logType: ${logItemType}`);
288
+ logger.debug(`WARN: We have unknown logType: ${logItemType}`);
289
+ return;
290
+ }
291
+ logger.debug(`No logItemType: ${logItemType}`);
258
292
  }
259
- return logger.debug(`No logItemType: ${logItemType}`);
260
- }
261
293
  }
262
- //# sourceMappingURL=mongoLog.js.map
294
+ //# sourceMappingURL=mongoLog.js.map
@@ -1,7 +1 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/mongoLog.js"],
4
- "sourcesContent": ["import {MongoClient} from 'mongodb';\nimport httpStatus from 'http-status';\nimport {createLogger, Error as ApiError} from '@natlibfi/melinda-commons';\nimport {logError, assertString} from './utils.js';\nimport {LOG_ITEM_TYPE} from './constants.js';\n\n/**\n * Create log operator\n * @param {String} MONGO_URI connnection address to mongo\n * @param {String} dbName Mongo DB name, defaults 'rest-api'\n * @param {Object} deps optional dependencies, defaults {}. When deps.collection (a Mongo collection object) is provided, no real Mongo connection is made (used by unit tests)\n * @returns {Object} containing all log handling functions\n */\nexport default async function (MONGO_URI, dbName = 'rest-api', deps = {}) {\n const logger = createLogger();\n\n // blobSequence filters: falsy/undefined keeps the legacy behaviour (no\n // blobSequence in the filter). Otherwise a number or a string parseable\n // to an integer (existing parseInt behaviour) is accepted, anything else\n // is rejected with 400.\n function buildBlobSequenceFilter(correlationId, blobSequence) {\n if (!blobSequence) {\n return {correlationId};\n }\n if (typeof blobSequence === 'number') {\n return {correlationId, blobSequence: parseInt(blobSequence, 10)};\n }\n if (typeof blobSequence === 'string') {\n const parsed = parseInt(blobSequence, 10);\n if (!Number.isNaN(parsed)) {\n return {correlationId, blobSequence: parsed};\n }\n }\n throw new ApiError(httpStatus.BAD_REQUEST, 'blobSequence must be a number or a numeric string');\n }\n\n // Connect to mongo (MONGO), unless the logs collection is injected via\n // deps (used by unit tests to avoid a real connection)\n const collection = 'logs';\n let db;\n if (deps.collection) {\n db = {collection: () => deps.collection};\n } else {\n const client = await MongoClient.connect(MONGO_URI);\n db = client.db(dbName);\n }\n return {addLogItem, query, queryById, getListOfLogs, getListOfCatalogers, getListOfCorrelationIds, getExpandedListOfLogs, protect, unprotect, remove, removeBySequences};\n\n /**\n * Add log item to collection\n * @param {Object} logItem contains log item data\n * @returns void\n */\n async function addLogItem(logItem) {\n const time = new Date();\n const newLogItem = {\n ...logItem,\n creationTime: time,\n protected: false\n };\n try {\n // console.log(newLogItem); // eslint-disable-line\n checkLogItemType(logItem.logItemType, false);\n const result = await db.collection(collection).insertOne(newLogItem);\n if (result.acknowledged) {\n const {blobSequence, blobSequenceStart, blobSequenceEnd} = logItem;\n const itemString = blobSequenceStart && blobSequenceEnd ? `${blobSequenceStart} - ${blobSequenceEnd}` : `${blobSequence}`;\n logger.info(`*** New ${logItem.logItemType} added for ${logItem.correlationId}, blobSequence(s): ${itemString}. ***`);\n // console.log('addLogItem done', result); // eslint-disable-line\n return;\n }\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR);\n } catch (error) {\n const errorMessage = error.payload || error.message || '';\n logError(error);\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);\n }\n }\n\n /**\n * Query log items\n * @param {Integer} limit defaults 5\n * @param {Integer} skip defaults 0\n * @param {Object} rest query params\n * @returns result array\n */\n async function query({limit = 5, skip = 0, ...rest}) {\n logger.debug(`Query params: ${JSON.stringify(rest)}`);\n logger.debug(`Limit and skip params: ${limit} | ${skip}`);\n checkLogItemType(rest.logItemType, false);\n // rest is an internal, trusted query object built by the calling service:\n // callers must not splice raw user input into it. Its keys may legitimately\n // use dot notation and $-operators, which is why rest is not\n // field-sanitized here.\n const result = await db.collection(collection)\n .find(rest)\n .sort({creationTime: 1})\n .skip(parseInt(skip, 10))\n .limit(parseInt(limit, 10))\n .toArray();\n //logger.debug(`Query result: ${result}`);\n logger.debug(`Query result: ${result.length > 0 ? `Found ${result.length} log items! (skip: ${skip} limit: ${limit})` : 'Not found!'}`);\n return result;\n }\n\n // DEVELOP: queryById returns jsut one (randomish) log! is this useful?\n /**\n * Get single log item by correlationId\n * @param {String} correlationId\n * @param {String} logItemType constant LOG_ITEM_TYPE defaults LOG_ITEM_TYPE.MERGE_LOG\n * @param {Integer} skip defaults 0\n * @param {Integer} limit defaults 1\n * @returns query result array\n */\n async function queryById(correlationId, logItemType = LOG_ITEM_TYPE.MERGE_LOG, skip = 0, limit = 1) {\n assertString(correlationId, 'correlationId');\n logger.debug(`QueryById: ${correlationId}, logItemType: ${logItemType}, skip: ${skip}, limit: ${limit}`);\n const result = await db.collection(collection)\n .find({correlationId, logItemType})\n .sort({blobSequence: 1})\n .skip(parseInt(skip, 10))\n .limit(parseInt(limit, 10))\n .toArray();\n logger.debug(`Query result: ${result.length > 0 ? `Found ${result.length} log items!` : 'Not found!'}`);\n return result;\n }\n\n // getListOfLogs returns list of correlationIds that have logs of given logItemType\n // if logItemType is not given, getListOfLogs returns list of correlationIds that have MERGE_LOG\n /**\n * Get list of correlationIds of logs filtered by logItemType\n * @param {String} logItemType constant LOG_ITEM_TYPE defaults LOG_ITEM_TYPE.MERGE_LOG\n * @returns Array of query results\n */\n async function getListOfLogs(logItemType = LOG_ITEM_TYPE.MERGE_LOG) {\n checkLogItemType(logItemType, true);\n //logger.debug(logItemType);\n // console.log(`${JSON.stringify(logItemType)}`);\n const result = await db.collection(collection)\n .distinct('correlationId', {logItemType: logItemType});\n logger.debug(`Query result for getListOfLogs: ${result.length > 0 ? `Found ${result.length} correlationIds for ${logItemType}!` : 'Not found!'}`);\n return result;\n }\n\n /**\n * Get list of catalogers from all available logs\n * @returns Array of query results\n */\n async function getListOfCatalogers() {\n logger.debug(`Getting list of Catalogers`);\n\n const result = await db.collection(collection)\n .distinct('cataloger');\n\n return result;\n }\n\n /**\n * Get list of correlationIds from all available logs\n * @returns Array of query results\n */\n async function getListOfCorrelationIds() {\n logger.debug(`Getting list of CorrelationIds`);\n\n const result = await db.collection(collection)\n .distinct('correlationId');\n\n return result;\n }\n\n\n /**\n * Get filtered list of logs with extra info. Give params in Object\n * @param {[String]} logItemTypes: String array of logItemTypes. Defaults [LOG_ITEM_TYPE.MERGE_LOG, LOG_ITEM_TYPE.MATCH_LOG]. When provided, must be an array and every element is validated (unknown types throw)\n * @param {[String]} catalogers: String array of wanted catalogers. Defaults []\n * @param {String|Date} dateBefore: upper bound, the day itself is EXCLUDED. 'YYYY-MM-DD' or Date, anchored to UTC. Defaults new Date()\n * @param {String|Date} dateAfter: lower bound, the day itself is INCLUDED. 'YYYY-MM-DD' or Date, anchored to UTC. Defaults '1970-01-01' (no lower bound)\n * @param {Boolean} test: kept for backwards compatibility only; no longer changes the match\n * @returns Parsed Object {'correlationId', 'logItemType', 'creationTime', 'cataloger', 'logCount'}\n */\n // test no longer changes the match behaviour (kept in the\n // signature for backwards compatibility only)\n // eslint-disable-next-line no-unused-vars\n async function getExpandedListOfLogs({logItemTypes, catalogers = [], dateBefore = new Date(), dateAfter = '1970-01-01', test = false}) {\n // An explicitly provided logItemTypes is validated per element (unknown\n // types throw); when it is omitted, the trusted default pair is used so\n // legacy callers that never pass it keep working unchanged\n const wantedLogItemTypes = logItemTypes === undefined\n ? [LOG_ITEM_TYPE.MERGE_LOG, LOG_ITEM_TYPE.MATCH_LOG]\n : logItemTypes;\n if (!Array.isArray(wantedLogItemTypes)) {\n throw new ApiError(httpStatus.BAD_REQUEST, `logItemTypes must be an array: ${logItemTypes}`);\n }\n if (logItemTypes !== undefined) {\n logItemTypes.forEach(logItemType => {\n if (Object.values(LOG_ITEM_TYPE).includes(logItemType)) {\n return;\n }\n throw new ApiError(httpStatus.BAD_REQUEST, `Unknown logItemType: ${logItemType}`);\n });\n }\n logger.debug(`commons/getExpandedListOfLogs: logItemTypes: ${JSON.stringify(wantedLogItemTypes)}, dateAfter: ${dateAfter}, dateBefore: ${dateBefore}}, catalogers: ${JSON.stringify(catalogers)}`);\n logger.silly(JSON.stringify(generateMatchObject({logItemTypes: wantedLogItemTypes, catalogers, dateBefore, dateAfter})));\n //logger.debug(`Getting expanded list of logs`);\n const pipeline = [\n // currently return only MERGE_LOG and MATCH_LOG\n generateMatchObject({logItemTypes: wantedLogItemTypes, catalogers, dateBefore, dateAfter}),\n {\n '$sort':\n {'correlationId': 1, 'logItemType': 1, 'creationTime': 1}\n },\n {\n '$group':\n {\n '_id': {'correlationId': '$correlationId', 'logItemType': '$logItemType'},\n 'creationTime': {'$first': '$creationTime'},\n 'cataloger': {'$first': '$cataloger'},\n 'logCount': {'$sum': 1}\n }\n },\n // after $group the output has no top-level correlationId /\n // logItemType, so the sort must address them via _id\n {\n '$sort':\n {'_id.correlationId': 1, '_id.logItemType': 1, 'creationTime': 1}\n }\n ];\n\n const result = await db.collection(collection)\n .aggregate(pipeline)\n .toArray();\n\n const fixedResult = result.map((logListing) => {\n const {correlationId, logItemType} = logListing._id;\n const {cataloger, creationTime, logCount} = logListing;\n return {correlationId, logItemType, cataloger, creationTime, logCount};\n });\n\n logger.silly(`Query result: ${JSON.stringify(result)}`);\n logger.silly(`Query result: ${JSON.stringify(fixedResult)}`);\n\n logger.debug(`Query result: ${fixedResult.length > 0 ? `Found ${fixedResult.length} log items!` : 'Not found!'}`);\n return fixedResult;\n\n /**\n * Generate match object for aggregation pipeline\n * @param {[String]} logItemTypes: String array of logItemTypes.\n * @param {[String]} catalogers: String array of wanted catalogers\n * @param {String|Date} dateBefore: upper bound. Date strings are anchored at UTC midnight of the day after; Date instances are used as-is\n * @param {String|Date} dateAfter: lower bound. Date strings are anchored at UTC midnight of that day (inclusive); Date instances are used as-is\n * @returns Match Object\n */\n function generateMatchObject({logItemTypes, catalogers, dateBefore, dateAfter}) {\n const matchOptions = {\n '$match': {\n 'logItemType': logItemTypes.length > 0 ? {'$in': logItemTypes} : /.*/ui,\n 'cataloger': catalogers.length > 0 ? {'$in': catalogers} : /.*/ui,\n // creationTime is stored as a Date, so the bounds must be\n // Dates too (the old test=true branch compared against ISO strings\n // and never matched; the old non-test branch relied on\n // local-timezone parsing of new Date('YYYY-MM-DD')). Date strings\n // are anchored at UTC midnight so the result is deterministic\n // regardless of the server timezone.\n 'creationTime': {\n '$gte': dateToUtcStartOfDay(dateAfter),\n '$lt': dateToUtcExclusiveUpperBound(dateBefore)\n }\n }\n };\n\n return matchOptions;\n\n // Date string 'YYYY-MM-DD' -> UTC midnight of that day (inclusive\n // lower bound). Date instance or any other string format -> parsed\n // with Date (a timestamp, not a day).\n function dateToUtcStartOfDay(value) {\n if (value instanceof Date) {\n return value;\n }\n const parts = String(value).slice(0, 10).split('-');\n if (parts.length === 3) {\n return new Date(Date.UTC(parts[0], parts[1] - 1, parts[2]));\n }\n return new Date(value);\n }\n\n // Date string 'YYYY-MM-DD' -> UTC midnight of the NEXT day (exclusive\n // upper bound). Date instance or any other string format -> parsed\n // with Date (a timestamp, not a day).\n function dateToUtcExclusiveUpperBound(value) {\n if (value instanceof Date) {\n return value;\n }\n const parts = String(value).slice(0, 10).split('-');\n if (parts.length === 3) {\n return new Date(Date.UTC(parts[0], parts[1] - 1, parts[2]) + 86400000);\n }\n return new Date(value);\n }\n }\n }\n\n /**\n * Protect logs from cleaning. Idempotent: always sets protected to true\n * (a second call leaves the logs protected, unlike the old toggle).\n * Forced cleaning defaults 30days\n * @param {String} correlationId\n * @param {Integer} blobSequence\n * @returns result\n */\n async function protect(correlationId, blobSequence) {\n logger.info(`Protecting in Mongo (${collection}) correlationId: ${correlationId}, blobSequence: ${blobSequence}`);\n assertString(correlationId, 'correlationId');\n const filter = buildBlobSequenceFilter(correlationId, blobSequence);\n\n try {\n const result = await db.collection(collection).updateMany(\n filter,\n [\n {\n $set: {\n modificationTime: new Date(),\n // plain true, not a $not toggle: protect must be idempotent\n protected: true\n }\n }\n ]\n );\n return result;\n } catch (error) {\n const errorMessage = error.payload || error.message || '';\n logError(error);\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);\n }\n }\n\n /**\n * Unprotect logs so regular (non-forced) cleaning can remove them.\n * Same signature and behavior as protect, but sets protected to false.\n * @param {String} correlationId\n * @param {Integer} blobSequence\n * @returns result\n */\n async function unprotect(correlationId, blobSequence) {\n logger.info(`Unprotecting in Mongo (${collection}) correlationId: ${correlationId}, blobSequence: ${blobSequence}`);\n assertString(correlationId, 'correlationId');\n const filter = buildBlobSequenceFilter(correlationId, blobSequence);\n\n try {\n const result = await db.collection(collection).updateMany(\n filter,\n [\n {\n $set: {\n modificationTime: new Date(),\n protected: false\n }\n }\n ]\n );\n return result;\n } catch (error) {\n const errorMessage = error.payload || error.message || '';\n logError(error);\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);\n }\n }\n\n /**\n * Remove logs\n * @param {String} correlationId\n * @param {Boolean} force defaults false\n * @returns result\n */\n async function remove(correlationId, force = false) {\n logger.info(`Removing from Mongo (${collection}) correlationId: ${correlationId}`);\n assertString(correlationId, 'correlationId');\n const filter = force ? {correlationId} : {correlationId, protected: {$ne: true}};\n\n try {\n const result = await db.collection(collection).deleteMany(filter);\n return result;\n } catch (error) {\n const errorMessage = error.payload || error.message || '';\n logError(error);\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);\n }\n }\n\n /**\n * Remove logs by sequences\n * @param {String} correlationId\n * @param {[Integer]} sequences\n * @param {Boolean} force defaults false\n * @returns result\n */\n async function removeBySequences(correlationId, sequences = [], force = false) {\n logger.info(`Removing from Mongo (${collection}) correlationId: ${correlationId}, sequences: ${sequences.length}`);\n assertString(correlationId, 'correlationId');\n // NOTE: this matches only single-sequence items (blobSequence), NOT bulk\n // range items (blobSequenceStart/blobSequenceEnd); a requested sequence\n // inside a bulk range will not match and its logs are kept\n // blobSequences are integers that start from 1\n // we accept also strings that are convertilble to integers greated than 0\n // validate consistently via Number() and store the\n // converted numbers, since blobSequence is stored as a number in Mongo\n const cleanSequences = sequences\n .map(sequence => Number(sequence))\n .filter(sequence => Number.isInteger(sequence) && sequence > 0);\n\n if (sequences.length !== cleanSequences.length) {\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Invalid sequences in removeBySequences. Sequences should be positive integers`);\n }\n\n // use the numeric cleanSequences in BOTH branches (the non-forced\n // branch used to pass raw `sequences`, so string inputs like '1' would\n // never match the stored numeric blobSequence)\n const filter = force\n ? {correlationId, blobSequence: {$in: cleanSequences}}\n : {correlationId, blobSequence: {$in: cleanSequences}, protected: {$ne: true}};\n\n try {\n const result = await db.collection(collection).deleteMany(filter);\n return result;\n } catch (error) {\n const errorMessage = error.payload || error.message || '';\n logError(error);\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);\n }\n }\n\n /**\n * Checks existence and validity of logItemType\n * @param {String} logItemType constant LOG_ITEM_TYPE\n * @param {Boolean} errorUnknown defaults false\n * @returns void\n */\n function checkLogItemType(logItemType, errorUnknown = false) {\n if (logItemType) {\n const typeInLogItemTypes = Object.values(LOG_ITEM_TYPE).indexOf(logItemType) > -1;\n if (typeInLogItemTypes) {\n return logger.debug(`Valid logItemType: ${logItemType}`);\n }\n if (errorUnknown) {\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Unknown logItemType: ${logItemType}`);\n }\n return logger.debug(`WARN: We have unknown logType: ${logItemType}`);\n }\n\n return logger.debug(`No logItemType: ${logItemType}`);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["logItemTypes", "catalogers", "dateBefore", "dateAfter"]
7
- }
1
+ {"version":3,"file":"mongoLog.js","sourceRoot":"","sources":["../src/mongoLog.ts"],"names":[],"mappings":"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"}