@tstdl/base 0.92.123 → 0.92.125

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 (221) hide show
  1. package/ai/ai-file.service.js +23 -18
  2. package/ai/ai.service.d.ts +4 -12
  3. package/ai/ai.service.js +79 -147
  4. package/ai/functions.d.ts +1 -1
  5. package/ai/types.d.ts +3 -1
  6. package/api/server/gateway.js +6 -6
  7. package/authentication/authentication.api.js +24 -24
  8. package/authentication/server/authentication.service.js +20 -20
  9. package/browser/page-controller.js +1 -1
  10. package/context/context.js +5 -5
  11. package/document-management/api/document-management.api.d.ts +60 -215
  12. package/document-management/api/document-management.api.js +32 -68
  13. package/document-management/models/document-assignment-scope.model.d.ts +11 -0
  14. package/document-management/models/{document-request-assignment-task-collection.model.js → document-assignment-scope.model.js} +14 -10
  15. package/document-management/models/document-assignment-task.model.d.ts +13 -0
  16. package/document-management/models/document-assignment-task.model.js +38 -0
  17. package/document-management/models/document-category.model.d.ts +2 -0
  18. package/document-management/models/document-category.model.js +7 -1
  19. package/document-management/models/{document-collection-document.model.d.ts → document-collection-assignment.model.d.ts} +1 -1
  20. package/document-management/models/{document-collection-document.model.js → document-collection-assignment.model.js} +7 -7
  21. package/document-management/models/document-collection.model.d.ts +2 -0
  22. package/document-management/models/document-collection.model.js +10 -0
  23. package/document-management/models/document-property-value.model.d.ts +3 -11
  24. package/document-management/models/document-property-value.model.js +15 -46
  25. package/document-management/models/document-property.model.d.ts +2 -1
  26. package/document-management/models/document-property.model.js +2 -2
  27. package/document-management/models/document-request-submission.model.d.ts +7 -0
  28. package/document-management/models/document-request-submission.model.js +34 -0
  29. package/document-management/models/document-request-template.d.ts +2 -4
  30. package/document-management/models/document-request-template.js +3 -8
  31. package/document-management/models/document-request.model.d.ts +14 -6
  32. package/document-management/models/document-request.model.js +22 -12
  33. package/document-management/models/document-type-validation.model.d.ts +6 -0
  34. package/document-management/models/document-type-validation.model.js +34 -0
  35. package/document-management/models/document-type.model.d.ts +0 -1
  36. package/document-management/models/document-type.model.js +0 -5
  37. package/document-management/models/document-validation-definition.model.d.ts +10 -0
  38. package/document-management/models/document-validation-definition.model.js +39 -0
  39. package/document-management/models/document-validation-execution-related-document.model.d.ts +7 -0
  40. package/document-management/models/document-validation-execution-related-document.model.js +34 -0
  41. package/document-management/models/document-validation-execution.model.d.ts +26 -0
  42. package/document-management/models/document-validation-execution.model.js +72 -0
  43. package/document-management/models/document-workflow.model.d.ts +35 -0
  44. package/document-management/models/document-workflow.model.js +70 -0
  45. package/document-management/models/document.model.d.ts +12 -1
  46. package/document-management/models/document.model.js +21 -5
  47. package/document-management/models/index.d.ts +10 -5
  48. package/document-management/models/index.js +10 -5
  49. package/document-management/models/service-models/categories-and-types.view-model.d.ts +3 -3
  50. package/document-management/models/service-models/categories-and-types.view-model.js +2 -21
  51. package/document-management/models/service-models/document-folders.view-model.d.ts +7 -14
  52. package/document-management/models/service-models/document-folders.view-model.js +20 -44
  53. package/document-management/models/service-models/document-management.view-model.d.ts +41 -0
  54. package/document-management/models/service-models/{document.view-model.js → document-management.view-model.js} +43 -26
  55. package/document-management/models/service-models/document.service-model.d.ts +51 -81
  56. package/document-management/models/service-models/document.service-model.js +30 -28
  57. package/document-management/models/service-models/enriched/enriched-document-assignment.view.d.ts +11 -0
  58. package/document-management/models/service-models/enriched/enriched-document-assignment.view.js +12 -0
  59. package/document-management/models/service-models/enriched/enriched-document-category.view.d.ts +13 -0
  60. package/document-management/models/service-models/enriched/enriched-document-category.view.js +47 -0
  61. package/document-management/models/service-models/enriched/enriched-document-collection.view.d.ts +22 -0
  62. package/document-management/models/service-models/enriched/enriched-document-collection.view.js +89 -0
  63. package/document-management/models/service-models/enriched/enriched-document-file.view.d.ts +12 -0
  64. package/document-management/models/service-models/enriched/enriched-document-file.view.js +16 -0
  65. package/document-management/models/service-models/enriched/enriched-document-management-data.view.d.ts +41 -0
  66. package/document-management/models/service-models/enriched/enriched-document-management-data.view.js +130 -0
  67. package/document-management/models/service-models/enriched/enriched-document-request.view.d.ts +17 -0
  68. package/document-management/models/service-models/enriched/enriched-document-request.view.js +52 -0
  69. package/document-management/models/service-models/enriched/enriched-document-type.view.d.ts +9 -0
  70. package/document-management/models/service-models/enriched/enriched-document-type.view.js +10 -0
  71. package/document-management/models/service-models/enriched/enriched-document.view.d.ts +28 -0
  72. package/document-management/models/service-models/enriched/enriched-document.view.js +77 -0
  73. package/document-management/models/service-models/enriched/enriched.d.ts +18 -0
  74. package/document-management/models/service-models/enriched/enriched.js +39 -0
  75. package/document-management/models/service-models/enriched/index.d.ts +9 -0
  76. package/document-management/models/service-models/enriched/index.js +9 -0
  77. package/document-management/models/service-models/index.d.ts +2 -2
  78. package/document-management/models/service-models/index.js +2 -2
  79. package/document-management/models/service-models/normalized-requests-template-data.model.d.ts +12 -10
  80. package/document-management/models/service-models/normalized-requests-template-data.model.js +5 -4
  81. package/document-management/models/service-models/stats.view-model.d.ts +7 -5
  82. package/document-management/models/service-models/stats.view-model.js +19 -9
  83. package/document-management/server/module.d.ts +2 -2
  84. package/document-management/server/module.js +3 -7
  85. package/document-management/server/schemas.d.ts +18 -23
  86. package/document-management/server/schemas.js +18 -23
  87. package/document-management/server/services/document-category-type.service.d.ts +25 -0
  88. package/document-management/server/services/document-category-type.service.js +66 -0
  89. package/document-management/server/services/document-collection.service.d.ts +13 -0
  90. package/document-management/server/services/document-collection.service.js +41 -0
  91. package/document-management/server/services/document-file.service.d.ts +17 -0
  92. package/document-management/server/services/document-file.service.js +204 -0
  93. package/document-management/server/services/document-management-ai.service.d.ts +22 -0
  94. package/document-management/server/services/document-management-ai.service.js +340 -0
  95. package/document-management/server/services/document-management-ancillary.service.d.ts +127 -3
  96. package/document-management/server/services/document-management-ancillary.service.js +24 -0
  97. package/document-management/server/services/document-management.service.d.ts +10 -122
  98. package/document-management/server/services/document-management.service.js +106 -888
  99. package/document-management/server/services/document-property.service.d.ts +84 -0
  100. package/document-management/server/services/document-property.service.js +87 -0
  101. package/document-management/server/services/document-request.service.d.ts +30 -0
  102. package/document-management/server/services/document-request.service.js +138 -0
  103. package/document-management/server/services/document-validation.service.d.ts +20 -0
  104. package/document-management/server/services/document-validation.service.js +145 -0
  105. package/document-management/server/services/document-workflow.service.d.ts +20 -0
  106. package/document-management/server/services/document-workflow.service.js +132 -0
  107. package/document-management/server/services/document.service.d.ts +16 -0
  108. package/document-management/server/services/document.service.js +81 -0
  109. package/document-management/server/services/index.d.ts +9 -0
  110. package/document-management/server/services/index.js +9 -0
  111. package/document-management/server/validators/ai-validation-executor.d.ts +19 -0
  112. package/document-management/server/validators/ai-validation-executor.js +51 -0
  113. package/document-management/server/validators/index.d.ts +2 -0
  114. package/document-management/server/validators/index.js +2 -0
  115. package/document-management/server/validators/single-document-validation-executor.d.ts +16 -0
  116. package/document-management/server/validators/single-document-validation-executor.js +20 -0
  117. package/document-management/server/validators/validator.d.ts +21 -0
  118. package/document-management/server/validators/validator.js +2 -0
  119. package/eslint.config.js +31 -17
  120. package/examples/document-management/main.d.ts +18 -3
  121. package/examples/document-management/main.js +28 -12
  122. package/file/mime-type.js +2 -9
  123. package/formats.d.ts +5 -2
  124. package/formats.js +32 -23
  125. package/http/client/http-client.js +1 -1
  126. package/injector/injector.js +2 -2
  127. package/object-storage/s3/s3.object-storage.js +1 -1
  128. package/orm/data-types/bytea.d.ts +8 -0
  129. package/orm/data-types/bytea.js +8 -0
  130. package/orm/data-types/index.d.ts +4 -0
  131. package/orm/data-types/index.js +4 -0
  132. package/orm/data-types/numeric-date.d.ts +9 -0
  133. package/orm/data-types/numeric-date.js +9 -0
  134. package/orm/data-types/timestamp.d.ts +9 -0
  135. package/orm/data-types/timestamp.js +9 -0
  136. package/orm/decorators.d.ts +139 -5
  137. package/orm/decorators.js +50 -0
  138. package/orm/entity.d.ts +19 -0
  139. package/orm/entity.js +19 -0
  140. package/orm/index.d.ts +5 -0
  141. package/orm/index.js +5 -0
  142. package/orm/query.d.ts +51 -0
  143. package/orm/query.js +6 -0
  144. package/orm/repository.types.d.ts +54 -2
  145. package/orm/server/database-schema.d.ts +34 -0
  146. package/orm/server/database-schema.js +29 -0
  147. package/orm/server/database.d.ts +19 -1
  148. package/orm/server/database.js +17 -3
  149. package/orm/server/drizzle/schema-converter.d.ts +2 -1
  150. package/orm/server/drizzle/schema-converter.js +12 -1
  151. package/orm/server/encryption.d.ts +16 -0
  152. package/orm/server/encryption.js +29 -4
  153. package/orm/server/index.d.ts +7 -0
  154. package/orm/server/index.js +7 -0
  155. package/orm/server/module.d.ts +20 -0
  156. package/orm/server/module.js +9 -0
  157. package/orm/server/query-converter.d.ts +17 -0
  158. package/orm/server/query-converter.js +66 -11
  159. package/orm/server/repository.d.ts +324 -18
  160. package/orm/server/repository.js +344 -73
  161. package/orm/server/transaction.d.ts +5 -5
  162. package/orm/server/transaction.js +5 -5
  163. package/orm/server/transactional.d.ts +75 -0
  164. package/orm/server/transactional.js +134 -0
  165. package/orm/server/types.d.ts +1 -0
  166. package/orm/sqls.d.ts +55 -0
  167. package/orm/sqls.js +60 -0
  168. package/orm/types.d.ts +67 -4
  169. package/orm/utils.d.ts +19 -3
  170. package/orm/utils.js +12 -0
  171. package/package.json +32 -31
  172. package/password/password-check-result.model.d.ts +9 -7
  173. package/password/password-check-result.model.js +8 -8
  174. package/password/password-check.js +5 -7
  175. package/password/password-check.localization.js +12 -12
  176. package/pdf/pdf.service.js +1 -1
  177. package/pdf/utils.d.ts +9 -0
  178. package/pdf/utils.js +19 -2
  179. package/process/spawn.d.ts +11 -4
  180. package/process/spawn.js +42 -5
  181. package/queue/postgres/queue.js +5 -5
  182. package/queue/queue.d.ts +6 -4
  183. package/queue/queue.js +6 -6
  184. package/schema/schemas/one-or-many.d.ts +2 -1
  185. package/schema/schemas/one-or-many.js +1 -1
  186. package/search-index/elastic/model/index-mapping.d.ts +1 -1
  187. package/search-index/elastic/model/index-mapping.js +0 -1
  188. package/search-index/elastic/search-index.d.ts +1 -2
  189. package/search-index/elastic/search-index.js +3 -3
  190. package/types.d.ts +1 -0
  191. package/utils/async-hook/async-hook.d.ts +9 -0
  192. package/utils/async-hook/async-hook.js +21 -0
  193. package/utils/async-hook/index.d.ts +1 -0
  194. package/utils/async-hook/index.js +1 -0
  195. package/utils/compression.js +1 -1
  196. package/utils/function/class.d.ts +6 -0
  197. package/utils/function/class.js +9 -0
  198. package/utils/function/index.d.ts +1 -0
  199. package/utils/function/index.js +1 -0
  200. package/utils/function/memoize.d.ts +18 -0
  201. package/utils/function/memoize.js +41 -2
  202. package/utils/jwt.d.ts +1 -1
  203. package/utils/jwt.js +5 -5
  204. package/utils/object/forward-ref.d.ts +3 -2
  205. package/utils/object/forward-ref.js +12 -12
  206. package/utils/object/lazy-property.js +2 -2
  207. package/utils/proxy.js +1 -1
  208. package/utils/stream/{readable-stream-from-promise.d.ts → from-promise.d.ts} +1 -0
  209. package/utils/stream/from-promise.js +27 -0
  210. package/utils/stream/index.d.ts +1 -1
  211. package/utils/stream/index.js +1 -1
  212. package/utils/stream/stream-reader.js +71 -31
  213. package/document-management/models/document-request-assignment-task-collection.model.d.ts +0 -7
  214. package/document-management/models/document-request-assignment-task.model.d.ts +0 -14
  215. package/document-management/models/document-request-assignment-task.model.js +0 -77
  216. package/document-management/models/document-request-file.model.d.ts +0 -16
  217. package/document-management/models/document-request-file.model.js +0 -86
  218. package/document-management/models/service-models/document.view-model.d.ts +0 -41
  219. package/document-management/models/service-models/normalized-document-collection-view.model.d.ts +0 -73
  220. package/document-management/models/service-models/normalized-document-collection-view.model.js +0 -110
  221. package/utils/stream/readable-stream-from-promise.js +0 -8
