@flusys/nestjs-localization 7.1.0 → 8.0.0

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 (117) hide show
  1. package/config/index.d.ts +3 -3
  2. package/controllers/index.d.ts +3 -3
  3. package/controllers/language.controller.d.ts +4 -4
  4. package/controllers/translation-key.controller.d.ts +3 -3
  5. package/controllers/translation.controller.d.ts +4 -4
  6. package/docs/index.d.ts +1 -1
  7. package/docs/localization-swagger.config.d.ts +1 -1
  8. package/dtos/index.d.ts +3 -3
  9. package/dtos/translation.dto.d.ts +2 -2
  10. package/entities/index.d.ts +6 -6
  11. package/entities/language.entity.d.ts +1 -1
  12. package/entities/translation-key.entity.d.ts +1 -1
  13. package/entities/translation.entity.d.ts +2 -2
  14. package/fesm/349.js +1179 -0
  15. package/fesm/692.js +1205 -0
  16. package/fesm/config/index.js +101 -3
  17. package/fesm/controllers/index.js +15 -3
  18. package/fesm/docs/index.js +126 -1
  19. package/fesm/dtos/index.js +680 -3
  20. package/fesm/entities/index.js +405 -8
  21. package/fesm/index.js +257 -7
  22. package/fesm/interfaces/index.js +18 -4
  23. package/fesm/modules/index.js +152 -1
  24. package/fesm/runtime.js +85 -0
  25. package/fesm/services/index.js +15 -5
  26. package/index.d.ts +7 -7
  27. package/interfaces/index.d.ts +4 -4
  28. package/interfaces/language.interface.d.ts +1 -1
  29. package/interfaces/localization-module-options.interface.d.ts +3 -3
  30. package/interfaces/translation-key.interface.d.ts +1 -1
  31. package/interfaces/translation.interface.d.ts +3 -3
  32. package/modules/index.d.ts +1 -1
  33. package/modules/localization.module.d.ts +2 -2
  34. package/package.json +25 -34
  35. package/services/index.d.ts +5 -5
  36. package/services/language.service.d.ts +6 -6
  37. package/services/localization-config.service.d.ts +3 -3
  38. package/services/localization-datasource.provider.d.ts +3 -3
  39. package/services/translation-key.service.d.ts +6 -6
  40. package/services/translation.service.d.ts +5 -5
  41. package/cjs/config/event-actions.js +0 -33
  42. package/cjs/config/index.js +0 -20
  43. package/cjs/config/localization.constants.js +0 -11
  44. package/cjs/config/message-keys.js +0 -41
  45. package/cjs/controllers/index.js +0 -20
  46. package/cjs/controllers/language.controller.js +0 -188
  47. package/cjs/controllers/language.controller.spec.js +0 -154
  48. package/cjs/controllers/translation-key.controller.js +0 -135
  49. package/cjs/controllers/translation-key.controller.spec.js +0 -70
  50. package/cjs/controllers/translation.controller.js +0 -195
  51. package/cjs/controllers/translation.controller.spec.js +0 -169
  52. package/cjs/docs/index.js +0 -11
  53. package/cjs/docs/localization-swagger.config.js +0 -111
  54. package/cjs/docs/localization-swagger.config.spec.js +0 -30
  55. package/cjs/dtos/index.js +0 -20
  56. package/cjs/dtos/language.dto.js +0 -213
  57. package/cjs/dtos/translation-key.dto.js +0 -215
  58. package/cjs/dtos/translation.dto.js +0 -269
  59. package/cjs/entities/index.js +0 -42
  60. package/cjs/entities/index.spec.js +0 -18
  61. package/cjs/entities/language.entity.js +0 -126
  62. package/cjs/entities/translation-key.entity.js +0 -126
  63. package/cjs/entities/translation.entity.js +0 -120
  64. package/cjs/index.js +0 -24
  65. package/cjs/interfaces/index.js +0 -21
  66. package/cjs/interfaces/language.interface.js +0 -4
  67. package/cjs/interfaces/localization-module-options.interface.js +0 -4
  68. package/cjs/interfaces/translation-key.interface.js +0 -4
  69. package/cjs/interfaces/translation.interface.js +0 -4
  70. package/cjs/modules/index.js +0 -18
  71. package/cjs/modules/localization.module.js +0 -116
  72. package/cjs/modules/localization.module.spec.js +0 -132
  73. package/cjs/services/index.js +0 -22
  74. package/cjs/services/language.service.js +0 -181
  75. package/cjs/services/language.service.spec.js +0 -256
  76. package/cjs/services/localization-config.service.js +0 -66
  77. package/cjs/services/localization-config.service.spec.js +0 -80
  78. package/cjs/services/localization-datasource.provider.js +0 -79
  79. package/cjs/services/localization-datasource.provider.spec.js +0 -85
  80. package/cjs/services/translation-key.service.js +0 -179
  81. package/cjs/services/translation-key.service.spec.js +0 -303
  82. package/cjs/services/translation.service.js +0 -228
  83. package/cjs/services/translation.service.spec.js +0 -530
  84. package/fesm/config/event-actions.js +0 -12
  85. package/fesm/config/localization.constants.js +0 -1
  86. package/fesm/config/message-keys.js +0 -20
  87. package/fesm/controllers/language.controller.js +0 -178
  88. package/fesm/controllers/language.controller.spec.js +0 -150
  89. package/fesm/controllers/translation-key.controller.js +0 -125
  90. package/fesm/controllers/translation-key.controller.spec.js +0 -66
  91. package/fesm/controllers/translation.controller.js +0 -185
  92. package/fesm/controllers/translation.controller.spec.js +0 -165
  93. package/fesm/docs/localization-swagger.config.js +0 -101
  94. package/fesm/docs/localization-swagger.config.spec.js +0 -26
  95. package/fesm/dtos/language.dto.js +0 -192
  96. package/fesm/dtos/translation-key.dto.js +0 -194
  97. package/fesm/dtos/translation.dto.js +0 -239
  98. package/fesm/entities/index.spec.js +0 -14
  99. package/fesm/entities/language.entity.js +0 -116
  100. package/fesm/entities/translation-key.entity.js +0 -116
  101. package/fesm/entities/translation.entity.js +0 -110
  102. package/fesm/interfaces/language.interface.js +0 -1
  103. package/fesm/interfaces/localization-module-options.interface.js +0 -1
  104. package/fesm/interfaces/translation-key.interface.js +0 -1
  105. package/fesm/interfaces/translation.interface.js +0 -1
  106. package/fesm/modules/localization.module.js +0 -106
  107. package/fesm/modules/localization.module.spec.js +0 -128
  108. package/fesm/services/language.service.js +0 -171
  109. package/fesm/services/language.service.spec.js +0 -252
  110. package/fesm/services/localization-config.service.js +0 -56
  111. package/fesm/services/localization-config.service.spec.js +0 -76
  112. package/fesm/services/localization-datasource.provider.js +0 -69
  113. package/fesm/services/localization-datasource.provider.spec.js +0 -81
  114. package/fesm/services/translation-key.service.js +0 -169
  115. package/fesm/services/translation-key.service.spec.js +0 -299
  116. package/fesm/services/translation.service.js +0 -218
  117. package/fesm/services/translation.service.spec.js +0 -526
