Допустим, у нас есть модель с именем Label
const { Model } = require('objection')
class Label extends Model {
static get tableName() {
return "labels"
}
static get jsonSchema () {
return {
type: 'object',
required: [],
properties: {
id: { type: 'integer' },
name: { type: 'string' }
}
}
}
}
Теперь мы хотим получить последнюю метку в модели.
const label = await Label.query()
.orderby('id', 'desc')
.limit(1).first()
Хотя это дает нам последнюю метку, у нее есть несколько недостатков:
- это многословно
- Это требует слишком много повторного набора текста и, следовательно, подвержено ошибкам.
- Его сложнее проверить
- Это плохо читается
- И все становится только хуже, когда его используют в сочетании с другими методами.
Вот 3 подхода к этому:
- Модификаторы
- Обычный метод класса
- Пользовательский объект QueryBuilder
Давайте погрузимся в каждый из них один за другим.
Подход 1: Модификаторы
Модификаторы - мой предпочтительный способ решить эту проблему. Мы указываем функцию объекта модификаторов, которая:
- получает
query
в качестве параметра - затем он изменяет запрос, добавляя свои фильтры и т. д.
Label.modifiers.last = query => {
query.orderby('id', 'desc').limit(1).first()
}
Теперь давайте получим последнюю запись, используя этот модификатор
const label = await Label.query().modify('last')
Это читается намного лучше, вся логика инкапсулирована в одну функцию, и мы можем легко протестировать эту функцию.
Журналы показывают, что он работал:
select "labels".* from "labels" order by "id" DESC limit 1
С параметрами
Давайте создадим еще один модификатор, который получает все метки, начинающиеся с переданных букв.
Label.modifiers.startsWith = (query, letters) => {
query.where('name', 'like', `${letters}%`)
}
Теперь давайте запустим его
labels = await Label.query().modify('startsWith', 'XYYZ')
И журналы показывают:
select "labels".* from "labels" where "name" like "AC%"
Объединение нескольких функций модификатора
Именно здесь, я думаю, начинают проявляться функции-модификаторы, как и области действия в Rails.
Допустим, нам нужна последняя метка, начинающаяся с «А». Мы можем добиться этого, используя наши функции-модификаторы startsWith
и last
вместе.
const label = await Label.query().modify('startsWith','A').modify('last')
И в наших логах есть:
select "labels".* from "labels" where "name" like "A%" order by "id" DESC limit 1
Подход 2: метод класса на метке
Обычный статический метод класса Label. Мы можем заставить этот метод возвращать последнюю запись:
Label.last = () => {
return await Label.orderby('id', 'desc').limit(1).first()
}
Это выполняет свою работу, но не так хорошо, как функция-модификатор. Да, он хорошо читается и инкапсулирует работу, но он не возвращает объект запроса и, следовательно, не может быть связан
Подход 3: Пользовательский QueryBuilder
Мы можем создать наш пользовательский объект запроса и сделать так, чтобы класс метки использовал наш объект запроса. В нашем пользовательском объекте запроса мы можем определить пользовательские методы, которые напрямую изменяют объект query()
.
Это позволит нам изменить запрос, вызвав внутренний метод объекта запроса, не записывая слова modify
и явно не давая понять, что мы модифицируем запрос.
Давайте посмотрим пример:
class MyQueryBuilder extends QueryBuilder {
last () {
logger.info('inside last')
this.orderBy('id', 'desc').limit(1).first()
return this
}
}
class Label exteds Model {
static get QueryBuilder () {
return MyQueryBuilder
}
}
Теперь, чтобы использовать его:
cons label = await Label.query().last()
Я считаю такой подход злоупотреблением властью. Это работает, но у нас есть более чистый способ изменения запроса, и мы должны сделать это вместо того, чтобы определять пользовательский объект запроса, который имеет специальные внутренние методы.
Я думаю, что этот пользовательский класс запросов может иметь хорошие варианты использования для других вещей, таких как ведение журнала, выполнение некоторых других вызовов службы и т. д.
Вывод
modifiers
великолепны. возможность связать их в цепочку делает их активом.
Что дальше
Используйте модификаторы со сложными запросами, которые используют:
- присоединиться
- graphFetch (нетерпеливая загрузка)
- используйте
ref
там, где у нас есть неоднозначные имена таблиц
Первоначально опубликовано на https://sandeep45.github.io.