@@ -1,218 +1,88 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
8
- if (value !== null && value !== void 0) {
9
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
10
- var dispose, inner;
11
- if (async) {
12
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
13
- dispose = value[Symbol.asyncDispose];
14
- }
15
- if (dispose === void 0) {
16
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
17
- dispose = value[Symbol.dispose];
18
- if (async) inner = dispose;
19
- }
20
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
21
- if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
22
- env.stack.push({ value: value, dispose: dispose, async: async });
23
- }
24
- else if (async) {
25
- env.stack.push({ async: true });
26
- }
27
- return value;
28
- };
29
- var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
30
- return function (env) {
31
- function fail(e) {
32
- env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
33
- env.hasError = true;
34
- }
35
- var r, s = 0;
36
- function next() {
37
- while (r = env.stack.pop()) {
38
- try {
39
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
40
- if (r.dispose) {
41
- var result = r.dispose.call(r.value);
42
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
43
- }
44
- else s |= 1;
45
- }
46
- catch (e) {
47
- fail(e);
48
- }
49
- }
50
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
51
- if (env.hasError) throw env.error;
52
- }
53
- return next();
54
- };
55
- })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
56
- var e = new Error(message);
57
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
58
- });
59
- var DocumentManagementService_1;
60
- import { and, eq, inArray, ne, notExists, sql } from 'drizzle-orm';
61
- import { P, match } from 'ts-pattern';
62
- import { AiService } from '../../../ai/index.js';
63
1
  import { Enumerable } from '../../../enumerable/index.js';
64
- import { BadRequestError } from '../../../errors/index.js';
65
- import { getMimeType, getMimeTypeExtensions } from '../../../file/index.js';
66
- import { TemporaryFile } from '../../../file/server/index.js';
67
- import { Singleton, afterResolve, inject } from '../../../injector/index.js';
68
- import { Logger } from '../../../logger/logger.js';
69
- import { MessageBus } from '../../../message-bus/message-bus.js';
70
- import { ObjectStorage } from '../../../object-storage/index.js';
71
- import { TRANSACTION_TIMESTAMP, arrayAgg, coalesce, getEntityMap, jsonAgg, toJsonb } from '../../../orm/index.js';
72
- import { DatabaseConfig, getRepository, injectRepository } from '../../../orm/server/index.js';
73
- import { getPdfPageCount } from '../../../pdf/index.js';
74
- import { Queue } from '../../../queue/queue.js';
75
- import { array, boolean, enumeration, integer, nullable, number, object, string } from '../../../schema/index.js';
76
- import { distinct, toArray } from '../../../utils/array/index.js';
2
+ import { inject } from '../../../injector/index.js';
3
+ import { getEntityMap } from '../../../orm/index.js';
4
+ import { Transactional, injectRepository } from '../../../orm/server/index.js';
5
+ import { distinct } from '../../../utils/array/index.js';
77
6
  import { compareByValueSelectionToOrder } from '../../../utils/comparison.js';
78
- import { digest } from '../../../utils/cryptography.js';
79
- import { currentTimestamp, dateObjectToNumericDate } from '../../../utils/date-time.js';
80
- import { groupToMap } from '../../../utils/iterable-helpers/index.js';
81
- import { fromEntries, objectEntries } from '../../../utils/object/object.js';
82
- import { readBinaryStream } from '../../../utils/stream/index.js';
83
- import { tryIgnoreLogAsync } from '../../../utils/try-ignore.js';
84
- import { assertBooleanPass, assertDefined, assertDefinedPass, assertNotNullPass, assertNumberPass, assertStringPass, isBoolean, isDefined, isNotNull, isNull, isNumber, isString, isUint8Array, isUndefined } from '../../../utils/type-guards.js';
85
- import { millisecondsPerMinute } from '../../../utils/units.js';
86
- import { union } from 'drizzle-orm/pg-core';
87
- import { debounceTime, filter, map } from 'rxjs';
88
- import { Document, DocumentCategory, DocumentCollection, DocumentCollectionDocument, DocumentFile, DocumentProperty, DocumentPropertyDataType, DocumentPropertyValue, DocumentRequest, DocumentRequestAssignmentTask, DocumentRequestAssignmentTaskCollection, DocumentRequestAssignmentTaskPropertyValue, DocumentRequestCollection, DocumentRequestFile, DocumentRequestFilePropertyValue, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentTypeProperty } from '../../models/index.js';
89
- import { DocumentManagementConfig } from '../module.js';
90
- import { documentCategory, documentCollectionDocument, documentProperty, documentRequest, documentRequestAssignmentTask, documentRequestAssignmentTaskCollection, documentRequestAssignmentTaskPropertyValue, documentRequestCollection, documentRequestFile, documentType } from '../schemas.js';
7
+ import { groupToMap, groupToSingleMap } from '../../../utils/iterable-helpers/index.js';
8
+ import { fromEntries, objectEntries } from '../../../utils/object/index.js';
9
+ import { assertDefinedPass, isNotNull, isNull, isUndefined } from '../../../utils/type-guards.js';
10
+ import { DocumentApproval, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentFile, DocumentRequest, DocumentRequestCollection, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentValidationExecution, DocumentWorkflowStep } from '../../models/index.js';
11
+ import { DocumentCategoryTypeService, enumTypeKey } from './document-category-type.service.js';
91
12
  import { DocumentManagementAncillaryService } from './document-management-ancillary.service.js';
