Skip to content

Commit

Permalink
feat: fullname search (#8641)
Browse files Browse the repository at this point in the history
* feat: fullname search

* fix: take last element

* fix: attempt to fix psql like query

* feat: upgrade sript, another fix attempt

* fix: psql test

* fix: psql scan

* feat: add debug for test

* feat: test collate

* feat: cleanup

* fix: upgrade script
  • Loading branch information
barisusakli committed Sep 12, 2020
1 parent 9389749 commit 4be693f
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/controllers/admin/users.js
Expand Up @@ -42,7 +42,7 @@ usersController.search = async function (req, res) {
match: query,
limit: hardCap,
});
return data.map(data => data.split(':')[1]);
return data.map(data => data.split(':').pop());
},
});

Expand Down
12 changes: 6 additions & 6 deletions src/database/postgres/sorted.js
Expand Up @@ -582,31 +582,31 @@ DELETE FROM "legacy_zset" z
if (min.match(/^\(/)) {
q.values.push(min.substr(1));
q.suffix += 'GT';
q.where += ` AND z."value" > $` + q.values.length + `::TEXT`;
q.where += ` AND z."value" > $` + q.values.length + `::TEXT COLLATE "C"`;
} else if (min.match(/^\[/)) {
q.values.push(min.substr(1));
q.suffix += 'GE';
q.where += ` AND z."value" >= $` + q.values.length + `::TEXT`;
q.where += ` AND z."value" >= $` + q.values.length + `::TEXT COLLATE "C"`;
} else {
q.values.push(min);
q.suffix += 'GE';
q.where += ` AND z."value" >= $` + q.values.length + `::TEXT`;
q.where += ` AND z."value" >= $` + q.values.length + `::TEXT COLLATE "C"`;
}
}

if (max !== '+') {
if (max.match(/^\(/)) {
q.values.push(max.substr(1));
q.suffix += 'LT';
q.where += ` AND z."value" < $` + q.values.length + `::TEXT`;
q.where += ` AND z."value" < $` + q.values.length + `::TEXT COLLATE "C"`;
} else if (max.match(/^\[/)) {
q.values.push(max.substr(1));
q.suffix += 'LE';
q.where += ` AND z."value" <= $` + q.values.length + `::TEXT`;
q.where += ` AND z."value" <= $` + q.values.length + `::TEXT COLLATE "C"`;
} else {
q.values.push(max);
q.suffix += 'LE';
q.where += ` AND z."value" <= $` + q.values.length + `::TEXT`;
q.where += ` AND z."value" <= $` + q.values.length + `::TEXT COLLATE "C"`;
}
}

Expand Down
26 changes: 26 additions & 0 deletions src/upgrades/1.15.0/fullname_search_set.js
@@ -0,0 +1,26 @@
'use strict';

const db = require('../../database');

const batch = require('../../batch');
const user = require('../../user');

module.exports = {
name: 'Create fullname search set',
timestamp: Date.UTC(2020, 8, 11),
method: async function () {
const progress = this.progress;

await batch.processSortedSet('users:joindate', async function (uids) {
progress.incr(uids.length);
const userData = await user.getUsersFields(uids, ['uid', 'fullname']);
const bulkAdd = userData
.filter(u => u.uid && u.fullname)
.map(u => ['fullname:sorted', 0, u.fullname.toLowerCase() + ':' + u.uid]);
await db.sortedSetAddBulk(bulkAdd);
}, {
batch: 500,
progress: this.progress,
});
},
};
4 changes: 4 additions & 0 deletions src/user/create.js
Expand Up @@ -94,6 +94,10 @@ module.exports = function (User) {
bulkAdd.push(['user:' + userData.uid + ':emails', timestamp, userData.email + ':' + timestamp]);
}

if (userData.fullname) {
bulkAdd.push(['fullname:sorted', 0, userData.fullname.toLowerCase() + ':' + userData.uid]);
}

await Promise.all([
db.incrObjectField('global', 'userCount'),
db.sortedSetAddBulk(bulkAdd),
Expand Down
4 changes: 4 additions & 0 deletions src/user/delete.js
Expand Up @@ -136,6 +136,10 @@ module.exports = function (User) {
bulkRemove.push(['email:sorted', userData.email.toLowerCase() + ':' + uid]);
}

if (userData.fullname) {
bulkRemove.push(['fullname:sorted', userData.fullname.toLowerCase() + ':' + uid]);
}

await Promise.all([
db.sortedSetRemoveBulk(bulkRemove),
db.decrObjectField('global', 'userCount'),
Expand Down
8 changes: 8 additions & 0 deletions src/user/profile.js
Expand Up @@ -263,6 +263,14 @@ module.exports = function (User) {
async function updateFullname(uid, newFullname) {
const fullname = await User.getUserField(uid, 'fullname');
await updateUidMapping('fullname', uid, newFullname, fullname);
if (newFullname !== fullname) {
if (fullname) {
await db.sortedSetRemove('fullname:sorted', fullname.toLowerCase() + ':' + uid);
}
if (newFullname) {
await db.sortedSetAdd('fullname:sorted', 0, newFullname.toLowerCase() + ':' + uid);
}
}
}

User.changePassword = async function (uid, data) {
Expand Down
2 changes: 1 addition & 1 deletion src/user/search.js
Expand Up @@ -63,7 +63,7 @@ module.exports = function (User) {
hardCap = hardCap || resultsPerPage * 10;

const data = await db.getSortedSetRangeByLex(searchBy + ':sorted', min, max, 0, hardCap);
const uids = data.map(data => data.split(':')[1]);
const uids = data.map(data => data.split(':').pop());
return uids;
}

Expand Down
16 changes: 16 additions & 0 deletions test/user.js
Expand Up @@ -399,6 +399,22 @@ describe('User', function () {
});
});

it('should search users by fullname', async function () {
const uid = await User.create({ username: 'fullnamesearch1', fullname: 'Mr. Fullname' });
const data = await socketUser.search({ uid: adminUid }, { query: 'mr', searchBy: 'fullname' });
assert(Array.isArray(data.users));
assert.equal(data.users.length, 1);
assert.equal(uid, data.users[0].uid);
});

it('should search users by fullname', async function () {
const uid = await User.create({ username: 'fullnamesearch2', fullname: 'Baris:Usakli' });
const data = await socketUser.search({ uid: adminUid }, { query: 'baris:', searchBy: 'fullname' });
assert(Array.isArray(data.users));
assert.equal(data.users.length, 1);
assert.equal(uid, data.users[0].uid);
});

it('should return empty array if query is empty', function (done) {
socketUser.search({ uid: testUid }, { query: '' }, function (err, data) {
assert.ifError(err);
Expand Down

0 comments on commit 4be693f

Please sign in to comment.