README
@alt-point/active-models
Пакет с базовыми классами на es6/TS для упрощения работы со структурами данных.
Какие проблемы поможет решить?
- Реализовать модели данных с реактивными свойствами (
ActiveModel); - Контролировать целостность структур данных (
ActiveModel.fillable,ActiveModel.hidden,ActiveModel.protected); - Контролировать тип и целостность данных в каждом конкретном свойстве в рантайме;
Installation
yarn
yarn add @alt-point/active-models
npm
npm install --save @alt-point/active-models
ActiveModel
Класс реализован с использованием Proxy.
Назначение: контроль целостности структуры и типов данных моделей приходящих из внешних источников/подсистем (DTO)
Пример, иллюстрирующий применение, пример с декораторами
Есть 2 стула 2 варианта, либо использовать статическое api, либо юзать декораторы:
@Decorators
@ActiveField(opts: ActiveFieldDescriptor)
type ActiveFieldDescriptor = object & {
setter?: Setter<any> // ассессор на установку значения
getter?: Getter<any> // ацессор на получение значения
validator?: Validator<any> // валидатор на установку значения
readonly?: boolean // поле модели будет доступно только на чтение
hidden?: boolean // поле скрыто из перечисляемых свойств
fillable?: boolean // поле доступно для установки и изменения
protected?: boolean // запрещено удалять поле из модели
attribute?: any // Значение по умолчанию для поля модели в момент создания объекта
value?: any // алиас для `attribute`
}
Notice:
Для того, что бы были задействованы атрибуты (значения по умолчанию для полей модели) необходимо создавать экземпляр модели через фабричный метод
ActiveModel.create(data), либо же определить логику установки значений в конструкторе явно, например такclass SomeModeal extends ActiveModel { constructor (data?: any) { super(data) if (data) { this.fill(data) } } }
Static Api:
static get $attributes
Default value: {}
Description: Структура объекта по умолчанию, а так же значения свойств по умолчанию. Даже если значение не
передано в data в конструкторе, будет установлено из $attributes
Example:
static get $attributes () {
return {
id: '',
login: '',
password: '',
createdAt: ''
}
}
static get fillable
Default value: []
Description: Массив имён свойств, которые могут быть установлены через конструктор. Если массив пуст, то можно устанавливать любые свойства. Если массив заполнен, то в модель можно установить только перечисленные свойства и их значения.
Example:
static get fillable () {
return [
'id',
'password',
'property',
'createdAt'
]
}
static protected
Default value: []
Description: Массив имён свойств, которые запрещено удалять у объекта, если массив пустой, то удалять можно любые свойства.
Example:
static get protected () {
return [
'id',
'login',
'password',
'createdAt'
]
}
static hidden
Default value: []
Description: Массив имён свойств, которые не должны быть перечисляемыми, а следовательно и не будут попадать в вывод Object.keys, Reflect.ownKeys, JSON.stringify, etc.
Example:
static get hidden () {
return [
'password'
]
}
static setter${PascalPropertyName}(model, prop, value, receiver)
Description: Для того что бы определить сеттер для свойства модели необходимо добавить классу, унаследованному от ActiveModel
статический метод с префиксом setter + имя в PascalCase свойства (разделители [-_.+*/:? ] не будут учитываться)
Example:
static setterMyIntegerPropertyName (model, prop, value = 0, receiver) {
Reflect.set(model, prop, Number.parseInt(value), receiver)
}
static getter{PascalPropertyName}(model, prop)
Description: Для того что бы определить геттер для свойства модели необходимо добавить классу, унаследованному от ActiveModel
статический метод с префиксом getter + имя в PascalCase свойства (разделители [-_.+*/:? ] не будут учитываться)
Example:
static getterGoodsSumWeight (model) {
return model.goods.reduce((a, { weight }) => a + weight, 0)
}
static sanitize(data)
Description: Статический метод преобразования/очистки данных переданных в конструктор.
По умолчанию возвращает lodash.cloneDeep(data).
CallableModel
Базовый класс, реализованный также через Proxy, чтобы можно было обращаться с объектом как с функцией.
Пример использования:
import { CallableModel } from '@alt-point/active-models'
class Notify extends CallableModel {
// Define
__call (...args) {
return this.success(...args)
}
success (successMessage) {
alert(successMessage)
}
silent (message) {
console.log('Silent message:' + message)
}
}
Дальше можем создать объект класса Notify как плагин в Nuxt.js/Vue.js и использовать:
// плагин
export default (ctx, inject) => {
ctx.$notify = new Notify()
inject('notify', new Notify())
}
// в компоненте теперь можно юзать:
this.$notify.silent('Write notice to console!')
this.$notify('Alert!')
Enum
enum реализованный на Map
const OrderStatuses = new Enum(['new', 'complete', 'shipping'], 'new')
OrderStatuses.values() // ['new', 'complete', 'shipping']
OrderStatuses.validate('G-gurda') // throw Value must be include one of type: new, complete, 'shipping; Provide value "G-gurda"
OrderStatuses.default // 'new'
TODO:
- Добавить больше примеров использования;
- Тесты;
- TS;
- Добавить примеры использования моделей на
node.js; - Translate to english and others languages;