@drax/settings-back 0.11.3

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 (52) hide show
  1. package/dist/controller/SettingController.js +89 -0
  2. package/dist/factory/SettingServiceFactory.js +24 -0
  3. package/dist/index.js +8 -0
  4. package/dist/interfaces/ISettingRepository.js +1 -0
  5. package/dist/model/SettingsModel.js +28 -0
  6. package/dist/permissions/SettingPermissions.js +8 -0
  7. package/dist/repository/mongo/SettingMongoRepository.js +13 -0
  8. package/dist/repository/sqlite/SettingSqliteRepository.js +113 -0
  9. package/dist/routes/SettingRoutes.js +10 -0
  10. package/dist/schemas/SettingSchema.js +7 -0
  11. package/dist/services/SettingService.js +95 -0
  12. package/package.json +66 -0
  13. package/src/controller/SettingController.ts +92 -0
  14. package/src/factory/SettingServiceFactory.ts +32 -0
  15. package/src/index.ts +24 -0
  16. package/src/interfaces/ISettingRepository.ts +6 -0
  17. package/src/model/SettingsModel.ts +46 -0
  18. package/src/permissions/SettingPermissions.ts +9 -0
  19. package/src/repository/mongo/SettingMongoRepository.ts +23 -0
  20. package/src/repository/sqlite/SettingSqliteRepository.ts +176 -0
  21. package/src/routes/SettingRoutes.ts +17 -0
  22. package/src/schemas/SettingSchema.ts +11 -0
  23. package/src/services/SettingService.ts +111 -0
  24. package/test/repository/mongo/MongoInMemory.ts +43 -0
  25. package/test/repository/mongo/SettingMongoRepository.test.ts +180 -0
  26. package/test/repository/sqlite/SettingSqliteRepository.test.ts +175 -0
  27. package/test/services/SettingService.test.ts +319 -0
  28. package/test.db +0 -0
  29. package/tsconfig.json +16 -0
  30. package/tsconfig.tsbuildinfo +1 -0
  31. package/types/controller/SettingController.d.ts +15 -0
  32. package/types/controller/SettingController.d.ts.map +1 -0
  33. package/types/factory/SettingServiceFactory.d.ts +4 -0
  34. package/types/factory/SettingServiceFactory.d.ts.map +1 -0
  35. package/types/index.d.ts +11 -0
  36. package/types/index.d.ts.map +1 -0
  37. package/types/interfaces/ISettingRepository.d.ts +6 -0
  38. package/types/interfaces/ISettingRepository.d.ts.map +1 -0
  39. package/types/model/SettingsModel.d.ts +19 -0
  40. package/types/model/SettingsModel.d.ts.map +1 -0
  41. package/types/permissions/SettingPermissions.d.ts +8 -0
  42. package/types/permissions/SettingPermissions.d.ts.map +1 -0
  43. package/types/repository/mongo/SettingMongoRepository.d.ts +9 -0
  44. package/types/repository/mongo/SettingMongoRepository.d.ts.map +1 -0
  45. package/types/repository/sqlite/SettingSqliteRepository.d.ts +22 -0
  46. package/types/repository/sqlite/SettingSqliteRepository.d.ts.map +1 -0
  47. package/types/routes/SettingRoutes.d.ts +4 -0
  48. package/types/routes/SettingRoutes.d.ts.map +1 -0
  49. package/types/schemas/SettingSchema.d.ts +10 -0
  50. package/types/schemas/SettingSchema.d.ts.map +1 -0
  51. package/types/services/SettingService.d.ts +23 -0
  52. package/types/services/SettingService.d.ts.map +1 -0
