Допустим, у нас есть модель с именем 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()

Хотя это дает нам последнюю метку, у нее есть несколько недостатков:

  1. это многословно
  2. Это требует слишком много повторного набора текста и, следовательно, подвержено ошибкам.
  3. Его сложнее проверить
  4. Это плохо читается
  5. И все становится только хуже, когда его используют в сочетании с другими методами.

Вот 3 подхода к этому:

  1. Модификаторы
  2. Обычный метод класса
  3. Пользовательский объект QueryBuilder

Давайте погрузимся в каждый из них один за другим.

Подход 1: Модификаторы

Модификаторы - мой предпочтительный способ решить эту проблему. Мы указываем функцию объекта модификаторов, которая:

  1. получает query в качестве параметра
  2. затем он изменяет запрос, добавляя свои фильтры и т. д.
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.