@@ -21,14 +21,9 @@ var User = module.exports = function User(_node) {
21
21
22
22
// Public instance properties:
23
23
24
- // TODO: Using native Neo4j IDs is now discouraged; switch to an indexed+unique
25
- // property instead, e.g. `email` or `username` or etc.
26
- Object . defineProperty ( User . prototype , 'id' , {
27
- get : function ( ) { return this . _node . _id ; }
28
- } ) ;
29
-
30
- Object . defineProperty ( User . prototype , 'name' , {
31
- get : function ( ) { return this . _node . properties [ 'name' ] ; }
24
+ // The user's username, e.g. 'aseemk'.
25
+ Object . defineProperty ( User . prototype , 'username' , {
26
+ get : function ( ) { return this . _node . properties [ 'username' ] ; }
32
27
} ) ;
33
28
34
29
// Private helpers:
@@ -37,10 +32,10 @@ Object.defineProperty(User.prototype, 'name', {
37
32
// instance properties), selects only whitelisted ones for editing, validates
38
33
// them, and translates them to the corresponding internal db properties.
39
34
function translate ( props ) {
40
- // Today, the only property we have is `name`; it's the same; and it needs
41
- // no validation. (Might want to validate things like length, Unicode , etc.)
35
+ // Today, the only property we have is `username`.
36
+ // TODO: Validate it. E.g. length, acceptable chars , etc.
42
37
return {
43
- name : props . name ,
38
+ username : props . username ,
44
39
} ;
45
40
}
46
41
@@ -52,14 +47,13 @@ User.prototype.patch = function (props, callback) {
52
47
var safeProps = translate ( props ) ;
53
48
54
49
var query = [
55
- 'MATCH (user:User)' ,
56
- 'WHERE ID(user) = {id}' ,
50
+ 'MATCH (user:User {username: {username}})' ,
57
51
'SET user += {props}' ,
58
52
'RETURN user' ,
59
53
] . join ( '\n' ) ;
60
54
61
55
var params = {
62
- id : this . id ,
56
+ username : this . username ,
63
57
props : safeProps ,
64
58
} ;
65
59
@@ -72,7 +66,7 @@ User.prototype.patch = function (props, callback) {
72
66
if ( err ) return callback ( err ) ;
73
67
74
68
if ( ! results . length ) {
75
- err = new Error ( 'User has been deleted! ID : ' + self . id ) ;
69
+ err = new Error ( 'User has been deleted! Username : ' + self . username ) ;
76
70
return callback ( err ) ;
77
71
}
78
72
@@ -89,14 +83,13 @@ User.prototype.del = function (callback) {
89
83
// (Note that this'll still fail if there are any relationships attached
90
84
// of any other types, which is good because we don't expect any.)
91
85
var query = [
92
- 'MATCH (user:User)' ,
93
- 'WHERE ID(user) = {userId}' ,
86
+ 'MATCH (user:User {username: {username}})' ,
94
87
'OPTIONAL MATCH (user) -[rel:follows]- (other)' ,
95
88
'DELETE user, rel' ,
96
89
] . join ( '\n' )
97
90
98
91
var params = {
99
- userId : this . id
92
+ username : this . username ,
100
93
} ;
101
94
102
95
db . cypher ( {
@@ -109,14 +102,14 @@ User.prototype.del = function (callback) {
109
102
110
103
User . prototype . follow = function ( other , callback ) {
111
104
var query = [
112
- 'MATCH (user:User) ,(other:User )' ,
113
- 'WHERE ID(user) = {userId} AND ID(other) = {otherId} ' ,
105
+ 'MATCH (user:User {username: {thisUsername}} )' ,
106
+ 'MATCH (other:User {username: {otherUsername}}) ' ,
114
107
'MERGE (user) -[rel:follows]-> (other)' ,
115
108
] . join ( '\n' )
116
109
117
110
var params = {
118
- userId : this . id ,
119
- otherId : other . id ,
111
+ thisUsername : this . username ,
112
+ otherUsername : other . username ,
120
113
} ;
121
114
122
115
db . cypher ( {
@@ -129,14 +122,15 @@ User.prototype.follow = function (other, callback) {
129
122
130
123
User . prototype . unfollow = function ( other , callback ) {
131
124
var query = [
132
- 'MATCH (user:User) -[rel:follows]-> (other:User)' ,
133
- 'WHERE ID(user) = {userId} AND ID(other) = {otherId}' ,
125
+ 'MATCH (user:User {username: {thisUsername}})' ,
126
+ 'MATCH (other:User {username: {otherUsername}})' ,
127
+ 'MATCH (user) -[rel:follows]-> (other)' ,
134
128
'DELETE rel' ,
135
129
] . join ( '\n' )
136
130
137
131
var params = {
138
- userId : this . id ,
139
- otherId : other . id ,
132
+ thisUsername : this . username ,
133
+ otherUsername : other . username ,
140
134
} ;
141
135
142
136
db . cypher ( {
@@ -152,14 +146,14 @@ User.prototype.unfollow = function (other, callback) {
152
146
User . prototype . getFollowingAndOthers = function ( callback ) {
153
147
// Query all users and whether we follow each one or not:
154
148
var query = [
155
- 'MATCH (user:User), (other:User)' ,
149
+ 'MATCH (user:User {username: {thisUsername}})' ,
150
+ 'MATCH (other:User)' ,
156
151
'OPTIONAL MATCH (user) -[rel:follows]-> (other)' ,
157
- 'WHERE ID(user) = {userId}' ,
158
152
'RETURN other, COUNT(rel)' , // COUNT(rel) is a hack for 1 or 0
159
153
] . join ( '\n' )
160
154
161
155
var params = {
162
- userId : this . id ,
156
+ thisUsername : this . username ,
163
157
} ;
164
158
165
159
var user = this ;
@@ -176,7 +170,7 @@ User.prototype.getFollowingAndOthers = function (callback) {
176
170
var other = new User ( results [ i ] [ 'other' ] ) ;
177
171
var follows = results [ i ] [ 'COUNT(rel)' ] ;
178
172
179
- if ( user . id === other . id ) {
173
+ if ( user . username === other . username ) {
180
174
continue ;
181
175
} else if ( follows ) {
182
176
following . push ( other ) ;
@@ -191,15 +185,14 @@ User.prototype.getFollowingAndOthers = function (callback) {
191
185
192
186
// Static methods:
193
187
194
- User . get = function ( id , callback ) {
188
+ User . get = function ( username , callback ) {
195
189
var query = [
196
- 'MATCH (user:User)' ,
197
- 'WHERE ID(user) = {id}' ,
190
+ 'MATCH (user:User {username: {username}})' ,
198
191
'RETURN user' ,
199
192
] . join ( '\n' )
200
193
201
194
var params = {
202
- id : parseInt ( id , 10 ) ,
195
+ username : username ,
203
196
} ;
204
197
205
198
db . cypher ( {
@@ -208,7 +201,7 @@ User.get = function (id, callback) {
208
201
} , function ( err , results ) {
209
202
if ( err ) return callback ( err ) ;
210
203
if ( ! results . length ) {
211
- err = new Error ( 'No such user with ID : ' + id ) ;
204
+ err = new Error ( 'No such user with username : ' + username ) ;
212
205
return callback ( err ) ;
213
206
}
214
207
var user = new User ( results [ 0 ] [ 'user' ] ) ;
@@ -253,3 +246,20 @@ User.create = function (props, callback) {
253
246
callback ( null , user ) ;
254
247
} ) ;
255
248
} ;
249
+
250
+ // Static initialization:
251
+
252
+ // Register our unique username constraint.
253
+ // TODO: This is done async'ly (fire and forget) here for simplicity,
254
+ // but this would be better as a formal schema migration script or similar.
255
+ db . createConstraint ( {
256
+ label : 'User' ,
257
+ property : 'username' ,
258
+ } , function ( err , constraint ) {
259
+ if ( err ) throw err ; // Failing fast for now, by crash the application.
260
+ if ( constraint ) {
261
+ console . log ( '(Registered unique usernames constraint.)' ) ;
262
+ } else {
263
+ // Constraint already present; no need to log anything.
264
+ }
265
+ } )
0 commit comments