Кастомные методы
Kodzero SDK позволяет расширять модели собственными методами для реализации бизнес-логики.
Регистрация метода
Используйте статический метод registerMethod() для добавления кастомных методов к модели:
typescript
Model.registerMethod('methodName', function() {
// Внутри метода доступен this — экземпляр модели
const data = this.data()
// ...
})Простой пример
typescript
interface Car {
_id: string | null
make: string
model: string
year: number
}
const Car = kodzero.createModel<Car>({
collection: 'cars'
})
// Регистрируем кастомный метод
Car.registerMethod('getDescription', function() {
const data = this.data()
return `${data.make} ${data.model} (${data.year})`
})
// Использование
const car = await Car.get('car_id')
console.log(car.getDescription())
// "Toyota Corolla (2020)"Типизация кастомных методов
Для полной поддержки TypeScript создайте интерфейс для кастомных методов:
typescript
// Интерфейс данных
interface Car {
_id: string | null
make: string
model: string
year: number
price: number
}
// Интерфейс кастомных методов
interface CarMethods {
getDescription: () => string
isVintage: () => boolean
applyDiscount: (percent: number) => number
}
// Создаём модель с обоими типами
const Car = kodzero.createModel<Car, CarMethods>({
collection: 'cars'
})
// Регистрируем методы
Car.registerMethod('getDescription', function() {
const data = this.data()
return `${data.make} ${data.model} (${data.year})`
})
Car.registerMethod('isVintage', function() {
return this.data().year < 1980
})
Car.registerMethod('applyDiscount', function(percent: number) {
const price = this.data().price
return price - (price * percent / 100)
})
// Теперь TypeScript знает о кастомных методах
const car = await Car.get('car_id')
car.getDescription() // ✅ TypeScript знает тип возвращаемого значения
car.isVintage() // ✅
car.applyDiscount(10) // ✅
car.unknownMethod() // ❌ Ошибка компиляцииПрактические примеры
Форматирование данных
typescript
interface User {
_id: string | null
firstName: string
lastName: string
email: string
}
interface UserMethods {
getFullName: () => string
getInitials: () => string
formatEmail: () => string
}
const User = kodzero.createModel<User, UserMethods>({
collection: 'users'
})
User.registerMethod('getFullName', function() {
const { firstName, lastName } = this.data()
return `${firstName} ${lastName}`
})
User.registerMethod('getInitials', function() {
const { firstName, lastName } = this.data()
return `${firstName[0]}${lastName[0]}`.toUpperCase()
})
User.registerMethod('formatEmail', function() {
return this.data().email.toLowerCase()
})Вычисляемые свойства
typescript
interface Order {
_id: string | null
items: Array<{ name: string; price: number; quantity: number }>
discount: number
}
interface OrderMethods {
getSubtotal: () => number
getDiscount: () => number
getTotal: () => number
getItemCount: () => number
}
const Order = kodzero.createModel<Order, OrderMethods>({
collection: 'orders'
})
Order.registerMethod('getSubtotal', function() {
return this.data().items.reduce((sum, item) => {
return sum + (item.price * item.quantity)
}, 0)
})
Order.registerMethod('getDiscount', function() {
const subtotal = this.getSubtotal()
return subtotal * (this.data().discount / 100)
})
Order.registerMethod('getTotal', function() {
return this.getSubtotal() - this.getDiscount()
})
Order.registerMethod('getItemCount', function() {
return this.data().items.reduce((count, item) => count + item.quantity, 0)
})
// Использование
const order = await Order.get('order_id')
console.log('Подитог:', order.getSubtotal())
console.log('Скидка:', order.getDiscount())
console.log('Итого:', order.getTotal())
console.log('Товаров:', order.getItemCount())Бизнес-логика
typescript
interface Task {
_id: string | null
title: string
status: 'pending' | 'in_progress' | 'completed'
priority: 'low' | 'medium' | 'high'
dueDate: string
}
interface TaskMethods {
isOverdue: () => boolean
isHighPriority: () => boolean
canComplete: () => boolean
getStatusLabel: () => string
}
const Task = kodzero.createModel<Task, TaskMethods>({
collection: 'tasks'
})
Task.registerMethod('isOverdue', function() {
const dueDate = new Date(this.data().dueDate)
return dueDate < new Date() && this.data().status !== 'completed'
})
Task.registerMethod('isHighPriority', function() {
return this.data().priority === 'high'
})
Task.registerMethod('canComplete', function() {
return this.data().status !== 'completed'
})
Task.registerMethod('getStatusLabel', function() {
const labels = {
pending: 'Ожидает',
in_progress: 'В работе',
completed: 'Завершена'
}
return labels[this.data().status]
})
// Использование
const tasks = await Task.findMany()
const overdueTasks = tasks.filter(async (taskData) => {
const task = await Task.get(taskData._id)
return task.isOverdue()
})Доступ к данным в методах
Внутри кастомного метода:
this.data()— получить текущие данныеthis.set(key, value)— изменить данныеthis.save()— сохранить измененияthis.update()— обновить документthis.delete()— удалить документthis.validate()— валидировать данные
typescript
interface Product {
_id: string | null
name: string
price: number
stock: number
}
interface ProductMethods {
reduceStock: (quantity: number) => Promise<void>
isInStock: () => boolean
}
const Product = kodzero.createModel<Product, ProductMethods>({
collection: 'products'
})
Product.registerMethod('reduceStock', async function(quantity: number) {
const currentStock = this.data().stock
if (currentStock < quantity) {
throw new Error('Недостаточно товара на складе')
}
this.set('stock', currentStock - quantity)
await this.update()
})
Product.registerMethod('isInStock', function() {
return this.data().stock > 0
})
// Использование
const product = await Product.get('product_id')
if (product.isInStock()) {
await product.reduceStock(5)
}