@nestjslatam/ddd-lib 1.0.55 → 2.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.
- package/README.md +396 -18
- package/{dist/aggregate-root.d.ts → aggregate-root.d.ts} +2 -1
- package/{dist/broken-rules.manager.d.ts → broken-rules.manager.d.ts} +1 -1
- package/package.json +41 -52
- package/{dist/tracking-state-manager.d.ts → tracking-state-manager.d.ts} +1 -1
- package/{dist/tracking-state-manager.js → tracking-state-manager.js} +6 -6
- package/{dist/validator-rule.manager.d.ts → validator-rule.manager.d.ts} +2 -1
- package/{dist/valueobject.d.ts → valueobject.d.ts} +2 -1
- package/{dist/valueobject.js → valueobject.js} +2 -2
- package/{dist/valueobjects → valueobjects}/number-notnull.validator.d.ts +1 -1
- package/{dist/valueobjects → valueobjects}/number-notnull.validator.js +2 -2
- package/{dist/valueobjects → valueobjects}/number-positive.validator.d.ts +1 -1
- package/{dist/valueobjects → valueobjects}/number-positive.validator.js +2 -2
- package/{dist/valueobjects → valueobjects}/string-notnullorempty.validator.d.ts +1 -1
- package/{dist/valueobjects → valueobjects}/string-notnullorempty.validator.js +2 -2
- package/src/types.d.ts +0 -7
- /package/{dist/aggregate-root.js → aggregate-root.js} +0 -0
- /package/{dist/broken-rules.manager.js → broken-rules.manager.js} +0 -0
- /package/{dist/core → core}/aggregate/aggregate-equality.d.ts +0 -0
- /package/{dist/core → core}/aggregate/aggregate-equality.js +0 -0
- /package/{dist/core → core}/aggregate/aggregate-identity.d.ts +0 -0
- /package/{dist/core → core}/aggregate/aggregate-identity.js +0 -0
- /package/{dist/core → core}/aggregate/aggregate-serializer.d.ts +0 -0
- /package/{dist/core → core}/aggregate/aggregate-serializer.js +0 -0
- /package/{dist/core → core}/aggregate/aggregate-validation-orchestrator.d.ts +0 -0
- /package/{dist/core → core}/aggregate/aggregate-validation-orchestrator.js +0 -0
- /package/{dist/core → core}/aggregate/index.d.ts +0 -0
- /package/{dist/core → core}/aggregate/index.js +0 -0
- /package/{dist/core → core}/business-rules/impl/broken-rule.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/broken-rule.js +0 -0
- /package/{dist/core → core}/business-rules/impl/broken-rules-extension.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/broken-rules-extension.js +0 -0
- /package/{dist/core → core}/business-rules/impl/index.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/index.js +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/index.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/index.js +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.base.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.base.js +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.context-args.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.context-args.js +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.context.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.context.js +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/reflection-type-extensions.d.ts +0 -0
- /package/{dist/core → core}/business-rules/impl/property-change/reflection-type-extensions.js +0 -0
- /package/{dist/core → core}/business-rules/index.d.ts +0 -0
- /package/{dist/core → core}/business-rules/index.js +0 -0
- /package/{dist/core → core}/index.d.ts +0 -0
- /package/{dist/core → core}/index.js +0 -0
- /package/{dist/core → core}/repositories/index.d.ts +0 -0
- /package/{dist/core → core}/repositories/index.js +0 -0
- /package/{dist/core → core}/repositories/repository-read.interface.d.ts +0 -0
- /package/{dist/core → core}/repositories/repository-read.interface.js +0 -0
- /package/{dist/core → core}/repositories/repository-write.interface.d.ts +0 -0
- /package/{dist/core → core}/repositories/repository-write.interface.js +0 -0
- /package/{dist/core → core}/tracking-state/impl/index.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/impl/index.js +0 -0
- /package/{dist/core → core}/tracking-state/impl/nested-property-change-detector.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/impl/nested-property-change-detector.js +0 -0
- /package/{dist/core → core}/tracking-state/impl/tracking-props.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/impl/tracking-props.js +0 -0
- /package/{dist/core → core}/tracking-state/impl/tracking-state-transition.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/impl/tracking-state-transition.js +0 -0
- /package/{dist/core → core}/tracking-state/index.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/index.js +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/ichange-detector.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/ichange-detector.js +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/idomain-primitive.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/idomain-primitive.js +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/index.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/index.js +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/itracking-props.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/itracking-props.js +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/itracking-state-manager.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/itracking-state-manager.js +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/itracking-state-transitions.d.ts +0 -0
- /package/{dist/core → core}/tracking-state/interfaces/itracking-state-transitions.js +0 -0
- /package/{dist/core → core}/validator-rules/impl/abstract-rule-validator.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/impl/abstract-rule-validator.js +0 -0
- /package/{dist/core → core}/validator-rules/impl/abstract-validator.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/impl/abstract-validator.js +0 -0
- /package/{dist/core → core}/validator-rules/impl/entity-validator.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/impl/entity-validator.js +0 -0
- /package/{dist/core → core}/validator-rules/impl/index.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/impl/index.js +0 -0
- /package/{dist/core → core}/validator-rules/impl/value-object-validator.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/impl/value-object-validator.js +0 -0
- /package/{dist/core → core}/validator-rules/index.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/index.js +0 -0
- /package/{dist/core → core}/validator-rules/interfaces/index.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/interfaces/index.js +0 -0
- /package/{dist/core → core}/validator-rules/interfaces/irule-context.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/interfaces/irule-context.js +0 -0
- /package/{dist/core → core}/validator-rules/interfaces/irule-validator.d.ts +0 -0
- /package/{dist/core → core}/validator-rules/interfaces/irule-validator.js +0 -0
- /package/{dist/ddd.module.d.ts → ddd.module.d.ts} +0 -0
- /package/{dist/ddd.module.js → ddd.module.js} +0 -0
- /package/{dist/ddd.service.d.ts → ddd.service.d.ts} +0 -0
- /package/{dist/ddd.service.js → ddd.service.js} +0 -0
- /package/{dist/domain-event.d.ts → domain-event.d.ts} +0 -0
- /package/{dist/domain-event.js → domain-event.js} +0 -0
- /package/{dist/enum.d.ts → enum.d.ts} +0 -0
- /package/{dist/enum.js → enum.js} +0 -0
- /package/{dist/exceptions → exceptions}/domain.exception.d.ts +0 -0
- /package/{dist/exceptions → exceptions}/domain.exception.js +0 -0
- /package/{dist/helpers → helpers}/datetime.helper.d.ts +0 -0
- /package/{dist/helpers → helpers}/datetime.helper.js +0 -0
- /package/{dist/helpers → helpers}/domain-object.helper.d.ts +0 -0
- /package/{dist/helpers → helpers}/domain-object.helper.js +0 -0
- /package/{dist/helpers → helpers}/index.d.ts +0 -0
- /package/{dist/helpers → helpers}/index.js +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/index.js → index.js} +0 -0
- /package/{dist/state-transition.manager.d.ts → state-transition.manager.d.ts} +0 -0
- /package/{dist/state-transition.manager.js → state-transition.manager.js} +0 -0
- /package/{dist/validator-rule.manager.js → validator-rule.manager.js} +0 -0
- /package/{dist/valueobjects → valueobjects}/id.valueobject.d.ts +0 -0
- /package/{dist/valueobjects → valueobjects}/id.valueobject.js +0 -0
- /package/{dist/valueobjects → valueobjects}/index.d.ts +0 -0
- /package/{dist/valueobjects → valueobjects}/index.js +0 -0
- /package/{dist/valueobjects → valueobjects}/number.valueobject.d.ts +0 -0
- /package/{dist/valueobjects → valueobjects}/number.valueobject.js +0 -0
- /package/{dist/valueobjects → valueobjects}/string.valueobject.d.ts +0 -0
- /package/{dist/valueobjects → valueobjects}/string.valueobject.js +0 -0
package/README.md
CHANGED
|
@@ -1,30 +1,408 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nestjslatam/ddd-lib
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A comprehensive Domain-Driven Design (DDD) library for NestJS applications, providing building blocks and patterns to implement clean, maintainable, and scalable enterprise applications.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@nestjslatam/ddd-lib)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## ⚠️ Development Status
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
**Version 2.0.0** - This library is actively developed and NOT recommended for production use. Breaking changes may occur between minor versions.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
- TypeScript Support: Take advantage of the static typing and modern features of TypeScript, enhancing the development experience and catching errors early in the development process.
|
|
13
|
-
- Node.js Compatibility: DDD Library for NESTJS is built to support Node.js, allowing you to harness the full power of JavaScript on the server side.
|
|
14
|
-
- Domain-Driven Design Principles: Embrace the core principles of DDD effortlessly. DDD Library for NESTJS provides abstractions and utilities that align with DDD concepts, allowing you to model your domain in a clear and expressive manner.
|
|
15
|
-
- Modularity and Extensibility: Enjoy a modular and extensible architecture that adapts to the complexity of your application. DDD Library for NESTJS empowers you to build scalable systems by encapsulating domain logic in a modular fashion.
|
|
16
|
-
- Community-Driven: As an open-source project, DDD Library for NESTJS thrives on community collaboration. Contribute, share your insights, and join the growing community of developers dedicated to enhancing DDD practices within NESTJS.
|
|
12
|
+
## 🎯 What is Domain-Driven Design?
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
Domain-Driven Design has proven to be a game-changer in building scalable and maintainable applications by placing the domain at the heart of the software design process. This library simplifies the application of DDD concepts within the NestJS framework, empowering developers to create well-architected, domain-centric solutions.
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
## ✨ Key Features
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
### 🏗️ Core DDD Building Blocks
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
- **Aggregate Roots**: Base class `DddAggregateRoot` with built-in validation and state tracking
|
|
21
|
+
- **Value Objects**: `StringValueObject`, `NumberValueObject` with immutability
|
|
22
|
+
- **Entities**: Rich domain entities with identity
|
|
23
|
+
- **Domain Events**: Event-driven architecture support
|
|
24
|
+
- **Repositories**: Read/Write repository pattern interfaces
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
### 🔍 Advanced Features
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
- **Automatic State Tracking**: Track entity state (new, modified, deleted)
|
|
29
|
+
- **Validation Framework**: `AbstractRuleValidator` for custom business rules
|
|
30
|
+
- **Business Rules Management**: Broken rules collection and validation orchestration
|
|
31
|
+
- **Property Change Tracking**: Detect and react to property changes
|
|
32
|
+
- **Type Safety**: Full TypeScript support with complete type definitions
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
### 🚀 Framework Integration
|
|
35
|
+
|
|
36
|
+
- **NestJS Native**: Built specifically for NestJS framework
|
|
37
|
+
- **TypeScript First**: Leverages TypeScript's type system
|
|
38
|
+
- **Node.js Compatible**: Works seamlessly with Node.js ecosystem
|
|
39
|
+
- **Modular Architecture**: Import only what you need
|
|
40
|
+
|
|
41
|
+
## 📦 Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @nestjslatam/ddd-lib
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Peer Dependencies
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install @nestjs/common @nestjs/core rxjs uuid
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 🚀 Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Create a Value Object
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { StringValueObject, AbstractRuleValidator } from '@nestjslatam/ddd-lib';
|
|
59
|
+
|
|
60
|
+
// Custom validator
|
|
61
|
+
class EmailValidator extends AbstractRuleValidator<Email> {
|
|
62
|
+
constructor(subject: Email) {
|
|
63
|
+
super(subject);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public addRules(): void {
|
|
67
|
+
const value = this.subject.getValue();
|
|
68
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
69
|
+
|
|
70
|
+
if (!emailRegex.test(value)) {
|
|
71
|
+
this.addBrokenRule('value', 'Invalid email format');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Value Object
|
|
77
|
+
export class Email extends StringValueObject {
|
|
78
|
+
private constructor(value: string) {
|
|
79
|
+
super(value);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static create(value: string): Email {
|
|
83
|
+
const email = new Email(value);
|
|
84
|
+
|
|
85
|
+
if (!email.isValid) {
|
|
86
|
+
const errors = email.brokenRules.getBrokenRules();
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Invalid email: ${errors.map((e) => e.message).join(', ')}`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return email;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
protected override addValidators(): void {
|
|
96
|
+
super.addValidators();
|
|
97
|
+
this.validatorRules.add(new EmailValidator(this));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. Create an Aggregate Root
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { DddAggregateRoot, IdValueObject } from '@nestjslatam/ddd-lib';
|
|
106
|
+
import { Email } from './value-objects/email';
|
|
107
|
+
|
|
108
|
+
interface UserProps {
|
|
109
|
+
email: Email;
|
|
110
|
+
name: string;
|
|
111
|
+
isActive: boolean;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export class User extends DddAggregateRoot<UserProps> {
|
|
115
|
+
private constructor(
|
|
116
|
+
id: IdValueObject,
|
|
117
|
+
props: UserProps,
|
|
118
|
+
createdAt?: Date,
|
|
119
|
+
updatedAt?: Date,
|
|
120
|
+
) {
|
|
121
|
+
super(id, props, createdAt, updatedAt);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static create(email: Email, name: string): User {
|
|
125
|
+
const id = IdValueObject.create();
|
|
126
|
+
const user = new User(id, {
|
|
127
|
+
email,
|
|
128
|
+
name,
|
|
129
|
+
isActive: false,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
user.validate();
|
|
133
|
+
return user;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Business methods
|
|
137
|
+
activate(): void {
|
|
138
|
+
if (this.props.isActive) {
|
|
139
|
+
throw new Error('User is already active');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.props.isActive = true;
|
|
143
|
+
this.trackingState.markAsDirty();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
deactivate(): void {
|
|
147
|
+
if (!this.props.isActive) {
|
|
148
|
+
throw new Error('User is already inactive');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.props.isActive = false;
|
|
152
|
+
this.trackingState.markAsDirty();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Getters
|
|
156
|
+
get email(): Email {
|
|
157
|
+
return this.props.email;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
get name(): string {
|
|
161
|
+
return this.props.name;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
get isActive(): boolean {
|
|
165
|
+
return this.props.isActive;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 3. Use in Your Service
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { Injectable } from '@nestjs/common';
|
|
174
|
+
import { User } from './domain/user';
|
|
175
|
+
import { Email } from './domain/value-objects/email';
|
|
176
|
+
|
|
177
|
+
@Injectable()
|
|
178
|
+
export class UserService {
|
|
179
|
+
async createUser(emailStr: string, name: string): Promise<User> {
|
|
180
|
+
const email = Email.create(emailStr);
|
|
181
|
+
const user = User.create(email, name);
|
|
182
|
+
|
|
183
|
+
// Check state
|
|
184
|
+
console.log(user.trackingState.isNew); // true
|
|
185
|
+
console.log(user.trackingState.isDirty); // false
|
|
186
|
+
console.log(user.isValid()); // true
|
|
187
|
+
|
|
188
|
+
// Business logic
|
|
189
|
+
user.activate();
|
|
190
|
+
console.log(user.trackingState.isDirty); // true
|
|
191
|
+
|
|
192
|
+
return user;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## 📚 Core Concepts
|
|
198
|
+
|
|
199
|
+
### Aggregate Roots
|
|
200
|
+
|
|
201
|
+
Aggregate roots are the entry points to your domain model. They enforce consistency boundaries and business rules.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { DddAggregateRoot } from '@nestjslatam/ddd-lib';
|
|
205
|
+
|
|
206
|
+
export class Order extends DddAggregateRoot<OrderProps> {
|
|
207
|
+
// Your domain logic
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Features:**
|
|
212
|
+
|
|
213
|
+
- ✅ Automatic state tracking (new, dirty, deleted)
|
|
214
|
+
- ✅ Built-in validation orchestration
|
|
215
|
+
- ✅ Domain event support
|
|
216
|
+
- ✅ Broken rules management
|
|
217
|
+
|
|
218
|
+
### Value Objects
|
|
219
|
+
|
|
220
|
+
Value objects are immutable and represent domain concepts without identity.
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { StringValueObject, NumberValueObject } from '@nestjslatam/ddd-lib';
|
|
224
|
+
|
|
225
|
+
export class Money extends NumberValueObject {
|
|
226
|
+
// Your value object logic
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Built-in Validators:**
|
|
231
|
+
|
|
232
|
+
- `StringNotNullOrEmptyValidator` - Ensures string is not null or empty
|
|
233
|
+
- `NumberNotNullValidator` - Ensures number is not null
|
|
234
|
+
- `NumberPositiveValidator` - Ensures number is positive
|
|
235
|
+
|
|
236
|
+
### Custom Validators
|
|
237
|
+
|
|
238
|
+
Create business rule validators by extending `AbstractRuleValidator`.
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { AbstractRuleValidator } from '@nestjslatam/ddd-lib';
|
|
242
|
+
|
|
243
|
+
export class PriceRangeValidator extends AbstractRuleValidator<Price> {
|
|
244
|
+
public addRules(): void {
|
|
245
|
+
const value = this.subject.getValue();
|
|
246
|
+
|
|
247
|
+
if (value < 0) {
|
|
248
|
+
this.addBrokenRule('value', 'Price cannot be negative');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (value > 999999.99) {
|
|
252
|
+
this.addBrokenRule('value', 'Price exceeds maximum');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### State Tracking
|
|
259
|
+
|
|
260
|
+
Every aggregate automatically tracks its state:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
const product = Product.create(name, price);
|
|
264
|
+
|
|
265
|
+
product.trackingState.isNew; // true
|
|
266
|
+
product.trackingState.isDirty; // false
|
|
267
|
+
product.trackingState.isDeleted; // false
|
|
268
|
+
|
|
269
|
+
product.changePrice(newPrice);
|
|
270
|
+
product.trackingState.isDirty; // true
|
|
271
|
+
|
|
272
|
+
product.trackingState.markAsDeleted();
|
|
273
|
+
product.trackingState.isDeleted; // true
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## 🏗️ Architecture Example
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
src/
|
|
280
|
+
├── domain/
|
|
281
|
+
│ ├── aggregates/
|
|
282
|
+
│ │ └── product.ts # Extends DddAggregateRoot
|
|
283
|
+
│ ├── value-objects/
|
|
284
|
+
│ │ ├── price.ts # Extends NumberValueObject
|
|
285
|
+
│ │ └── product-name.ts # Extends StringValueObject
|
|
286
|
+
│ └── validators/
|
|
287
|
+
│ └── price-range.validator.ts # Extends AbstractRuleValidator
|
|
288
|
+
├── application/
|
|
289
|
+
│ ├── commands/
|
|
290
|
+
│ └── queries/
|
|
291
|
+
└── infrastructure/
|
|
292
|
+
└── repositories/
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## 🔄 Version 2.0.0 Changes
|
|
296
|
+
|
|
297
|
+
### What's New
|
|
298
|
+
|
|
299
|
+
**NPM Package Distribution**
|
|
300
|
+
|
|
301
|
+
- Library is now published as a standalone NPM package
|
|
302
|
+
- No need for monorepo or path mappings
|
|
303
|
+
- Standard Node.js module resolution
|
|
304
|
+
|
|
305
|
+
**Eliminated Circular Dependencies**
|
|
306
|
+
|
|
307
|
+
- Refactored internal imports to eliminate circular references
|
|
308
|
+
- Direct imports from specific modules
|
|
309
|
+
- Reliable runtime behavior
|
|
310
|
+
|
|
311
|
+
**Pre-compiled Distribution**
|
|
312
|
+
|
|
313
|
+
- Published as compiled JavaScript with TypeScript declarations
|
|
314
|
+
- Faster application startup
|
|
315
|
+
- Better tree-shaking support
|
|
316
|
+
|
|
317
|
+
**Improved Type Definitions**
|
|
318
|
+
|
|
319
|
+
- Complete `.d.ts` files for all exports
|
|
320
|
+
- Better IDE support and autocomplete
|
|
321
|
+
- Source maps for debugging
|
|
322
|
+
|
|
323
|
+
### Breaking Changes from 1.x.x
|
|
324
|
+
|
|
325
|
+
1. **Installation Method**
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Before (1.x.x) - Local library
|
|
329
|
+
# Used path mappings in tsconfig.json
|
|
330
|
+
|
|
331
|
+
# After (2.0.0) - NPM package
|
|
332
|
+
npm install @nestjslatam/ddd-lib
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
2. **Import Paths**
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Before (1.x.x)
|
|
339
|
+
import { DddAggregateRoot } from '@nestjslatam/ddd-lib/aggregate-root';
|
|
340
|
+
|
|
341
|
+
// After (2.0.0)
|
|
342
|
+
import { DddAggregateRoot } from '@nestjslatam/ddd-lib';
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
3. **No Path Mappings Required**
|
|
346
|
+
```json
|
|
347
|
+
// tsconfig.json - NO LONGER NEEDED
|
|
348
|
+
{
|
|
349
|
+
"paths": {
|
|
350
|
+
"@nestjslatam/ddd-lib": ["libs/ddd/src"]
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## 📖 API Reference
|
|
356
|
+
|
|
357
|
+
### Exported Classes
|
|
358
|
+
|
|
359
|
+
**Base Classes:**
|
|
360
|
+
|
|
361
|
+
- `DddAggregateRoot<T>` - Base class for aggregate roots
|
|
362
|
+
- `StringValueObject` - Base class for string value objects
|
|
363
|
+
- `NumberValueObject` - Base class for number value objects
|
|
364
|
+
- `IdValueObject` - UUID-based identity value object
|
|
365
|
+
|
|
366
|
+
**Validators:**
|
|
367
|
+
|
|
368
|
+
- `AbstractRuleValidator<T>` - Base class for custom validators
|
|
369
|
+
- `StringNotNullOrEmptyValidator` - Built-in string validator
|
|
370
|
+
- `NumberNotNullValidator` - Built-in number validator
|
|
371
|
+
- `NumberPositiveValidator` - Built-in positive number validator
|
|
372
|
+
|
|
373
|
+
**Managers:**
|
|
374
|
+
|
|
375
|
+
- `BrokenRulesManager` - Manages validation errors
|
|
376
|
+
- `ValidatorRuleManager` - Manages validator rules
|
|
377
|
+
- `TrackingStateManager` - Manages entity state
|
|
378
|
+
|
|
379
|
+
**Interfaces:**
|
|
380
|
+
|
|
381
|
+
- `IDomainReadRepository<T>` - Read repository interface
|
|
382
|
+
- `IDomainWriteRepository<T>` - Write repository interface
|
|
383
|
+
|
|
384
|
+
## 🤝 Contributing
|
|
385
|
+
|
|
386
|
+
We welcome contributions! This is an open-source project maintained by the NestJS LATAM community.
|
|
387
|
+
|
|
388
|
+
## 📄 License
|
|
389
|
+
|
|
390
|
+
This library is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
391
|
+
|
|
392
|
+
## 🔗 Links
|
|
393
|
+
|
|
394
|
+
- [NPM Package](https://www.npmjs.com/package/@nestjslatam/ddd-lib)
|
|
395
|
+
- [GitHub Repository](https://github.com/nestjslatam/ddd)
|
|
396
|
+
- [Sample Application](https://github.com/nestjslatam/ddd/tree/main/src)
|
|
397
|
+
- [NestJS LATAM](http://nestjslatam.org/)
|
|
398
|
+
|
|
399
|
+
## 👥 Author
|
|
400
|
+
|
|
401
|
+
**Alberto Arroyo Raygada**
|
|
402
|
+
|
|
403
|
+
- Email: beyondnet.peru@gmail.com
|
|
404
|
+
- Website: [http://nestjslatam.org/](http://nestjslatam.org/)
|
|
405
|
+
|
|
406
|
+
## 🙏 Acknowledgments
|
|
407
|
+
|
|
408
|
+
This library is inspired by Domain-Driven Design principles and built specifically for the NestJS ecosystem. Special thanks to the NestJS and DDD communities for their invaluable insights and contributions.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AggregateRoot } from '@nestjs/cqrs';
|
|
2
2
|
import { BrokenRulesManager } from './broken-rules.manager';
|
|
3
|
-
import { AbstractRuleValidator
|
|
3
|
+
import { AbstractRuleValidator } from './core/validator-rules';
|
|
4
|
+
import { TrackingProps } from './core/tracking-state';
|
|
4
5
|
import { TrackingStateManager } from './tracking-state-manager';
|
|
5
6
|
import { ValidatorRuleManager } from './validator-rule.manager';
|
|
6
7
|
import { IdValueObject } from './valueobjects';
|
package/package.json
CHANGED
|
@@ -1,52 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@nestjslatam/ddd-lib",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A
|
|
5
|
-
"main": "
|
|
6
|
-
"types": "
|
|
7
|
-
"private": false,
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"dependencies": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"uuid": "^11.1.0"
|
|
43
|
-
},
|
|
44
|
-
"peerDependencies": {
|
|
45
|
-
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
46
|
-
"@nestjs/core": "^10.0.0 || ^11.0.0"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@nestjs/cli": "^11.0.6",
|
|
50
|
-
"@nestjs/config": "^4.0.2"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@nestjslatam/ddd-lib",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "A comprehensive Domain-Driven Design library for NestJS - Build scalable, maintainable enterprise applications",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"private": false,
|
|
8
|
+
"keywords": [
|
|
9
|
+
"nestjs",
|
|
10
|
+
"nestjslatam",
|
|
11
|
+
"ddd",
|
|
12
|
+
"domain-driven-design",
|
|
13
|
+
"aggregate",
|
|
14
|
+
"value-object",
|
|
15
|
+
"entity"
|
|
16
|
+
],
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "Alberto Arroyo Raygada",
|
|
19
|
+
"email": "beyondnet.peru@gmail.com",
|
|
20
|
+
"url": "http://nestjslatam.org/"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/nestjslatam/ddd"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"**/*.js",
|
|
29
|
+
"**/*.d.ts",
|
|
30
|
+
"!**/*.spec.js",
|
|
31
|
+
"!**/*.spec.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
35
|
+
"@nestjs/core": "^10.0.0 || ^11.0.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"rxjs": "^7.8.2",
|
|
39
|
+
"uuid": "^11.1.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IChangeDetector, IProps, ITrackingProps, ITrackingStateManager, ITrackingStateTransitions } from './core';
|
|
1
|
+
import { IChangeDetector, IProps, ITrackingProps, ITrackingStateManager, ITrackingStateTransitions } from './core/tracking-state';
|
|
2
2
|
export declare class TrackingStateManager implements ITrackingStateManager, ITrackingStateTransitions {
|
|
3
3
|
private _isNew;
|
|
4
4
|
private _isDirty;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TrackingStateManager = void 0;
|
|
4
|
-
const
|
|
4
|
+
const impl_1 = require("./core/tracking-state/impl");
|
|
5
5
|
class TrackingStateManager {
|
|
6
6
|
get isNew() {
|
|
7
7
|
return this._isNew;
|
|
@@ -20,7 +20,7 @@ class TrackingStateManager {
|
|
|
20
20
|
this._isDirty = false;
|
|
21
21
|
this._isSelfDeleted = false;
|
|
22
22
|
this._isDeleted = false;
|
|
23
|
-
this.changeDetector = changeDetector || new
|
|
23
|
+
this.changeDetector = changeDetector || new impl_1.NestedPropertyChangeDetector();
|
|
24
24
|
this.markAsClean();
|
|
25
25
|
}
|
|
26
26
|
get trackingProps() {
|
|
@@ -36,16 +36,16 @@ class TrackingStateManager {
|
|
|
36
36
|
return this;
|
|
37
37
|
}
|
|
38
38
|
markAsDirty() {
|
|
39
|
-
|
|
39
|
+
impl_1.TrackingStateTransition.toDirty(this);
|
|
40
40
|
}
|
|
41
41
|
markAsNew() {
|
|
42
|
-
|
|
42
|
+
impl_1.TrackingStateTransition.toNew(this);
|
|
43
43
|
}
|
|
44
44
|
markAsSelfDeleted() {
|
|
45
|
-
|
|
45
|
+
impl_1.TrackingStateTransition.toSelfDeleted(this);
|
|
46
46
|
}
|
|
47
47
|
markAsDeleted() {
|
|
48
|
-
|
|
48
|
+
impl_1.TrackingStateTransition.toDeleted(this);
|
|
49
49
|
}
|
|
50
50
|
markAsClean() {
|
|
51
51
|
this._isDirty = false;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { BrokenRule
|
|
1
|
+
import { BrokenRule } from './core/business-rules';
|
|
2
|
+
import { ClassType, IRuleValidator } from './core/validator-rules';
|
|
2
3
|
export declare class ValidatorRuleManager<TValidator extends IRuleValidator> {
|
|
3
4
|
private readonly _validators;
|
|
4
5
|
add(rule: TValidator): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BrokenRulesManager } from './broken-rules.manager';
|
|
2
|
-
import { AbstractNotifyPropertyChanged
|
|
2
|
+
import { AbstractNotifyPropertyChanged } from './core/business-rules/impl/property-change';
|
|
3
|
+
import { AbstractRuleValidator } from './core/validator-rules';
|
|
3
4
|
import { TrackingStateManager } from './tracking-state-manager';
|
|
4
5
|
import { ValidatorRuleManager } from './validator-rule.manager';
|
|
5
6
|
export declare abstract class DddValueObject<TValue> extends AbstractNotifyPropertyChanged {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DddValueObject = void 0;
|
|
4
4
|
const broken_rules_manager_1 = require("./broken-rules.manager");
|
|
5
|
-
const
|
|
5
|
+
const property_change_1 = require("./core/business-rules/impl/property-change");
|
|
6
6
|
const domain_exception_1 = require("./exceptions/domain.exception");
|
|
7
7
|
const tracking_state_manager_1 = require("./tracking-state-manager");
|
|
8
8
|
const validator_rule_manager_1 = require("./validator-rule.manager");
|
|
9
|
-
class DddValueObject extends
|
|
9
|
+
class DddValueObject extends property_change_1.AbstractNotifyPropertyChanged {
|
|
10
10
|
get isValid() {
|
|
11
11
|
return this.brokenRules.getBrokenRules().length === 0;
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractRuleValidator } from '../core';
|
|
1
|
+
import { AbstractRuleValidator } from '../core/validator-rules/impl/abstract-rule-validator';
|
|
2
2
|
import { DddValueObject } from '../valueobject';
|
|
3
3
|
export declare class NumberNotNullValidator extends AbstractRuleValidator<DddValueObject<number>> {
|
|
4
4
|
private readonly options;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NumberNotNullValidator = void 0;
|
|
4
|
-
const
|
|
5
|
-
class NumberNotNullValidator extends
|
|
4
|
+
const abstract_rule_validator_1 = require("../core/validator-rules/impl/abstract-rule-validator");
|
|
5
|
+
class NumberNotNullValidator extends abstract_rule_validator_1.AbstractRuleValidator {
|
|
6
6
|
constructor(subject, options) {
|
|
7
7
|
super(subject);
|
|
8
8
|
this.options = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractRuleValidator } from '../core';
|
|
1
|
+
import { AbstractRuleValidator } from '../core/validator-rules/impl/abstract-rule-validator';
|
|
2
2
|
import { DddValueObject } from '../valueobject';
|
|
3
3
|
export declare class NumberPositiveValidator extends AbstractRuleValidator<DddValueObject<number>> {
|
|
4
4
|
private readonly options;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NumberPositiveValidator = void 0;
|
|
4
|
-
const
|
|
5
|
-
class NumberPositiveValidator extends
|
|
4
|
+
const abstract_rule_validator_1 = require("../core/validator-rules/impl/abstract-rule-validator");
|
|
5
|
+
class NumberPositiveValidator extends abstract_rule_validator_1.AbstractRuleValidator {
|
|
6
6
|
constructor(subject, options) {
|
|
7
7
|
super(subject);
|
|
8
8
|
this.options = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractRuleValidator } from '../core';
|
|
1
|
+
import { AbstractRuleValidator } from '../core/validator-rules/impl/abstract-rule-validator';
|
|
2
2
|
import { DddValueObject } from '../valueobject';
|
|
3
3
|
export declare class StringNotNullOrEmptyValidator extends AbstractRuleValidator<DddValueObject<string>> {
|
|
4
4
|
private readonly options;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StringNotNullOrEmptyValidator = void 0;
|
|
4
|
-
const
|
|
5
|
-
class StringNotNullOrEmptyValidator extends
|
|
4
|
+
const abstract_rule_validator_1 = require("../core/validator-rules/impl/abstract-rule-validator");
|
|
5
|
+
class StringNotNullOrEmptyValidator extends abstract_rule_validator_1.AbstractRuleValidator {
|
|
6
6
|
constructor(subject, options) {
|
|
7
7
|
super(subject);
|
|
8
8
|
this.options = {
|
package/src/types.d.ts
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.base.d.ts
RENAMED
|
File without changes
|
/package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.base.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.context.d.ts
RENAMED
|
File without changes
|
/package/{dist/core → core}/business-rules/impl/property-change/notify-property-changed.context.js
RENAMED
|
File without changes
|
/package/{dist/core → core}/business-rules/impl/property-change/reflection-type-extensions.d.ts
RENAMED
|
File without changes
|
/package/{dist/core → core}/business-rules/impl/property-change/reflection-type-extensions.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|