@declaro/data 2.0.0-beta.14 → 2.0.0-beta.140
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/{LICENSE → LICENSE.md} +1 -1
- package/README.md +0 -0
- package/dist/browser/index.js +26 -0
- package/dist/browser/index.js.map +93 -0
- package/dist/node/index.cjs +13372 -0
- package/dist/node/index.cjs.map +93 -0
- package/dist/node/index.js +13351 -0
- package/dist/node/index.js.map +93 -0
- package/dist/ts/application/model-controller.d.ts +60 -0
- package/dist/ts/application/model-controller.d.ts.map +1 -0
- package/dist/ts/application/model-controller.test.d.ts +2 -0
- package/dist/ts/application/model-controller.test.d.ts.map +1 -0
- package/dist/ts/application/read-only-model-controller.d.ts +24 -0
- package/dist/ts/application/read-only-model-controller.d.ts.map +1 -0
- package/dist/ts/application/read-only-model-controller.test.d.ts +2 -0
- package/dist/ts/application/read-only-model-controller.test.d.ts.map +1 -0
- package/dist/ts/domain/events/domain-event.d.ts +41 -0
- package/dist/ts/domain/events/domain-event.d.ts.map +1 -0
- package/dist/ts/domain/events/domain-event.test.d.ts +2 -0
- package/dist/ts/domain/events/domain-event.test.d.ts.map +1 -0
- package/dist/ts/domain/events/event-types.d.ts +37 -0
- package/dist/ts/domain/events/event-types.d.ts.map +1 -0
- package/dist/ts/domain/events/mutation-event.d.ts +41 -0
- package/dist/ts/domain/events/mutation-event.d.ts.map +1 -0
- package/dist/ts/domain/events/mutation-event.test.d.ts +2 -0
- package/dist/ts/domain/events/mutation-event.test.d.ts.map +1 -0
- package/dist/ts/domain/events/query-event.d.ts +8 -0
- package/dist/ts/domain/events/query-event.d.ts.map +1 -0
- package/dist/ts/domain/events/query-event.test.d.ts +2 -0
- package/dist/ts/domain/events/query-event.test.d.ts.map +1 -0
- package/dist/ts/domain/events/request-event.d.ts +26 -0
- package/dist/ts/domain/events/request-event.d.ts.map +1 -0
- package/dist/ts/domain/events/request-event.test.d.ts +2 -0
- package/dist/ts/domain/events/request-event.test.d.ts.map +1 -0
- package/dist/ts/domain/interfaces/repository.d.ts +110 -0
- package/dist/ts/domain/interfaces/repository.d.ts.map +1 -0
- package/dist/ts/domain/models/pagination.d.ts +28 -0
- package/dist/ts/domain/models/pagination.d.ts.map +1 -0
- package/dist/ts/domain/services/base-model-service.d.ts +23 -0
- package/dist/ts/domain/services/base-model-service.d.ts.map +1 -0
- package/dist/ts/domain/services/model-service-args.d.ts +9 -0
- package/dist/ts/domain/services/model-service-args.d.ts.map +1 -0
- package/dist/ts/domain/services/model-service.d.ts +99 -0
- package/dist/ts/domain/services/model-service.d.ts.map +1 -0
- package/dist/ts/domain/services/model-service.normalization.test.d.ts +2 -0
- package/dist/ts/domain/services/model-service.normalization.test.d.ts.map +1 -0
- package/dist/ts/domain/services/model-service.test.d.ts +2 -0
- package/dist/ts/domain/services/model-service.test.d.ts.map +1 -0
- package/dist/ts/domain/services/read-only-model-service.d.ts +90 -0
- package/dist/ts/domain/services/read-only-model-service.d.ts.map +1 -0
- package/dist/ts/domain/services/read-only-model-service.test.d.ts +2 -0
- package/dist/ts/domain/services/read-only-model-service.test.d.ts.map +1 -0
- package/dist/ts/index.d.ts +18 -0
- package/dist/ts/index.d.ts.map +1 -0
- package/dist/ts/shared/utils/schema-inference.d.ts +23 -0
- package/dist/ts/shared/utils/schema-inference.d.ts.map +1 -0
- package/dist/ts/shared/utils/schema-inheritance.d.ts +24 -0
- package/dist/ts/shared/utils/schema-inheritance.d.ts.map +1 -0
- package/dist/ts/shared/utils/schema-inheritance.test.d.ts +2 -0
- package/dist/ts/shared/utils/schema-inheritance.test.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/animal-schema.d.ts +57 -0
- package/dist/ts/shared/utils/test/animal-schema.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/animal-trait-schema.d.ts +55 -0
- package/dist/ts/shared/utils/test/animal-trait-schema.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/elephant-schema.d.ts +30 -0
- package/dist/ts/shared/utils/test/elephant-schema.d.ts.map +1 -0
- package/dist/ts/shared/utils/test/elephant-trait-schema.d.ts +26 -0
- package/dist/ts/shared/utils/test/elephant-trait-schema.d.ts.map +1 -0
- package/dist/ts/test/mock/models/mock-book-models.d.ts +42 -0
- package/dist/ts/test/mock/models/mock-book-models.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.assign.test.d.ts +2 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.assign.test.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.basic.test.d.ts +2 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.basic.test.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.bulk-upsert.test.d.ts +2 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.bulk-upsert.test.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.count.test.d.ts +2 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.count.test.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.d.ts +62 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.search.test.d.ts +2 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.search.test.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.trash.test.d.ts +2 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.trash.test.d.ts.map +1 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.upsert.test.d.ts +2 -0
- package/dist/ts/test/mock/repositories/mock-memory-repository.upsert.test.d.ts.map +1 -0
- package/package.json +46 -42
- package/src/application/model-controller.test.ts +694 -0
- package/src/application/model-controller.ts +186 -0
- package/src/application/read-only-model-controller.test.ts +335 -0
- package/src/application/read-only-model-controller.ts +79 -0
- package/src/domain/events/domain-event.test.ts +82 -0
- package/src/domain/events/domain-event.ts +69 -0
- package/src/domain/events/event-types.ts +37 -0
- package/src/domain/events/mutation-event.test.ts +390 -0
- package/src/domain/events/mutation-event.ts +53 -0
- package/src/domain/events/query-event.test.ts +228 -0
- package/src/domain/events/query-event.ts +14 -0
- package/src/domain/events/request-event.test.ts +38 -0
- package/src/domain/events/request-event.ts +47 -0
- package/src/domain/interfaces/repository.ts +136 -0
- package/src/domain/models/pagination.ts +28 -0
- package/src/domain/services/base-model-service.ts +54 -0
- package/src/domain/services/model-service-args.ts +9 -0
- package/src/domain/services/model-service.normalization.test.ts +704 -0
- package/src/domain/services/model-service.test.ts +1616 -0
- package/src/domain/services/model-service.ts +597 -0
- package/src/domain/services/read-only-model-service.test.ts +1130 -0
- package/src/domain/services/read-only-model-service.ts +211 -0
- package/src/index.ts +17 -4
- package/src/shared/utils/schema-inference.ts +26 -0
- package/src/shared/utils/schema-inheritance.test.ts +295 -0
- package/src/shared/utils/schema-inheritance.ts +28 -0
- package/src/shared/utils/test/animal-schema.ts +46 -0
- package/src/shared/utils/test/animal-trait-schema.ts +45 -0
- package/src/shared/utils/test/elephant-schema.ts +58 -0
- package/src/shared/utils/test/elephant-trait-schema.ts +53 -0
- package/src/test/mock/models/mock-book-models.ts +78 -0
- package/src/test/mock/repositories/mock-memory-repository.assign.test.ts +215 -0
- package/src/test/mock/repositories/mock-memory-repository.basic.test.ts +129 -0
- package/src/test/mock/repositories/mock-memory-repository.bulk-upsert.test.ts +159 -0
- package/src/test/mock/repositories/mock-memory-repository.count.test.ts +98 -0
- package/src/test/mock/repositories/mock-memory-repository.search.test.ts +265 -0
- package/src/test/mock/repositories/mock-memory-repository.trash.test.ts +736 -0
- package/src/test/mock/repositories/mock-memory-repository.ts +401 -0
- package/src/test/mock/repositories/mock-memory-repository.upsert.test.ts +108 -0
- package/dist/databaseConnection.d.ts +0 -24
- package/dist/datastoreAbstract.d.ts +0 -37
- package/dist/declaro-data.cjs +0 -1
- package/dist/declaro-data.mjs +0 -250
- package/dist/hydrateEntity.d.ts +0 -8
- package/dist/index.d.ts +0 -4
- package/dist/serverConnection.d.ts +0 -15
- package/dist/trackedStatus.d.ts +0 -15
- package/src/databaseConnection.ts +0 -137
- package/src/datastoreAbstract.ts +0 -190
- package/src/hydrateEntity.ts +0 -36
- package/src/placeholder.test.ts +0 -7
- package/src/serverConnection.ts +0 -74
- package/src/trackedStatus.ts +0 -35
- package/tsconfig.json +0 -10
- package/vite.config.ts +0 -23
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { IAuthSession } from '@declaro/auth'
|
|
2
|
+
import { type IEvent, type IActionDescriptor, ActionDescriptor, type IActionDescriptorInput } from '@declaro/core'
|
|
3
|
+
import { v4 as uuid } from 'uuid'
|
|
4
|
+
|
|
5
|
+
export interface IDomainEvent<T, M = any> extends IEvent {
|
|
6
|
+
eventId: string
|
|
7
|
+
data?: T
|
|
8
|
+
meta?: M
|
|
9
|
+
timestamp: Date
|
|
10
|
+
descriptor: IActionDescriptor
|
|
11
|
+
session?: IAuthSession
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IDomainEventOptions<TData, TMeta = any> {
|
|
15
|
+
type?: string
|
|
16
|
+
eventId?: string
|
|
17
|
+
data?: TData
|
|
18
|
+
timestamp?: Date
|
|
19
|
+
descriptor?: IActionDescriptorInput
|
|
20
|
+
session?: IAuthSession
|
|
21
|
+
meta?: TMeta
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface IDomainEventJSON<T, M = any> {
|
|
25
|
+
eventId: string
|
|
26
|
+
data?: T
|
|
27
|
+
meta: M
|
|
28
|
+
timestamp: string // JSON-compatible format
|
|
29
|
+
type: string
|
|
30
|
+
session?: { id: string } // Simplified session representation
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class DomainEvent<T, M = any> implements IDomainEvent<T, M> {
|
|
34
|
+
readonly eventId: string
|
|
35
|
+
public data?: T
|
|
36
|
+
public timestamp: Date
|
|
37
|
+
public type: string = 'UNKNOWN_EVENT'
|
|
38
|
+
public descriptor: ActionDescriptor
|
|
39
|
+
public session?: IAuthSession
|
|
40
|
+
public meta: M
|
|
41
|
+
|
|
42
|
+
constructor(options: IDomainEventOptions<T, M> = {}) {
|
|
43
|
+
if (options.type) {
|
|
44
|
+
this.type = options.type
|
|
45
|
+
}
|
|
46
|
+
this.eventId = options.eventId ?? uuid()
|
|
47
|
+
this.timestamp = options.timestamp ?? new Date()
|
|
48
|
+
this.descriptor = options.descriptor
|
|
49
|
+
? ActionDescriptor.fromJSON(options.descriptor)
|
|
50
|
+
: ActionDescriptor.fromString(this.type)
|
|
51
|
+
if (options.descriptor && this.type === 'UNKNOWN_EVENT') {
|
|
52
|
+
this.type = this.descriptor.toString()
|
|
53
|
+
}
|
|
54
|
+
this.data = options.data
|
|
55
|
+
this.meta = options.meta ?? ({} as M) // Ensure meta is always defined, defaulting to an empty object
|
|
56
|
+
this.session = options.session
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
toJSON(): IDomainEventJSON<T, M> {
|
|
60
|
+
return {
|
|
61
|
+
eventId: this.eventId,
|
|
62
|
+
data: this.data,
|
|
63
|
+
meta: this.meta,
|
|
64
|
+
timestamp: this.timestamp.toISOString(),
|
|
65
|
+
type: this.type,
|
|
66
|
+
session: this.session ? { id: this.session.id } : undefined,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export enum ModelQueryEvent {
|
|
2
|
+
BeforeLoad = 'beforeLoad',
|
|
3
|
+
AfterLoad = 'afterLoad',
|
|
4
|
+
BeforeLoadMany = 'beforeLoadMany',
|
|
5
|
+
AfterLoadMany = 'afterLoadMany',
|
|
6
|
+
BeforeSearch = 'beforeSearch',
|
|
7
|
+
AfterSearch = 'afterSearch',
|
|
8
|
+
BeforeCount = 'beforeCount',
|
|
9
|
+
AfterCount = 'afterCount',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export enum ModelMutationAction {
|
|
13
|
+
Create = 'create',
|
|
14
|
+
BeforeCreate = 'beforeCreate',
|
|
15
|
+
AfterCreate = 'afterCreate',
|
|
16
|
+
Update = 'update',
|
|
17
|
+
BeforeUpdate = 'beforeUpdate',
|
|
18
|
+
AfterUpdate = 'afterUpdate',
|
|
19
|
+
Duplicate = 'duplicate',
|
|
20
|
+
BeforeDuplicate = 'beforeDuplicate',
|
|
21
|
+
AfterDuplicate = 'afterDuplicate',
|
|
22
|
+
Remove = 'remove',
|
|
23
|
+
BeforeRemove = 'beforeRemove',
|
|
24
|
+
AfterRemove = 'afterRemove',
|
|
25
|
+
Restore = 'restore',
|
|
26
|
+
BeforeRestore = 'beforeRestore',
|
|
27
|
+
AfterRestore = 'afterRestore',
|
|
28
|
+
EmptyTrash = 'emptyTrash',
|
|
29
|
+
BeforeEmptyTrash = 'beforeEmptyTrash',
|
|
30
|
+
AfterEmptyTrash = 'afterEmptyTrash',
|
|
31
|
+
PermanentlyDeleteFromTrash = 'permanentlyDeleteFromTrash',
|
|
32
|
+
BeforePermanentlyDeleteFromTrash = 'beforePermanentlyDeleteFromTrash',
|
|
33
|
+
AfterPermanentlyDeleteFromTrash = 'afterPermanentlyDeleteFromTrash',
|
|
34
|
+
PermanentlyDelete = 'permanentlyDelete',
|
|
35
|
+
BeforePermanentlyDelete = 'beforePermanentlyDelete',
|
|
36
|
+
AfterPermanentlyDelete = 'afterPermanentlyDelete',
|
|
37
|
+
}
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { describe, it, expect } from 'bun:test'
|
|
2
|
+
import { MutationEvent } from './mutation-event'
|
|
3
|
+
import { ActionDescriptor, type IActionDescriptorInput } from '@declaro/core'
|
|
4
|
+
|
|
5
|
+
interface IBookResult {
|
|
6
|
+
id: string
|
|
7
|
+
title: string
|
|
8
|
+
description: string
|
|
9
|
+
author: string
|
|
10
|
+
year: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface IBookInput {
|
|
14
|
+
title: string
|
|
15
|
+
description: string
|
|
16
|
+
author: string
|
|
17
|
+
year: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('MutationEvent', () => {
|
|
21
|
+
it('should create a mutation event with input and descriptor', () => {
|
|
22
|
+
const input: IBookInput = {
|
|
23
|
+
title: 'Test Book',
|
|
24
|
+
description: 'A book for testing',
|
|
25
|
+
author: 'Author Name',
|
|
26
|
+
year: 2024,
|
|
27
|
+
}
|
|
28
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
29
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
30
|
+
|
|
31
|
+
expect(event.input).toEqual(input)
|
|
32
|
+
expect(event.descriptor.toString()).toEqual(new ActionDescriptor(descriptor).toString())
|
|
33
|
+
expect(event.meta).toEqual({})
|
|
34
|
+
expect(event.data).toBeUndefined()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should allow setting existing result in meta', () => {
|
|
38
|
+
const input: IBookInput = {
|
|
39
|
+
title: 'Test Book',
|
|
40
|
+
description: 'A book for testing',
|
|
41
|
+
author: 'Author Name',
|
|
42
|
+
year: 2024,
|
|
43
|
+
}
|
|
44
|
+
const existing: IBookResult = {
|
|
45
|
+
id: '1',
|
|
46
|
+
title: 'Old Title',
|
|
47
|
+
description: 'Old Description',
|
|
48
|
+
author: 'Old Author',
|
|
49
|
+
year: 2000,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'update' }
|
|
53
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input, {
|
|
54
|
+
existing,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
expect(event.input).toEqual(input)
|
|
58
|
+
expect(event.meta.existing).toEqual(existing)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should update meta correctly', () => {
|
|
62
|
+
const input: IBookInput = {
|
|
63
|
+
title: 'Test Book',
|
|
64
|
+
description: 'A book for testing',
|
|
65
|
+
author: 'Author Name',
|
|
66
|
+
year: 2024,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
70
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
71
|
+
|
|
72
|
+
const existing: IBookResult = {
|
|
73
|
+
id: '1',
|
|
74
|
+
title: 'Old Title',
|
|
75
|
+
description: 'Old Description',
|
|
76
|
+
author: 'Old Author',
|
|
77
|
+
year: 2000,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
event.setMeta({
|
|
81
|
+
existing,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
expect(event.meta.existing).toEqual(existing)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('should set result correctly', () => {
|
|
88
|
+
const input: IBookInput = {
|
|
89
|
+
title: 'Test Book',
|
|
90
|
+
description: 'A book for testing',
|
|
91
|
+
author: 'Author Name',
|
|
92
|
+
year: 2024,
|
|
93
|
+
}
|
|
94
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
95
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
96
|
+
|
|
97
|
+
expect(event.data).toBeUndefined()
|
|
98
|
+
|
|
99
|
+
const result: IBookResult = {
|
|
100
|
+
id: '1',
|
|
101
|
+
title: 'Test Book',
|
|
102
|
+
description: 'A book for testing',
|
|
103
|
+
author: 'Author Name',
|
|
104
|
+
year: 2024,
|
|
105
|
+
}
|
|
106
|
+
event.setResult(result)
|
|
107
|
+
|
|
108
|
+
expect(event.data).toEqual(result)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('should serialize to JSON with eventId and timestamp', () => {
|
|
112
|
+
const input: IBookInput = {
|
|
113
|
+
title: 'Test Book',
|
|
114
|
+
description: 'A book for testing',
|
|
115
|
+
author: 'Author Name',
|
|
116
|
+
year: 2024,
|
|
117
|
+
}
|
|
118
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
119
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
120
|
+
|
|
121
|
+
const result: IBookResult = {
|
|
122
|
+
id: '1',
|
|
123
|
+
title: 'Test Book',
|
|
124
|
+
description: 'A book for testing',
|
|
125
|
+
author: 'Author Name',
|
|
126
|
+
year: 2024,
|
|
127
|
+
}
|
|
128
|
+
event.setResult(result)
|
|
129
|
+
|
|
130
|
+
const json = event.toJSON()
|
|
131
|
+
|
|
132
|
+
expect(json.eventId).toBeDefined()
|
|
133
|
+
expect(json.timestamp).toBeDefined()
|
|
134
|
+
expect(json.type).toBe('books::book.create')
|
|
135
|
+
expect(json.input).toEqual(input)
|
|
136
|
+
expect(json.data).toEqual(result)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('should handle chaining of setter methods', () => {
|
|
140
|
+
const input: IBookInput = {
|
|
141
|
+
title: 'Test Book',
|
|
142
|
+
description: 'A book for testing',
|
|
143
|
+
author: 'Author Name',
|
|
144
|
+
year: 2024,
|
|
145
|
+
}
|
|
146
|
+
const existing: IBookResult = {
|
|
147
|
+
id: '1',
|
|
148
|
+
title: 'Old Title',
|
|
149
|
+
description: 'Old Description',
|
|
150
|
+
author: 'Old Author',
|
|
151
|
+
year: 2000,
|
|
152
|
+
}
|
|
153
|
+
const result: IBookResult = {
|
|
154
|
+
id: '1',
|
|
155
|
+
title: 'Test Book',
|
|
156
|
+
description: 'A book for testing',
|
|
157
|
+
author: 'Author Name',
|
|
158
|
+
year: 2024,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'update' }
|
|
162
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
163
|
+
.setMeta({ existing })
|
|
164
|
+
.setResult(result)
|
|
165
|
+
|
|
166
|
+
expect(event.input).toEqual(input)
|
|
167
|
+
expect(event.meta.existing).toEqual(existing)
|
|
168
|
+
expect(event.data).toEqual(result)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should update input after initialization', () => {
|
|
172
|
+
const input: IBookInput = {
|
|
173
|
+
title: 'Test Book',
|
|
174
|
+
description: 'A book for testing',
|
|
175
|
+
author: 'Author Name',
|
|
176
|
+
year: 2024,
|
|
177
|
+
}
|
|
178
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
179
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
180
|
+
|
|
181
|
+
const newInput: IBookInput = {
|
|
182
|
+
title: 'Updated Book',
|
|
183
|
+
description: 'Updated description',
|
|
184
|
+
author: 'New Author',
|
|
185
|
+
year: 2025,
|
|
186
|
+
}
|
|
187
|
+
event.setInput(newInput)
|
|
188
|
+
|
|
189
|
+
expect(event.input).toEqual(newInput)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it('should allow setting input multiple times', () => {
|
|
193
|
+
const input: IBookInput = {
|
|
194
|
+
title: 'First Book',
|
|
195
|
+
description: 'First description',
|
|
196
|
+
author: 'First Author',
|
|
197
|
+
year: 2024,
|
|
198
|
+
}
|
|
199
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
200
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
201
|
+
|
|
202
|
+
const secondInput: IBookInput = {
|
|
203
|
+
title: 'Second Book',
|
|
204
|
+
description: 'Second description',
|
|
205
|
+
author: 'Second Author',
|
|
206
|
+
year: 2025,
|
|
207
|
+
}
|
|
208
|
+
event.setInput(secondInput)
|
|
209
|
+
expect(event.input).toEqual(secondInput)
|
|
210
|
+
|
|
211
|
+
const thirdInput: IBookInput = {
|
|
212
|
+
title: 'Third Book',
|
|
213
|
+
description: 'Third description',
|
|
214
|
+
author: 'Third Author',
|
|
215
|
+
year: 2026,
|
|
216
|
+
}
|
|
217
|
+
event.setInput(thirdInput)
|
|
218
|
+
expect(event.input).toEqual(thirdInput)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('should return this from setInput for chaining', () => {
|
|
222
|
+
const input: IBookInput = {
|
|
223
|
+
title: 'Test Book',
|
|
224
|
+
description: 'A book for testing',
|
|
225
|
+
author: 'Author Name',
|
|
226
|
+
year: 2024,
|
|
227
|
+
}
|
|
228
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
229
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
230
|
+
|
|
231
|
+
const newInput: IBookInput = {
|
|
232
|
+
title: 'Updated Book',
|
|
233
|
+
description: 'Updated description',
|
|
234
|
+
author: 'New Author',
|
|
235
|
+
year: 2025,
|
|
236
|
+
}
|
|
237
|
+
const result: IBookResult = {
|
|
238
|
+
id: '1',
|
|
239
|
+
...newInput,
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const returned = event.setInput(newInput).setResult(result)
|
|
243
|
+
|
|
244
|
+
expect(returned).toBe(event)
|
|
245
|
+
expect(event.input).toEqual(newInput)
|
|
246
|
+
expect(event.data).toEqual(result)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('should replace entire input object when using setInput', () => {
|
|
250
|
+
const input: IBookInput = {
|
|
251
|
+
title: 'Original Book',
|
|
252
|
+
description: 'Original description',
|
|
253
|
+
author: 'Original Author',
|
|
254
|
+
year: 2024,
|
|
255
|
+
}
|
|
256
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'update' }
|
|
257
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
258
|
+
|
|
259
|
+
expect(event.input.title).toBe('Original Book')
|
|
260
|
+
|
|
261
|
+
const partialInput: IBookInput = {
|
|
262
|
+
title: 'New Title',
|
|
263
|
+
description: 'New description',
|
|
264
|
+
author: 'New Author',
|
|
265
|
+
year: 2025,
|
|
266
|
+
}
|
|
267
|
+
event.setInput(partialInput)
|
|
268
|
+
|
|
269
|
+
expect(event.input).toEqual(partialInput)
|
|
270
|
+
expect(event.input.title).toBe('New Title')
|
|
271
|
+
expect(event.input.year).toBe(2025)
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('should update existing in meta', () => {
|
|
275
|
+
const input: IBookInput = {
|
|
276
|
+
title: 'Test Book',
|
|
277
|
+
description: 'A book for testing',
|
|
278
|
+
author: 'Author Name',
|
|
279
|
+
year: 2024,
|
|
280
|
+
}
|
|
281
|
+
const existing: IBookResult = {
|
|
282
|
+
id: '1',
|
|
283
|
+
title: 'Old Title',
|
|
284
|
+
description: 'Old Description',
|
|
285
|
+
author: 'Old Author',
|
|
286
|
+
year: 2000,
|
|
287
|
+
}
|
|
288
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'update' }
|
|
289
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input, { existing })
|
|
290
|
+
|
|
291
|
+
const newExisting: IBookResult = {
|
|
292
|
+
id: '1',
|
|
293
|
+
title: 'Different Title',
|
|
294
|
+
description: 'Different Description',
|
|
295
|
+
author: 'Different Author',
|
|
296
|
+
year: 2010,
|
|
297
|
+
}
|
|
298
|
+
event.setMeta({ existing: newExisting })
|
|
299
|
+
|
|
300
|
+
expect(event.meta.existing).toEqual(newExisting)
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it('should handle delete action with existing record', () => {
|
|
304
|
+
const input = { id: '1' }
|
|
305
|
+
const existing: IBookResult = {
|
|
306
|
+
id: '1',
|
|
307
|
+
title: 'Book to Delete',
|
|
308
|
+
description: 'This will be deleted',
|
|
309
|
+
author: 'Some Author',
|
|
310
|
+
year: 2020,
|
|
311
|
+
}
|
|
312
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'delete' }
|
|
313
|
+
const event = new MutationEvent<IBookResult, { id: string }>(descriptor, input, { existing })
|
|
314
|
+
|
|
315
|
+
expect(event.descriptor.action).toBe('delete')
|
|
316
|
+
expect(event.meta.existing).toEqual(existing)
|
|
317
|
+
expect(event.input).toEqual(input)
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
it('should maintain type throughout lifecycle', () => {
|
|
321
|
+
const input: IBookInput = {
|
|
322
|
+
title: 'Test Book',
|
|
323
|
+
description: 'A book for testing',
|
|
324
|
+
author: 'Author Name',
|
|
325
|
+
year: 2024,
|
|
326
|
+
}
|
|
327
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
328
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
329
|
+
|
|
330
|
+
expect(event.type).toBe('books::book.create')
|
|
331
|
+
|
|
332
|
+
event.setInput({ ...input, title: 'Updated' })
|
|
333
|
+
expect(event.type).toBe('books::book.create')
|
|
334
|
+
|
|
335
|
+
const result: IBookResult = {
|
|
336
|
+
id: '1',
|
|
337
|
+
title: 'Updated',
|
|
338
|
+
description: 'A book for testing',
|
|
339
|
+
author: 'Author Name',
|
|
340
|
+
year: 2024,
|
|
341
|
+
}
|
|
342
|
+
event.setResult(result)
|
|
343
|
+
expect(event.type).toBe('books::book.create')
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it('should serialize existing to JSON for update action', () => {
|
|
347
|
+
const input: IBookInput = {
|
|
348
|
+
title: 'Updated Title',
|
|
349
|
+
description: 'Updated description',
|
|
350
|
+
author: 'Author Name',
|
|
351
|
+
year: 2024,
|
|
352
|
+
}
|
|
353
|
+
const existing: IBookResult = {
|
|
354
|
+
id: '1',
|
|
355
|
+
title: 'Old Title',
|
|
356
|
+
description: 'Old Description',
|
|
357
|
+
author: 'Old Author',
|
|
358
|
+
year: 2020,
|
|
359
|
+
}
|
|
360
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'update' }
|
|
361
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input, { existing })
|
|
362
|
+
|
|
363
|
+
const json = event.toJSON()
|
|
364
|
+
|
|
365
|
+
expect(json.meta.existing).toEqual(existing)
|
|
366
|
+
expect(json.input).toEqual(input)
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
it('should handle create action without existing', () => {
|
|
370
|
+
const input: IBookInput = {
|
|
371
|
+
title: 'New Book',
|
|
372
|
+
description: 'Brand new',
|
|
373
|
+
author: 'New Author',
|
|
374
|
+
year: 2024,
|
|
375
|
+
}
|
|
376
|
+
const descriptor: IActionDescriptorInput = { namespace: 'books', resource: 'book', action: 'create' }
|
|
377
|
+
const event = new MutationEvent<IBookResult, IBookInput>(descriptor, input)
|
|
378
|
+
|
|
379
|
+
expect(event.meta.existing).toBeUndefined()
|
|
380
|
+
expect(event.descriptor.action).toBe('create')
|
|
381
|
+
|
|
382
|
+
const result: IBookResult = {
|
|
383
|
+
id: '1',
|
|
384
|
+
...input,
|
|
385
|
+
}
|
|
386
|
+
event.setResult(result)
|
|
387
|
+
|
|
388
|
+
expect(event.data).toEqual(result)
|
|
389
|
+
})
|
|
390
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { IActionDescriptorInput } from '@declaro/core'
|
|
2
|
+
import { RequestEvent, type IRequestEventMeta } from './request-event'
|
|
3
|
+
|
|
4
|
+
export interface IMutationEventMeta<TResult> extends IRequestEventMeta {
|
|
5
|
+
existing?: TResult
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ICreateEventMeta<TResult, TInput> extends IMutationEventMeta<TResult> {
|
|
9
|
+
args?: {
|
|
10
|
+
input: TInput
|
|
11
|
+
options?: Record<string, unknown>
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface IUpdateEventMeta<TResult, TLookup, TInput> extends IMutationEventMeta<TResult> {
|
|
16
|
+
args?: {
|
|
17
|
+
lookup: TLookup
|
|
18
|
+
input: TInput
|
|
19
|
+
options?: Record<string, unknown>
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface IRemoveEventMeta<TResult, TLookup> extends IMutationEventMeta<TResult> {
|
|
24
|
+
args?: {
|
|
25
|
+
lookup: TLookup
|
|
26
|
+
options?: Record<string, unknown>
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface IRestoreEventMeta<TResult, TLookup> extends IMutationEventMeta<TResult> {
|
|
31
|
+
args?: {
|
|
32
|
+
lookup: TLookup
|
|
33
|
+
options?: Record<string, unknown>
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface IDuplicateEventMeta<TResult, TLookup, TInput> extends IMutationEventMeta<TResult> {
|
|
38
|
+
args?: {
|
|
39
|
+
lookup: TLookup
|
|
40
|
+
overrides?: Partial<TInput>
|
|
41
|
+
options?: Record<string, unknown>
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class MutationEvent<
|
|
46
|
+
TResult,
|
|
47
|
+
TInput,
|
|
48
|
+
TMeta extends IMutationEventMeta<TResult> = IMutationEventMeta<TResult>,
|
|
49
|
+
> extends RequestEvent<TResult, TInput, TMeta> {
|
|
50
|
+
constructor(descriptor: IActionDescriptorInput, input: TInput, meta: TMeta = {} as TMeta) {
|
|
51
|
+
super(descriptor, input, meta)
|
|
52
|
+
}
|
|
53
|
+
}
|