Рубрики
Без рубрики

Booksheld.js: Node.js Orm

Автор оригинала: Scott Robinson.

Одним из наиболее распространенных ресурсов, с которыми вы взаимодействуете на языке, похожему на Node.js (в первую очередь, язык, ориентированный на веб-баз данных. А с SQL, являющимся наиболее распространенным из всех различных типов, вам понадобится хорошая библиотека, чтобы помочь вам взаимодействовать с ней и ее многочисленными функциями.

Booksheld.js является одним из самых популярных из пакетов ORM Node.js. Это связано с Knex.js , который является гибким строителем запроса, который работает с PostgreSQL, MySQL и SQLite3. Bookshelf.js Создается на вершине этого путем предоставления функциональности для создания моделей данных, формирующих отношения между этими моделями, а другие общие задачи, необходимые при запросе базы данных.

Книжная полка также поддерживает несколько заканчиваемых базы данных, например MySQL , PostgreSQL и SQLite Отказ Таким образом, вы можете легко переключать базы данных при необходимости или использовать меньшую БД, как SQLite во время разработки и PostGre в производстве.

На протяжении всей этой статьи я покажу вам, как максимально получить из этого узла ORM, включая подключение к базе данных, создание моделей и сохранения объектов/загрузки объектов.

Установить книжную полку

Книжная полка немного отличается от большинства узел в том, что он не устанавливает все его зависимости для вас автоматически. В этом случае вы должны вручную установить KNEX наряду с книжной полкой:

$ npm install knex --save
$ npm install bookshelf --save

В дополнение к этому, вам нужно выбрать, какую базу данных вы захотите использовать книжную полку. Ваш выбор:

Они могут быть установлены с:

$ npm install pg --save
$ npm install mysql --save
$ npm install mariasql --save
$ npm install sqlite3 --save

Одна вещь, которую я склонен делать с моими проектами, устанавливает DB-класс производства (например, Postgre), используя --save , при использовании --save-dev Для меньшего БД, как SQLite для использования во время развития.

$ npm install pg --save
$ npm install sqlite3 --save-dev

Таким образом, мы можем легко переключаться между базами данных в производстве и развитии без необходимости беспокоиться о затоплении моей производственной среды с ненужными зависимостями.

Подключение к базе данных

Все функции нижнего уровня, такие как подключение к базе данных, обрабатываются базовой библиотекой Knex. Итак, естественно, для инициализации вашего книжная полка Экземпляр вам нужно создать Knex Экземпляр во-первых, как это:

var knex = require('knex')({
    client: 'sqlite3',
    connection: {
        filename: './db.sqlite'
    }
});

var bookshelf = require('bookshelf')(knex);

И теперь вы можете использовать книжная полка экземпляр для создания ваших моделей.

Настройка таблиц

Knex, как свои собственные состояния веб-сайта, это «батареи включали» SQL Sureder Suilder, поэтому вы можете сделать практически во что-либо через Knex, которые вы хотите сделать с RAW SQL. Одной из этих важных особенностей является создание и манипуляция таблиц. KNEX можно использовать непосредственно для настройки вашей схемы в базе данных (думайте, что инициализация базы данных, миграция схемы и т. Д.).

Итак, прежде всего, вы захотите создать свой стол, используя Knex.schema.Createtable () , который создаст и вернет табличный объект, который содержит кучу Схема здания Функции, как table.ruements () , Table.String () и table.date () Отказ Для каждой модели вы создаете, вам нужно сделать что-то подобное для каждого:

knex.schema.createTable('users', function(table) {
    table.increments();
    table.string('name');
    table.string('email', 128);
    table.string('role').defaultTo('admin');
    table.string('password');
    table.timestamps();
});

Здесь вы можете увидеть, что мы создаем таблицу под названием «пользователи», которые мы затем инициализируем с столбцами «Name», «Email», «роль» и «пароль». Мы даже можем сделать его еще раз и указать максимальную длину колонны строки (128 для столбца «Email») или значение по умолчанию («admin» для столбца «Роль»).

Некоторые удобные функции также предоставляются, как Timestamps () Отказ Эта функция добавит две столбцы Timestamp в таблицу, Create_at и updated_at Отказ Если вы используете это, рассмотрите также установить Hastimestamps недвижимость на правда В вашей модели (см. «Создание модели» ниже).

Есть несколько дополнительных вариантов, вы можете указать для каждой таблицы/столбца, поэтому я определенно рекомендую проверить полный Документация KNEX Больше подробностей.

Создание модели

Один из моих волок о книжной полке – это то, что вам всегда нужна инициализированная книжная полка Экземпляр для создания модели, поэтому структурирование некоторых приложений может быть немного грязной, если вы сохраните все свои модели в разных файлах. Лично я предпочитаю просто сделать книжная полка глобальный с использованием Global.Bookfhelf , но это не обязательно лучший способ сделать это.

Во всяком случае, давайте посмотрим, что нужно для создания простой модели:

var User = bookshelf.Model.extend({
    tableName: 'users',
    hasTimestamps: true,

    verifyPassword: function(password) {
        return this.get('password') === password;
    }
}, {
    byEmail: function(email) {
        return this.forge().query({where:{ email: email }}).fetch();
    }
});

Здесь у нас есть довольно простая модель, чтобы продемонстрировать некоторые доступные функции. Прежде всего, Только Требуемое свойство - Табличное значение

Что касается остальных свойств/функций, вот быстрое подкладка того, что Пользователь включает:

  • Табличное значение : Строка, которая сообщает модели, где сохранять и загружать данные из дБ (обязательно)
  • Hastimestamps : Логическое значение, рассказывая модели, нужна ли нам Create_at и updated_at метки времени
  • VerifyPassword : Функция экземпляра
  • BYEMAIL : Функция класса (статическая)

Так, например, мы будем использовать BYEMAIL Как более короткий способ запросить пользователь по адресу электронной почты:

User.byEmail('[email protected]').then(function(u) {
    console.log('Got user:', u.get('name'));
});

Обратите внимание, как вы получаете доступ к данным модели на книжной полке. Вместо того, чтобы использовать прямое свойство (например u.name ), мы должны использовать .get () метод.

Поддержка ES6

По состоянию на время этого письма книжная полка не имеет полной поддержки ES6 (см. этот вопрос ). Тем не менее, вы все еще можете написать большую часть вашего моделей, используя новые классы ES6. Используя модель сверху, мы можем повторно создать его, используя новые Класс Синтаксис, как это:

class User extends bookshelf.Model {
    get tableName() {
        return 'users';
    }

    get hasTimestamps() {
        return true;
    }

    verifyPassword(password) {
        return this.get('password') === password;
    }

    static byEmail(email) {
        return this.forge().query({where:{ email: email }}).fetch();
    }
}

И теперь эта модель может быть использована точно так же, как и раньше. Этот метод не даст вам никаких функциональных преимуществ, но для некоторых людей более знакомы, поэтому воспользуйтесь этим, если вы хотите.

Коллекции

На книжной полке вам также необходимо создать отдельный объект для коллекций данной модели. Так что, если вы хотите выполнить операцию на нескольких Пользователь S В то же время, например, вам нужно создать Коллекция Отказ

Продолжая с нашим примером сверху, вот как мы создадим Пользователи Коллекция объект:

var Users = bookshelf.Collection.extend({
    model: User
});

Довольно просто, верно? Теперь мы можем легко запросить все пользователи (хотя это было уже возможно с помощью модели, используя .Fetchall () ):

Users.forge().fetch().then(function(users) {
    console.log('Got a bunch of users!');
});

Даже лучше, теперь мы можем использовать несколько приятных способов модели в коллекции в целом, а не на необходимость итерации по каждой модели индивидуально. Один из этих методов, которые, кажется, получают много использования, особенно в веб-приложениях, это .tojson () :

exports.get = function(req, res) {
    Users.forge().fetch().then(function(users) {
        res.json(users.toJSON());
    });
};

Это возвращает простой объект JavaScript всей коллекции.

Расширение ваших моделей

Как разработчик, один из самых важных принципов, которые я следовал, является Сухой (Не повторяйте себя) Принцип. Это только одна из многих причин, почему расширение модели/схемы настолько важно для вашего дизайна программного обеспечения.

Использование книжной полки .exend () Способ, вы можете наследовать все свойства, методы экземпляра и методы классов базовой модели. Таким образом, вы можете создать и воспользоваться базовыми методами, которые еще не предусмотрены, например .find () , .findone () , так далее.

Один из величайших примеров расширения модели находится в Bookshelf-ModelBase Проект, который предоставляет многие из пропущенных методов, которые вы ожидаете прийти стандарт в большинстве ОРМ.

Если вы должны были создать свою собственную простую базовую модель, это может выглядеть так:

var model = bookshelf.Model.extend({
    hasTimestamps: ['created_at', 'updated_at'],
}, {
    findAll: function(filter, options) {
        return this.forge().where(filter).fetchAll(options);
    },

    findOne: function(query, options) {
        return this.forge(query).fetch(options);
    },

    create: function(data, options) {
        return this.forge(data).save(null, options);
    },
});

Теперь все ваши модели могут воспользоваться этими полезными методами.

Сохранение и обновление моделей

Существует пара разных способов сохранения моделей в книжной полке в зависимости от ваших предпочтений и формата ваших данных.

Первый, и самый очевидный способ, чтобы просто позвонить .save () на экземпляре модели.

var user = new User();
user.set('name', 'Joe');
user.set('email', '[email protected]');
user.set('age', 28);

user.save().then(function(u) {
    console.log('User saved:', u.get('name'));
});

Это работает для модели, которую вы создаете сами (например, приведенные выше) или с экземплярами модели, которые возвращаются вам из звонка запроса.

Другой вариант – использовать .FORGE () метод и инициализировать его с данными. «Forge» – это действительно просто сложный путь для создания новой модели (например, Новый пользователь () ). Но таким образом вам не нужна дополнительная линия для создания модели перед запуском строки запроса/сохранения.

Использование .FORGE () Вышеуказанный код будет выглядеть так:

var data = {
    name: 'Joe',
    email: '[email protected]',
    age: 28
}

User.forge(data).save().then(function(u) {
    console.log('User saved:', u.get('name'));
});

Это не сэкономит вам какие-либо строки кода, но это может быть удобно, если данные на самом деле входит JSON или что-то в этом роде.

Модели загрузки

Здесь я расскажу о том, как загружать модели из базы данных с помощью книжной полки.

В то время как .FORGE () На самом деле не помогал нам так много в сохранении документов, это, безусловно, помогает в загрузке их. Было бы немного неловко создать пустой экземпляр модели, чтобы загрузить данные из базы данных, поэтому мы используем .FORGE () вместо.

Самый простой пример загрузки – просто получить одну модель, используя .fetch () :

User.forge({email: '[email protected]'}).fetch().then(function(user) {
    console.log('Got user:', user.get('name'));
});

Все, что мы делаем здесь, схватывает одну модель, которая соответствует данному запросу. Как вы можете себе представить, запрос может быть таким сложным, как вы хотели бы (например, ограничения на имя и age колонны).

Так же, как в простых старом SQL, вы можете значительно настроить запрос и возвращаемые данные. Например, этот запрос даст нам только данные, которые нам нужно аутентифицировать пользователя:

var email = '...';
var plainTextPassword = '...';

User.forge({email: email}).fetch({columns: ['email', 'password_hash', 'salt']})
.then(function(user) {
    if (user.verifyPassword(plainTextPassword)) {
        console.log('User logged in!');
    } else {
        console.log('Authentication failed...');
    }
});

Принимая это еще дальше, мы можем использовать утром Опция автоматически загружать связанные модели, которые мы увидим в следующем разделе.

Модель отношения

Во многих приложениях ваши модели должны будут обратиться к другим моделям, которые достигаются в SQL с использованием внешних ключей. Простая версия этого поддерживается в книжной полке через отношения.

В рамках вашей модели вы можете точно сказать, как именно другие модели связаны друг с другом. Это достигается с использованием Приятно () , Hasmany () и Hasone () (среди других) методы.

Итак, скажем, у вас есть две модели, пользователь и адрес. Пользователь может иметь несколько адресов (один для доставки, один для выставления счетов и т. Д.), Но адрес может принадлежать только одному пользователю. Учитывая это, мы могли бы установить наши модели как это:

var User = bookshelf.Model.extend({
    tableName: 'users',
    
    addresses: function() {
        return this.hasMany('Address', 'user_id');
    },
});

var Address = bookshelf.Model.extend({
    tableName: 'addresses',
    
    user: function() {
        return this.belongsTo('User', 'user_id');
    },
});

Обратите внимание, что я использую Реестр плагин Здесь, что позволяет мне обратиться к адресной модели со строкой.

Hasmany () и Приятно () Методы сообщают книгу, как каждая модель связана друг с другом. Пользователь «имеет много» адресов, а адрес «принадлежит« одному пользователю ». Второй аргумент – это имя столбца, которое указывает местоположение ключа модели. В этом случае оба Ссылка моделей user_id столбец в адресной таблице.

Теперь мы можем воспользоваться этим отношением, используя утолщенный Опция на .fetch () методы. Так что, если я хотел загрузить пользователь и Все их адреса с одним звонком, я мог бы просто сделать:

User.forge({email: '[email protected]'}).fetch({withRelated: ['addresses']})
.then(function(user) {
    console.log('Got user:', user.get('name'));
    console.log('Got addresses:', user.related('addresses'));
});

Если бы мы были получить модель пользователя без утолщенный Вариант тогда user.related («адреса») просто вернется пустой объект сбора.

Обязательно воспользуйтесь этими методами соотношения, они гораздо легче использовать, чем создание собственного SQL Joins:)

