-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathusers-and-roles.js
207 lines (184 loc) · 6.37 KB
/
users-and-roles.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// Example: Users and Roles
// A more complicated example, we define some data structures to represent
// Users and Roles and the relationships between them.
// Require our dependencies.
var Backing = require('backing');
var Realm = require('../').Realm;
// Define our backing store.
// Realms need somewhere to store their data
var backing = new Backing({
// The name which identifies the store.
// This will form part of the filename for the database files.
name: 'example-users-and-roles',
// The size of each arena. This is the number of bytes which will
// be preallocated at a time. In this example we're using 1 Mb
// but in production you should almost always set this to the largest
// possible value - 2Gb.
arenaSize: 1024 * 1024,
// The configuration for the arena source, which is responsible
// for loading data files and allocating new arenas when we run out of space.
arenaSource: {
// The type or arenas this source provides.
// This can be either 'mmap' or 'array-buffer'.
// When using 'array-buffer', the data will be stored in memory
// and not persisted to disk.
type: 'mmap',
// The name of the folder containing the data files.
// This only applies to 'mmap' and will cause an error if `type` is set to 'array-buffer'.
dirname: __dirname + '/../data'
}
});
// Define our realm.
var realm = new Realm(backing);
// `T` is an object containing all the registered types in the realm, e.g. `T.String` or `T.Object`.
var T = realm.T;
// Structs are fixed-layout objects whose property names and corresponding types are predefined.
var StructType = realm.StructType;
// HashSets are Sets of values which support very fast lookup operations but do not support in-order iteration.
var HashSetType = realm.HashSetType;
// HashMaps are Maps of key / values with support for very fast lookup operations but do not support in-order iteration.
var HashMapType = realm.HashMapType;
// Define our types here so that we can export them later.
// (This is so that you can `require()` this file in a REPL).
var User, Role, UserMap, RoleMap;
// Initialize the realm, loading the data files. (Returns a promise)
realm.init().then(function () {
// `Role` and `User` need to be able to reference each other, because a `Role` has
// many users and a `User` has many roles. This presents a problem though because
// `User` has not been defined yet so there's no way for us to reference it.
// The answer is to create `Role` but defer defining its layout until after `User` has been created.
Role = new StructType();
// Now we can define our `User` type.
User = new StructType({
// Users have names.
name: T.String,
// Holds whether or not the user is active.
isActive: T.Boolean,
// A set of roles that this user belongs to.
// Note that we're using `Role.ref` rather than `Role` because we want to reference
// a role rather than embedding it directly within this struct.
// Note that if we did use `Role` heere, we would get a `TypeError` because the layout of `Role`
// has not yet been defined.
roles: new HashSetType(Role.ref)
});
// Now that `User` has been defined, we can finalize our `Role`'s layout.
Role.finalize({
// Roles have names.
name: T.String,
// A set of references to users that belong to this `Role`.
users: new HashSetType(User.ref)
});
// Declare a type which can represent a map of strings to users.
UserMap = new HashMapType(T.String, User);
// Declare a type which can represent a map to strings to roles.
RoleMap = new HashMapType(T.String, Role);
// If this is the first time we've been run, create our test data,
// or if the test data has been modfied, reset it to expected values.
ensureCollectionsExist();
ensureBuiltinRolesExist();
ensureBuiltinUsersExist();
// Get a refrence to the map of strings to users.
var users = realm.get('users');
// get a reference to the map of strings to roles
var roles = realm.get('roles');
// Dump what we know about the users.
users.forEach((user, name) => {
console.log(name, 'is an',(user.isActive ? 'active' : 'inactive'),'user who is a member of', Array.from(user.roles, role => role.name).join(', '))
});
// Export some variables for REPL convenience:
exports.Role = Role;
exports.User = User;
exports.UserMap = UserMap;
exports.RoleMap = RoleMap;
exports.roles = roles;
exports.users = users;
});
/**
* Ensures that the users and roles collections exist.
*/
function ensureCollectionsExist () {
if (!realm.has('users')) {
realm.set('users', new UserMap());
}
if (!realm.has('roles')) {
realm.set('roles', new RoleMap());
}
}
/**
* Ensures that the demo roles exist.
*/
function ensureBuiltinRolesExist () {
addRole('admin');
addRole('user');
addRole('guest');
}
/**
* Ensure that the demo users exist and have the right activation status.
*/
function ensureBuiltinUsersExist () {
activate(addUser('Alice', ['admin', 'user']));
activate(addUser('George', ['user']));
deactivate(addUser('Bob', ['guest']));
}
/**
* Add the role with the given name to the list, if it doesn't already exist.
*/
function addRole (name) {
var roles = realm.get('roles');
if (!roles.has(name)) {
console.log('Adding role', name);
roles.set(name, {name: name, users: []});
}
else {
console.log('Role', name, 'already exists');
}
}
/**
* Add a new user with the given name and roles.
*/
function addUser (name, roleNames) {
var users = realm.get('users');
if (!users.has(name)) {
console.log('Adding user', name);
user = users.set(name, {
name: name,
roles: []
});
}
else {
console.log('Loading existing user', name);
}
var user = users.get(name);
assignRoles(user, roleNames);
return user;
}
/**
* Assign the roles with the given names to the given user.
*/
function assignRoles (user, roleNames) {
var roles = realm.get('roles');
roleNames.forEach(function (roleName) {
role = roles.get(roleName);
role.users.add(user);
user.roles.add(role);
});
}
/**
* Activate the given user.
*/
function activate (user) {
user.isActive = true;
}
/**
* Deactivate the given user.
*/
function deactivate (user) {
user.isActive = false;
}
// Export some variables for REPL convenience:
exports.realm = realm;
exports.backing = backing;
exports.addRole = addRole;
exports.addUser = addUser;
exports.activate = activate;
exports.deactivate = deactivate;