feat(admin-next): support nickname#discriminator user search

master
moonrailgun 18 hours ago
parent 564c30914c
commit 7109e7ae0f

@ -6,7 +6,7 @@
"scripts": {
"dev": "nodemon",
"start": "cross-env NODE_ENV=production node dist/admin-next/src/server/index.js",
"test": "node --test -r ts-node/register src/client/*.test.ts src/client/*.test.tsx",
"test": "node --test -r ts-node/register src/client/*.test.ts src/client/*.test.tsx src/server/middleware/express-mongoose-ra-json-server/utils/*.test.ts",
"check:type": "tsc --noEmit",
"build": "pnpm build:client && pnpm build:server",
"build:client": "vite build",

@ -30,6 +30,9 @@ export interface raExpressMongooseOptions<T> {
/** Fields to search from ?q (used for autofill and search) */
q?: string[];
/** Extra $or condition built from ?q, e.g. structured `nickname#discriminator` */
qFilter?: (q: string) => Record<string, any> | undefined;
/** Base name for ACLs (e.g. list operation does baseName.list) */
aclName?: string;
@ -67,6 +70,7 @@ export function raExpressMongoose<T extends ADPBaseModel, I>(
) {
const {
q,
qFilter,
allowedRegexFields = [],
readOnlyFields,
inputTransformer = (input: any) => input,
@ -105,7 +109,8 @@ export function raExpressMongoose<T extends ADPBaseModel, I>(
),
model,
allowedRegexFields,
q
q,
qFilter
),
};
let query = model.find(filterQuery);

@ -0,0 +1,36 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import parseQuery from './parseQuery';
const model: any = { schema: { path: () => ({ cast: (v: any) => v }) } };
const uniqueName = (q: string) => {
const [nickname, discriminator] = q.split('#');
return discriminator ? { nickname, discriminator } : undefined;
};
test('adds nickname#discriminator match to $or', () => {
const result = parseQuery(
{ q: 'admin#6485' },
model,
['nickname'],
['nickname', 'email'],
uniqueName
);
assert.equal(result.q, undefined);
assert.deepEqual(result.$or.at(-1), {
nickname: 'admin',
discriminator: '6485',
});
});
test('keeps plain search unchanged without #', () => {
const result = parseQuery(
{ q: 'admin' },
model,
['nickname'],
['nickname', 'email'],
uniqueName
);
assert.equal(result.$or.length, 2);
assert.deepEqual(result.$or[1], { email: 'admin' });
});

@ -11,6 +11,7 @@ interface parseQueryParam {
* Turns ?q into $or queries, deletes q
* @param {Object} results Original object with the q field
* @param {string[]} fields Fields to apply q to
* @param {Function} qFilter Optional extra $or condition built from q
*/
export default function parseQuery<
T extends parseQueryParam,
@ -19,7 +20,8 @@ export default function parseQuery<
result: T,
model: M,
allowedRegexes: string[],
fields?: string[]
fields?: string[],
qFilter?: (q: string) => Record<string, any> | undefined
): T & { $or?: any } {
if (!fields) return result;
if (result.q) {
@ -32,6 +34,8 @@ export default function parseQuery<
const newFilter = { [field]: result.q };
result.$or.push(castFilter(newFilter, model, allowedRegexes));
});
const extra = qFilter?.(String(result.q));
if (extra) result.$or.push(extra);
delete result.q;
}
return result;

@ -177,6 +177,10 @@ router.use(
auth(),
raExpressMongoose(userModel, {
q: ['_id', 'nickname', 'email'],
qFilter: (q) => {
const [nickname, discriminator] = q.split('#');
return discriminator ? { nickname, discriminator } : undefined;
},
allowedRegexFields: ['nickname'],
})
);

Loading…
Cancel
Save