Добро

Книжная полка – одна из тех библиотек, которые, кажется, пытаются не стать чрезмерно раздутым и просто прилипают к основным функциям. Это здорово, потому что функции, которые являются Там работает очень хорошо.

Книжная полка также имеет приятный, мощный API, который позволяет вам легко создавать свое приложение поверх него. Таким образом, вам не нужно бороться с методами высокого уровня, которые сделали плохие предположения о том, как они будут использоваться.

Плохо

Пока я думаю, что приятно, что книжная полка/Knex предоставляет вам некоторые функции более низкого уровня, я все еще думаю, что есть место для улучшения. Например, все настройки таблицы/схемы остаются в зависимости от вас, и нет простого способа указать свою схему (например, в простом объекте JS) в модели. Настройка таблицы/схемы должна быть указана в вызовах API, что не так просто читать и отладки.

Еще одна боя боя – это то, как они покинули многие из методов помощника, которые должны прийти стандартными с базовой моделью, например .create () , .findone () , .upsert () и проверка данных. Это именно поэтому я упомянул Bookshelf-ModelBase Проект ранее, поскольку он заполняет многие из этих пробелов.

Заключение

В целом я стал довольно поклонником использования книжной полки/Knex для работы SQL, хотя я думаю, что некоторые из проблем, которые я только что упомянул, может быть отключенным для многих разработчиков, которые используются для использования ОРМ, которые делают только для всего для их из коробки. С другой стороны, для других разработчиков, которые любят иметь много контроля, это идеальная библиотека для использования.

Хотя я попытался охватить как можно больше основных API в этой статье, есть еще несколько функций, на которых я не прикоснулся, поэтому обязательно проверьте Проектная документация для получения дополнительной информации.

Вы использовали bookshelf.js или knex.js? Как вы думаете? Дайте нам знать об этом в комментариях!