@flusys/nestjs-localization 6.4.0 → 6.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,6 +66,11 @@ let LanguageService = class LanguageService extends _classes.ApiService {
66
66
  }
67
67
  async setAsDefault(id) {
68
68
  await this.ensureDataSourceRepository();
69
+ const previousDefaults = await this.repository.find({
70
+ where: {
71
+ isDefault: true
72
+ }
73
+ });
69
74
  await this.repository.update({
70
75
  isDefault: true
71
76
  }, {
@@ -76,11 +81,21 @@ let LanguageService = class LanguageService extends _classes.ApiService {
76
81
  }, {
77
82
  isDefault: true
78
83
  });
79
- return this.repository.findOne({
84
+ const language = await this.repository.findOne({
80
85
  where: {
81
86
  id
82
87
  }
83
88
  });
89
+ await Promise.all([
90
+ this.clearCacheForAll(),
91
+ this.clearCacheForId([
92
+ ...previousDefaults,
93
+ {
94
+ id
95
+ }
96
+ ])
97
+ ]);
98
+ return language;
84
99
  }
85
100
  constructor(cacheManager, utilsService, dataSourceProvider){
86
101
  super('language', cacheManager, utilsService, LanguageService.name, true, 'localization', _entities.Language, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService;
@@ -30,6 +30,15 @@ function buildLanguage(overrides = {}) {
30
30
  describe('LanguageService', ()=>{
31
31
  let service;
32
32
  let mockRepo;
33
+ const mockUtilsService = {
34
+ clearCache: jest.fn(),
35
+ getCacheKey: jest.fn().mockReturnValue('cache-key'),
36
+ trackCacheKey: jest.fn()
37
+ };
38
+ // Call history is shared across tests in this file; reset it so each cache assertion is exact.
39
+ beforeEach(()=>{
40
+ mockUtilsService.clearCache.mockClear();
41
+ });
33
42
  beforeEach(async ()=>{
34
43
  mockRepo = (0, _repositorymock.createMockRepository)();
35
44
  const mockDataSourceProvider = (0, _repositorymock.createMockDataSourceProvider)(mockRepo);
@@ -42,7 +51,7 @@ describe('LanguageService', ()=>{
42
51
  },
43
52
  {
44
53
  provide: _modules.UtilsService,
45
- useValue: {}
54
+ useValue: mockUtilsService
46
55
  },
47
56
  {
48
57
  provide: _localizationdatasourceprovider.LocalizationDataSourceProvider,
@@ -108,6 +117,9 @@ describe('LanguageService', ()=>{
108
117
  });
109
118
  });
110
119
  describe('setAsDefault', ()=>{
120
+ beforeEach(()=>{
121
+ mockRepo.find.mockResolvedValue([]);
122
+ });
111
123
  it('unsets the previous default and sets the requested language as default', async ()=>{
112
124
  const newDefault = buildLanguage({
113
125
  id: 'lang-2',
@@ -133,6 +145,24 @@ describe('LanguageService', ()=>{
133
145
  });
134
146
  expect(result).toEqual(newDefault);
135
147
  });
148
+ it('invalidates the language list cache and both the old and new default entries', async ()=>{
149
+ const previousDefault = buildLanguage({
150
+ id: 'lang-1',
151
+ isDefault: true,
152
+ code: 'en'
153
+ });
154
+ mockRepo.find.mockResolvedValue([
155
+ previousDefault
156
+ ]);
157
+ mockRepo.findOne.mockResolvedValue(buildLanguage({
158
+ id: 'lang-2',
159
+ isDefault: true
160
+ }));
161
+ await service.setAsDefault('lang-2');
162
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('language', expect.anything());
163
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('language', expect.anything(), 'lang-1');
164
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('language', expect.anything(), 'lang-2');
165
+ });
136
166
  it('returns null when the id does not correspond to any language after the update', async ()=>{
137
167
  mockRepo.findOne.mockResolvedValue(null);
138
168
  const result = await service.setAsDefault('non-existent-id');
@@ -132,11 +132,16 @@ let TranslationService = class TranslationService extends _classes.ApiService {
132
132
  }
133
133
  }
134
134
  await queryRunner.commitTransaction();
135
- return this.repository.find({
135
+ const saved = await this.repository.find({
136
136
  where: {
137
137
  id: (0, _typeorm.In)(resultIds)
138
138
  }
139
139
  });
140
+ await Promise.all([
141
+ this.clearCacheForAll(),
142
+ this.clearCacheForId(saved)
143
+ ]);
144
+ return saved;
140
145
  } catch (error) {
141
146
  await queryRunner.rollbackTransaction();
142
147
  throw error;
@@ -66,6 +66,15 @@ function buildTranslation(overrides = {}) {
66
66
  };
67
67
  }
68
68
  describe('TranslationService', ()=>{
69
+ const mockUtilsService = {
70
+ clearCache: jest.fn(),
71
+ getCacheKey: jest.fn().mockReturnValue('cache-key'),
72
+ trackCacheKey: jest.fn()
73
+ };
74
+ // Call history is shared across tests in this file; reset it so each cache assertion is exact.
75
+ beforeEach(()=>{
76
+ mockUtilsService.clearCache.mockClear();
77
+ });
69
78
  let service;
70
79
  let mockRepo;
71
80
  // `TranslationService` uses joins/aggregate query-builder methods (innerJoin, innerJoinAndSelect,
@@ -98,11 +107,6 @@ describe('TranslationService', ()=>{
98
107
  createQueryRunner: jest.fn()
99
108
  };
100
109
  mockDataSourceProvider.getDataSource.mockResolvedValue(fakeDataSource);
101
- const mockUtilsService = {
102
- clearCache: jest.fn(),
103
- getCacheKey: jest.fn().mockReturnValue('cache-key'),
104
- trackCacheKey: jest.fn()
105
- };
106
110
  const module = await _testing.Test.createTestingModule({
107
111
  providers: [
108
112
  _translationservice.TranslationService,
@@ -275,6 +279,25 @@ describe('TranslationService', ()=>{
275
279
  });
276
280
  expect(result).toHaveLength(1);
277
281
  });
282
+ it('invalidates the translation list cache and each written entry after committing', async ()=>{
283
+ const queryRunner = buildQueryRunner();
284
+ fakeDataSource.createQueryRunner.mockReturnValue(queryRunner);
285
+ mockRepo.find.mockResolvedValue([
286
+ buildTranslation({
287
+ id: 'translation-1'
288
+ })
289
+ ]);
290
+ await service.bulkUpdate([
291
+ {
292
+ id: 'translation-1',
293
+ languageId: 'lang-en',
294
+ translationKeyId: 'tkey-1',
295
+ value: 'Updated'
296
+ }
297
+ ]);
298
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('translation', expect.anything());
299
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('translation', expect.anything(), 'translation-1');
300
+ });
278
301
  it('creates new translations when no id is provided', async ()=>{
279
302
  const queryRunner = buildQueryRunner();
280
303
  fakeDataSource.createQueryRunner.mockReturnValue(queryRunner);
@@ -56,6 +56,11 @@ export class LanguageService extends ApiService {
56
56
  }
57
57
  async setAsDefault(id) {
58
58
  await this.ensureDataSourceRepository();
59
+ const previousDefaults = await this.repository.find({
60
+ where: {
61
+ isDefault: true
62
+ }
63
+ });
59
64
  await this.repository.update({
60
65
  isDefault: true
61
66
  }, {
@@ -66,11 +71,21 @@ export class LanguageService extends ApiService {
66
71
  }, {
67
72
  isDefault: true
68
73
  });
69
- return this.repository.findOne({
74
+ const language = await this.repository.findOne({
70
75
  where: {
71
76
  id
72
77
  }
73
78
  });
79
+ await Promise.all([
80
+ this.clearCacheForAll(),
81
+ this.clearCacheForId([
82
+ ...previousDefaults,
83
+ {
84
+ id
85
+ }
86
+ ])
87
+ ]);
88
+ return language;
74
89
  }
75
90
  constructor(cacheManager, utilsService, dataSourceProvider){
76
91
  super('language', cacheManager, utilsService, LanguageService.name, true, 'localization', Language, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService;
@@ -26,6 +26,15 @@ function buildLanguage(overrides = {}) {
26
26
  describe('LanguageService', ()=>{
27
27
  let service;
28
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
+ });
29
38
  beforeEach(async ()=>{
30
39
  mockRepo = createMockRepository();
31
40
  const mockDataSourceProvider = createMockDataSourceProvider(mockRepo);
@@ -38,7 +47,7 @@ describe('LanguageService', ()=>{
38
47
  },
39
48
  {
40
49
  provide: UtilsService,
41
- useValue: {}
50
+ useValue: mockUtilsService
42
51
  },
43
52
  {
44
53
  provide: LocalizationDataSourceProvider,
@@ -104,6 +113,9 @@ describe('LanguageService', ()=>{
104
113
  });
105
114
  });
106
115
  describe('setAsDefault', ()=>{
116
+ beforeEach(()=>{
117
+ mockRepo.find.mockResolvedValue([]);
118
+ });
107
119
  it('unsets the previous default and sets the requested language as default', async ()=>{
108
120
  const newDefault = buildLanguage({
109
121
  id: 'lang-2',
@@ -129,6 +141,24 @@ describe('LanguageService', ()=>{
129
141
  });
130
142
  expect(result).toEqual(newDefault);
131
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
+ });
132
162
  it('returns null when the id does not correspond to any language after the update', async ()=>{
133
163
  mockRepo.findOne.mockResolvedValue(null);
134
164
  const result = await service.setAsDefault('non-existent-id');
@@ -122,11 +122,16 @@ export class TranslationService extends ApiService {
122
122
  }
123
123
  }
124
124
  await queryRunner.commitTransaction();
125
- return this.repository.find({
125
+ const saved = await this.repository.find({
126
126
  where: {
127
127
  id: In(resultIds)
128
128
  }
129
129
  });
130
+ await Promise.all([
131
+ this.clearCacheForAll(),
132
+ this.clearCacheForId(saved)
133
+ ]);
134
+ return saved;
130
135
  } catch (error) {
131
136
  await queryRunner.rollbackTransaction();
132
137
  throw error;
@@ -62,6 +62,15 @@ function buildTranslation(overrides = {}) {
62
62
  };
63
63
  }
64
64
  describe('TranslationService', ()=>{
65
+ const mockUtilsService = {
66
+ clearCache: jest.fn(),
67
+ getCacheKey: jest.fn().mockReturnValue('cache-key'),
68
+ trackCacheKey: jest.fn()
69
+ };
70
+ // Call history is shared across tests in this file; reset it so each cache assertion is exact.
71
+ beforeEach(()=>{
72
+ mockUtilsService.clearCache.mockClear();
73
+ });
65
74
  let service;
66
75
  let mockRepo;
67
76
  // `TranslationService` uses joins/aggregate query-builder methods (innerJoin, innerJoinAndSelect,
@@ -94,11 +103,6 @@ describe('TranslationService', ()=>{
94
103
  createQueryRunner: jest.fn()
95
104
  };
96
105
  mockDataSourceProvider.getDataSource.mockResolvedValue(fakeDataSource);
97
- const mockUtilsService = {
98
- clearCache: jest.fn(),
99
- getCacheKey: jest.fn().mockReturnValue('cache-key'),
100
- trackCacheKey: jest.fn()
101
- };
102
106
  const module = await Test.createTestingModule({
103
107
  providers: [
104
108
  TranslationService,
@@ -271,6 +275,25 @@ describe('TranslationService', ()=>{
271
275
  });
272
276
  expect(result).toHaveLength(1);
273
277
  });
278
+ it('invalidates the translation list cache and each written entry after committing', async ()=>{
279
+ const queryRunner = buildQueryRunner();
280
+ fakeDataSource.createQueryRunner.mockReturnValue(queryRunner);
281
+ mockRepo.find.mockResolvedValue([
282
+ buildTranslation({
283
+ id: 'translation-1'
284
+ })
285
+ ]);
286
+ await service.bulkUpdate([
287
+ {
288
+ id: 'translation-1',
289
+ languageId: 'lang-en',
290
+ translationKeyId: 'tkey-1',
291
+ value: 'Updated'
292
+ }
293
+ ]);
294
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('translation', expect.anything());
295
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('translation', expect.anything(), 'translation-1');
296
+ });
274
297
  it('creates new translations when no id is provided', async ()=>{
275
298
  const queryRunner = buildQueryRunner();
276
299
  fakeDataSource.createQueryRunner.mockReturnValue(queryRunner);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-localization",
3
- "version": "6.4.0",
3
+ "version": "6.4.1",
4
4
  "description": "Localization module for multi-language support",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -80,7 +80,7 @@
80
80
  "express": "^5.0.0"
81
81
  },
82
82
  "dependencies": {
83
- "@flusys/nestjs-core": "6.4.0",
84
- "@flusys/nestjs-shared": "6.4.0"
83
+ "@flusys/nestjs-core": "6.4.1",
84
+ "@flusys/nestjs-shared": "6.4.1"
85
85
  }
86
86
  }