@declaro/data 2.0.0-beta.96 → 2.0.0-beta.97
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.
- package/dist/browser/index.js +2 -2
- package/dist/browser/index.js.map +3 -3
- package/dist/node/index.cjs +13 -7
- package/dist/node/index.cjs.map +3 -3
- package/dist/node/index.js +13 -7
- package/dist/node/index.js.map +3 -3
- package/dist/ts/test/mock/repositories/mock-memory-repository.d.ts +8 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/test/mock/repositories/mock-memory-repository.test.ts +204 -0
- package/src/test/mock/repositories/mock-memory-repository.ts +24 -9
|
@@ -7,6 +7,7 @@ export interface IMockMemoryRepositoryArgs<TSchema extends AnyModelSchema> {
|
|
|
7
7
|
schema: TSchema;
|
|
8
8
|
lookup?: (data: InferDetail<TSchema>, lookup: InferLookup<TSchema>) => boolean;
|
|
9
9
|
filter?: (data: InferSummary<TSchema>, filters: InferFilters<TSchema>) => boolean;
|
|
10
|
+
assign?: (data: InferDetail<TSchema>, input: InferInput<TSchema>) => InferDetail<TSchema>;
|
|
10
11
|
}
|
|
11
12
|
export declare class MockMemoryRepository<TSchema extends AnyModelSchema> implements IRepository<TSchema> {
|
|
12
13
|
protected args: IMockMemoryRepositoryArgs<TSchema>;
|
|
@@ -31,6 +32,13 @@ export declare class MockMemoryRepository<TSchema extends AnyModelSchema> implem
|
|
|
31
32
|
* @returns Filtered array of items
|
|
32
33
|
*/
|
|
33
34
|
protected applyFilters(input: InferFilters<TSchema>): InferDetail<TSchema>[];
|
|
35
|
+
/**
|
|
36
|
+
* Assign input data to existing data using the provided assign function or default Object.assign
|
|
37
|
+
* @param existingData - The existing data to merge with
|
|
38
|
+
* @param input - The input data to assign
|
|
39
|
+
* @returns The merged data
|
|
40
|
+
*/
|
|
41
|
+
protected assignInput(existingData: InferDetail<TSchema>, input: InferInput<TSchema>): InferDetail<TSchema>;
|
|
34
42
|
protected generatePrimaryKey(): Promise<string | number>;
|
|
35
43
|
}
|
|
36
44
|
//# sourceMappingURL=mock-memory-repository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-memory-repository.d.ts","sourceRoot":"","sources":["../../../../../src/test/mock/repositories/mock-memory-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAqB,MAAM,eAAe,CAAA;AAC5F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAA;AAExE,OAAO,KAAK,EACR,WAAW,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,YAAY,EACf,MAAM,wCAAwC,CAAA;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kDAAkD,CAAA;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAA;AAE5F,MAAM,WAAW,yBAAyB,CAAC,OAAO,SAAS,cAAc;IACrE,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,OAAO,CAAA;IAC9E,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"mock-memory-repository.d.ts","sourceRoot":"","sources":["../../../../../src/test/mock/repositories/mock-memory-repository.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@declaro/data",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.97",
|
|
4
4
|
"description": "A data-mapper framework for managing application data across integrated systems.",
|
|
5
5
|
"main": "dist/node/index.cjs",
|
|
6
6
|
"module": "dist/node/index.js",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"@declaro/zod": "^2.0.0-beta.51"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@declaro/auth": "^2.0.0-beta.
|
|
26
|
-
"@declaro/core": "^2.0.0-beta.
|
|
27
|
-
"@declaro/zod": "^2.0.0-beta.
|
|
25
|
+
"@declaro/auth": "^2.0.0-beta.97",
|
|
26
|
+
"@declaro/core": "^2.0.0-beta.97",
|
|
27
|
+
"@declaro/zod": "^2.0.0-beta.97",
|
|
28
28
|
"crypto-browserify": "^3.12.1",
|
|
29
29
|
"typescript": "^5.8.3",
|
|
30
30
|
"uuid": "^11.1.0",
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"require": "./dist/node/index.cjs",
|
|
44
44
|
"browser": "./dist/browser/index.js"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "f5735a57bfd6cc342c60e9974395c389f43c3f93"
|
|
47
47
|
}
|
|
@@ -712,4 +712,208 @@ describe('MockMemoryRepository', () => {
|
|
|
712
712
|
expect(await repository.load({ id: 100 })).toEqual(inputs[99])
|
|
713
713
|
})
|
|
714
714
|
})
|
|
715
|
+
|
|
716
|
+
describe('assign functionality', () => {
|
|
717
|
+
it('should use default Object.assign for create when no custom assign function is provided', async () => {
|
|
718
|
+
const input = { title: 'Test Book', author: 'Author Name', publishedDate: new Date() }
|
|
719
|
+
const createdItem = await repository.create(input)
|
|
720
|
+
|
|
721
|
+
expect(createdItem).toMatchObject(input)
|
|
722
|
+
expect(createdItem.id).toBeDefined()
|
|
723
|
+
})
|
|
724
|
+
|
|
725
|
+
it('should use default Object.assign for update when no custom assign function is provided', async () => {
|
|
726
|
+
const input = { id: 42, title: 'Test Book', author: 'Author Name', publishedDate: new Date() }
|
|
727
|
+
const createdItem = await repository.create(input)
|
|
728
|
+
|
|
729
|
+
const updateInput = { title: 'Updated Book', author: 'Updated Author', publishedDate: new Date() }
|
|
730
|
+
const updatedItem = await repository.update({ id: createdItem.id }, updateInput)
|
|
731
|
+
|
|
732
|
+
expect(updatedItem).toEqual({
|
|
733
|
+
id: createdItem.id,
|
|
734
|
+
title: 'Updated Book',
|
|
735
|
+
author: 'Updated Author',
|
|
736
|
+
publishedDate: updateInput.publishedDate,
|
|
737
|
+
})
|
|
738
|
+
})
|
|
739
|
+
|
|
740
|
+
it('should use default Object.assign for upsert when no custom assign function is provided', async () => {
|
|
741
|
+
const input = { id: 42, title: 'Test Book', author: 'Author Name', publishedDate: new Date() }
|
|
742
|
+
const upsertedItem = await repository.upsert(input)
|
|
743
|
+
|
|
744
|
+
expect(upsertedItem).toEqual(input)
|
|
745
|
+
|
|
746
|
+
const updateInput = { id: 42, title: 'Updated Book', author: 'Updated Author', publishedDate: new Date() }
|
|
747
|
+
const updatedItem = await repository.upsert(updateInput)
|
|
748
|
+
|
|
749
|
+
expect(updatedItem).toEqual(updateInput)
|
|
750
|
+
})
|
|
751
|
+
|
|
752
|
+
it('should use custom assign function for create operation', async () => {
|
|
753
|
+
const customAssignMock = mock((existing: any, input: any) => ({
|
|
754
|
+
...existing,
|
|
755
|
+
...input,
|
|
756
|
+
customField: 'custom_create_value',
|
|
757
|
+
}))
|
|
758
|
+
|
|
759
|
+
const customRepository = new MockMemoryRepository({
|
|
760
|
+
schema: mockSchema,
|
|
761
|
+
assign: customAssignMock,
|
|
762
|
+
})
|
|
763
|
+
|
|
764
|
+
const input = { title: 'Test Book', author: 'Author Name', publishedDate: new Date() }
|
|
765
|
+
const createdItem = await customRepository.create(input)
|
|
766
|
+
|
|
767
|
+
expect(customAssignMock).toHaveBeenCalledWith({}, input)
|
|
768
|
+
expect((createdItem as any).customField).toBe('custom_create_value')
|
|
769
|
+
expect(createdItem).toMatchObject(input)
|
|
770
|
+
})
|
|
771
|
+
|
|
772
|
+
it('should use custom assign function for update operation', async () => {
|
|
773
|
+
const customAssignMock = mock((existing: any, input: any) => ({
|
|
774
|
+
...existing,
|
|
775
|
+
...input,
|
|
776
|
+
customField: 'custom_update_value',
|
|
777
|
+
lastModified: new Date('2023-01-01'),
|
|
778
|
+
}))
|
|
779
|
+
|
|
780
|
+
const customRepository = new MockMemoryRepository({
|
|
781
|
+
schema: mockSchema,
|
|
782
|
+
assign: customAssignMock,
|
|
783
|
+
})
|
|
784
|
+
|
|
785
|
+
const input = { id: 42, title: 'Test Book', author: 'Author Name', publishedDate: new Date() }
|
|
786
|
+
const createdItem = await customRepository.create(input)
|
|
787
|
+
|
|
788
|
+
const updateInput = { title: 'Updated Book', author: 'Updated Author', publishedDate: new Date() }
|
|
789
|
+
const updatedItem = await customRepository.update({ id: createdItem.id }, updateInput)
|
|
790
|
+
|
|
791
|
+
expect(customAssignMock).toHaveBeenCalledWith(createdItem, updateInput)
|
|
792
|
+
expect((updatedItem as any).customField).toBe('custom_update_value')
|
|
793
|
+
expect((updatedItem as any).lastModified).toEqual(new Date('2023-01-01'))
|
|
794
|
+
expect(updatedItem.title).toBe('Updated Book')
|
|
795
|
+
})
|
|
796
|
+
|
|
797
|
+
it('should use custom assign function for upsert operation on existing item', async () => {
|
|
798
|
+
const customAssignMock = mock((existing: any, input: any) => ({
|
|
799
|
+
...existing,
|
|
800
|
+
...input,
|
|
801
|
+
mergeTimestamp: new Date('2023-01-01'),
|
|
802
|
+
isUpserted: true,
|
|
803
|
+
}))
|
|
804
|
+
|
|
805
|
+
const customRepository = new MockMemoryRepository({
|
|
806
|
+
schema: mockSchema,
|
|
807
|
+
assign: customAssignMock,
|
|
808
|
+
})
|
|
809
|
+
|
|
810
|
+
const input = { id: 42, title: 'Test Book', author: 'Author Name', publishedDate: new Date() }
|
|
811
|
+
const createdItem = await customRepository.create(input)
|
|
812
|
+
|
|
813
|
+
const upsertInput = { id: 42, title: 'Upserted Book', author: 'Upserted Author', publishedDate: new Date() }
|
|
814
|
+
const upsertedItem = await customRepository.upsert(upsertInput)
|
|
815
|
+
|
|
816
|
+
// Should have been called twice: once for create, once for upsert
|
|
817
|
+
expect(customAssignMock).toHaveBeenCalledTimes(2)
|
|
818
|
+
expect(customAssignMock).toHaveBeenLastCalledWith(createdItem, upsertInput)
|
|
819
|
+
expect((upsertedItem as any).mergeTimestamp).toEqual(new Date('2023-01-01'))
|
|
820
|
+
expect((upsertedItem as any).isUpserted).toBe(true)
|
|
821
|
+
expect(upsertedItem.title).toBe('Upserted Book')
|
|
822
|
+
})
|
|
823
|
+
|
|
824
|
+
it('should use custom assign function for upsert operation on new item', async () => {
|
|
825
|
+
const customAssignMock = mock((existing: any, input: any) => ({
|
|
826
|
+
...existing,
|
|
827
|
+
...input,
|
|
828
|
+
createdViaUpsert: true,
|
|
829
|
+
}))
|
|
830
|
+
|
|
831
|
+
const customRepository = new MockMemoryRepository({
|
|
832
|
+
schema: mockSchema,
|
|
833
|
+
assign: customAssignMock,
|
|
834
|
+
})
|
|
835
|
+
|
|
836
|
+
const input = { id: 42, title: 'Test Book', author: 'Author Name', publishedDate: new Date() }
|
|
837
|
+
const upsertedItem = await customRepository.upsert(input)
|
|
838
|
+
|
|
839
|
+
expect(customAssignMock).toHaveBeenCalledWith({}, input)
|
|
840
|
+
expect((upsertedItem as any).createdViaUpsert).toBe(true)
|
|
841
|
+
expect(upsertedItem).toMatchObject(input)
|
|
842
|
+
})
|
|
843
|
+
|
|
844
|
+
it('should use custom assign function for bulkUpsert operation', async () => {
|
|
845
|
+
const customAssignMock = mock((existing: any, input: any) => ({
|
|
846
|
+
...existing,
|
|
847
|
+
...input,
|
|
848
|
+
bulkProcessed: true,
|
|
849
|
+
}))
|
|
850
|
+
|
|
851
|
+
const customRepository = new MockMemoryRepository({
|
|
852
|
+
schema: mockSchema,
|
|
853
|
+
assign: customAssignMock,
|
|
854
|
+
})
|
|
855
|
+
|
|
856
|
+
const inputs = [
|
|
857
|
+
{ id: 1, title: 'Book 1', author: 'Author 1', publishedDate: new Date() },
|
|
858
|
+
{ id: 2, title: 'Book 2', author: 'Author 2', publishedDate: new Date() },
|
|
859
|
+
]
|
|
860
|
+
|
|
861
|
+
const results = await customRepository.bulkUpsert(inputs)
|
|
862
|
+
|
|
863
|
+
expect(customAssignMock).toHaveBeenCalledTimes(2)
|
|
864
|
+
expect((results[0] as any).bulkProcessed).toBe(true)
|
|
865
|
+
expect((results[1] as any).bulkProcessed).toBe(true)
|
|
866
|
+
expect(results[0]).toMatchObject(inputs[0])
|
|
867
|
+
expect(results[1]).toMatchObject(inputs[1])
|
|
868
|
+
})
|
|
869
|
+
|
|
870
|
+
it('should handle complex custom assign logic with conditional merging', async () => {
|
|
871
|
+
const customAssign = (existing: any, input: any) => {
|
|
872
|
+
const result = { ...existing, ...input }
|
|
873
|
+
|
|
874
|
+
// Custom logic: preserve original author if input doesn't have one
|
|
875
|
+
if (!input.author && existing.author) {
|
|
876
|
+
result.author = existing.author
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// Custom logic: track modification count
|
|
880
|
+
result.modificationCount = (existing.modificationCount || 0) + 1
|
|
881
|
+
|
|
882
|
+
return result
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const customRepository = new MockMemoryRepository({
|
|
886
|
+
schema: mockSchema,
|
|
887
|
+
assign: customAssign,
|
|
888
|
+
})
|
|
889
|
+
|
|
890
|
+
const input = { id: 42, title: 'Test Book', author: 'Original Author', publishedDate: new Date() }
|
|
891
|
+
const createdItem = await customRepository.create(input)
|
|
892
|
+
|
|
893
|
+
expect((createdItem as any).modificationCount).toBe(1)
|
|
894
|
+
|
|
895
|
+
// Update with partial data - use existing values for required fields
|
|
896
|
+
const updateInput = {
|
|
897
|
+
title: 'Updated Book',
|
|
898
|
+
author: createdItem.author,
|
|
899
|
+
publishedDate: createdItem.publishedDate,
|
|
900
|
+
}
|
|
901
|
+
const updatedItem = await customRepository.update({ id: createdItem.id }, updateInput)
|
|
902
|
+
|
|
903
|
+
expect(updatedItem.author).toBe('Original Author')
|
|
904
|
+
expect(updatedItem.title).toBe('Updated Book')
|
|
905
|
+
expect((updatedItem as any).modificationCount).toBe(2)
|
|
906
|
+
|
|
907
|
+
// Update with new author
|
|
908
|
+
const updateWithAuthor = {
|
|
909
|
+
title: updatedItem.title,
|
|
910
|
+
author: 'New Author',
|
|
911
|
+
publishedDate: updatedItem.publishedDate,
|
|
912
|
+
}
|
|
913
|
+
const finalItem = await customRepository.update({ id: createdItem.id }, updateWithAuthor)
|
|
914
|
+
|
|
915
|
+
expect(finalItem.author).toBe('New Author')
|
|
916
|
+
expect((finalItem as any).modificationCount).toBe(3)
|
|
917
|
+
})
|
|
918
|
+
})
|
|
715
919
|
})
|
|
@@ -17,6 +17,7 @@ export interface IMockMemoryRepositoryArgs<TSchema extends AnyModelSchema> {
|
|
|
17
17
|
schema: TSchema
|
|
18
18
|
lookup?: (data: InferDetail<TSchema>, lookup: InferLookup<TSchema>) => boolean
|
|
19
19
|
filter?: (data: InferSummary<TSchema>, filters: InferFilters<TSchema>) => boolean
|
|
20
|
+
assign?: (data: InferDetail<TSchema>, input: InferInput<TSchema>) => InferDetail<TSchema>
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export class MockMemoryRepository<TSchema extends AnyModelSchema> implements IRepository<TSchema> {
|
|
@@ -140,17 +141,16 @@ export class MockMemoryRepository<TSchema extends AnyModelSchema> implements IRe
|
|
|
140
141
|
throw new Error('Item with the same primary key already exists')
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
}
|
|
144
|
+
const baseData = {} as InferDetail<TSchema>
|
|
145
|
+
const payload = this.assignInput(baseData, input)
|
|
146
146
|
|
|
147
147
|
if (!payload[this.entityMetadata.primaryKey]) {
|
|
148
148
|
// Generate a new primary key if not provided
|
|
149
149
|
payload[this.entityMetadata.primaryKey!] = await this.generatePrimaryKey()
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
this.data.set(payload[this.entityMetadata.primaryKey!], payload
|
|
153
|
-
return payload
|
|
152
|
+
this.data.set(payload[this.entityMetadata.primaryKey!], payload)
|
|
153
|
+
return payload
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
async update(lookup: InferLookup<TSchema>, input: InferInput<TSchema>): Promise<InferDetail<TSchema>> {
|
|
@@ -167,7 +167,7 @@ export class MockMemoryRepository<TSchema extends AnyModelSchema> implements IRe
|
|
|
167
167
|
throw new Error('Item not found')
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
const updatedItem =
|
|
170
|
+
const updatedItem = this.assignInput(existingItem, input)
|
|
171
171
|
this.data.set(primaryKeyValue, updatedItem)
|
|
172
172
|
return updatedItem
|
|
173
173
|
}
|
|
@@ -179,13 +179,13 @@ export class MockMemoryRepository<TSchema extends AnyModelSchema> implements IRe
|
|
|
179
179
|
|
|
180
180
|
async upsert(input: InferInput<TSchema>, options?: ICreateOptions | IUpdateOptions): Promise<InferDetail<TSchema>> {
|
|
181
181
|
const primaryKeyValue = input[this.entityMetadata.primaryKey]
|
|
182
|
-
let existingItem: InferDetail<TSchema>
|
|
182
|
+
let existingItem: InferDetail<TSchema> = {} as InferDetail<TSchema>
|
|
183
183
|
|
|
184
184
|
if (primaryKeyValue) {
|
|
185
|
-
existingItem = this.data.get(primaryKeyValue) ?? {}
|
|
185
|
+
existingItem = this.data.get(primaryKeyValue) ?? ({} as InferDetail<TSchema>)
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
const updatedItem =
|
|
188
|
+
const updatedItem = this.assignInput(existingItem, input)
|
|
189
189
|
if (!updatedItem[this.entityMetadata.primaryKey!]) {
|
|
190
190
|
updatedItem[this.entityMetadata.primaryKey!] = await this.generatePrimaryKey()
|
|
191
191
|
}
|
|
@@ -218,6 +218,21 @@ export class MockMemoryRepository<TSchema extends AnyModelSchema> implements IRe
|
|
|
218
218
|
})
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Assign input data to existing data using the provided assign function or default Object.assign
|
|
223
|
+
* @param existingData - The existing data to merge with
|
|
224
|
+
* @param input - The input data to assign
|
|
225
|
+
* @returns The merged data
|
|
226
|
+
*/
|
|
227
|
+
protected assignInput(existingData: InferDetail<TSchema>, input: InferInput<TSchema>): InferDetail<TSchema> {
|
|
228
|
+
if (typeof this.args.assign === 'function') {
|
|
229
|
+
return this.args.assign(existingData, input)
|
|
230
|
+
} else {
|
|
231
|
+
// Default implementation using Object.assign
|
|
232
|
+
return Object.assign({}, existingData, input) as InferDetail<TSchema>
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
221
236
|
protected async generatePrimaryKey() {
|
|
222
237
|
const lookupModel: Model<any, any> = this.args.schema.definition.lookup
|
|
223
238
|
const lookupMeta = await lookupModel.toJSONSchema()
|