@tstdl/base 0.93.96 → 0.93.98

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 (48) hide show
  1. package/audit/auditor.d.ts +1 -1
  2. package/cookie/cookie.js +5 -1
  3. package/css/css-variables.d.ts +38 -0
  4. package/css/css-variables.js +38 -0
  5. package/document-management/api/document-management.api.d.ts +15 -1
  6. package/document-management/api/document-management.api.js +8 -1
  7. package/document-management/models/document-category.model.js +0 -1
  8. package/document-management/models/document-property.model.js +0 -1
  9. package/document-management/server/api/document-management.api.d.ts +1 -0
  10. package/document-management/server/api/document-management.api.js +13 -1
  11. package/document-management/server/drizzle/{0000_needy_steel_serpent.sql → 0000_silly_chimera.sql} +0 -2
  12. package/document-management/server/drizzle/meta/0000_snapshot.json +1 -15
  13. package/document-management/server/drizzle/meta/_journal.json +2 -2
  14. package/document-management/server/services/document-statistics.service.d.ts +6 -0
  15. package/document-management/server/services/document-statistics.service.js +167 -0
  16. package/document-management/server/services/index.d.ts +1 -0
  17. package/document-management/server/services/index.js +1 -0
  18. package/document-management/service-models/document-statistics.view-model.d.ts +38 -0
  19. package/document-management/service-models/document-statistics.view-model.js +160 -0
  20. package/document-management/service-models/index.d.ts +1 -0
  21. package/document-management/service-models/index.js +1 -0
  22. package/document-management/tests/document-management-core.test.js +2 -2
  23. package/document-management/tests/document-management.api.test.d.ts +1 -0
  24. package/document-management/tests/document-management.api.test.js +102 -0
  25. package/document-management/tests/document-statistics.service.test.d.ts +1 -0
  26. package/document-management/tests/document-statistics.service.test.js +495 -0
  27. package/document-management/tests/enum-helpers.test.js +3 -2
  28. package/enumeration/enumeration.d.ts +24 -0
  29. package/enumeration/enumeration.js +20 -0
  30. package/examples/document-management/main.js +1 -1
  31. package/intl/number-parser.d.ts +16 -9
  32. package/intl/number-parser.js +31 -19
  33. package/module/module.js +3 -0
  34. package/object-storage/google/google.object-storage-provider.d.ts +0 -1
  35. package/object-storage/google/google.object-storage-provider.js +0 -1
  36. package/object-storage/index.d.ts +0 -1
  37. package/object-storage/index.js +0 -1
  38. package/object-storage/s3/s3.object-storage-provider.d.ts +0 -1
  39. package/object-storage/s3/s3.object-storage-provider.js +0 -1
  40. package/package.json +1 -1
  41. package/pool/pool.d.ts +1 -1
  42. package/promise/cancelable-promise.d.ts +1 -0
  43. package/promise/cancelable-promise.js +1 -0
  44. package/promise/index.d.ts +1 -0
  45. package/promise/index.js +1 -0
  46. package/random/number-generator/index.d.ts +1 -0
  47. package/random/number-generator/index.js +1 -0
  48. package/sse/data-stream.js +16 -3
@@ -43,7 +43,7 @@ type AuditEvents = Record<string, UndefinableJsonObject>;
43
43
  *
44
44
  * @template Events A record mapping event action names to their specific `details` payload types.
45
45
  */
