bookshelf.js笔记

0 简介

bookshelf是一个JS库,用于处理数据库请求,原理是ORM(对象关系映射)。

1 ORM

ORM是一种将关系型数据库对象化的方法,可以屏蔽底层异构的数据库类型。

2 关联

和关系型数据库的实体关系类似,bookshelf的models之间的关系有一对一,一对多,多对多。

2.1 一对一

一对一的关系通过belongsTohasOnemorphOne来定义。

var Book = bookshelf.Model.extend({
  tableName: 'books',
  summary: function() {
    return this.hasOne(Summary);
  }
});

var Summary = bookshelf.Model.extend({
  tableName: 'summaries',
  book: function() {
    return this.belongsTo(Book);
  }
});

2.2 一对多

一对多的关系通过belongsTohasManymorphMany /morphTothrough定义。

var Book = bookshelf.Model.extend({
  tableName: 'books',
  pages: function() {
    return this.hasMany(Page);
  }
});

var Page = bookshelf.Model.extend({
  tableName: 'pages',
  book: function() {
    return this.belongsTo(Book);
  }
});

2.3 多对多

多对多的关系通过belongsToManythrough定义。

var Book = bookshelf.Model.extend({
  tableName: 'books',
  authors: function() {
    return this.belongsToMany(Author);
  }
});

var Author = bookshelf.Model.extend({
  tableName: 'authors',
  books: function() {
    return this.belongsToMany(Book);
  }
});

2.4 Polymorphic(多态关系)

这种关系下,一个model可以属于多个model。

var Site = bookshelf.Model.extend({
  tableName: 'sites',
  photo: function() {
    return this.morphOne(Photo, 'imageable');
  }
});

var Post = bookshelf.Model.extend({
  tableName: 'posts',
  photos: function() {
    return this.morphMany(Photo, 'imageable');
  }
});

var Photo = bookshelf.Model.extend({
  tableName: 'photos',
  imageable: function() {
    return this.morphTo('imageable', Site, Post);
  }
});

列名最好是用下划线的格式命名。

3 Bookshelf类

bookshelf对象的实例化,需要传入一个knex实例作为参数。

3.1 构造方法

new Bookshelf(knex)

3.2 成员

bookshelf.knex

返回被引用的knex实例

3.3 方法

bookshelf.transaction(transactionCallback)

返回事务处理回调函数的Promise实例

4 Model类

model通过指定表名以及与其他model的关系来表示单个数据库表(原文为individual database rows,不知道怎么翻译更好),可以通过特定的方法扩展。

4.1 构造方法

new Model (attributes, [options])

attributes,用于初始化model的属性
[options],指定表名,时间戳,解析器等

4.2 静态方法

Model.collection([models],[options])

实例化Collection对象,将当前model设置为collection的目标
返回Collection对象

Model.count([column],[options])

返回查找到的记录的数量。

Model.extend([prototypeProperties],[classProperties])

用于扩展bookshelf.Model类,扩展的方法都是直接定义在原型链上,子类可以继续扩展。

var checkit  = require('checkit');
var Promise  = require('bluebird');
var bcrypt   = Promise.promisifyAll(require('bcrypt'));

var Customer = bookshelf.Model.extend({
  initialize: function() {
    this.on('saving', this.validateSave);
  },

  validateSave: function() {
    return checkit(rules).run(this.attributes);
  },

  account: function() {
    return this.belongsTo(Account);
  },
}, {
  login: Promise.method(function(email, password) {
    if (!email || !password) throw new Error('Email and password are both required');
    return new this({email: email.toLowerCase().trim()}).fetch({require: true}).tap(function(customer) {
      return bcrypt.compareAsync(password, customer.get('password'))
        .then(function(res) {
          if (!res) throw new Error('Invalid password');
        });
    });
  })
});

Customer.login(email, password)
  .then(function(customer) {
    res.json(customer.omit('password'));
  }).catch(Customer.NotFoundError, function() {
    res.json(400, {error: email + ' not found'});
  }).catch(function(err) {
    console.error(err);
  });
