bookshelf.js中的多重关系

时间:2017-01-05 01:21:23

标签: javascript node.js postgresql orm bookshelf.js

我正在尝试使用bookshelf.js作为Postgresql的ORM在node.js应用程序中实现基于角色的访问控制。我有以下架构:

USERS <- USERS_ROLES -> ROLES <- ROLES_RIGHTS -> RIGHTS

我希望能够获得用户拥有的所有权利。在sql中,我会这样做:

SELECT rights.*
FROM rights
INNER JOIN roles_rights ON roles_rights.right_id=rights.id
INNER JOIN users_roles ON users_roles.role_id = roles_rights.role_id
WHERE users_roles.user_id=1
GROUP BY rights.id

对Bookshelf.js来说相对较新,我在确定如何设置关系方面遇到了一些麻烦。这是我的第一次尝试:

const User = bookshelf.Model.extend({

  tableName: 'users',

  roles: function() {
    return this.belongsToMany(Role, 'users_roles', 'user_id', 'role_id')
  },

  rights: function() {
    return this.belongsToMany(Right, 'users_roles', 'user_id', 'role_id')
      .query(qb => qb
        .innerJoin('roles_rights', 'roles_rights.right_id', 'rights.id')
      )
  }

})

const Role = bookshelf.Model.extend({

  tableName: 'roles',

  rights: function() {
    return this.belongsToMany(Right, 'roles_rights', 'role_id', 'right_id')
  },

  users: function() {
    return this.belongsToMany(User, 'users_roles', 'user_id', 'role_id')
  }

})

const Right = bookshelf.Model.extend({

  tableName: 'rights',

  roles: function() {
    return this.belongsToMany(Role, 'users_roles', 'user_id', 'role_id')
  }

})

它不起作用......: - (

最终,我想让这个查询起作用:

User.where({ id: req.user.get('id') })
  .fetch({ withRelated: ['rights'] })
  .then(user => {
    ...
  })
})

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

在经历了同样的问题一段时间之后,这是我最接近可用的解决方案。

如果没有对您描述的模型进行任何修改(除了从rights模型中删除User关系),您可以这样做:

User.where({ id: req.user.get('id') })
  .fetch({ withRelated: ['roles.rights'] })
  .then(user => {
    console.log(JSON.stringify(user));
  })
})

我发现这对我的用例更好,因为我将始终拥有用户角色和角色权限。

这样的事情:

{
  id: 12
  roles: [
    {
      id: 21,
      rights: [
        {
          id: 11,
          name: 'DELETE'
        }
      ]
    }
  ]
}

如果您确实需要用户从所有用户角色组合的所有权限,您可以使用Bookshelf的虚拟插件并创建虚拟行。

const User = bookshelf.Model.extend({

  tableName: 'users',

  roles: function() {
    return this.belongsToMany(Role, 'users_roles', 'user_id', 'role_id')
  },

  virtuals: {
    rights: {
      get: function () {
        const rightsIds = new Set();
        return this.related('roles').reduce((rights, group) => {
          return group.related('rights').reduce((rights, right) => {
            if (!rightsIds.has(right.id)) {
              rightsIds.add(right.id);
              rights.push(right);
            }
            return rights;
          }, rights);
        }, []);
      }
    }
  },
});

像这样使用:

User.where({ id: req.user.get('id') })
  .fetch({ withRelated: ['roles.rights'] })
  .then(user => {
    console.log(JSON.stringify(user.get('rights'));
  })
})

初始化bookshelf时必须启用虚拟插件:

bookshelf.plugin(['virtuals']);

这不是最优雅的解决方案,但如果你想用书架做所有事情,就是这样。每当书架让我失望时我就会使用knex(这种情况会发生很多)。