92
- const defaultGenerationOptions = {
93
- model: 'gemini-2.0-flash',
94
- generationOptions: {
95
- maxOutputTokens: 2048,
96
- temperature: 0.2,
97
- topP: 0.2
98
- }
99
- };
100
- let DocumentManagementService = DocumentManagementService_1 = class DocumentManagementService extends getRepository(DocumentCollection) {
101
- #aiService = inject(AiService);
102
- ancillaryService = inject(DocumentManagementAncillaryService);
103
- documentCategoryService = injectRepository(DocumentCategory);
104
- documentCollectionDocumentService = injectRepository(DocumentCollectionDocument);
105
- documentFileService = injectRepository(DocumentFile);
106
- documentPropertyService = injectRepository(DocumentProperty);
107
- documentPropertyValueService = injectRepository(DocumentPropertyValue);
108
- documentRequestAssignmentTaskCollectionService = injectRepository(DocumentRequestAssignmentTaskCollection);
109
- documentRequestAssignmentTaskService = injectRepository(DocumentRequestAssignmentTask);
110
- documentRequestCollectionService = injectRepository(DocumentRequestCollection);
111
- documentRequestFilePropertyValueService = injectRepository(DocumentRequestFilePropertyValue);
112
- documentRequestAssignmentTaskPropertyValueService = injectRepository(DocumentRequestAssignmentTaskPropertyValue);
113
- documentRequestFileService = injectRepository(DocumentRequestFile);
114
- documentRequestService = injectRepository(DocumentRequest);
115
- documentRequestsTemplateService = injectRepository(DocumentRequestsTemplate);
116
- documentRequestTemplateService = injectRepository(DocumentRequestTemplate);
117
- documentService = injectRepository(Document);
118
- documentTypePropertyService = injectRepository(DocumentTypeProperty);
119
- documentTypeService = injectRepository(DocumentType);
120
- fileObjectStorage = inject(ObjectStorage, inject(DocumentManagementConfig).fileObjectStorageModule);
121
- extractionQueue = inject((Queue), { name: 'DocumentManagement:extraction', processTimeout: 15 * millisecondsPerMinute });
122
- assignmentQueue = inject((Queue), { name: 'DocumentManagement:assignment', processTimeout: 15 * millisecondsPerMinute });
123
- collectionChangeMessageBus = inject((MessageBus), 'DocumentManagement:collectionChange');
124
- logger = inject(Logger, DocumentManagementService_1.name);
125
- [afterResolve](_, { cancellationSignal }) {
126
- if (this.isFork) {
127
- return;
128
- }
129
- this.processQueues(cancellationSignal);
130
- }
131
- changes$(collectionIds) {
132
- const collectionIdsArray = toArray(collectionIds);
133
- return this.collectionChangeMessageBus.allMessages$.pipe(filter((message) => isUndefined(message) || collectionIdsArray.some((id) => message.includes(id))), debounceTime(250), map(() => undefined));
134
- }
135
- processQueues(cancellationSignal) {
136
- this.extractionQueue.process({ concurrency: 5, cancellationSignal }, async (job) => {
137
- const [entry] = objectEntries(job.data);
138
- this.logger.verbose(`Processing extraction job for ${entry?.[0]} ${entry?.[1]}`);
139
- await match(job.data)
140
- .with({ documentId: P.string.select() }, async (documentId) => this.enrichDocument(documentId))
141
- .with({ requestFileId: P.string.select() }, async (requestFileId) => this.enrichDocumentRequestFile(requestFileId))
142
- .with({ requestAssignmentTaskId: P.string.select() }, async (requestAssignmentTaskId) => this.enrichDocumentRequestAssignmentTask(requestAssignmentTaskId))
143
- .exhaustive();
144
- }, this.logger);
145
- this.assignmentQueue.process({ concurrency: 5, cancellationSignal }, async (job) => {
146
- this.logger.verbose(`Processing assignment job "${job.data.requestAssignmentTaskId}"`);
147
- await this.assignDocumentRequest(job.data.requestAssignmentTaskId);
148
- }, this.logger);
149
- }
150
- async resolveNames(...collectionsOrIds) {
151
- if (collectionsOrIds.length == 0) {
152
- return [];
153
- }
154
- const loadIds = collectionsOrIds.filter((collection) => isString(collection));
155
- if (loadIds.length == 0) {
156
- return this.ancillaryService.resolveNames(collectionsOrIds);
157
- }
158
- const loadedCollections = await this.loadManyByQuery({ id: { $in: loadIds } });
159
- const collections = collectionsOrIds.map((collectionOrId) => isString(collectionOrId)
160
- ? assertDefinedPass(loadedCollections.find((collection) => collection.id == collectionOrId), `Could not load collection "${collectionOrId}".`)
161
- : collectionOrId);
162
- return this.ancillaryService.resolveNames(collections);
163
- }
164
- async resolveNamesMap(...collectionsOrIds) {
165
- const names = await this.resolveNames(...collectionsOrIds);
166
- const entries = collectionsOrIds.map((collectionOrId, index) => [isString(collectionOrId) ? collectionOrId : collectionOrId.id, names[index]]);
167
- return fromEntries(entries);
168
- }
169
- async loadData(collectionIds, collectionsMetadata) {
170
- return this.transaction(async (_, transaction) => {
171
- const [collections, collectionDocuments, requestCollections, categories, types] = await Promise.all([
172
- this.withTransaction(transaction).loadMany(collectionIds),
173
- this.documentCollectionDocumentService.withTransaction(transaction).loadManyByQuery({ collectionId: { $in: collectionIds } }),
174
- this.documentRequestCollectionService.withTransaction(transaction).loadManyByQuery({ collectionId: { $in: collectionIds } }),
175
- this.documentCategoryService.withTransaction(transaction).loadManyByQuery({}, { order: 'label' }),
176
- this.documentTypeService.withTransaction(transaction).loadManyByQuery({}, { order: 'label' })
13
+ import { DocumentPropertyService } from './document-property.service.js';
14
+ import { DocumentWorkflowService } from './document-workflow.service.js';
15
+ import { DocumentService } from './document.service.js';
16
+ export class DocumentManagementService extends Transactional {
17
+ #ancillaryService = inject(DocumentManagementAncillaryService);
18
+ #documentCategoryTypeService = inject(DocumentCategoryTypeService);
19
+ #documentCollectionRepository = injectRepository(DocumentCollection);
20
+ #documentCategoryRepository = injectRepository(DocumentCategory);
21
+ #documentCollectionAssignmentRepository = injectRepository(DocumentCollectionAssignment);
22
+ #documentFileRepository = injectRepository(DocumentFile);
23
+ #documentService = inject(DocumentService);
24
+ #documentPropertyService = inject(DocumentPropertyService);
25
+ #documentRequestCollectionRepository = injectRepository(DocumentRequestCollection);
26
+ #documentRequestRepository = injectRepository(DocumentRequest);
27
+ #documentRequestsTemplateRepository = injectRepository(DocumentRequestsTemplate);
28
+ #documentRequestTemplateRepository = injectRepository(DocumentRequestTemplate);
29
+ #documentTypeRepository = injectRepository(DocumentType);
30
+ #documentWorkflowService = inject(DocumentWorkflowService);
31
+ #documentValidationExecutionRepository = injectRepository(DocumentValidationExecution);
32
+ async loadData(collectionIds) {
33
+ return this.transaction(async (tx) => {
34
+ const [collections, collectionsMetadataMap, collectionAssignments, requestCollections, categories, types] = await Promise.all([
35
+ this.#documentCollectionRepository.withTransaction(tx).loadMany(collectionIds),
36
+ this.#ancillaryService.resolveMetadataMap(...collectionIds),
37
+ this.#documentCollectionAssignmentRepository.withTransaction(tx).loadManyByQuery({ collectionId: { $in: collectionIds } }),
38
+ this.#documentRequestCollectionRepository.withTransaction(tx).loadManyByQuery({ collectionId: { $in: collectionIds } }),
39
+ this.#documentCategoryRepository.withTransaction(tx).loadManyByQuery({}, { order: 'label' }),
40
+ this.#documentTypeRepository.withTransaction(tx).loadManyByQuery({}, { order: 'label' }),
177
41
  ]);
178
- const documentIds = collectionDocuments.map((document) => document.documentId);
179
42
  const requestIds = requestCollections.map((requestCollection) => requestCollection.requestId);
180
- const [documents, requests, requestFiles, propertyValues, extractionJobs] = await Promise.all([
181
- this.documentService.withTransaction(transaction).loadManyByQuery({ id: { $in: documentIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
182
- this.documentRequestService.withTransaction(transaction).loadManyByQuery({ id: { $in: requestIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
183
- this.documentRequestFileService.withTransaction(transaction).loadManyByQuery({ requestId: { $in: requestIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
184
- this.documentPropertyValueService.withTransaction(transaction).loadManyByQuery({ documentId: { $in: documentIds } }),
185
- this.extractionQueue.getByTags(documentIds)
43
+ const requests = await this.#documentRequestRepository.withTransaction(tx).loadManyByQuery({ id: { $in: requestIds } }, { order: { 'metadata.createTimestamp': 'desc' } });
44
+ const collectionDocumentIds = collectionAssignments.map((document) => document.documentId);
45
+ const requestDocumentIds = requests.map((request) => request.documentId).filter(isNotNull);
46
+ const documentIds = distinct([...collectionDocumentIds, ...requestDocumentIds]);
47
+ const [documents, propertyValues] = await Promise.all([
48
+ this.#documentService.withTransaction(tx).repository.loadManyByQuery({ id: { $in: documentIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
49
+ this.#documentPropertyService.withTransaction(tx).loadDocumentProperties(documentIds),
186
50
  ]);
187
51
  const documentFileIds = documents.map((document) => document.fileId);
188
- const requestFileIds = requestFiles.map((requestFile) => requestFile.fileId);
189
- const files = await this.documentFileService.withTransaction(transaction).loadManyByQuery({ id: { $in: [...documentFileIds, ...requestFileIds] } }, { order: { 'metadata.createTimestamp': 'desc' } });
190
- const requestsFilesMap = groupToMap(requestFiles, (requestFile) => requestFile.requestId);
52
+ const workflowRelevantDocumentIds = documents.map((document) => (document.approval == DocumentApproval.Pending) ? document.id : null).filter(isNotNull);
53
+ const [files, currentWorkflows] = await Promise.all([
54
+ this.#documentFileRepository.withTransaction(tx).loadManyByQuery({ id: { $in: documentFileIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
55
+ this.#documentWorkflowService.loadLatestWorkflows(workflowRelevantDocumentIds),
56
+ ]);
57
+ const documentIdMap = getEntityMap(documents);
58
+ const documentWorkflowMap = groupToSingleMap(currentWorkflows, (workflow) => workflow.documentId);
191
59
  const valuesMap = Enumerable.from(propertyValues).groupToMap((value) => value.documentId);
192
- const collectionViews = collections.toSorted(compareByValueSelectionToOrder(collectionIds, (collection) => collection.id)).map((collection) => ({
193
- ...collection,
194
- name: collectionsMetadata?.[collection.id]?.name ?? null,
195
- group: collectionsMetadata?.[collection.id]?.group ?? null
196
- }));
60
+ const validationWorkflowIds = currentWorkflows.map((workflow) => (workflow.step == DocumentWorkflowStep.Validation) ? workflow.id : null).filter(isNotNull);
61
+ const validations = await this.#documentValidationExecutionRepository.loadManyByQuery({ workflowId: { $in: validationWorkflowIds } });
62
+ const workflowValidationMap = groupToMap(validations, (validation) => validation.workflowId);
63
+ const collectionViews = collections.toSorted(compareByValueSelectionToOrder(collectionIds, (collection) => collection.id)).map((collection) => {
64
+ const metadata = assertDefinedPass(collectionsMetadataMap[collection.id]);
65
+ return ({
66
+ ...collection,
67
+ name: metadata.name,
68
+ group: metadata.group,
69
+ });
70
+ });
197
71
  const documentViews = documents.map((document) => {
198
- const job = extractionJobs.find((job) => job.tag == document.id);
72
+ const currentWorkflow = documentWorkflowMap.get(document.id) ?? null;
73
+ const validations = (isNotNull(currentWorkflow) && (currentWorkflow.step == DocumentWorkflowStep.Validation)) ? workflowValidationMap.get(currentWorkflow.id) ?? [] : null;
199
74
  return {
200
75
  ...document,
201
- collectionAssignments: collectionDocuments.filter((collectionDocument) => collectionDocument.documentId == document.id).map(({ collectionId, archiveTimestamp }) => ({ collectionId, archiveTimestamp })),
76
+ collectionAssignments: collectionAssignments.filter((collectionDocument) => collectionDocument.documentId == document.id),
202
77
  properties: valuesMap.get(document.id) ?? [],
203
- extractionStatus: isUndefined(job)
204
- ? null
205
- : isNull(job.lastDequeueTimestamp)
206
- ? 'pending'
207
- : (job.tries >= this.extractionQueue.maxTries) && (job.lastDequeueTimestamp >= (currentTimestamp() + this.extractionQueue.processTimeout))
208
- ? 'error'
209
- : 'extracting'
78
+ currentWorkflow,
79
+ validations,
210
80
  };
211
81
  });
212
82
  const requestViews = requests.map((request) => ({
213
83
  ...request,
214
84
  collectionIds: requestCollections.filter((requestCollection) => requestCollection.requestId == request.id).map((requestCollection) => requestCollection.collectionId),
215
- requestFiles: requestsFilesMap.get(request.id) ?? []
85
+ document: isNull(request.documentId) ? null : documentIdMap.get(request.documentId) ?? null,
216
86
  }));
217
87
  return {
218
88
  collections: collectionViews,
@@ -220,710 +90,58 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
220
90
  requests: requestViews,
221
91
  files,
222
92
  categories,
223
- types
93
+ types,
224
94
  };
225
95
  });
226
96
  }
227
97
  async loadDocumentRequestsTemplateData() {
228
98
  const [requestsTemplates, requestTemplates] = await Promise.all([
229
- this.documentRequestsTemplateService.loadManyByQuery({}, { order: 'label' }),
230
- this.documentRequestTemplateService.loadManyByQuery({})
99
+ this.#documentRequestsTemplateRepository.loadManyByQuery({}, { order: 'label' }),
100
+ this.#documentRequestTemplateRepository.loadManyByQuery({}),
231
101
  ]);
232
102
  const templates = requestsTemplates.map((requestsTemplate) => ({
233
103
  ...requestsTemplate,
234
- requestTemplates: requestTemplates.filter((requestTemplate) => requestTemplate.requestsTemplateId == requestsTemplate.id)
104
+ requestTemplates: requestTemplates.filter((requestTemplate) => requestTemplate.requestsTemplateId == requestsTemplate.id),
235
105
  }));
236
106
  return { templates };
237
107
  }
238
- async loadCategoriesAndTypes() {
239
- const [categories, types] = await Promise.all([
240
- this.documentCategoryService.loadManyByQuery({}, { order: 'label' }),
241
- this.documentTypeService.loadManyByQuery({}, { order: 'label' })
242
- ]);
243
- return { categories, types };
244
- }
245
- async loadDocument(id) {
246
- return this.documentService.load(id);
247
- }
248
- async loadDocumentFile(id) {
249
- return this.documentFileService.load(id);
250
- }
251
- async loadType(id) {
252
- return this.documentTypeService.load(id);
253
- }
254
- async getFileContent(fileId) {
255
- const key = getDocumentFileKey(fileId);
256
- return this.fileObjectStorage.getContent(key);
257
- }
258
- getFileContentStream(fileId) {
259
- const key = getDocumentFileKey(fileId);
260
- return this.fileObjectStorage.getContentStream(key);
261
- }
262
- async getFileContentUrl(fileId, title, download = false) {
263
- const file = await this.documentFileService.load(fileId);
264
- return this.getDocumentFileContentObjectUrl(title ?? fileId, file, download);
265
- }
266
- async createCategory(parameters) {
267
- return this.documentCategoryService.insert(parameters);
268
- }
269
- async createType(parameters) {
270
- return this.documentTypeService.insert(parameters);
271
- }
272
- async createCollection(parameters) {
273
- return this.insert(parameters ?? {});
274
- }
275
- async collectionHasDocumentByFilter(collectionId, filter) {
276
- const collectionDocuments = await this.documentCollectionDocumentService.loadManyByQuery({ collectionId });
277
- const documentIds = collectionDocuments.map((cd) => cd.documentId);
278
- return this.documentService.hasByQuery({ $and: [{ id: { $in: documentIds } }, filter] });
279
- }
280
- async getRequestFilesStats(collectionIds) {
281
- const collectionRequests = await this.documentRequestCollectionService.loadManyByQuery({ collectionId: { $in: toArray(collectionIds) } });
282
- const requestIds = collectionRequests.map((collectionRequest) => collectionRequest.requestId);
283
- const filteredRequests = await this.documentRequestService.loadManyByQuery({ id: { $in: requestIds }, completed: false });
284
- const filteredRequestIds = filteredRequests.map((request) => request.id);
285
- const requiredFilesCount = filteredRequests.reduce((sum, request) => sum + request.requiredFilesCount, 0);
286
- const [pendingFilesCount, approvedFilesCount] = await Promise.all([
287
- this.documentRequestFileService.countByQuery({ requestId: { $in: filteredRequestIds }, approval: null }),
288
- this.documentRequestFileService.countByQuery({ requestId: { $in: filteredRequestIds }, approval: true })
289
- ]);
290
- return { requiredFilesCount, requiredFilesLeft: Math.max(0, requiredFilesCount - approvedFilesCount), pendingFilesCount, approvedFilesCount };
291
- }
292
- async createDocumentRequestsTemplate(parameters) {
293
- return this.documentRequestsTemplateService.insert(parameters);
294
- }
295
- async updateDocumentRequestsTemplate({ id, label, metadata }) {
296
- return this.documentRequestsTemplateService.update(id, { label, metadata });
297
- }
298
- async applyDocumentRequestsTemplate({ id, collectionIds, metadata }) {
299
- const requestTemplates = await this.documentRequestTemplateService.loadManyByQuery({ requestsTemplateId: id });
300
- await this.documentRequestService.transaction(async (_, transaction) => {
301
- for (const { typeId, requiredFilesCount, comment } of requestTemplates) {
302
- await this.createDocumentRequest({ typeId, requiredFilesCount, comment, collectionIds, metadata }, transaction);
303
- }
304
- });
305
- }
306
- async deleteDocumentRequestsTemplate(parameters) {
307
- return this.documentRequestsTemplateService.delete(parameters.id);
308
- }
309
- async createDocumentRequestTemplate(parameters) {
310
- return this.documentRequestTemplateService.insert(parameters);
311
- }
312
- async updateDocumentRequestTemplate({ id, typeId, requiredFilesCount, comment, metadata }) {
313
- return this.documentRequestTemplateService.update(id, { typeId, requiredFilesCount, comment, metadata });
314
- }
315
- async deleteDocumentRequestTemplate(parameters) {
316
- return this.documentRequestTemplateService.delete(parameters.id);
317
- }
318
- async createDocument({ typeId, title, subtitle, pages, date, summary, tags, validated, originalFileName, collectionIds, properties, metadata }, content) {
319
- const collectionIdsArray = toArray(collectionIds);
320
- const document = await this.documentService.transaction(async (_, transaction) => {
321
- const documentFile = await this.createDocumentFile(content, originalFileName, transaction);
322
- const document = await this.documentService.withTransaction(transaction).insert({ fileId: documentFile.id, typeId, title, subtitle, pages, date, summary, tags, metadata, validated });
323
- for (const collectionId of collectionIdsArray) {
324
- await this.documentCollectionDocumentService.withTransaction(transaction).insert({ collectionId, documentId: document.id, archiveTimestamp: null });
325
- }
326
- if (isDefined(properties)) {
327
- await this.setPropertyValues({ documentId: document.id, properties }, transaction);
328
- }
329
- return document;
330
- });
331
- void tryIgnoreLogAsync(this.logger, async () => this.extractionQueue.enqueue({ documentId: document.id }, { tag: document.id }));
332
- this.publishChange({ collectionIds: collectionIdsArray });
333
- return document;
334
- }
335
- async approveDocumentRequestFile({ id, approvalComment, documentMetadata, requestFileMetadata }) {
336
- return this.documentRequestFileService.transaction(async (_, transaction) => {
337
- const requestFile = await this.documentRequestFileService.withTransaction(transaction).load(id);
338
- const requestCollections = await this.documentRequestCollectionService.withTransaction(transaction).loadManyByQuery({ requestId: requestFile.requestId });
339
- if (requestFile.approval == true) {
340
- throw new BadRequestError('Document request file already accepted.');
341
- }
342
- const request = await this.documentRequestService.withTransaction(transaction).load(requestFile.requestId);
343
- const document = await this.documentService.withTransaction(transaction).insert({
344
- fileId: requestFile.fileId,
345
- typeId: request.typeId,
346
- title: requestFile.title,
347
- subtitle: requestFile.subtitle,
348
- pages: requestFile.pages,
349
- date: requestFile.date,
350
- summary: requestFile.summary,
351
- tags: requestFile.tags,
352
- validated: true,
353
- metadata: documentMetadata
354
- });
355
- for (const { collectionId } of requestCollections) {
356
- await this.addDocumentToCollection({ collectionId, documentId: document.id }, transaction);
357
- }
358
- await this.documentRequestFileService.withTransaction(transaction).update(id, { approval: true, approvalComment, approvalTimestamp: TRANSACTION_TIMESTAMP, createdDocumentId: document.id, metadata: requestFileMetadata });
359
- return document;
360
- });
361
- }
362
- async rejectDocumentRequestFile({ id, approvalComment, metadata }) {
363
- const requestFile = await this.documentRequestFileService.transaction(async (_, transaction) => {
364
- const requestFile = await this.documentRequestFileService.withTransaction(transaction).load(id);
365
- if (requestFile.approval == true) {
366
- throw new BadRequestError('Document request file already accepted.');
367
- }
368
- return this.documentRequestFileService.withTransaction(transaction).update(id, { approval: false, approvalComment, approvalTimestamp: TRANSACTION_TIMESTAMP, metadata });
369
- });
370
- this.publishChange({ requestIds: [requestFile.requestId] });
371
- }
372
- async updateDocumentRequestFile({ id, title, approvalComment, metadata }) {
373
- const result = await this.documentRequestFileService.update(id, { title, approvalComment, metadata });
374
- this.publishChange({ requestIds: [result.requestId] });
375
- return result;
376
- }
377
- async deleteDocumentRequestFile({ id, metadata }) {
378
- const requestFile = await this.documentRequestFileService.load(id);
379
- if (isNotNull(requestFile.approval)) {
380
- throw new BadRequestError('Only pending request files can be deleted.');
381
- }
382
- await this.documentRequestFileService.delete(id, metadata);
383
- this.publishChange({ requestIds: [requestFile.requestId] });
384
- }
385
- async createDocumentFile(content, originalFileName, transaction) {
386
- const contentAsUint8Array = isUint8Array(content) ? content : await readBinaryStream(content);
387
- const hash = await digest('SHA-256', contentAsUint8Array).toHex();
388
- const mimeType = await getMimeType(contentAsUint8Array);
389
- return this.documentFileService.useTransaction(transaction, async (_, transaction) => {
390
- const documentFile = await this.documentFileService
391
- .withTransaction(transaction)
392
- .insert({
393
- originalFileName,
394
- mimeType,
395
- hash,
396
- size: contentAsUint8Array.length
397
- });
398
- const key = getDocumentFileKey(documentFile.id);
399
- await this.fileObjectStorage.uploadObject(key, contentAsUint8Array);
400
- return documentFile;
401
- });
402
- }
403
- async createDocumentRequestFile({ requestId, title, subtitle, date, summary, tags, originalFileName, metadata }, content) {
404
- const documentRequestFile = await this.documentRequestFileService.transaction(async (_, transaction) => {
405
- const [request, existingRequestFiles] = await Promise.all([
406
- this.documentRequestService.withTransaction(transaction).load(requestId),
407
- this.documentRequestFileService.withTransaction(transaction).loadManyByQuery({ requestId })
408
- ]);
409
- const filesCountLeft = (request.completed ? 0 : request.requiredFilesCount) - existingRequestFiles.reduce((sum, requestFile) => sum + ((requestFile.approval != false) ? 1 : 0), 0);
410
- if (filesCountLeft <= 0) {
411
- throw new BadRequestError('Maximum amount of allowed files reached.');
412
- }
413
- const file = await this.createDocumentFile(content, originalFileName, transaction);
414
- const result = await this.documentRequestFileService
415
- .withTransaction(transaction)
416
- .insert({
417
- requestId,
418
- fileId: file.id,
419
- title,
420
- subtitle,
421
- pages: null,
422
- date,
423
- summary,
424
- tags,
425
- createdDocumentId: null,
426
- approval: null,
427
- approvalComment: null,
428
- approvalTimestamp: null,
429
- metadata
430
- });
431
- return result;
432
- });
433
- void tryIgnoreLogAsync(this.logger, async () => this.extractionQueue.enqueue({ requestFileId: documentRequestFile.id }));
434
- this.publishChange({ requestIds: [documentRequestFile.requestId] });
435
- return documentRequestFile;
436
- }
437
- async createDocumentRequest(parameters, transaction) {
438
- if (parameters.collectionIds.length == 0) {
439
- throw new BadRequestError('No target collectionId specified.');
440
- }
441
- const result = await this.documentRequestService.useTransaction(transaction, async (_, tx) => {
442
- const request = await this.documentRequestService.withTransaction(tx).insert({ ...parameters, completed: false });
443
- const newDocumentRequestCollections = parameters.collectionIds.map((collectionId) => ({ requestId: request.id, collectionId }));
444
- await this.documentRequestCollectionService.withTransaction(tx).insertMany(newDocumentRequestCollections);
445
- return request;
446
- });
447
- this.publishChange({ collectionIds: parameters.collectionIds });
448
- return result;
449
- }
450
- async createDocumentRequestAssignmentTask({ originalFileName, collectionIds }, content) {
451
- if (collectionIds.length == 0) {
452
- throw new BadRequestError('No target collectionId specified.');
453
- }
454
- const file = await this.createDocumentFile(content, originalFileName);
455
- return this.documentRequestAssignmentTaskService.transaction(async (_, transaction) => {
456
- const task = await this.documentRequestAssignmentTaskService.withTransaction(transaction).insert({
457
- fileId: file.id,
458
- assignedRequestFileId: null,
459
- typeId: null,
460
- title: null,
461
- subtitle: null,
462
- pages: null,
463
- date: null,
464
- summary: null,
465
- tags: null,
466
- assignmentTries: 0
467
- });
468
- const newTaksCollections = collectionIds.map((collectionId) => ({ requestAssignmentTaskId: task.id, collectionId }));
469
- await this.documentRequestAssignmentTaskCollectionService.withTransaction(transaction).insertMany(newTaksCollections);
470
- void tryIgnoreLogAsync(this.logger, async () => this.extractionQueue.enqueue({ requestAssignmentTaskId: task.id }));
471
- this.publishChange({ collectionIds });
472
- return task;
473
- });
474
- }
475
- async updateDocument(parameters, transaction) {
476
- const { id: documentId, properties: propertyUpdates, ...update } = parameters;
477
- await this.documentService.useTransaction(transaction, async (repository, tx) => {
478
- await repository.update(documentId, update);
479
- if (isDefined(propertyUpdates)) {
480
- await this.setPropertyValues({ documentId, properties: propertyUpdates }, tx);
481
- }
482
- });
483
- this.publishChange({ documentIds: [documentId] });
484
- }
485
- async updateDocumentRequest(parameters, transaction) {
486
- const { id: documentRequestId, ...update } = parameters;
487
- const requestFiles = await this.documentRequestFileService.withOptionalTransaction(transaction).loadManyByQuery({ requestId: parameters.id });
488
- if (parameters.completed == true) {
489
- const hasCreatedDocument = requestFiles.some((requestFile) => isNotNull(requestFile.createdDocumentId));
490
- if (!hasCreatedDocument) {
491
- throw new BadRequestError('Cannot complete requests which has no approved files.');
492
- }
493
- }
494
- await this.documentRequestService.withOptionalTransaction(transaction).update(documentRequestId, update);
495
- this.publishChange({ requestIds: [documentRequestId] });
496
- }
497
- async deleteDocumentRequest({ id, metadata }, transaction) {
498
- const requestFiles = await this.documentRequestFileService.loadManyByQuery({ requestId: id });
499
- const hasCreatedDocument = requestFiles.some((requestFile) => isNotNull(requestFile.createdDocumentId));
500
- if (hasCreatedDocument) {
501
- throw new BadRequestError('Cannot delete requests which has approved files.');
502
- }
503
- await this.documentRequestService.withOptionalTransaction(transaction).delete(id, metadata);
504
- this.publishChange({ requestIds: [id] });
505
- }
506
- async setPropertyValues({ documentId, requestFileId, requestAssignmentTaskId, properties: items }, transaction) {
507
- if ((items.length == 0)) {
508
- return;
509
- }
510
- if ((Number(isDefined(documentId)) + Number(isDefined(requestFileId)) + Number(isDefined(requestAssignmentTaskId))) != 1) {
511
- throw new BadRequestError('Exactly one of documentId, requestFileId or requestAssignmentTaskId must be specified.');
512
- }
513
- await this.documentPropertyService.useTransaction(transaction, async (_, tx) => {
514
- const propertyIds = items.map((property) => property.propertyId);
515
- const properties = await this.documentPropertyService.withTransaction(tx).loadManyByQuery({ id: { $in: propertyIds } });
516
- const propertiesMap = getEntityMap(properties);
517
- const propertyItems = items.map(({ propertyId, value, metadata }) => {
518
- const property = assertDefinedPass(propertiesMap.get(propertyId));
519
- validatePropertyValue(propertyId, property.dataType, value);
520
- return {
521
- propertyId,
522
- text: (property.dataType == 'text') ? assertStringPass(value) : null,
523
- integer: (property.dataType == 'integer') ? assertNumberPass(value) : null,
524
- decimal: (property.dataType == 'decimal') ? assertNumberPass(value) : null,
525
- boolean: (property.dataType == 'boolean') ? assertBooleanPass(value) : null,
526
- date: (property.dataType == 'date') ? assertNumberPass(value) : null,
527
- metadata
528
- };
529
- });
530
- if (isDefined(documentId)) {
531
- await this.documentPropertyValueService.withTransaction(tx)
532
- .upsertMany(['documentId', 'propertyId'], propertyItems.map((propertyItem) => ({ ...propertyItem, documentId })));
533
- }
534
- else if (isDefined(requestFileId)) {
535
- await this.documentRequestFilePropertyValueService.withTransaction(tx)
536
- .upsertMany(['requestFileId', 'propertyId'], propertyItems.map((propertyItem) => ({ ...propertyItem, requestFileId })));
108
+ async initializeCategoriesAndTypes(categoryNames, categoryParents, typeNames, typeCategories) {
109
+ const categoryEntries = objectEntries(categoryNames);
110
+ const typeEntries = objectEntries(typeNames);
111
+ const { categoryMap, typeMap } = await this.transaction(async (tx) => {
112
+ const { categories, types } = await this.#documentCategoryTypeService.loadCategoriesAndTypes();
113
+ const enumKeyCategoryMap = groupToSingleMap(categories, (category) => category.metadata.attributes[enumTypeKey]);
114
+ const enumKeyTypeMap = groupToSingleMap(types, (type) => type.metadata.attributes[enumTypeKey]);
115
+ for (const [key, label] of categoryEntries) {
116
+ const category = enumKeyCategoryMap.get(key);
117
+ const parentId = assertDefinedPass(categoryParents[key], `Parent category not defined for ${key}`);
118
+ if (isUndefined(category)) {
119
+ const category = await this.#documentCategoryTypeService.withTransaction(tx).createCategory(label, parentId, key);
120
+ categories.push(category);
121
+ }
122
+ else if ((category.label != label) || (category.parentId != parentId)) {
123
+ await this.#documentCategoryTypeService.withTransaction(tx).updateCategory(category.id, { label, parentId });
124
+ }
537
125
  }
538
- else if (isDefined(requestAssignmentTaskId)) {
539
- await this.documentRequestAssignmentTaskPropertyValueService.withTransaction(tx)
540
- .upsertMany(['requestAssignmentTaskId', 'propertyId'], propertyItems.map((propertyItem) => ({ ...propertyItem, requestAssignmentTaskId })));
126
+ for (const [key, label] of typeEntries) {
127
+ const type = enumKeyTypeMap.get(key);
128
+ const enumCategory = typeCategories[key];
129
+ const category = assertDefinedPass(enumKeyCategoryMap.get(enumCategory));
130
+ if (isUndefined(type)) {
131
+ const type = await this.#documentCategoryTypeService.createType(label, category.id, key);
132
+ types.push(type);
133
+ }
134
+ else if ((type.categoryId != category.id) || (type.label != label)) {
135
+ await this.#documentCategoryTypeService.withTransaction(tx).updateType(type.id, { categoryId: category.id, label: label });
136
+ }
541
137
  }
138
+ return { categoryMap: enumKeyCategoryMap, typeMap: enumKeyTypeMap };
542
139
  });
543
- this.publishChange({
544
- documentIds: isDefined(documentId) ? [documentId] : undefined,
545
- requestFileIds: isDefined(requestFileId) ? [requestFileId] : undefined,
546
- requestAssignmentTaskIds: isDefined(requestAssignmentTaskId) ? [requestAssignmentTaskId] : undefined
547
- });
548
- }
549
- async addDocumentToCollection(parameters, transaction) {
550
- await this.documentCollectionDocumentService.withOptionalTransaction(transaction).upsert(['collectionId', 'documentId'], { ...parameters, archiveTimestamp: null });
551
- this.publishChange({ documentIds: [parameters.documentId] });
552
- }
553
- async archiveDocument({ collectionId, documentId, metadata }) {
554
- await this.documentCollectionDocumentService.updateByQuery({ collectionId, documentId }, { archiveTimestamp: TRANSACTION_TIMESTAMP, metadata });
555
- this.publishChange({ documentIds: [documentId] });
556
- }
557
- async createProperty(parameters) {
558
- return this.documentPropertyService.insert(parameters);
559
- }
560
- async assignPropertyToType(parameters) {
561
- await this.documentTypePropertyService.insert(parameters);
562
- }
563
- async enrichDocument(documentId) {
564
- const document = await this.documentService.load(documentId);
565
- const { properties, ...extractionResult } = await this.extractFileInformation(document.fileId, document.typeId);
566
- this.logger.trace(`Applying extraction to document ${document.id}`);
567
- await this.documentService.transaction(async (documentService, transaction) => {
568
- await documentService.update(document.id, { ...extractionResult, validated: false });
569
- await this.setPropertyValues({ documentId, properties: properties }, transaction);
570
- });
571
- this.publishChange({ documentIds: [documentId] });
572
- }
573
- async enrichDocumentRequestFile(requestFileId) {
574
- const requestFile = await this.documentRequestFileService.load(requestFileId);
575
- const request = await this.documentRequestService.load(requestFile.requestId);
576
- const { properties, typeId: _, ...extractionResult } = await this.extractFileInformation(requestFile.fileId, request.typeId);
577
- await this.documentRequestFileService.transaction(async (documentRequestFileService, transaction) => {
578
- await documentRequestFileService.update(requestFile.id, extractionResult);
579
- await this.setPropertyValues({ requestFileId, properties: properties }, transaction);
580
- });
581
- this.publishChange({ requestIds: [request.id] });
582
- }
583
- async enrichDocumentRequestAssignmentTask(requestAssignmentTaskId) {
584
- const task = await this.documentRequestAssignmentTaskService.load(requestAssignmentTaskId);
585
- const { properties, ...extractionResult } = await this.extractFileInformation(task.fileId);
586
- await this.documentRequestAssignmentTaskService.transaction(async (documentRequestAssignmentTaskService, transaction) => {
587
- await documentRequestAssignmentTaskService.update(task.id, extractionResult);
588
- await this.setPropertyValues({ requestAssignmentTaskId, properties: properties }, transaction);
589
- });
590
- void tryIgnoreLogAsync(this.logger, async () => this.assignmentQueue.enqueue({ requestAssignmentTaskId }));
591
- this.publishChange({ requestAssignmentTaskIds: [requestAssignmentTaskId] });
592
- }
593
- async assignDocumentRequest(requestAssignmentTaskId) {
594
- const session = this.documentRequestAssignmentTaskCollectionService.session;
595
- const requestAssignmentTaskProperties = session.$with('requestAssignmentTaskProperty').as(session
596
- .select({
597
- requestAssignmentTaskId: documentRequestAssignmentTaskPropertyValue.requestAssignmentTaskId,
598
- propertyId: documentRequestAssignmentTaskPropertyValue.propertyId,
599
- label: documentProperty.label,
600
- value: coalesce(toJsonb(documentRequestAssignmentTaskPropertyValue.text), toJsonb(documentRequestAssignmentTaskPropertyValue.integer), toJsonb(documentRequestAssignmentTaskPropertyValue.decimal), toJsonb(documentRequestAssignmentTaskPropertyValue.boolean), toJsonb(documentRequestAssignmentTaskPropertyValue.date)).as('value')
601
- })
602
- .from(documentRequestAssignmentTaskPropertyValue)
603
- .innerJoin(documentProperty, eq(documentProperty.id, documentRequestAssignmentTaskPropertyValue.propertyId)));
604
- const [task] = await session
605
- .with(requestAssignmentTaskProperties)
606
- .select({
607
- fileId: documentRequestAssignmentTask.fileId,
608
- collectionIds: arrayAgg(documentRequestAssignmentTaskCollection.collectionId),
609
- typeCategory: documentCategory.label,
610
- typeGroup: documentType.group,
611
- typeLabel: documentType.label,
612
- title: documentRequestAssignmentTask.title,
613
- subtitle: documentRequestAssignmentTask.subtitle,
614
- pages: documentRequestAssignmentTask.pages,
615
- date: documentRequestAssignmentTask.date,
616
- summary: documentRequestAssignmentTask.summary,
617
- tags: documentRequestAssignmentTask.tags,
618
- assignmentTries: documentRequestAssignmentTask.assignmentTries,
619
- properties: sql `coalesce(${jsonAgg(requestAssignmentTaskProperties)} FILTER (WHERE ${requestAssignmentTaskProperties.propertyId} IS NOT NULL), '[]'::json)`
620
- })
621
- .from(documentRequestAssignmentTask)
622
- .innerJoin(documentRequestAssignmentTaskCollection, eq(documentRequestAssignmentTaskCollection.requestAssignmentTaskId, documentRequestAssignmentTask.id))
623
- .innerJoin(documentType, eq(documentType.id, documentRequestAssignmentTask.typeId))
624
- .innerJoin(documentCategory, eq(documentCategory.id, documentType.categoryId))
625
- .leftJoin(requestAssignmentTaskProperties, eq(requestAssignmentTaskProperties.requestAssignmentTaskId, documentRequestAssignmentTask.id))
626
- .where(eq(documentRequestAssignmentTask.id, requestAssignmentTaskId))
627
- .groupBy(documentRequestAssignmentTask.fileId, requestAssignmentTaskProperties.label, documentCategory.label, documentType.group, documentType.label, documentRequestAssignmentTask.title, documentRequestAssignmentTask.subtitle, documentRequestAssignmentTask.pages, documentRequestAssignmentTask.date, documentRequestAssignmentTask.summary, documentRequestAssignmentTask.tags, documentRequestAssignmentTask.assignmentTries);
628
- assertDefined(task);
629
- if (task.assignmentTries >= 3) {
630
- this.logger.error(`Ignoring assignment task "${requestAssignmentTaskId}" because max tries are reached.`);
631
- return;
632
- }
633
- const requestsWithoutFiles = await session
634
- .select({
635
- id: documentRequest.id,
636
- collectionIds: arrayAgg(documentRequestCollection.collectionId),
637
- documentCategory: documentCategory.label,
638
- documentGroup: documentType.group,
639
- documentType: documentType.label,
640
- comment: documentRequest.comment
641
- })
642
- .from(documentRequest)
643
- .innerJoin(documentRequestCollection, eq(documentRequestCollection.requestId, documentRequest.id))
644
- .innerJoin(documentType, eq(documentType.id, documentRequest.typeId))
645
- .innerJoin(documentCategory, eq(documentCategory.id, documentType.categoryId))
646
- .where(and(inArray(documentRequestCollection.collectionId, task.collectionIds), notExists(session
647
- .select()
648
- .from(documentRequestFile)
649
- .where(and(eq(documentRequestFile.requestId, documentRequest.id), ne(documentRequestFile.approval, false))))))
650
- .groupBy(documentRequest.id, documentCategory.label, documentType.group, documentType.label, documentRequest.comment);
651
- const requestsCollectionIds = distinct(requestsWithoutFiles.flatMap((request) => request.collectionIds));
652
- const collectionNamesMap = await this.resolveNamesMap(...requestsCollectionIds);
653
- const requests = requestsWithoutFiles.map((request) => ({
654
- id: request.id,
655
- collections: request.collectionIds.map((collectionId) => assertDefinedPass(collectionNamesMap[collectionId])),
656
- documentCategory: request.documentCategory,
657
- documentGroup: request.documentGroup ?? undefined,
658
- documentType: request.documentType,
659
- comment: request.comment ?? undefined
660
- }));
661
- const propertyEntries = task.properties.map((property) => [property.label, assertNotNullPass(property.value)]);
662
- const context = {
663
- file: {
664
- documentCategory: task.typeCategory,
665
- documentGroup: task.typeGroup ?? undefined,
666
- documentType: task.typeLabel,
667
- properties: fromEntries(propertyEntries)
668
- },
669
- requests
140
+ const mappedCategories = categoryEntries.map(([key]) => [key, assertDefinedPass(categoryMap.get(key), 'Could not map document category.')]);
141
+ const mappedTypes = typeEntries.map(([key]) => [key, assertDefinedPass(typeMap.get(key), 'Could not map document type.')]);
142
+ return {
143
+ categories: fromEntries(mappedCategories),
144
+ types: fromEntries(mappedTypes),
670
145
  };
671
- const result = await this.#aiService.generate({
672
- ...defaultGenerationOptions,
673
- generationOptions: {
674
- maxOutputTokens: 100,
675
- temperature: 0,
676
- topP: 0.2
677
- },
678
- generationSchema: object({ requestId: nullable(string()) }),
679
- contents: [{
680
- role: 'user',
681
- parts: [
682
- {
683
- text: `<context>
684
- ${JSON.stringify(context, null, 2)}
685
- </context>
686
-
687
- Ordne die Datei unter "file" der passenden Anforderungen unter "requests" zu. Gib es als JSON im angegebenen Schema aus. Wenn keine Anforderung passt, setze requestId auf null.`
688
- }
689
- ]
690
- }]
691
- });
692
- await this.documentRequestAssignmentTaskService.update(requestAssignmentTaskId, { assignmentTries: sql `${documentRequestAssignmentTask.assignmentTries} + 1` });
693
- if (isNull(result.json.requestId)) {
694
- return;
695
- }
696
- await this.documentRequestFileService.transaction(async (_, transaction) => {
697
- const requestFile = await this.documentRequestFileService.withTransaction(transaction).insert({
698
- requestId: result.json.requestId,
699
- fileId: task.fileId,
700
- title: task.title,
701
- subtitle: task.subtitle,
702
- pages: task.pages,
703
- date: task.date,
704
- summary: task.summary,
705
- tags: task.tags,
706
- createdDocumentId: null,
707
- approval: null,
708
- approvalComment: null,
709
- approvalTimestamp: null
710
- });
711
- await this.setPropertyValues({ requestFileId: requestFile.id, properties: task.properties }, transaction);
712
- });
713
- this.publishChange({ collectionIds: requestsCollectionIds });
714
- }
715
- async extractFileInformation(fileId, assumeTypeId) {
716
- const env_1 = { stack: [], error: void 0, hasError: false };
717
- try {
718
- const file = await this.documentFileService.load(fileId);
719
- const fileContentStream = this.getDocumentFileContentStream(fileId);
720
- const tmpFile = __addDisposableResource(env_1, await TemporaryFile.from(fileContentStream), true);
721
- const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: file.mimeType });
722
- const pages = file.mimeType.includes('pdf')
723
- ? await tryIgnoreLogAsync(this.logger, async () => {
724
- this.logger.trace(`Extracting pdf page count for file ${fileId}`);
725
- return getPdfPageCount(tmpFile.path);
726
- }, null)
727
- : null;
728
- const types = await this.documentTypeService.session
729
- .select({
730
- typeId: documentType.id,
731
- categoryLabel: documentCategory.label,
732
- typeGroup: documentType.group,
733
- typeLabel: documentType.label
734
- })
735
- .from(documentType)
736
- .leftJoin(documentCategory, eq(documentCategory.id, documentType.categoryId))
737
- .where(isString(assumeTypeId) ? eq(documentType.id, assumeTypeId) : undefined);
738
- const typeLabelEntries = types.map((type) => ({ id: type.typeId, label: `${type.categoryLabel} | ${type.typeGroup} | ${type.typeLabel}` }));
739
- const typeLabels = typeLabelEntries.map(({ label }) => label);
740
- this.logger.trace(`Classifying document file ${fileId}`);
741
- const documentTypeGeneration = await this.#aiService.generate({
742
- ...defaultGenerationOptions,
743
- generationSchema: object({
744
- documentType: enumeration(typeLabels)
745
- }),
746
- contents: [
747
- {
748
- role: 'user',
749
- parts: [
750
- { file: filePart.file },
751
- { text: `Klassifiziere den Inhalt des Dokuments in das angegebenen JSON Schema.` }
752
- ]
753
- }
754
- ]
755
- });
756
- const typeId = typeLabelEntries.find((entry) => entry.label == documentTypeGeneration.json.documentType)?.id;
757
- const typeProperties = isDefined(typeId) ? await this.documentTypePropertyService.loadManyByQuery({ typeId }) : undefined;
758
- const propertyIds = typeProperties?.map((property) => property.propertyId);
759
- const properties = isDefined(propertyIds) ? await this.documentPropertyService.loadManyByQuery({ id: { $in: propertyIds } }) : undefined;
760
- const propertiesSchemaEntries = properties?.map((property) => {
761
- const schema = match(property.dataType)
762
- .with('text', () => nullable(string()))
763
- .with('integer', () => nullable(integer()))
764
- .with('decimal', () => nullable(number()))
765
- .with('boolean', () => nullable(boolean()))
766
- .with('date', () => nullable(object({ year: integer(), month: integer(), day: integer() })))
767
- .exhaustive();
768
- return [property.label, schema];
769
- });
770
- const generationSchema = object({
771
- documentTitle: string(),
772
- documentSubtitle: nullable(string()),
773
- documentSummary: string(),
774
- documentTags: array(string()),
775
- documentDate: nullable(object({ year: integer(), month: integer(), day: integer() })),
776
- ...((isUndefined(propertiesSchemaEntries) || (propertiesSchemaEntries.length == 0))
777
- ? {}
778
- : { documentProperties: object(fromEntries(propertiesSchemaEntries)) })
779
- });
780
- this.logger.trace(`Extracting document file ${fileId}`);
781
- const { json: extraction } = await this.#aiService.generate({
782
- model: 'gemini-2.0-flash',
783
- generationOptions: {
784
- maxOutputTokens: 2048,
785
- temperature: 0.2,
786
- topP: 0.2
787
- },
788
- generationSchema,
789
- contents: [
790
- {
791
- role: 'user',
792
- parts: [
793
- { file: filePart.file },
794
- {
795
- text: `Extrahiere den Inhalt des Dokuments in das angegebenen JSON Schema.
796
-
797
- Gib in der summary ausführlich an, welche Informationen in dem Dokument vorkommen(ohne konkrete Werte).
798
- Erstelle bis zu 7 möglichst spezifische Tags.
799
- Antworte auf deutsch.`
800
- }
801
- ]
802
- }
803
- ]
804
- });
805
- const filteredDocumentTags = extraction.documentTags.filter((tag) => (tag != extraction.documentTitle) && (tag != extraction.documentSubtitle));
806
- const date = isNotNull(extraction.documentDate) ? dateObjectToNumericDate(extraction.documentDate) : null;
807
- const parsedProperties = isUndefined(extraction.documentProperties)
808
- ? []
809
- : objectEntries(extraction.documentProperties)
810
- .map(([propertyLabel, rawValue]) => {
811
- if (isNull(rawValue)) {
812
- return null;
813
- }
814
- const property = assertDefinedPass(properties?.find((property) => property.label == propertyLabel));
815
- const value = match(rawValue)
816
- .with({ year: P.number }, (val) => dateObjectToNumericDate(val))
817
- .otherwise((val) => val);
818
- return { propertyId: property.id, dataType: property.dataType, value };
819
- })
820
- .filter(isNotNull);
821
- return {
822
- typeId: typeId ?? null,
823
- title: extraction.documentTitle,
824
- subtitle: extraction.documentSubtitle,
825
- pages,
826
- date,
827
- summary: extraction.documentSummary,
828
- tags: filteredDocumentTags,
829
- properties: parsedProperties
830
- };
831
- }
832
- catch (e_1) {
833
- env_1.error = e_1;
834
- env_1.hasError = true;
835
- }
836
- finally {
837
- const result_1 = __disposeResources(env_1);
838
- if (result_1)
839
- await result_1;
840
- }
841
- }
842
- async getDocumentFileContent(fileId) {
843
- const key = getDocumentFileKey(fileId);
844
- return this.fileObjectStorage.getContent(key);
845
- }
846
- getDocumentFileContentStream(fileId) {
847
- const key = getDocumentFileKey(fileId);
848
- return this.fileObjectStorage.getContentStream(key);
849
- }
850
- async getDocumentFileContentObjectUrl(title, file, download) {
851
- const key = getDocumentFileKey(file.id);
852
- const fileExtension = getMimeTypeExtensions(file.mimeType)[0] ?? 'bin';
853
- const disposition = download ? 'attachment' : 'inline';
854
- const filename = `${title}.${fileExtension}`;
855
- return this.fileObjectStorage.getDownloadUrl(key, currentTimestamp() + (5 * millisecondsPerMinute), {
856
- 'Response-Content-Type': file.mimeType,
857
- 'Response-Content-Disposition': `${disposition}; filename = "${encodeURIComponent(filename)}"`
858
- });
859
- }
860
- publishChange({ collectionIds, documentIds, requestIds, requestFileIds, requestAssignmentTaskIds: requestAssignmentTasksIds }) {
861
- void tryIgnoreLogAsync(this.logger, async () => {
862
- const queries = [
863
- isUndefined(documentIds)
864
- ? undefined
865
- : this.session
866
- .selectDistinct({ collectionId: documentCollectionDocument.collectionId })
867
- .from(documentCollectionDocument)
868
- .where(inArray(documentCollectionDocument.documentId, documentIds)),
869
- isUndefined(requestIds)
870
- ? undefined
871
- : this.session
872
- .selectDistinct({ collectionId: documentRequestCollection.collectionId })
873
- .from(documentRequestCollection)
874
- .where(inArray(documentRequestCollection.requestId, requestIds)),
875
- isUndefined(requestFileIds)
876
- ? undefined
877
- : this.session
878
- .selectDistinct({ collectionId: documentRequestCollection.collectionId })
879
- .from(documentRequestFile)
880
- .innerJoin(documentRequestCollection, eq(documentRequestCollection.requestId, documentRequestFile.requestId))
881
- .where(inArray(documentRequestFile.requestId, requestFileIds)),
882
- isUndefined(requestAssignmentTasksIds)
883
- ? undefined
884
- : this.session
885
- .selectDistinct({ collectionId: documentRequestAssignmentTaskCollection.collectionId })
886
- .from(documentRequestAssignmentTaskCollection)
887
- .where(inArray(documentRequestAssignmentTaskCollection.requestAssignmentTaskId, requestAssignmentTasksIds))
888
- ];
889
- const filteredQueries = queries.filter(isDefined);
890
- const mappings = (filteredQueries.length == 1)
891
- ? await filteredQueries[0]
892
- : (filteredQueries.length > 1)
893
- ? await union(filteredQueries[0], filteredQueries[1], ...filteredQueries.slice(2))
894
- : [];
895
- const allCollectionIds = distinct([
896
- ...(collectionIds ?? []),
897
- ...mappings.map((mapping) => mapping.collectionId)
898
- ]);
899
- if (allCollectionIds.length == 0) {
900
- return;
901
- }
902
- this.collectionChangeMessageBus.publishAndForget(allCollectionIds);
903
- });
904
- }
905
- };
906
- DocumentManagementService = DocumentManagementService_1 = __decorate([
907
- Singleton({
908
- providers: [
909
- { provide: DatabaseConfig, useFactory: (_, context) => context.resolve(DocumentManagementConfig).database ?? context.resolve(DatabaseConfig, undefined, { skipSelf: true }) }
910
- ]
911
- })
912
- ], DocumentManagementService);
913
- export { DocumentManagementService };
914
- function getDocumentFileKey(id) {
915
- return `${id.slice(0, 2)} /${id.slice(0, 4)}/${id} `;
916
- }
917
- const validators = {
918
- [DocumentPropertyDataType.Text]: (value) => isString(value) || isNull(value),
919
- [DocumentPropertyDataType.Integer]: (value) => isNumber(value) || isNull(value),
920
- [DocumentPropertyDataType.Decimal]: (value) => isNumber(value) || isNull(value),
921
- [DocumentPropertyDataType.Boolean]: (value) => isBoolean(value) || isNull(value),
922
- [DocumentPropertyDataType.Date]: (value) => isNumber(value) || isNull(value)
923
- };
924
- function validatePropertyValue(propertyId, dataType, value) {
925
- const valid = validators[dataType](value);
926
- if (!valid) {
927
- throw new BadRequestError(`Invalid value for data type ${dataType} for property ${propertyId}.`);
928
146
  }
929
147
  }