Model.fetchAll()

获取给定model的全部实例

Model.forge([attributes], [options])

用于实例化Model的函数

4.3 成员

model.hasTimestamps

用于设置created_atupdated_at属性,如果要修改默认的列名,则传入一个数组,第一个元素用于替换created_at,第二个元素用于替换updated_at

hasTimestamps: ['createdAt', 'updatedAt']
model.idAttribute

用于指定唯一键

model.tableName

用于指定model对应的数据库表名,不可缺省

4.4 方法

官方文档仅仅按字母顺序罗列了所有的方法,我按照各个方法的用途大致将其归类如下:

  • 用于定义关系
  • 用于操作数据库
  • 用于操作属性
  • 用于操作model
  • 用于事件处理

4.4.1 用于定义关系的方法

model.hasOne(Target, [foreignKey])

用于定义一对一的关系。
Target,用于指明要关联的model
foreignKey,用于指明Target model的外键
返回Model

model.hasMany(Target, [foreignKey])

用于定义一对多的关系。
Target,用于指明要关联的model
foreignKey,用于指明Target model的外键
返回Collection

model.belongsTo(Target, [foreignKey])

用于和hasOne以及hasMany搭配使用。
Target用于指定与之产生关联的另一个model
foreignKey用于指定外键
返回model

model.belongsToMany(Target, [table], [foreignKey], [otherKey])

用于定义多对多的关系,即当前model通过(through)其他表与一个或多个Target关联(join)。
Target,用于指明与当前model关联的model
table,用于指明相互关联的那张表
foreignKey,用于指明当前model的外键
otherKey,用于指明Target model的外键
返回Collection对象

当相互关联的那张表有主键或是其他一些信息时,可以使用through

let Doctor = bookshelf.Model.extend({
  patients: function() {
    return this.belongsToMany(Patient).through(Appointment);
  }
});

let Appointment = bookshelf.Model.extend({
  patient: function() {
    return this.belongsTo(Patient);
  },
  doctor: function() {
    return this.belongsTo(Doctor);
  }
});

let Patient = bookshelf.Model.extend({
  doctors: function() {
    return this.belongsToMany(Doctor).through(Appointment);
  }
});
model.morphOne(Target, [name], [columnNames], [morphValue])

用于

model.morphTo(name, [columnNames], …Target)
model.morphMany(Target, [name], [columnNames], [morphValue])
model.through(Interim, [throughForeignKey], [otherKey])

4.4.2 用于操作数据库的方法

model.count([column], [options])

column默认为*
对查询到的记录计数。
需要在query之后调用。

model.destroy([options])

用于执行delete操作,用model的主键作为删除的约束条件。

会触发destroyingdestroyed事件。

[options]

  • [transacting] 按照事务的操作运行请求
  • [require = true],会在没有删除任何内容的情况下抛出错误 Model.NoRowsDeletedError

例子:

// delete from `User` where id = 1
new User({id: 1})
  .destroy()
  .then(function(model) {
    // ...
  });
model.fetch([options])

用于执行select操作,任何已经设置过的属性都可以作为约束条件。

会触发fetchingfetched事件。

[options]

  • [require=false],当设置为true时,如果结果集为空,拒绝返回的响应并抛出错误NotFoundError
  • [columns=’*’],指定要取得的列(字段)
  • [transacting],按照事务的操作运行请求
  • [withRelated],要获得的关系

例如

// select * from `books` where `ISBN-13` = '9780440180296' new Book({'ISBN-13': '9780440180296'}) .fetch() .then(function(model) { // outputs 'Slaughterhouse Five' console.log(model.get('title'));
  });

复杂一些的例子:

let Book = bookshelf.Model.extend({
  tableName: 'books',
  editions: function() {
    return this.hasMany(Edition);
  },
  chapters: function() {
    return this.hasMany(Chapter);
  },
  genre: function() {
    return this.belongsTo(Genre);
  }
})

