Skip to content
Permalink
Browse files

feat(User): add Datastore support

  • Loading branch information...
mistydemeo committed Jan 10, 2019
1 parent a494d0e commit 40712e134161032300f759b7b9ecb1085a1d17bc
Showing with 99 additions and 2 deletions.
  1. +15 −0 docs/scripting.md
  2. +10 −2 src/brain.js
  3. +40 −0 src/user.js
  4. +34 −0 test/datastore_test.js
@@ -623,6 +623,21 @@ robot.respond /sleep it off/i, (res) ->
res.reply 'zzzzz'
```

The datastore also allows setting and getting values which are scoped to individual users:

```coffeescript
module.exports = (robot) ->
robot.respond /who is @?([\w .\-]+)\?*$/i, (res) ->
name = res.match[1].trim()
users = robot.brain.usersForFuzzyName(name)
if users.length is 1
user = users[0]
user.get('roles').then (roles) ->
res.send "#{name} is #{roles.join(', ')}"
```

## Script Loading

There are three main sources to load scripts from:
@@ -10,7 +10,7 @@ const User = require('./user')
// 2. If the original object was a User object, the original object
// 3. If the original object was a plain JavaScript object, return
// a User object with all of the original object's properties.
let reconstructUserIfNecessary = function (user) {
let reconstructUserIfNecessary = function (user, robot) {
if (!user) {
return null
}
@@ -20,6 +20,9 @@ let reconstructUserIfNecessary = function (user) {
delete user.id
// Use the old user as the "options" object,
// populating the new user with its values.
// Also add the `robot` field so it gets a reference.
user.robot = robot

return new User(id, user)
} else {
return user
@@ -36,6 +39,7 @@ class Brain extends EventEmitter {
users: {},
_private: {}
}
this.robot = robot

this.autoSave = true

@@ -142,7 +146,7 @@ class Brain extends EventEmitter {
if (data && data.users) {
for (let k in data.users) {
let user = this.data.users[k]
this.data.users[k] = reconstructUserIfNecessary(user)
this.data.users[k] = reconstructUserIfNecessary(user, this.robot)
}
}

@@ -161,6 +165,10 @@ class Brain extends EventEmitter {
// Returns a User instance of the specified user.
userForId (id, options) {
let user = this.data.users[id]
if (!options) {
options = {}
}
options.robot = this.robot

if (!user) {
user = new User(id, options)
@@ -1,5 +1,7 @@
'use strict'

const DataStoreUnavailable = require('./datastore').DataStoreUnavailable

class User {
// Represents a participating user in the chat.
//
@@ -12,6 +14,17 @@ class User {
options = {}
}

// Define a getter method so we don't actually store the
// robot itself on the user object, preventing it from
// being serialized into the brain.
if (options.robot) {
let robot = options.robot
delete options.robot
this._getRobot = function () { return robot }
} else {
this._getRobot = function () { }
}

Object.keys(options).forEach((key) => {
this[key] = options[key]
})
@@ -20,6 +33,33 @@ class User {
this.name = this.id.toString()
}
}

set (key, value) {
this._checkDatastoreAvailable()
return this._getDatastore()._set(this._constructKey(key), value, 'users')
}

get (key) {
this._checkDatastoreAvailable()
return this._getDatastore()._get(this._constructKey(key), 'users')
}

_constructKey (key) {
return `${this.id}+${key}`
}

_checkDatastoreAvailable () {
if (!this._getDatastore()) {
throw new DataStoreUnavailable('datastore is not initialized')
}
}

_getDatastore () {
let robot = this._getRobot()
if (robot) {
return robot.datastore
}
}
}

module.exports = User
@@ -113,4 +113,38 @@ describe('Datastore', function () {
})
})
})

describe('User scope', function () {
it('has access to the robot object', function () {
let user = this.robot.brain.userForId('1')
expect(user._getRobot()).to.equal(this.robot)
})

it('can store user data which is separate from global data', function () {
let user = this.robot.brain.userForId('1')
return user.set('blah', 'blah').then(() => {
return user.get('blah').then((userBlah) => {
return this.robot.datastore.get('blah').then((datastoreBlah) => {
expect(userBlah).to.not.equal(datastoreBlah)
expect(userBlah).to.equal('blah')
expect(datastoreBlah).to.be.an('undefined')
})
})
})
})

it('stores user data separate per-user', function () {
let userOne = this.robot.brain.userForId('1')
let userTwo = this.robot.brain.userForId('2')
return userOne.set('blah', 'blah').then(() => {
return userOne.get('blah').then((valueOne) => {
return userTwo.get('blah').then((valueTwo) => {
expect(valueOne).to.not.equal(valueTwo)
expect(valueOne).to.equal('blah')
expect(valueTwo).to.be.an('undefined')
})
})
})
})
})
})

0 comments on commit 40712e1

Please sign in to comment.
You can’t perform that action at this time.