@nx-ddd/firestore
v19.2.1
Published
A Firestore adapter for @nx-ddd/core that provides seamless integration with Firebase Cloud Firestore.
Readme
@nx-ddd/firestore
A Firestore adapter for @nx-ddd/core that provides seamless integration with Firebase Cloud Firestore.
Installation
npm install @nx-ddd/firestoreFeatures
1. Repository Implementation
import { FirestoreRepository } from '@nx-ddd/firestore';
@Injectable()
export class UserFirestoreRepository extends FirestoreRepository<User> implements UserRepository {
constructor(firestore: Firestore) {
super(firestore, 'users');
}
async findByEmail(email: string): Promise<User | null> {
const snapshot = await this.collection
.where('email', '==', email)
.limit(1)
.get();
return this.toEntity(snapshot.docs[0]);
}
}2. Entity Mapping
import { FirestoreEntity } from '@nx-ddd/firestore';
@FirestoreEntity({
collection: 'users',
converters: {
createdAt: FirestoreTimestampConverter,
updatedAt: FirestoreTimestampConverter
}
})
export class User extends Entity {
constructor(
id: ID,
public readonly email: string,
public readonly name: string,
public readonly createdAt: Date,
public readonly updatedAt: Date
) {
super(id);
}
}3. Transaction Support
import { FirestoreTransactional } from '@nx-ddd/firestore';
@Injectable()
export class UserService {
constructor(private readonly firestore: Firestore) {}
@FirestoreTransactional()
async createUserWithProfile(data: UserData): Promise<void> {
const user = new User(/* ... */);
const profile = new Profile(/* ... */);
await this.userRepository.save(user);
await this.profileRepository.save(profile);
}
}4. Query Building
import { FirestoreQueryBuilder } from '@nx-ddd/firestore';
@Injectable()
export class UserQueryService {
constructor(private readonly builder: FirestoreQueryBuilder) {}
async findActiveUsers(): Promise<User[]> {
return this.builder
.collection('users')
.where('status', '==', 'active')
.orderBy('lastLoginAt', 'desc')
.limit(10)
.execute();
}
}Advanced Features
1. Batch Operations
import { FirestoreBatch } from '@nx-ddd/firestore';
@Injectable()
export class UserBatchService {
constructor(private readonly batch: FirestoreBatch) {}
async deactivateUsers(userIds: string[]): Promise<void> {
this.batch.begin();
for (const id of userIds) {
this.batch.update(`users/${id}`, { status: 'inactive' });
}
await this.batch.commit();
}
}2. Real-time Updates
import { FirestoreObservable } from '@nx-ddd/firestore';
@Injectable()
export class UserStreamService {
constructor(private readonly observable: FirestoreObservable) {}
watchUserChanges(userId: string): Observable<User> {
return this.observable
.document(`users/${userId}`)
.valueChanges()
.pipe(
map(data => new User(data))
);
}
}3. Sub-collections
import { FirestoreSubCollection } from '@nx-ddd/firestore';
@Injectable()
export class UserDocumentRepository extends FirestoreRepository<UserDocument> {
constructor(firestore: Firestore) {
super(firestore, 'users/:userId/documents');
}
async findUserDocuments(userId: string): Promise<UserDocument[]> {
return this.find({ userId });
}
}Best Practices
- Use repository pattern for data access
- Implement proper error handling
- Use transactions for atomic operations
- Leverage batch operations for bulk updates
- Consider real-time updates when appropriate
- Structure collections and sub-collections carefully
- Implement proper security rules
License
MIT