new Book({'ISBN-13': '9780440180296'}).fetch({
  withRelated: [
    'genre', 'editions',
    { chapters: function(query) { query.orderBy('chapter_number'); }}
  ]
}).then(function(book) {
  console.log(book.related('genre').toJSON());
  console.log(book.related('editions').toJSON());
  console.log(book.toJSON());
});
model.fetchAll([options])
model.fetchPage(options)

按页获取数据库内容
pageSize为一页的记录数
page为总页数

model.load(relations, [options])
model.orderBy(sort, order)

对结果集排序
sort指定排序的标准(列名)
order指定升序(ASC)还是降序(DESC)

model.query(arguments)

用于构造请求。

例如:

model
  .query('where', 'other_id', '=', '5')
  .fetch()
  .then(function(model) {
    // ...
  });

model
  .query({where: {other_id: '5'}, orWhere: {key: 'value'}})
  .fetch()
  .then(function(model) {
    // ...
  });

model.query(function(qb) {
  qb.where('other_person', 'LIKE', '%Demo').orWhere('other_id', '>', 10);
}).fetch()
  .then(function(model) {
    // ...
  });

let qb = model.query();
qb.where({id: 1}).select().then(function(resp) {
  // ...
});
model.resetQuery()

重置当前请求构造器的实例,会在每次数据库操作完成之后被Sync自动调用。

model.where(method)

约束操作范围

4.4.3 用于事件处理的方法

model.on()
model.off()
model.once(nameOrNames, callback)
model.trigger()
model.triggerThen(name, […args])

4.4.4 用于操作属性(attribute)的方法

model.clear()

将model的所有属性清除。
返回model

model.escape(attribute)

用于去掉属性中的html元字符。

model.format(attributes)

用于在存入数据库之前,将属性格式化。

model.get(attribute)

用于获取给定的属性的值

model.has(attribute)

用于判断给定的属性是否已经有值
true表示有
false表示null或undefined

model.hasChanged([attribute])

用于判断属性值是否被更改过
true表示自上次fetch、save或destroy之后属性被修改过
false表示没有
如果没有指定参数,则任意属性被修改过都会返回false。

model.parse(response)
model.previous(attribute)

返回给定属性的上一个值,如果没有被修改过,则返回undefined。

model.previousAttributes()

返回上次修改之前的所有属性值。

model.refresh(options)
model.serialize([options])

将属性序列化(默认会序列化成JSON格式)
默认下,参数shallow=false,会将所有相关联的对象全部JSON化(调用toJSON)

model.set(attribute, [value], [options])

给属性设置值,
如果unset=true,表示移除该属性

model.toJSON([options])

会自动调用JSON.stringify方法。

model.unset(attribute)

用于移除给定的属性,如果不存在则不进行任何操作。
返回model。

4.4.5 用于操作model的方法

model.clone()

返回一个与model完全一样的新实例(所有属性,关系都相同)。

model.isNew()

用于检测model的id,来判断该model是否是新定义的。

model.related(name)

name表示要获取的关系
返回这个model定义的方法所指明的特定的关系,如果不存在则返回undefined。

model.save([key], [val], [attrs], [options])

用于对属性执行insertupdate操作。
如果,在参数中设置{patch:true}则只会进行更新操作。

这个过程会有几种事件类型

  • “creating”
  • “updating”
  • “created”
  • “updated”
  • “saving”
  • “saved”

insert的过程中触发creating、saving、created、saved
update的过程中触发updating、saving、updated、saved

model.timestamp([options])

给model添加时间戳属性

5 Event类

继承自Model和Collection

5.1 方法

event.off(name) //解除事件监听器
event.on(name,callback) //添加事件监听器
event.once(name,callback) //添加一次性事件监听器,触发一次后就销毁
event.triggle(name,[...args]) //用于触发事件
event.triggleThen(name,[...args]) //以Promise的方式用于触发事件,有事件失败则全部失败。

6 Knex Query Builder

bookshelf是基于Knex库构建的,许多语法需要参考knex。
其中最核心的部分就是请求构造器。

你可能感兴趣的:(node-js,bookshelf,orm,Node.js)