46
- export declare class Auditor<Events extends AuditEvents = Record<never, never>> implements Resolvable<AuditorArgument> {
46
+ export declare class Auditor<Events extends AuditEvents = AuditEvents> implements Resolvable<AuditorArgument> {
47
47
  #private;
48
48
  /**
49
49
  * The module path for this auditor instance.
package/cookie/cookie.js CHANGED
@@ -56,10 +56,14 @@ export function parseCookieString(cookieString) {
56
56
  .split(';')
57
57
  .map((cookiePartString) => {
58
58
  const splitIndex = cookiePartString.indexOf('=');
59
+ if (splitIndex == -1) {
60
+ return [cookiePartString.trim(), ''];
61
+ }
59
62
  const name = cookiePartString.slice(0, splitIndex).trim();
60
63
  const rawValue = trim(cookiePartString.slice(splitIndex + 1).trim(), '"');
61
64
  const value = decodeURIComponent(rawValue);
62
65
  return [name, value];
63
- });
66
+ })
67
+ .filter(([name]) => name.length > 0);
64
68
  return new Map(cookieEntries);
65
69
  }
@@ -1,14 +1,52 @@
1
+ /**
2
+ * Utility for programmatically managing CSS variables using Constructable Stylesheets.
3
+ */
1
4
  export declare class CssVariables implements Disposable {
2
5
  #private;
3
6
  readonly selector: string;
4
7
  readonly prefix: string;
8
+ /**
9
+ * Creates an instance of CssVariables.
10
+ * @param selector The CSS selector where variables should be applied. Defaults to `:root`.
11
+ * @param prefix Optional prefix for variable names.
12
+ */
5
13
  constructor(selector: string | null, prefix?: string);
14
+ /**
15
+ * Disposes the stylesheet by removing it from `document.adoptedStyleSheets`.
16
+ */
6
17
  [Symbol.dispose](): void;
18
+ /**
19
+ * Sets a CSS variable.
20
+ * @param name The name of the variable.
21
+ * @param value The value of the variable.
22
+ */
7
23
  set(name: string, value: string): void;
24
+ /**
25
+ * Sets multiple CSS variables at once.
26
+ * @param variables A record of variable names and values, or an array of entries.
27
+ */
8
28
  setMany(variables: Record<string, string> | readonly (readonly [string, string])[]): void;
29
+ /**
30
+ * Gets the value of a CSS variable.
31
+ * @param name The name of the variable.
32
+ * @returns The value of the variable, or `null` if not set.
33
+ */
9
34
  get(name: string): string | null;
35
+ /**
36
+ * Deletes a CSS variable.
37
+ * @param name The name of the variable to delete.
38
+ */
10
39
  delete(name: string): void;
40
+ /**
41
+ * Clears all CSS variables managed by this instance.
42
+ */
11
43
  clear(): void;
12
44
  private _prefix;
13
45
  }
46
+ /**
47
+ * Creates a new {@link CssVariables} instance.
48
+ * @param selector The CSS selector where variables should be applied. Defaults to `:root`.
49
+ * @param prefix Optional prefix for variable names.
50
+ * @returns A new CssVariables instance.
51
+ */
14
52
  export declare function cssVariables(selector?: string | null, prefix?: string): CssVariables;
@@ -1,32 +1,57 @@
1
1
  import { objectEntries } from '../utils/object/object.js';
2
2
  import { isArray } from '../utils/type-guards.js';
3
+ /**
4
+ * Utility for programmatically managing CSS variables using Constructable Stylesheets.
5
+ */
3
6
  export class CssVariables {
4
7
  #styleSheet = new CSSStyleSheet();
5
8
  #cssRule;
6
9
  selector;
7
10
  prefix;
11
+ /**
12
+ * Creates an instance of CssVariables.
13
+ * @param selector The CSS selector where variables should be applied. Defaults to `:root`.
14
+ * @param prefix Optional prefix for variable names.
15
+ */
8
16
  constructor(selector, prefix = '') {
9
17
  this.selector = selector ?? ':root';
10
18
  this.prefix = prefix;
11
19
  document.adoptedStyleSheets.push(this.#styleSheet);
12
20
  this.#cssRule = createCssRule(this.#styleSheet, `${this.selector} {}`);
13
21
  }
22
+ /**
23
+ * Disposes the stylesheet by removing it from `document.adoptedStyleSheets`.
24
+ */
14
25
  [Symbol.dispose]() {
15
26
  const index = document.adoptedStyleSheets.indexOf(this.#styleSheet);
16
27
  if (index != -1) {
17
28
  document.adoptedStyleSheets.splice(index, 1);
18
29
  }
19
30
  }
31
+ /**
32
+ * Sets a CSS variable.
33
+ * @param name The name of the variable.
34
+ * @param value The value of the variable.
35
+ */
20
36
  set(name, value) {
21
37
  const prefixed = this._prefix(name);
22
38
  this.#cssRule.style.setProperty(prefixed, value);
23
39
  }
40
+ /**
41
+ * Sets multiple CSS variables at once.
42
+ * @param variables A record of variable names and values, or an array of entries.
43
+ */
24
44
  setMany(variables) {
25
45
  const entries = isArray(variables) ? variables : objectEntries(variables);
26
46
  for (const [name, value] of entries) {
27
47
  this.set(name, value);
28
48
  }
29
49
  }
50
+ /**
51
+ * Gets the value of a CSS variable.
52
+ * @param name The name of the variable.
53
+ * @returns The value of the variable, or `null` if not set.
54
+ */
30
55
  get(name) {
31
56
  const prefixed = this._prefix(name);
32
57
  const rawValue = this.#cssRule.style.getPropertyValue(prefixed);
@@ -35,10 +60,17 @@ export class CssVariables {
35
60
  }
36
61
  return rawValue;
37
62
  }
63
+ /**
64
+ * Deletes a CSS variable.
65
+ * @param name The name of the variable to delete.
66
+ */
38
67
  delete(name) {
39
68
  const prefixed = this._prefix(name);
40
69
  this.#cssRule.style.removeProperty(prefixed);
41
70
  }
71
+ /**
72
+ * Clears all CSS variables managed by this instance.
73
+ */
42
74
  clear() {
43
75
  this.#cssRule.style.cssText = '';
44
76
  }
@@ -47,6 +79,12 @@ export class CssVariables {
47
79
  return prefixed.startsWith('--') ? prefixed : `--${prefixed}`;
48
80
  }
49
81
  }
82
+ /**
83
+ * Creates a new {@link CssVariables} instance.
84
+ * @param selector The CSS selector where variables should be applied. Defaults to `:root`.
85
+ * @param prefix Optional prefix for variable names.
86
+ * @returns A new CssVariables instance.
87
+ */
50
88
  export function cssVariables(selector = null, prefix = '') {
51
89
  return new CssVariables(selector, prefix);
52
90
  }
@@ -1,6 +1,6 @@
1
1
  import { DataStream } from '../../sse/index.js';
2
2
  import { Document, DocumentCategory, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType } from '../models/index.js';
3
- import { CategoriesAndTypesData, DocumentCategoryView, DocumentManagementData, DocumentRequestsTemplateData } from '../service-models/index.js';
3
+ import { CategoriesAndTypesData, DocumentCategoryView, DocumentManagementData, DocumentRequestsTemplateData, DocumentStatistics, GetDocumentStatisticsOptions } from '../service-models/index.js';
4
4
  export type DocumentManagementApiDefinition = typeof documentManagementApiDefinition;
5
5
  export declare const documentManagementApiDefinition: {
6
6
  resource: string;
@@ -14,6 +14,13 @@ export declare const documentManagementApiDefinition: {
14
14
  result: typeof DocumentManagementData;
15
15
  credentials: true;
16
16
  };
17
+ getStatistics: {
18
+ resource: string;
19
+ method: "POST";
20
+ parameters: typeof GetDocumentStatisticsOptions;
21
+ result: typeof DocumentStatistics;
22
+ credentials: true;
23
+ };
17
24
  getCategoriesAndTypes: {
18
25
  resource: string;
19
26
  method: "GET";
@@ -423,6 +430,13 @@ declare const _DocumentManagementApi: import("../../api/client/index.js").ApiCli
423
430
  result: typeof DocumentManagementData;
424
431
  credentials: true;
425
432
  };
433
+ getStatistics: {
434
+ resource: string;
435
+ method: "POST";
436
+ parameters: typeof GetDocumentStatisticsOptions;
437
+ result: typeof DocumentStatistics;
438
+ credentials: true;
439
+ };
426
440
  getCategoriesAndTypes: {
427
441
  resource: string;
428
442
  method: "GET";
@@ -13,7 +13,7 @@ import { array, boolean, literal, number, object, optional, string } from '../..
13
13
  import { DataStream } from '../../sse/index.js';
14
14
  import { policy } from '../authorization/index.js';
15
15
  import { Document, DocumentCategory, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType } from '../models/index.js';
16
- import { addOrArchiveDocumentToOrFromCollectionParametersSchema, applyDocumentRequestsTemplateParametersSchema, CategoriesAndTypesData, createDocumentCategoryParametersSchema, createDocumentParametersSchema, createDocumentRequestParametersSchema, createDocumentRequestsTemplateParametersSchema, createDocumentRequestTemplateParametersSchema, createDocumentTypeParametersSchema, deleteDocumentRequestParametersSchema, deleteDocumentRequestsTemplateParametersSchema, deleteDocumentRequestTemplateParametersSchema, DocumentCategoryView, DocumentManagementData, DocumentRequestsTemplateData, loadDataParametersSchema, proceedDocumentWorkflowParametersSchema, updateDocumentParametersSchema, updateDocumentRequestParametersSchema, updateDocumentRequestsTemplateParametersSchema, updateDocumentRequestTemplateParametersSchema } from '../service-models/index.js';
16
+ import { addOrArchiveDocumentToOrFromCollectionParametersSchema, applyDocumentRequestsTemplateParametersSchema, CategoriesAndTypesData, createDocumentCategoryParametersSchema, createDocumentParametersSchema, createDocumentRequestParametersSchema, createDocumentRequestsTemplateParametersSchema, createDocumentRequestTemplateParametersSchema, createDocumentTypeParametersSchema, deleteDocumentRequestParametersSchema, deleteDocumentRequestsTemplateParametersSchema, deleteDocumentRequestTemplateParametersSchema, DocumentCategoryView, DocumentManagementData, DocumentRequestsTemplateData, DocumentStatistics, GetDocumentStatisticsOptions, loadDataParametersSchema, proceedDocumentWorkflowParametersSchema, updateDocumentParametersSchema, updateDocumentRequestParametersSchema, updateDocumentRequestsTemplateParametersSchema, updateDocumentRequestTemplateParametersSchema } from '../service-models/index.js';
17
17
  export const documentManagementApiDefinition = defineApi({
18
18
  resource: 'document-management',
19
19
  endpoints: {
@@ -24,6 +24,13 @@ export const documentManagementApiDefinition = defineApi({
24
24
  result: DocumentManagementData,
25
25
  credentials: true,
26
26
  },
27
+ getStatistics: {
28
+ resource: 'stats',
29
+ method: 'POST',
30
+ parameters: GetDocumentStatisticsOptions,
31
+ result: DocumentStatistics,
32
+ credentials: true,
33
+ },
27
34
  getCategoriesAndTypes: {
28
35
  resource: 'categories-and-types',
29
36
  method: 'GET',
@@ -23,7 +23,6 @@ __decorate([
23
23
  ], DocumentCategory.prototype, "parentId", void 0);
24
24
  __decorate([
25
25
  StringProperty(),
26
- Unique(),
27
26
  __metadata("design:type", String)
28
27
  ], DocumentCategory.prototype, "label", void 0);
29
28
  __decorate([
@@ -26,7 +26,6 @@ let DocumentProperty = class DocumentProperty extends TenantEntity {
26
26
  };
27
27
  __decorate([
28
28
  StringProperty(),
29
- Unique(),
30
29
  __metadata("design:type", String)
31
30
  ], DocumentProperty.prototype, "label", void 0);
32
31
  __decorate([
@@ -3,6 +3,7 @@ import { type DocumentManagementApiDefinition } from '../../api/index.js';
3
3
  export declare class DocumentManagementApiController implements ApiController<DocumentManagementApiDefinition> {
4
4
  #private;
5
5
  loadData(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadData'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'loadData'>>;
6
+ getStatistics(context: ApiRequestContext<DocumentManagementApiDefinition, 'getStatistics'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'getStatistics'>>;
6
7
  loadDataStream(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadDataStream'>): ApiServerResult<DocumentManagementApiDefinition, 'loadDataStream'>;
7
8
  loadDocumentRequestsTemplateData(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadDocumentRequestsTemplateData'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'loadDocumentRequestsTemplateData'>>;
8
9
  getCategoriesAndTypes(context: ApiRequestContext<DocumentManagementApiDefinition, 'getCategoriesAndTypes'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'getCategoriesAndTypes'>>;
@@ -15,9 +15,10 @@ import { toArray } from '../../../utils/array/index.js';
15
15
  import { documentManagementApiDefinition } from '../../api/index.js';
16
16
  import { DocumentManagementAuthorizationService } from '../../authorization/index.js';
17
17
  import { DocumentRequestCollectionAssignment } from '../../models/document-request-collection-assignment.model.js';
18
- import { DocumentCategoryTypeService, DocumentFileService, DocumentManagementService, DocumentRequestService, DocumentService, DocumentWorkflowService } from '../services/index.js';
18
+ import { DocumentCategoryTypeService, DocumentFileService, DocumentManagementService, DocumentRequestService, DocumentService, DocumentStatisticsService, DocumentWorkflowService } from '../services/index.js';
19
19
  let DocumentManagementApiController = class DocumentManagementApiController {
20
20
  #documentManagementService = inject(DocumentManagementService);
21
+ #documentStatisticsService = inject(DocumentStatisticsService);
21
22
  #authorizationService = inject(DocumentManagementAuthorizationService);
22
23
  #documentCategoryTypeService = inject(DocumentCategoryTypeService);
23
24
  #documentFileService = inject(DocumentFileService);
@@ -38,6 +39,17 @@ let DocumentManagementApiController = class DocumentManagementApiController {
38
39
  }
39
40
  return await this.#documentManagementService.loadData(tenantId, collectionIdArray);
40
41
  }
42
+ async getStatistics(context) {
43
+ const token = await context.getToken();
44
+ const tenantId = await this.#authorizationService.getTenantId(token);
45
+ for (const collectionId of context.parameters.collectionIds) {
46
+ const allowed = await this.#authorizationService.canReadCollection(collectionId, token);
47
+ if (!allowed) {
48
+ throw new ForbiddenError(`You are not allowed to read collection ${collectionId}`);
49
+ }
50
+ }
51
+ return await this.#documentStatisticsService.getStatistics(tenantId, context.parameters);
52
+ }
41
53
  async *loadDataStream(context) {
42
54
  const token = await context.getToken();
43
55
  const tenantId = await this.#authorizationService.getTenantId(token);
@@ -72,7 +72,6 @@ CREATE TABLE "document_management"."category" (
72
72
  "delete_timestamp" timestamp with time zone,
73
73
  "attributes" jsonb DEFAULT '{}'::jsonb NOT NULL,
74
74
  CONSTRAINT "category_tenant_id_id_pk" PRIMARY KEY("tenant_id","id"),
75
- CONSTRAINT "category_label_unique" UNIQUE("label"),
76
75
  CONSTRAINT "category_tenant_id_key_unique" UNIQUE("tenant_id","key"),
77
76
  CONSTRAINT "category_tenant_id_parent_id_label_unique" UNIQUE("tenant_id","parent_id","label")
78
77
  );
@@ -117,7 +116,6 @@ CREATE TABLE "document_management"."property" (
117
116
  "delete_timestamp" timestamp with time zone,
118
117
  "attributes" jsonb DEFAULT '{}'::jsonb NOT NULL,
119
118
  CONSTRAINT "property_tenant_id_id_pk" PRIMARY KEY("tenant_id","id"),
120
- CONSTRAINT "property_label_unique" UNIQUE("label"),
121
119
  CONSTRAINT "property_tenant_id_key_unique" UNIQUE("tenant_id","key"),
122
120
  CONSTRAINT "property_tenant_id_label_unique" UNIQUE("tenant_id","label")
123
121
  );
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "bc835c07-b4ae-40f1-9d65-cfca1dcca765",
2
+ "id": "fee5df5b-e30c-483a-a4f2-fff78256e1c2",
3
3
  "prevId": "00000000-0000-0000-0000-000000000000",
4
4
  "version": "7",
5
5
  "dialect": "postgresql",
@@ -542,13 +542,6 @@
542
542
  }
543
543
  },
544
544
  "uniqueConstraints": {
545
- "category_label_unique": {
546
- "name": "category_label_unique",
547
- "nullsNotDistinct": false,
548
- "columns": [
549
- "label"
550
- ]
551
- },
552
545
  "category_tenant_id_key_unique": {
553
546
  "name": "category_tenant_id_key_unique",
554
547
  "nullsNotDistinct": false,
@@ -922,13 +915,6 @@
922
915
  }
923
916
  },
924
917
  "uniqueConstraints": {
925
- "property_label_unique": {
926
- "name": "property_label_unique",
927
- "nullsNotDistinct": false,
928
- "columns": [
929
- "label"
930
- ]
931
- },
932
918
  "property_tenant_id_key_unique": {
933
919
  "name": "property_tenant_id_key_unique",
934
920
  "nullsNotDistinct": false,
@@ -5,8 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "7",
8
- "when": 1769181101684,
9
- "tag": "0000_needy_steel_serpent",
8
+ "when": 1769464843006,
9
+ "tag": "0000_silly_chimera",
10
10
  "breakpoints": true
11
11
  }
12
12
  ]
@@ -0,0 +1,6 @@
1
+ import { Transactional } from '../../../orm/server/index.js';
2
+ import { DocumentStatistics, GetDocumentStatisticsOptions } from '../../service-models/index.js';
3
+ export declare class DocumentStatisticsService extends Transactional {
4
+ #private;
5
+ getStatistics(tenantId: string, options: GetDocumentStatisticsOptions): Promise<DocumentStatistics>;
6
+ }
@@ -0,0 +1,167 @@
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
+ import { Transactional } from '../../../orm/server/index.js';
8
+ import { isDefined } from '../../../utils/type-guards.js';
9
+ import { and, count, countDistinct, eq, inArray, isNotNull, sql, sum } from 'drizzle-orm';
10
+ import { DocumentValidationResultStatus } from '../../models/document-validation-execution.model.js';
11
+ import { DocumentApproval } from '../../models/document.model.js';
12
+ import { DocumentStatistics, GetDocumentStatisticsOptions } from '../../service-models/index.js';
13
+ import { document, documentCollectionAssignment, documentTagAssignment, documentType, documentValidationExecution, documentWorkflow } from '../schemas.js';
14
+ import { DocumentManagementSingleton } from './singleton.js';
15
+ let DocumentStatisticsService = class DocumentStatisticsService extends Transactional {
16
+ async getStatistics(tenantId, options) {
17
+ const stats = {};
18
+ const conditions = [eq(document.tenantId, tenantId)];
19
+ const joinCollection = isDefined(options.collectionIds);
20
+ const joinType = isDefined(options.categoryIds);
21
+ if (isDefined(options.collectionIds)) {
22
+ conditions.push(inArray(documentCollectionAssignment.collectionId, options.collectionIds));
23
+ }
24
+ if (isDefined(options.categoryIds)) {
25
+ conditions.push(inArray(documentType.categoryId, options.categoryIds));
26
+ }
27
+ await Promise.all([
28
+ this.#calculateBasicStats(stats, options, conditions, joinCollection, joinType),
29
+ this.#calculateTypeBreakdown(stats, options, conditions, joinCollection, joinType),
30
+ this.#calculateMimeTypeDistribution(stats, options, conditions, joinCollection, joinType),
31
+ this.#calculateTagUsage(stats, options, conditions, joinCollection, joinType),
32
+ this.#calculateValidationFailures(stats, options, conditions, joinCollection, joinType),
33
+ ]);
34
+ return stats;
35
+ }
36
+ async #calculateBasicStats(stats, options, conditions, joinCollection, joinType) {
37
+ const select = {};
38
+ if (options.includeTotalCount == true) {
39
+ select['totalCount'] = count(document.id);
40
+ }
41
+ if (options.includeApprovalBreakdown == true) {
42
+ select['approvalPending'] = count(sql `CASE WHEN ${eq(document.approval, DocumentApproval.Pending)} THEN 1 END`);
43
+ select['approvalApproved'] = count(sql `CASE WHEN ${eq(document.approval, DocumentApproval.Approved)} THEN 1 END`);
44
+ select['approvalRejected'] = count(sql `CASE WHEN ${eq(document.approval, DocumentApproval.Rejected)} THEN 1 END`);
45
+ }
46
+ if (options.includeStorageUsage == true) {
47
+ select['storageUsage'] = sum(document.size);
48
+ }
49
+ if (options.includeTotalPages == true) {
50
+ select['totalPages'] = sum(document.pages);
51
+ }
52
+ if (options.includeDataQuality == true) {
53
+ select['missingType'] = count(sql `CASE WHEN ${document.typeId} IS NULL THEN 1 END`);
54
+ select['missingDate'] = count(sql `CASE WHEN ${document.date} IS NULL THEN 1 END`);
55
+ select['missingTitle'] = count(sql `CASE WHEN ${document.title} IS NULL THEN 1 END`);
56
+ }
57
+ if (options.includeCreatedLast30Days == true) {
58
+ const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
59
+ select['createdLast30Days'] = count(sql `CASE WHEN ${document.createTimestamp} > ${new Date(thirtyDaysAgo).toISOString()} THEN 1 END`);
60
+ }
61
+ if (Object.keys(select).length == 0) {
62
+ return;
63
+ }
64
+ let query = this.session.select(select).from(document).where(and(...conditions)).$dynamic();
65
+ query = this.#applyJoins(query, joinCollection, joinType);
66
+ const [result] = await query;
67
+ if (isDefined(result)) {
68
+ if (options.includeTotalCount == true) {
69
+ stats.totalCount = Number(result.totalCount);
70
+ }
71
+ if (options.includeApprovalBreakdown == true) {
72
+ stats.approvalBreakdown = {
73
+ [DocumentApproval.Pending]: Number(result.approvalPending),
74
+ [DocumentApproval.Approved]: Number(result.approvalApproved),
75
+ [DocumentApproval.Rejected]: Number(result.approvalRejected),
76
+ };
77
+ }
78
+ if (options.includeStorageUsage == true) {
79
+ stats.storageUsage = Number(result.storageUsage ?? 0);
80
+ }
81
+ if (options.includeTotalPages == true) {
82
+ stats.totalPages = Number(result.totalPages ?? 0);
83
+ }
84
+ if (options.includeDataQuality == true) {
85
+ stats.dataQuality = {
86
+ missingType: Number(result.missingType),
87
+ missingDate: Number(result.missingDate),
88
+ missingTitle: Number(result.missingTitle),
89
+ };
90
+ }
91
+ if (options.includeCreatedLast30Days == true) {
92
+ stats.createdLast30Days = Number(result.createdLast30Days);
93
+ }
94
+ }
95
+ }
96
+ async #calculateTypeBreakdown(stats, options, conditions, joinCollection, joinType) {
97
+ if (options.includeTypeBreakdown != true) {
98
+ return;
99
+ }
100
+ let query = this.session
101
+ .select({ typeId: document.typeId, count: count(document.id) })
102
+ .from(document)
103
+ .where(and(...conditions, isNotNull(document.typeId)))
104
+ .groupBy(document.typeId)
105
+ .$dynamic();
106
+ query = this.#applyJoins(query, joinCollection, joinType);
107
+ const results = await query;
108
+ stats.typeBreakdown = Object.fromEntries(results.map((r) => [r.typeId, r.count]));
109
+ }
110
+ async #calculateMimeTypeDistribution(stats, options, conditions, joinCollection, joinType) {
111
+ if (options.includeMimeTypeDistribution != true) {
112
+ return;
113
+ }
114
+ let query = this.session
115
+ .select({ mimeType: document.mimeType, count: count(document.id) })
116
+ .from(document)
117
+ .where(and(...conditions))
118
+ .groupBy(document.mimeType)
119
+ .$dynamic();
120
+ query = this.#applyJoins(query, joinCollection, joinType);
121
+ const results = await query;
122
+ stats.mimeTypeDistribution = Object.fromEntries(results.map((r) => [r.mimeType, r.count]));
123
+ }
124
+ async #calculateTagUsage(stats, options, conditions, joinCollection, joinType) {
125
+ if (options.includeTagUsage != true) {
126
+ return;
127
+ }
128
+ let query = this.session
129
+ .select({ tagId: documentTagAssignment.tagId, count: count(document.id) })
130
+ .from(document)
131
+ .innerJoin(documentTagAssignment, eq(documentTagAssignment.documentId, document.id))
132
+ .where(and(...conditions))
133
+ .groupBy(documentTagAssignment.tagId)
134
+ .$dynamic();
135
+ query = this.#applyJoins(query, joinCollection, joinType);
136
+ const results = await query;
137
+ stats.tagUsage = Object.fromEntries(results.map((r) => [r.tagId, r.count]));
138
+ }
139
+ async #calculateValidationFailures(stats, options, conditions, joinCollection, joinType) {
140
+ if (options.includeValidationFailures != true) {
141
+ return;
142
+ }
143
+ let query = this.session
144
+ .select({ count: countDistinct(document.id) })
145
+ .from(document)
146
+ .innerJoin(documentWorkflow, eq(documentWorkflow.documentId, document.id))
147
+ .innerJoin(documentValidationExecution, eq(documentValidationExecution.workflowId, documentWorkflow.id))
148
+ .where(and(...conditions, eq(documentValidationExecution.resultStatus, DocumentValidationResultStatus.Failed)))
149
+ .$dynamic();
150
+ query = this.#applyJoins(query, joinCollection, joinType);
151
+ const [result] = await query;
152
+ stats.validationFailures = (result?.count ?? 0);
153
+ }
154
+ #applyJoins(query, joinCollection, joinType) {
155
+ if (joinCollection) {
156
+ query = query.innerJoin(documentCollectionAssignment, eq(documentCollectionAssignment.documentId, document.id));
157
+ }
158
+ if (joinType) {
159
+ query = query.leftJoin(documentType, eq(documentType.id, document.typeId));
160
+ }
161
+ return query;
162
+ }
163
+ };
164
+ DocumentStatisticsService = __decorate([
165
+ DocumentManagementSingleton()
166
+ ], DocumentStatisticsService);
167
+ export { DocumentStatisticsService };
@@ -7,6 +7,7 @@ export * from './document-management-observation.service.js';
7
7
  export * from './document-management.service.js';
8
8
  export * from './document-property.service.js';
9
9
  export * from './document-request.service.js';
10
+ export * from './document-statistics.service.js';
10
11
  export * from './document-tag.service.js';
11
12
  export * from './document-validation.service.js';
12
13
  export * from './document-workflow.service.js';
@@ -7,6 +7,7 @@ export * from './document-management-observation.service.js';
7
7
  export * from './document-management.service.js';
8
8
  export * from './document-property.service.js';
9
9
  export * from './document-request.service.js';
10
+ export * from './document-statistics.service.js';
10
11
  export * from './document-tag.service.js';
11
12
  export * from './document-validation.service.js';
12
13
  export * from './document-workflow.service.js';
@@ -0,0 +1,38 @@
1
+ import type { Record } from '../../types/index.js';
2
+ import { DocumentApproval } from '../models/document.model.js';
3
+ export declare class DocumentApprovalBreakdown {
4
+ [DocumentApproval.Pending]: number;
5
+ [DocumentApproval.Approved]: number;
6
+ [DocumentApproval.Rejected]: number;
7
+ }
8
+ export declare class DocumentDataQualityMetrics {
9
+ missingType: number;
10
+ missingDate: number;
11
+ missingTitle: number;
12
+ }
13
+ export declare class DocumentStatistics {
14
+ totalCount?: number;
15
+ approvalBreakdown?: DocumentApprovalBreakdown;
16
+ typeBreakdown?: Record<string, number>;
17
+ storageUsage?: number;
18
+ mimeTypeDistribution?: Record<string, number>;
19
+ dataQuality?: DocumentDataQualityMetrics;
20
+ createdLast30Days?: number;
21
+ tagUsage?: Record<string, number>;
22
+ totalPages?: number;
23
+ validationFailures?: number;
24
+ }
25
+ export declare class GetDocumentStatisticsOptions {
26
+ includeTotalCount?: boolean;
27
+ includeApprovalBreakdown?: boolean;
28
+ includeTypeBreakdown?: boolean;
29
+ includeStorageUsage?: boolean;
30
+ includeMimeTypeDistribution?: boolean;
31
+ includeDataQuality?: boolean;
32
+ includeCreatedLast30Days?: boolean;
33
+ includeTagUsage?: boolean;
34
+ includeTotalPages?: boolean;
35
+ includeValidationFailures?: boolean;
36
+ collectionIds: string[];
37
+ categoryIds?: string[];
38
+ }