@globalart/ddd 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# @globalart/ddd
|
|
2
|
+
|
|
3
|
+
A comprehensive Domain-Driven Design (DDD) toolkit for NestJS applications, providing essential building blocks for building robust, maintainable domain models.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Aggregate Root**: Base class for domain aggregates with domain event management
|
|
8
|
+
- **Command & Query**: CQRS pattern implementation with command and query buses
|
|
9
|
+
- **Value Objects**: Type-safe value objects with equality comparison
|
|
10
|
+
- **Specifications**: Composite specification pattern for business rules
|
|
11
|
+
- **Filtering**: Advanced filtering system with type-safe field operations
|
|
12
|
+
- **Pagination**: Built-in pagination support with validation
|
|
13
|
+
- **Repository Pattern**: Abstract repository interface
|
|
14
|
+
- **Unit of Work**: Transaction management abstraction
|
|
15
|
+
- **Domain Events**: Event-driven architecture support
|
|
16
|
+
- **Exception Handling**: Domain-specific exception base classes
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @globalart/ddd
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Aggregate Root
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { AggregateRoot } from '@globalart/ddd';
|
|
30
|
+
|
|
31
|
+
class UserCreatedEvent {
|
|
32
|
+
constructor(public readonly userId: string, public readonly email: string) {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class User extends AggregateRoot<UserCreatedEvent> {
|
|
36
|
+
constructor(
|
|
37
|
+
public readonly id: string,
|
|
38
|
+
public readonly email: string,
|
|
39
|
+
public readonly name: string
|
|
40
|
+
) {
|
|
41
|
+
super();
|
|
42
|
+
this.addDomainEvent(new UserCreatedEvent(id, email));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Value Objects
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { ValueObject } from '@globalart/ddd';
|
|
51
|
+
|
|
52
|
+
class Email extends ValueObject<string> {
|
|
53
|
+
constructor(value: string) {
|
|
54
|
+
if (!this.isValidEmail(value)) {
|
|
55
|
+
throw new Error('Invalid email format');
|
|
56
|
+
}
|
|
57
|
+
super({ value });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private isValidEmail(email: string): boolean {
|
|
61
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Usage
|
|
66
|
+
const email = new Email('user@example.com');
|
|
67
|
+
const emailValue = email.unpack(); // 'user@example.com'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Commands and Queries
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { Command, Query } from '@globalart/ddd';
|
|
74
|
+
|
|
75
|
+
class CreateUserCommand extends Command {
|
|
76
|
+
constructor(
|
|
77
|
+
public readonly email: string,
|
|
78
|
+
public readonly name: string,
|
|
79
|
+
correlationId?: string
|
|
80
|
+
) {
|
|
81
|
+
super({ correlationId });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class GetUserQuery extends Query {
|
|
86
|
+
constructor(public readonly userId: string) {
|
|
87
|
+
super();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Specifications
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { CompositeSpecification } from '@globalart/ddd';
|
|
96
|
+
|
|
97
|
+
class UserEmailSpecification extends CompositeSpecification<User> {
|
|
98
|
+
isSatisfiedBy(user: User): boolean {
|
|
99
|
+
return user.email.includes('@');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
mutate(user: User): Result<User, string> {
|
|
103
|
+
return this.isSatisfiedBy(user)
|
|
104
|
+
? Ok(user)
|
|
105
|
+
: Err('Invalid email format');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
accept(visitor: ISpecVisitor): Result<void, string> {
|
|
109
|
+
return Ok(undefined);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Usage
|
|
114
|
+
const emailSpec = new UserEmailSpecification();
|
|
115
|
+
const isValid = emailSpec.isSatisfiedBy(user);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Filtering
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { StringFilter, NumberFilter, DateFilter } from '@globalart/ddd';
|
|
122
|
+
|
|
123
|
+
// String filtering
|
|
124
|
+
const nameFilter = new StringFilter('name', 'contains', 'john');
|
|
125
|
+
|
|
126
|
+
// Number filtering
|
|
127
|
+
const ageFilter = new NumberFilter('age', 'gte', 18);
|
|
128
|
+
|
|
129
|
+
// Date filtering
|
|
130
|
+
const createdFilter = new DateFilter('createdAt', 'after', new Date('2023-01-01'));
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Pagination
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { IPagination, paginationSchema } from '@globalart/ddd';
|
|
137
|
+
|
|
138
|
+
const pagination: IPagination = {
|
|
139
|
+
limit: 10,
|
|
140
|
+
offset: 0
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Validation
|
|
144
|
+
const result = paginationSchema.parse(pagination);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Repository Pattern
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { Repository } from '@globalart/ddd';
|
|
151
|
+
|
|
152
|
+
interface UserRepository extends Repository<User> {
|
|
153
|
+
findByEmail(email: string): Promise<User | null>;
|
|
154
|
+
findActiveUsers(): Promise<User[]>;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## API Reference
|
|
159
|
+
|
|
160
|
+
### Core Classes
|
|
161
|
+
|
|
162
|
+
- `AggregateRoot<E>` - Base class for domain aggregates
|
|
163
|
+
- `Command` - Base class for commands with correlation tracking
|
|
164
|
+
- `Query` - Base class for queries
|
|
165
|
+
- `ValueObject<T>` - Base class for value objects
|
|
166
|
+
- `CompositeSpecification<T>` - Base class for business rules
|
|
167
|
+
|
|
168
|
+
### Value Objects
|
|
169
|
+
|
|
170
|
+
- `Id` - UUID-based identifier
|
|
171
|
+
- `NanoId` - NanoID-based identifier
|
|
172
|
+
- `StringVO` - String value object
|
|
173
|
+
- `BooleanVO` - Boolean value object
|
|
174
|
+
- `DateVO` - Date value object
|
|
175
|
+
|
|
176
|
+
### Filtering
|
|
177
|
+
|
|
178
|
+
- `StringFilter` - String field filtering
|
|
179
|
+
- `NumberFilter` - Numeric field filtering
|
|
180
|
+
- `DateFilter` - Date field filtering
|
|
181
|
+
- `RootFilter` - Filter composition
|
|
182
|
+
|
|
183
|
+
### Utilities
|
|
184
|
+
|
|
185
|
+
- `IPagination` - Pagination interface
|
|
186
|
+
- `ISort` - Sorting interface
|
|
187
|
+
- `Repository<T>` - Repository interface
|
|
188
|
+
- `UnitOfWork` - Transaction management
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|
|
193
|
+
|
|
194
|
+
## Contributing
|
|
195
|
+
|
|
196
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|