@@ -0,0 +1,175 @@
1
+ import {describe, beforeAll, it, vi, expect} from "vitest"
2
+ import {SettingSqliteRepository} from "../../../src/repository/sqlite/SettingSqliteRepository.js";
3
+ import {ISetting, ISettingBase} from "@drax/settings-share";
4
+ import {AbstractSqliteRepository} from "@drax/crud-back";
5
+
6
+ describe('SettingSqliteRepository', () => {
7
+
8
+
9
+
10
+ beforeAll(async () => {
11
+ const repository = new SettingSqliteRepository("test.db", false)
12
+
13
+ })
14
+
15
+
16
+
17
+ // it('should verify that SettingSqliteRepository is an instance of AbstractSqliteRepository', () => {
18
+ // // Arrange
19
+ // const repository = new SettingSqliteRepository("test.db", false);
20
+ //
21
+ // // Assert
22
+ // expect(repository).toBeInstanceOf(AbstractSqliteRepository);
23
+ // });
24
+
25
+
26
+
27
+ it('should correctly handle adding a new setting to the repository', async () => {
28
+ // Arrange
29
+ const repository = new SettingSqliteRepository("test.db", false);
30
+ const newSetting: ISettingBase = {
31
+ key: 'newKey',
32
+ value: 'newValue',
33
+ label: 'New Key Label',
34
+ group: 'Default Group',
35
+ type: 'string',
36
+ options: []
37
+ };
38
+ const expectedSetting = {id: '2', ...newSetting};
39
+
40
+ // Mock the create method of the repository
41
+ vi.spyOn(repository, 'create').mockResolvedValue(expectedSetting);
42
+
43
+ // Act
44
+ const createdSetting = await repository.create(newSetting);
45
+
46
+ // Assert
47
+ expect(createdSetting).toEqual(expectedSetting);
48
+ expect(repository.create).toHaveBeenCalledWith(newSetting);
49
+ });
50
+
51
+ it('should correctly handle updating an existing setting in the repository', async () => {
52
+ // Arrange
53
+ const repository = new SettingSqliteRepository("test.db", false);
54
+ const existingSettingId = '1';
55
+ const updatedData: ISettingBase = {
56
+ key: 'existingKey',
57
+ value: 'updatedValue',
58
+ label: 'Updated Key Label',
59
+ group: 'Default Group',
60
+ type: 'string',
61
+ options: []
62
+ };
63
+ const expectedUpdatedSetting: ISetting = {
64
+ id: existingSettingId,
65
+ ...updatedData
66
+ };
67
+
68
+ // Mock the update method of the repository
69
+ vi.spyOn(repository, 'update').mockResolvedValue(expectedUpdatedSetting);
70
+
71
+ // Act
72
+ const updatedSetting = await repository.update(existingSettingId, updatedData);
73
+
74
+ // Assert
75
+ expect(updatedSetting).toEqual(expectedUpdatedSetting);
76
+ expect(repository.update).toHaveBeenCalledWith(existingSettingId, updatedData);
77
+ });
78
+
79
+
80
+ it('should correctly handle searching for a setting by _id', async () => {
81
+ // Arrange
82
+ const repository = new SettingSqliteRepository("test.db", false);
83
+ const settingId = '1';
84
+ const expectedSetting: ISetting = {
85
+ id: settingId,
86
+ key: 'existingKey',
87
+ value: 'existingValue',
88
+ label: 'Existing Key Label',
89
+ group: 'Default Group',
90
+ type: 'string',
91
+ options: []
92
+ };
93
+
94
+ // Mock the findById method of the repository
95
+ vi.spyOn(repository, 'findById').mockResolvedValue(expectedSetting);
96
+
97
+ // Act
98
+ const foundSetting = await repository.findById(settingId);
99
+
100
+ // Assert
101
+ expect(foundSetting).toEqual(expectedSetting);
102
+ expect(repository.findById).toHaveBeenCalledWith(settingId);
103
+ });
104
+
105
+
106
+ it('should correctly handle searching for a setting by key', async () => {
107
+ // Arrange
108
+ const repository = new SettingSqliteRepository("test.db", false);
109
+ const searchKey = 'sampleKey';
110
+ const expectedSettings: ISetting[] = [{
111
+ id: '1',
112
+ key: 'sampleKey',
113
+ value: 'sampleValue',
114
+ label: 'Sample Setting Label',
115
+ group: 'Sample Group',
116
+ type: 'string',
117
+ options: []
118
+ }];
119
+
120
+ // Mock the search method of the repository
121
+ vi.spyOn(repository, 'search').mockResolvedValue(expectedSettings);
122
+
123
+ // Act
124
+ const foundSettings = await repository.search(searchKey);
125
+
126
+ // Assert
127
+ expect(foundSettings).toEqual(expectedSettings);
128
+ expect(repository.search).toHaveBeenCalledWith(searchKey);
129
+ });
130
+
131
+
132
+
133
+ it('should correctly handle deleting a setting from the repository', async () => {
134
+ // Arrange
135
+ const repository = new SettingSqliteRepository("test.db", false);
136
+ const settingId = '1';
137
+ const expectedDeletionResult = true;
138
+
139
+ // Mock the delete method of the repository
140
+ vi.spyOn(repository, 'delete').mockResolvedValue(expectedDeletionResult);
141
+
142
+ // Act
143
+ const deletionResult = await repository.delete(settingId);
144
+
145
+ // Assert
146
+ expect(deletionResult).toBe(expectedDeletionResult);
147
+ expect(repository.delete).toHaveBeenCalledWith(settingId);
148
+ });
149
+
150
+
151
+ it('should correctly handle retrieving all settings from the repository', async () => {
152
+ // Arrange
153
+ const repository = new SettingSqliteRepository("test.db", false);
154
+ const expectedSettings: ISetting[] = [{
155
+ id: '1',
156
+ key: 'existingKey',
157
+ value: 'existingValue',
158
+ label: 'Existing Key Label',
159
+ group: 'Default Group',
160
+ type: 'string',
161
+ options: []
162
+ }];
163
+
164
+ // Mock the fetchAll method of the repository
165
+ vi.spyOn(repository, 'fetchAll').mockResolvedValue(expectedSettings);
166
+
167
+ // Act
168
+ const allSettings = await repository.fetchAll();
169
+
170
+ // Assert
171
+ expect(allSettings).toEqual(expectedSettings);
172
+ expect(repository.fetchAll).toHaveBeenCalled();
173
+ });
174
+
175
+ })
@@ -0,0 +1,319 @@
1
+ import {describe, beforeEach, it, vi, expect} from "vitest"
2
+ import {SettingService} from '../../src/services/SettingService';
3
+ import {ISettingRepository} from '../../src/interfaces/ISettingRepository';
4
+ import {ISetting, ISettingBase} from '@drax/settings-share';
5
+ import {IDraxPaginateResult} from "@drax/crud-share";
6
+
7
+ // Mock implementation of ISettingRepository
8
+ class MockSettingRepository implements ISettingRepository {
9
+ async findOneBy(field: string, value: string): Promise<ISetting | undefined> {
10
+ if (field === 'key' && value === 'existingKey') {
11
+ return {
12
+ id: '1',
13
+ key: 'existingKey',
14
+ value: 'existingValue',
15
+ label: 'Existing Key Label',
16
+ group: 'Default Group',
17
+ type: 'string',
18
+ options: []
19
+ } as ISetting;
20
+ }
21
+ return undefined;
22
+ }
23
+
24
+ async fetchAll(): Promise<ISetting[]> {
25
+ return [{
26
+ id: '1',
27
+ key: 'existingKey',
28
+ value: 'existingValue',
29
+ label: 'Existing Key Label', // Add missing properties
30
+ group: 'Default Group',
31
+ type: 'string',
32
+ options: []
33
+ }];
34
+
35
+ }
36
+
37
+ async create(data: ISettingBase): Promise<ISetting> {
38
+ return {id: '2', ...data} as ISetting;
39
+ }
40
+
41
+ async update(id: string, data: ISettingBase): Promise<ISetting> {
42
+ return {id, ...data} as ISetting;
43
+ }
44
+
45
+ async updatePartial(id: string, data: Partial<ISettingBase>): Promise<ISetting | undefined> {
46
+ return {id, ...data} as ISetting;
47
+ }
48
+
49
+ async paginate(): Promise<IDraxPaginateResult<ISetting>> {
50
+ return { page: 1, limit: 5, total: 1, items: [
51
+ {
52
+ id: '1',
53
+ key: 'existingKey',
54
+ value: 'existingValue',
55
+ label: 'Existing Key Label',
56
+ group: 'Default Group',
57
+ type: 'string',
58
+ options: []
59
+ }
60
+ ] };
61
+ }
62
+
63
+ async delete(id: string): Promise<boolean> {
64
+ return true;
65
+ }
66
+ }
67
+
68
+ function sleep(ms: number) {
69
+ return new Promise(resolve => setTimeout(resolve, ms));
70
+ }
71
+
72
+ describe('SettingService', () => {
73
+ let settingService: SettingService;
74
+ let mockRepository: MockSettingRepository;
75
+
76
+ beforeEach(() => {
77
+ mockRepository = new MockSettingRepository();
78
+ settingService = new SettingService(mockRepository);
79
+ });
80
+
81
+ it('should successfully create a setting when valid data is provided', async () => {
82
+ // Arrange
83
+ const validData: ISettingBase = {
84
+ key: 'newKey',
85
+ value: 'newValue',
86
+ label: 'New Key Label',
87
+ group: 'Default Group',
88
+ type: 'string',
89
+ options: []
90
+ };
91
+ const expectedSetting = {id: '2', ...validData};
92
+
93
+ // Act
94
+ const createdSetting = await settingService.create(validData);
95
+
96
+ // Assert
97
+ expect(createdSetting).toEqual(expectedSetting);
98
+ });
99
+
100
+ it('should throw a validation error when creating a setting with invalid data', async () => {
101
+ // Arrange
102
+ const invalidData: ISettingBase = {
103
+ key: '',
104
+ value: 'someValue',
105
+ label: 'Invalid Label',
106
+ group: 'Invalid Group',
107
+ type: 'string',
108
+ options: []
109
+ }; // Assuming an empty key is invalid
110
+
111
+ // Act & Assert
112
+ await expect(settingService.create(invalidData)).rejects.toThrowError();
113
+ });
114
+
115
+ it('should update an existing setting when valid data is provided', async () => {
116
+ // Arrange
117
+ const existingSetting = {id: '1', key: 'existingKey', value: 'existingValue'};
118
+ const updatedData: ISettingBase = {
119
+ key: 'existingKey',
120
+ value: 'updatedValue',
121
+ label: 'Existing Key Label',
122
+ group: 'Default Group',
123
+ type: 'string',
124
+ options: []
125
+ };
126
+ const expectedUpdatedSetting: ISetting = {
127
+ id: '1',
128
+ key: 'existingKey',
129
+ value: 'updatedValue',
130
+ label: 'Existing Key Label',
131
+ group: 'Default Group',
132
+ type: 'string',
133
+ options: []
134
+ };
135
+
136
+ // Mock the repository's update method
137
+ vi.spyOn(mockRepository, 'update').mockResolvedValue(expectedUpdatedSetting);
138
+
139
+ // Act
140
+ const updatedSetting = await settingService.update(existingSetting.id, updatedData);
141
+
142
+ // Assert
143
+ expect(updatedSetting).toEqual(expectedUpdatedSetting);
144
+ expect(mockRepository.update).toHaveBeenCalledWith(existingSetting.id, updatedData);
145
+ });
146
+
147
+ it('should cache a setting after fetching it by cache method and only call findByKey once', async () => {
148
+ // Arrange
149
+ const key = 'existingKey';
150
+ const expectedSetting: ISetting = {
151
+ id: '1',
152
+ key: 'existingKey',
153
+ value: 'existingValue',
154
+ label: 'Existing Key Label',
155
+ group: 'Default Group',
156
+ type: 'string',
157
+ options: []
158
+ };
159
+
160
+ // Mock the repository's findOneBy method
161
+ const findOneBySpy = vi.spyOn(mockRepository, 'findOneBy').mockResolvedValue(expectedSetting);
162
+
163
+ // Act
164
+ const firstFetch = await settingService.cache(key);
165
+ sleep(100)
166
+ const secondFetch = await settingService.cache(key);
167
+
168
+ // Assert
169
+ expect(firstFetch).toEqual(expectedSetting);
170
+ expect(secondFetch).toEqual(expectedSetting);
171
+ expect(findOneBySpy).toHaveBeenCalledTimes(1);
172
+ });
173
+
174
+ it('should return all settings when fetchAll is called', async () => {
175
+ // Arrange
176
+ const expectedSettings = [{
177
+ id: '1',
178
+ key: 'existingKey',
179
+ value: 'existingValue',
180
+ label: 'Existing Key Label',
181
+ group: 'Default Group',
182
+ type: 'string',
183
+ options: []
184
+ }];
185
+
186
+ // Act
187
+ const settings = await settingService.fetchAll();
188
+
189
+ // Assert
190
+ expect(settings).toEqual(expectedSettings);
191
+ });
192
+
193
+ it('should update the value of a setting when a valid ID and value are provided', async () => {
194
+ // Arrange
195
+ const settingId = '1';
196
+ const newValue = 'newUpdatedValue';
197
+ const expectedUpdatedSetting: ISetting = {
198
+ id: settingId,
199
+ key: 'existingKey',
200
+ value: newValue,
201
+ label: 'Existing Key Label',
202
+ group: 'Default Group',
203
+ type: 'string',
204
+ options: []
205
+ };
206
+
207
+ // Mock the repository's updatePartial method
208
+ vi.spyOn(mockRepository, 'updatePartial').mockResolvedValue(expectedUpdatedSetting);
209
+
210
+ // Act
211
+ const updatedSetting = await settingService.updateValue(settingId, newValue);
212
+
213
+ // Assert
214
+ expect(updatedSetting).toEqual(expectedUpdatedSetting);
215
+ expect(mockRepository.updatePartial).toHaveBeenCalledWith(settingId, {value: newValue});
216
+ });
217
+
218
+ it('should create a new setting if it does not exist when createOrUpdate is called', async () => {
219
+ // Arrange
220
+ const newSettingData: ISettingBase = {
221
+ key: 'newKey',
222
+ value: 'newValue',
223
+ label: 'New Key Label',
224
+ group: 'Default Group',
225
+ type: 'string',
226
+ options: []
227
+ };
228
+ const expectedNewSetting: ISetting = {
229
+ id: '2',
230
+ key: 'newKey',
231
+ value: 'newValue',
232
+ label: 'New Key Label',
233
+ group: 'Default Group',
234
+ type: 'string',
235
+ options: []
236
+ };
237
+
238
+ // Mock the repository's findOneBy and create methods
239
+ vi.spyOn(mockRepository, 'findOneBy').mockResolvedValue(undefined);
240
+ vi.spyOn(mockRepository, 'create').mockResolvedValue(expectedNewSetting);
241
+
242
+ // Act
243
+ const result = await settingService.createOrUpdate(newSettingData);
244
+
245
+ // Assert
246
+ expect(mockRepository.findOneBy).toHaveBeenCalledWith('key', newSettingData.key);
247
+ expect(mockRepository.create).toHaveBeenCalledWith(newSettingData);
248
+ expect(result).toEqual(expectedNewSetting);
249
+ });
250
+
251
+ it('should update an existing setting if it exists when createOrUpdate is called', async () => {
252
+ // Arrange
253
+ const existingSetting: ISetting = {
254
+ id: '1',
255
+ key: 'existingKey',
256
+ value: 'oldValue',
257
+ label: 'Existing Key Label',
258
+ group: 'Default Group',
259
+ type: 'string',
260
+ options: []
261
+ };
262
+ const updatedData: ISettingBase = {
263
+ key: 'existingKey',
264
+ value: 'newValue',
265
+ label: 'Existing Key Label',
266
+ group: 'Default Group',
267
+ type: 'string',
268
+ options: []
269
+ };
270
+ const expectedUpdatedSetting: ISetting = {
271
+ id: '1',
272
+ key: 'existingKey',
273
+ value: 'oldValue',
274
+ label: 'Existing Key Label',
275
+ group: 'Default Group',
276
+ type: 'string',
277
+ options: []
278
+ };
279
+
280
+ // Mock the repository's findOneBy and update methods
281
+ vi.spyOn(mockRepository, 'findOneBy').mockResolvedValue(existingSetting);
282
+ vi.spyOn(mockRepository, 'updatePartial').mockResolvedValue(expectedUpdatedSetting);
283
+
284
+ // Act
285
+ const result = await settingService.createOrUpdate(updatedData);
286
+
287
+ // Assert
288
+ expect(mockRepository.findOneBy).toHaveBeenCalledWith('key', updatedData.key);
289
+ expect(mockRepository.updatePartial).toHaveBeenCalledWith(existingSetting.id, updatedData);
290
+ expect(result).toEqual(expectedUpdatedSetting);
291
+ });
292
+
293
+ it('should return undefined when trying to find a setting by a non-existent key', async () => {
294
+ // Arrange
295
+ const nonExistentKey = 'nonExistentKey';
296
+
297
+ // Act
298
+ const result = await settingService.findByKey(nonExistentKey);
299
+
300
+ // Assert
301
+ expect(result).toBeUndefined();
302
+ });
303
+
304
+ it('should throw a validation error when updating a setting with invalid data', async () => {
305
+ // Arrange
306
+ const invalidData: ISettingBase = {
307
+ key: '',
308
+ value: 'someValue',
309
+ label: '',
310
+ group: '',
311
+ type: 'string',
312
+ options: []
313
+ }; // Assuming an empty key is invalid
314
+ const settingId = '1'; // Example setting ID
315
+
316
+ // Act & Assert
317
+ await expect(settingService.update(settingId, invalidData)).rejects.toThrowError();
318
+ });
319
+ });
package/test.db ADDED
Binary file
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist",
6
+ "declarationDir": "types"
7
+ },
8
+ "exclude": ["types", "test", "dist","node_modules","tmp"],
9
+ "ts-node": {
10
+ "esm": true
11
+ },
12
+ "tsc-alias": {
13
+ "resolveFullPaths": true,
14
+ "verbose": false
15
+ }
16
+ }