@@ -1,252 +0,0 @@
1
- import { Test } from '@nestjs/testing';
2
- import { UtilsService } from '@flusys/nestjs-shared/modules';
3
- import { createMockDataSourceProvider, createMockRepository } from '@test-utils/mocks/repository.mock';
4
- import { LanguageService } from './language.service';
5
- import { LocalizationDataSourceProvider } from './localization-datasource.provider';
6
- function buildLanguage(overrides = {}) {
7
- return {
8
- id: 'language-uuid-1',
9
- code: 'en',
10
- name: 'English',
11
- nativeName: 'English',
12
- direction: 'ltr',
13
- isActive: true,
14
- isDefault: false,
15
- serial: 1,
16
- isReadonly: false,
17
- createdAt: new Date(),
18
- updatedAt: new Date(),
19
- deletedAt: null,
20
- createdById: null,
21
- updatedById: null,
22
- deletedById: null,
23
- ...overrides
24
- };
25
- }
26
- describe('LanguageService', ()=>{
27
- let service;
28
- let mockRepo;
29
- const mockUtilsService = {
30
- clearCache: jest.fn(),
31
- getCacheKey: jest.fn().mockReturnValue('cache-key'),
32
- trackCacheKey: jest.fn()
33
- };
34
- // Call history is shared across tests in this file; reset it so each cache assertion is exact.
35
- beforeEach(()=>{
36
- mockUtilsService.clearCache.mockClear();
37
- });
38
- beforeEach(async ()=>{
39
- mockRepo = createMockRepository();
40
- const mockDataSourceProvider = createMockDataSourceProvider(mockRepo);
41
- const module = await Test.createTestingModule({
42
- providers: [
43
- LanguageService,
44
- {
45
- provide: 'CACHE_INSTANCE',
46
- useValue: {}
47
- },
48
- {
49
- provide: UtilsService,
50
- useValue: mockUtilsService
51
- },
52
- {
53
- provide: LocalizationDataSourceProvider,
54
- useValue: mockDataSourceProvider
55
- }
56
- ]
57
- }).compile();
58
- service = await module.resolve(LanguageService);
59
- });
60
- describe('getDefaultLanguage', ()=>{
61
- it('returns the language flagged as default', async ()=>{
62
- const defaultLanguage = buildLanguage({
63
- id: 'default-lang',
64
- isDefault: true,
65
- code: 'en'
66
- });
67
- mockRepo.findOne.mockResolvedValue(defaultLanguage);
68
- const result = await service.getDefaultLanguage();
69
- expect(mockRepo.findOne).toHaveBeenCalledWith({
70
- where: {
71
- isDefault: true,
72
- deletedAt: expect.anything()
73
- }
74
- });
75
- expect(result).toEqual(defaultLanguage);
76
- });
77
- it('returns null when no language is marked default', async ()=>{
78
- mockRepo.findOne.mockResolvedValue(null);
79
- const result = await service.getDefaultLanguage();
80
- expect(result).toBeNull();
81
- });
82
- });
83
- describe('getActiveLanguages', ()=>{
84
- it('returns active, non-deleted languages ordered by serial then name', async ()=>{
85
- const languages = [
86
- buildLanguage({
87
- code: 'en',
88
- serial: 1
89
- }),
90
- buildLanguage({
91
- code: 'bn',
92
- serial: 2
93
- })
94
- ];
95
- mockRepo.find.mockResolvedValue(languages);
96
- const result = await service.getActiveLanguages();
97
- expect(mockRepo.find).toHaveBeenCalledWith({
98
- where: {
99
- isActive: true,
100
- deletedAt: expect.anything()
101
- },
102
- order: {
103
- serial: 'ASC',
104
- name: 'ASC'
105
- }
106
- });
107
- expect(result).toHaveLength(2);
108
- });
109
- it('returns an empty array when no languages are active', async ()=>{
110
- mockRepo.find.mockResolvedValue([]);
111
- const result = await service.getActiveLanguages();
112
- expect(result).toEqual([]);
113
- });
114
- });
115
- describe('setAsDefault', ()=>{
116
- beforeEach(()=>{
117
- mockRepo.find.mockResolvedValue([]);
118
- });
119
- it('unsets the previous default and sets the requested language as default', async ()=>{
120
- const newDefault = buildLanguage({
121
- id: 'lang-2',
122
- isDefault: true,
123
- code: 'bn'
124
- });
125
- mockRepo.findOne.mockResolvedValue(newDefault);
126
- const result = await service.setAsDefault('lang-2');
127
- expect(mockRepo.update).toHaveBeenNthCalledWith(1, {
128
- isDefault: true
129
- }, {
130
- isDefault: false
131
- });
132
- expect(mockRepo.update).toHaveBeenNthCalledWith(2, {
133
- id: 'lang-2'
134
- }, {
135
- isDefault: true
136
- });
137
- expect(mockRepo.findOne).toHaveBeenCalledWith({
138
- where: {
139
- id: 'lang-2'
140
- }
141
- });
142
- expect(result).toEqual(newDefault);
143
- });
144
- it('invalidates the language list cache and both the old and new default entries', async ()=>{
145
- const previousDefault = buildLanguage({
146
- id: 'lang-1',
147
- isDefault: true,
148
- code: 'en'
149
- });
150
- mockRepo.find.mockResolvedValue([
151
- previousDefault
152
- ]);
153
- mockRepo.findOne.mockResolvedValue(buildLanguage({
154
- id: 'lang-2',
155
- isDefault: true
156
- }));
157
- await service.setAsDefault('lang-2');
158
- expect(mockUtilsService.clearCache).toHaveBeenCalledWith('language', expect.anything());
159
- expect(mockUtilsService.clearCache).toHaveBeenCalledWith('language', expect.anything(), 'lang-1');
160
- expect(mockUtilsService.clearCache).toHaveBeenCalledWith('language', expect.anything(), 'lang-2');
161
- });
162
- it('returns null when the id does not correspond to any language after the update', async ()=>{
163
- mockRepo.findOne.mockResolvedValue(null);
164
- const result = await service.setAsDefault('non-existent-id');
165
- expect(result).toBeNull();
166
- });
167
- it('still unsets other defaults first even when the target id is unknown (no exception thrown)', async ()=>{
168
- mockRepo.findOne.mockResolvedValue(null);
169
- await service.setAsDefault('unknown-id');
170
- expect(mockRepo.update).toHaveBeenCalledWith({
171
- isDefault: true
172
- }, {
173
- isDefault: false
174
- });
175
- });
176
- });
177
- describe('beforeUpdateOperation', ()=>{
178
- it('rejects renaming the code of a readonly language', async ()=>{
179
- mockRepo.find.mockResolvedValue([
180
- buildLanguage({
181
- isReadonly: true,
182
- code: 'en'
183
- })
184
- ]);
185
- await expect(service.beforeUpdateOperation({
186
- id: 'language-uuid-1',
187
- code: 'fr'
188
- }, null, {})).rejects.toThrow('Cannot modify code/name of readonly language');
189
- });
190
- it('allows updating isActive on a readonly language when identity fields are unchanged', async ()=>{
191
- mockRepo.find.mockResolvedValue([
192
- buildLanguage({
193
- isReadonly: true,
194
- code: 'en',
195
- name: 'English'
196
- })
197
- ]);
198
- await expect(service.beforeUpdateOperation({
199
- id: 'language-uuid-1',
200
- code: 'en',
201
- name: 'English',
202
- isActive: false
203
- }, null, {})).resolves.toBeUndefined();
204
- });
205
- it('allows any field change on a non-readonly language', async ()=>{
206
- mockRepo.find.mockResolvedValue([
207
- buildLanguage({
208
- isReadonly: false,
209
- code: 'en'
210
- })
211
- ]);
212
- await expect(service.beforeUpdateOperation({
213
- id: 'language-uuid-1',
214
- code: 'fr'
215
- }, null, {})).resolves.toBeUndefined();
216
- });
217
- });
218
- describe('beforeDeleteOperation', ()=>{
219
- it('rejects deleting a readonly language', async ()=>{
220
- mockRepo.find.mockResolvedValue([
221
- buildLanguage({
222
- isReadonly: true
223
- })
224
- ]);
225
- await expect(service.beforeDeleteOperation({
226
- id: 'language-uuid-1'
227
- }, null, {})).rejects.toThrow('Cannot delete readonly language');
228
- });
229
- it('rejects deleting the default language', async ()=>{
230
- mockRepo.find.mockResolvedValue([
231
- buildLanguage({
232
- isReadonly: false,
233
- isDefault: true
234
- })
235
- ]);
236
- await expect(service.beforeDeleteOperation({
237
- id: 'language-uuid-1'
238
- }, null, {})).rejects.toThrow('Cannot delete the default language');
239
- });
240
- it('allows deleting a non-readonly, non-default language', async ()=>{
241
- mockRepo.find.mockResolvedValue([
242
- buildLanguage({
243
- isReadonly: false,
244
- isDefault: false
245
- })
246
- ]);
247
- await expect(service.beforeDeleteOperation({
248
- id: 'language-uuid-1'
249
- }, null, {})).resolves.toBeUndefined();
250
- });
251
- });
252
- });
@@ -1,56 +0,0 @@
1
- function _define_property(obj, key, value) {
2
- if (key in obj) {
3
- Object.defineProperty(obj, key, {
4
- value: value,
5
- enumerable: true,
6
- configurable: true,
7
- writable: true
8
- });
9
- } else {
10
- obj[key] = value;
11
- }
12
- return obj;
13
- }
14
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- 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;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { Inject, Injectable } from '@nestjs/common';
29
- import { LOCALIZATION_MODULE_OPTIONS } from '../config/localization.constants';
30
- import { LocalizationModuleOptions } from '../interfaces';
31
- export class LocalizationConfigService {
32
- isCompanyFeatureEnabled() {
33
- return false;
34
- }
35
- getDatabaseMode() {
36
- return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
37
- }
38
- isMultiTenant() {
39
- return this.getDatabaseMode() === 'multi-tenant';
40
- }
41
- getOptions() {
42
- return this.options;
43
- }
44
- constructor(options){
45
- _define_property(this, "options", void 0);
46
- this.options = options;
47
- }
48
- }
49
- LocalizationConfigService = _ts_decorate([
50
- Injectable(),
51
- _ts_param(0, Inject(LOCALIZATION_MODULE_OPTIONS)),
52
- _ts_metadata("design:type", Function),
53
- _ts_metadata("design:paramtypes", [
54
- typeof LocalizationModuleOptions === "undefined" ? Object : LocalizationModuleOptions
55
- ])
56
- ], LocalizationConfigService);
@@ -1,76 +0,0 @@
1
- import { LocalizationConfigService } from './localization-config.service';
2
- function buildOptions(overrides = {}) {
3
- return {
4
- bootstrapAppConfig: undefined,
5
- config: undefined,
6
- ...overrides
7
- };
8
- }
9
- describe('LocalizationConfigService', ()=>{
10
- describe('isCompanyFeatureEnabled', ()=>{
11
- it('always returns false — localization module has no company scoping', ()=>{
12
- const service = new LocalizationConfigService(buildOptions());
13
- expect(service.isCompanyFeatureEnabled()).toBe(false);
14
- });
15
- it('returns false even when bootstrapAppConfig enables the company feature elsewhere', ()=>{
16
- const service = new LocalizationConfigService(buildOptions({
17
- bootstrapAppConfig: {
18
- databaseMode: 'single',
19
- enableCompanyFeature: true
20
- }
21
- }));
22
- expect(service.isCompanyFeatureEnabled()).toBe(false);
23
- });
24
- });
25
- describe('getDatabaseMode', ()=>{
26
- it('returns the configured database mode', ()=>{
27
- const service = new LocalizationConfigService(buildOptions({
28
- bootstrapAppConfig: {
29
- databaseMode: 'multi-tenant'
30
- }
31
- }));
32
- expect(service.getDatabaseMode()).toBe('multi-tenant');
33
- });
34
- it('defaults to "single" when bootstrapAppConfig is missing', ()=>{
35
- const service = new LocalizationConfigService(buildOptions({
36
- bootstrapAppConfig: undefined
37
- }));
38
- expect(service.getDatabaseMode()).toBe('single');
39
- });
40
- it('defaults to "single" when databaseMode is not set on bootstrapAppConfig', ()=>{
41
- const service = new LocalizationConfigService(buildOptions({
42
- bootstrapAppConfig: {}
43
- }));
44
- expect(service.getDatabaseMode()).toBe('single');
45
- });
46
- });
47
- describe('isMultiTenant', ()=>{
48
- it('returns true when database mode is multi-tenant', ()=>{
49
- const service = new LocalizationConfigService(buildOptions({
50
- bootstrapAppConfig: {
51
- databaseMode: 'multi-tenant'
52
- }
53
- }));
54
- expect(service.isMultiTenant()).toBe(true);
55
- });
56
- it('returns false when database mode is single', ()=>{
57
- const service = new LocalizationConfigService(buildOptions({
58
- bootstrapAppConfig: {
59
- databaseMode: 'single'
60
- }
61
- }));
62
- expect(service.isMultiTenant()).toBe(false);
63
- });
64
- });
65
- describe('getOptions', ()=>{
66
- it('returns the exact options object it was constructed with', ()=>{
67
- const options = buildOptions({
68
- config: {
69
- defaultLanguageCode: 'en'
70
- }
71
- });
72
- const service = new LocalizationConfigService(options);
73
- expect(service.getOptions()).toBe(options);
74
- });
75
- });
76
- });
@@ -1,69 +0,0 @@
1
- function _define_property(obj, key, value) {
2
- if (key in obj) {
3
- Object.defineProperty(obj, key, {
4
- value: value,
5
- enumerable: true,
6
- configurable: true,
7
- writable: true
8
- });
9
- } else {
10
- obj[key] = value;
11
- }
12
- return obj;
13
- }
14
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- 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;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
29
- import { Inject, Injectable, Optional, Scope } from '@nestjs/common';
30
- import { REQUEST } from '@nestjs/core';
31
- import { Request } from 'express';
32
- import { getLocalizationEntities } from '../entities';
33
- import { LocalizationConfigService } from './localization-config.service';
34
- export class LocalizationDataSourceProvider extends MultiTenantDataSourceService {
35
- static buildParentOptions(options) {
36
- return {
37
- bootstrapAppConfig: options.bootstrapAppConfig,
38
- defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
39
- tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
40
- tenants: options.config?.tenants
41
- };
42
- }
43
- async createDataSourceFromConfig(config) {
44
- const entities = getLocalizationEntities();
45
- return super.createDataSourceFromConfig(config, entities);
46
- }
47
- constructor(configService, request){
48
- super(LocalizationDataSourceProvider.buildParentOptions(configService.getOptions()), request);
49
- }
50
- }
51
- _define_property(LocalizationDataSourceProvider, "tenantConnections", new Map());
52
- _define_property(LocalizationDataSourceProvider, "singleDataSource", null);
53
- _define_property(LocalizationDataSourceProvider, "tenantsRegistry", new Map());
54
- _define_property(LocalizationDataSourceProvider, "initialized", false);
55
- _define_property(LocalizationDataSourceProvider, "connectionLocks", new Map());
56
- _define_property(LocalizationDataSourceProvider, "singleConnectionLock", null);
57
- LocalizationDataSourceProvider = _ts_decorate([
58
- Injectable({
59
- scope: Scope.REQUEST
60
- }),
61
- _ts_param(0, Inject(LocalizationConfigService)),
62
- _ts_param(1, Optional()),
63
- _ts_param(1, Inject(REQUEST)),
64
- _ts_metadata("design:type", Function),
65
- _ts_metadata("design:paramtypes", [
66
- typeof LocalizationConfigService === "undefined" ? Object : LocalizationConfigService,
67
- typeof Request === "undefined" ? Object : Request
68
- ])
69
- ], LocalizationDataSourceProvider);
@@ -1,81 +0,0 @@
1
- import { LocalizationDataSourceProvider } from './localization-datasource.provider';
2
- import { Language, Translation, TranslationKey } from '../entities';
3
- function buildConfigService(overrides = {}) {
4
- const options = {
5
- bootstrapAppConfig: {
6
- databaseMode: 'single'
7
- },
8
- config: {
9
- defaultDatabaseConfig: {
10
- type: 'mysql',
11
- host: 'localhost',
12
- port: 3306,
13
- username: 'root',
14
- password: 'password',
15
- database: 'flusys_test'
16
- },
17
- tenantDefaultDatabaseConfig: undefined,
18
- tenants: []
19
- },
20
- ...overrides
21
- };
22
- return {
23
- getOptions: jest.fn().mockReturnValue(options)
24
- };
25
- }
26
- describe('LocalizationDataSourceProvider', ()=>{
27
- afterEach(()=>{
28
- // Reset the isolated static caches this provider owns so tests don't leak state between runs.
29
- LocalizationDataSourceProvider.tenantConnections = new Map();
30
- LocalizationDataSourceProvider.singleDataSource = null;
31
- LocalizationDataSourceProvider.tenantsRegistry = new Map();
32
- LocalizationDataSourceProvider.initialized = false;
33
- LocalizationDataSourceProvider.connectionLocks = new Map();
34
- LocalizationDataSourceProvider.singleConnectionLock = null;
35
- });
36
- it('constructs and forwards bootstrap/database config to the base class', ()=>{
37
- const configService = buildConfigService();
38
- const provider = new LocalizationDataSourceProvider(configService, undefined);
39
- expect(configService.getOptions).toHaveBeenCalled();
40
- expect(provider.getDatabaseMode()).toBe('single');
41
- expect(provider.isMultiTenant()).toBe(false);
42
- });
43
- it('reflects multi-tenant mode from bootstrapAppConfig', ()=>{
44
- const configService = buildConfigService({
45
- bootstrapAppConfig: {
46
- databaseMode: 'multi-tenant'
47
- }
48
- });
49
- const provider = new LocalizationDataSourceProvider(configService, undefined);
50
- expect(provider.isMultiTenant()).toBe(true);
51
- });
52
- it('owns isolated static caches, separate from the base MultiTenantDataSourceService', ()=>{
53
- // Each DataSource Provider must override BOTH static cache properties and the
54
- // methods that read them — otherwise modules would share connections (see FLUSYS_NEST/CLAUDE.md).
55
- expect(LocalizationDataSourceProvider.tenantConnections).not.toBe(Object.getPrototypeOf(LocalizationDataSourceProvider).tenantConnections);
56
- });
57
- it('createDataSourceFromConfig builds a DataSource using all localization entities', async ()=>{
58
- const configService = buildConfigService();
59
- const provider = new LocalizationDataSourceProvider(configService, undefined);
60
- const fakeDataSource = {
61
- isInitialized: true
62
- };
63
- const superSpy = jest.spyOn(Object.getPrototypeOf(Object.getPrototypeOf(provider)), 'createDataSourceFromConfig').mockResolvedValue(fakeDataSource);
64
- const config = {
65
- type: 'mysql',
66
- host: 'localhost',
67
- port: 3306,
68
- username: 'root',
69
- password: 'password',
70
- database: 'flusys_test'
71
- };
72
- const result = await provider.createDataSourceFromConfig(config);
73
- expect(superSpy).toHaveBeenCalledWith(config, [
74
- Language,
75
- TranslationKey,
76
- Translation
77
- ]);
78
- expect(result).toBe(fakeDataSource);
79
- superSpy.mockRestore();
80
- });
81
- });