mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
Merge pull request #2858 from logto-io/gao-log-5112-core-query-factory-user
refactor(core): users and users roles query factories
This commit is contained in:
commit
2964ff9588
2 changed files with 294 additions and 225 deletions
|
@ -2,9 +2,10 @@ import type { User, CreateUser, UserWithRoleNames } from '@logto/schemas';
|
|||
import { SearchJointMode, Users } from '@logto/schemas';
|
||||
import type { OmitAutoSetFields } from '@logto/shared';
|
||||
import { conditionalSql, convertToIdentifiers } from '@logto/shared';
|
||||
import type { CommonQueryMethods } from 'slonik';
|
||||
import { sql } from 'slonik';
|
||||
|
||||
import { buildUpdateWhere } from '#src/database/update-where.js';
|
||||
import { buildUpdateWhereWithPool } from '#src/database/update-where.js';
|
||||
import envSet from '#src/env-set/index.js';
|
||||
import { DeletionError } from '#src/errors/SlonikError/index.js';
|
||||
import type { Search } from '#src/utils/search.js';
|
||||
|
@ -15,215 +16,261 @@ import { findUsersRolesByRoleId, findUsersRolesByUserId } from './users-roles.js
|
|||
|
||||
const { table, fields } = convertToIdentifiers(Users);
|
||||
|
||||
export const findUserByUsername = async (username: string) =>
|
||||
envSet.pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.username}=${username}
|
||||
`);
|
||||
|
||||
export const findUserByEmail = async (email: string) =>
|
||||
envSet.pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where lower(${fields.primaryEmail})=lower(${email})
|
||||
`);
|
||||
|
||||
export const findUserByPhone = async (phone: string) =>
|
||||
envSet.pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.primaryPhone}=${phone}
|
||||
`);
|
||||
|
||||
export const findUserById = async (id: string): Promise<UserWithRoleNames> => {
|
||||
const user = await envSet.pool.one<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.id}=${id}
|
||||
`);
|
||||
const userRoles = await findUsersRolesByUserId(user.id);
|
||||
|
||||
const roles =
|
||||
userRoles.length > 0 ? await findRolesByRoleIds(userRoles.map(({ roleId }) => roleId)) : [];
|
||||
|
||||
return {
|
||||
...user,
|
||||
roleNames: roles.map(({ name }) => name),
|
||||
};
|
||||
};
|
||||
|
||||
export const findUserByIdentity = async (target: string, userId: string) =>
|
||||
envSet.pool.maybeOne<User>(
|
||||
sql`
|
||||
const createUserQueries = (pool: CommonQueryMethods) => {
|
||||
const findUserByUsername = async (username: string) =>
|
||||
pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.identities}::json#>>'{${sql.identifier([target])},userId}' = ${userId}
|
||||
`
|
||||
);
|
||||
where ${fields.username}=${username}
|
||||
`);
|
||||
|
||||
export const hasUser = async (username: string, excludeUserId?: string) =>
|
||||
envSet.pool.exists(sql`
|
||||
select ${fields.id}
|
||||
from ${table}
|
||||
where ${fields.username}=${username}
|
||||
${conditionalSql(excludeUserId, (id) => sql`and ${fields.id}<>${id}`)}
|
||||
`);
|
||||
const findUserByEmail = async (email: string) =>
|
||||
pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where lower(${fields.primaryEmail})=lower(${email})
|
||||
`);
|
||||
|
||||
export const hasUserWithId = async (id: string) =>
|
||||
envSet.pool.exists(sql`
|
||||
select ${fields.id}
|
||||
from ${table}
|
||||
where ${fields.id}=${id}
|
||||
`);
|
||||
const findUserByPhone = async (phone: string) =>
|
||||
pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.primaryPhone}=${phone}
|
||||
`);
|
||||
|
||||
export const hasUserWithEmail = async (email: string, excludeUserId?: string) =>
|
||||
envSet.pool.exists(sql`
|
||||
select ${fields.primaryEmail}
|
||||
from ${table}
|
||||
where lower(${fields.primaryEmail})=lower(${email})
|
||||
${conditionalSql(excludeUserId, (id) => sql`and ${fields.id}<>${id}`)}
|
||||
`);
|
||||
const findUserById = async (id: string): Promise<UserWithRoleNames> => {
|
||||
const user = await pool.one<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.id}=${id}
|
||||
`);
|
||||
const userRoles = await findUsersRolesByUserId(user.id);
|
||||
|
||||
export const hasUserWithPhone = async (phone: string, excludeUserId?: string) =>
|
||||
envSet.pool.exists(sql`
|
||||
select ${fields.primaryPhone}
|
||||
from ${table}
|
||||
where ${fields.primaryPhone}=${phone}
|
||||
${conditionalSql(excludeUserId, (id) => sql`and ${fields.id}<>${id}`)}
|
||||
`);
|
||||
const roles =
|
||||
userRoles.length > 0 ? await findRolesByRoleIds(userRoles.map(({ roleId }) => roleId)) : [];
|
||||
|
||||
export const hasUserWithIdentity = async (target: string, userId: string) =>
|
||||
envSet.pool.exists(
|
||||
sql`
|
||||
return {
|
||||
...user,
|
||||
roleNames: roles.map(({ name }) => name),
|
||||
};
|
||||
};
|
||||
|
||||
const findUserByIdentity = async (target: string, userId: string) =>
|
||||
pool.maybeOne<User>(
|
||||
sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.identities}::json#>>'{${sql.identifier([target])},userId}' = ${userId}
|
||||
`
|
||||
);
|
||||
|
||||
const hasUser = async (username: string, excludeUserId?: string) =>
|
||||
pool.exists(sql`
|
||||
select ${fields.id}
|
||||
from ${table}
|
||||
where ${fields.identities}::json#>>'{${sql.identifier([target])},userId}' = ${userId}
|
||||
`
|
||||
);
|
||||
where ${fields.username}=${username}
|
||||
${conditionalSql(excludeUserId, (id) => sql`and ${fields.id}<>${id}`)}
|
||||
`);
|
||||
|
||||
const buildUserConditions = (search: Search, excludeUserIds: string[]) => {
|
||||
const hasSearch = search.matches.length > 0;
|
||||
const searchFields = [
|
||||
Users.fields.id,
|
||||
Users.fields.primaryEmail,
|
||||
Users.fields.primaryPhone,
|
||||
Users.fields.username,
|
||||
Users.fields.name,
|
||||
];
|
||||
const hasUserWithId = async (id: string) =>
|
||||
pool.exists(sql`
|
||||
select ${fields.id}
|
||||
from ${table}
|
||||
where ${fields.id}=${id}
|
||||
`);
|
||||
|
||||
if (excludeUserIds.length > 0) {
|
||||
// FIXME @sijie temp solution to filter out admin users,
|
||||
// It is too complex to use join
|
||||
return sql`
|
||||
where ${fields.id} not in (${sql.join(excludeUserIds, sql`, `)})
|
||||
${conditionalSql(
|
||||
hasSearch,
|
||||
() => sql`and (${buildConditionsFromSearch(search, searchFields)})`
|
||||
)}
|
||||
`;
|
||||
}
|
||||
const hasUserWithEmail = async (email: string, excludeUserId?: string) =>
|
||||
pool.exists(sql`
|
||||
select ${fields.primaryEmail}
|
||||
from ${table}
|
||||
where lower(${fields.primaryEmail})=lower(${email})
|
||||
${conditionalSql(excludeUserId, (id) => sql`and ${fields.id}<>${id}`)}
|
||||
`);
|
||||
|
||||
return conditionalSql(
|
||||
hasSearch,
|
||||
() => sql`where ${buildConditionsFromSearch(search, searchFields)}`
|
||||
);
|
||||
};
|
||||
const hasUserWithPhone = async (phone: string, excludeUserId?: string) =>
|
||||
pool.exists(sql`
|
||||
select ${fields.primaryPhone}
|
||||
from ${table}
|
||||
where ${fields.primaryPhone}=${phone}
|
||||
${conditionalSql(excludeUserId, (id) => sql`and ${fields.id}<>${id}`)}
|
||||
`);
|
||||
|
||||
export const defaultUserSearch = { matches: [], isCaseSensitive: false, joint: SearchJointMode.Or };
|
||||
const hasUserWithIdentity = async (target: string, userId: string) =>
|
||||
pool.exists(
|
||||
sql`
|
||||
select ${fields.id}
|
||||
from ${table}
|
||||
where ${fields.identities}::json#>>'{${sql.identifier([target])},userId}' = ${userId}
|
||||
`
|
||||
);
|
||||
|
||||
export const countUsers = async (
|
||||
search: Search = defaultUserSearch,
|
||||
excludeUserIds: string[] = []
|
||||
) =>
|
||||
envSet.pool.one<{ count: number }>(sql`
|
||||
select count(*)
|
||||
from ${table}
|
||||
${buildUserConditions(search, excludeUserIds)}
|
||||
`);
|
||||
const buildUserConditions = (search: Search, excludeUserIds: string[]) => {
|
||||
const hasSearch = search.matches.length > 0;
|
||||
const searchFields = [
|
||||
Users.fields.id,
|
||||
Users.fields.primaryEmail,
|
||||
Users.fields.primaryPhone,
|
||||
Users.fields.username,
|
||||
Users.fields.name,
|
||||
];
|
||||
|
||||
export const findUsers = async (
|
||||
limit: number,
|
||||
offset: number,
|
||||
search: Search,
|
||||
excludeUserIds: string[] = []
|
||||
) =>
|
||||
envSet.pool.any<User>(
|
||||
sql`
|
||||
select ${sql.join(
|
||||
Object.values(fields).map((field) => sql`${table}.${field}`),
|
||||
sql`,`
|
||||
)}
|
||||
if (excludeUserIds.length > 0) {
|
||||
// FIXME @sijie temp solution to filter out admin users,
|
||||
// It is too complex to use join
|
||||
return sql`
|
||||
where ${fields.id} not in (${sql.join(excludeUserIds, sql`, `)})
|
||||
${conditionalSql(
|
||||
hasSearch,
|
||||
() => sql`and (${buildConditionsFromSearch(search, searchFields)})`
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
return conditionalSql(
|
||||
hasSearch,
|
||||
() => sql`where ${buildConditionsFromSearch(search, searchFields)}`
|
||||
);
|
||||
};
|
||||
|
||||
const defaultUserSearch = { matches: [], isCaseSensitive: false, joint: SearchJointMode.Or };
|
||||
|
||||
const countUsers = async (search: Search = defaultUserSearch, excludeUserIds: string[] = []) =>
|
||||
pool.one<{ count: number }>(sql`
|
||||
select count(*)
|
||||
from ${table}
|
||||
${buildUserConditions(search, excludeUserIds)}
|
||||
limit ${limit}
|
||||
offset ${offset}
|
||||
`
|
||||
);
|
||||
`);
|
||||
|
||||
export const findUsersByIds = async (userIds: string[]) =>
|
||||
userIds.length > 0
|
||||
? envSet.pool.any<User>(sql`
|
||||
const findUsers = async (
|
||||
limit: number,
|
||||
offset: number,
|
||||
search: Search,
|
||||
excludeUserIds: string[] = []
|
||||
) =>
|
||||
pool.any<User>(
|
||||
sql`
|
||||
select ${sql.join(
|
||||
Object.values(fields).map((field) => sql`${table}.${field}`),
|
||||
sql`,`
|
||||
)}
|
||||
from ${table}
|
||||
${buildUserConditions(search, excludeUserIds)}
|
||||
limit ${limit}
|
||||
offset ${offset}
|
||||
`
|
||||
);
|
||||
|
||||
const findUsersByIds = async (userIds: string[]) =>
|
||||
pool.any<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`, `)}
|
||||
from ${table}
|
||||
where ${fields.id} in (${sql.join(userIds, sql`, `)})
|
||||
`)
|
||||
: [];
|
||||
`);
|
||||
|
||||
const updateUser = buildUpdateWhere<CreateUser, User>(Users, true);
|
||||
const updateUser = buildUpdateWhereWithPool(pool)<CreateUser, User>(Users, true);
|
||||
|
||||
export const updateUserById = async (
|
||||
id: string,
|
||||
set: Partial<OmitAutoSetFields<CreateUser>>,
|
||||
jsonbMode: 'replace' | 'merge' = 'merge'
|
||||
) => updateUser({ set, where: { id }, jsonbMode });
|
||||
const updateUserById = async (
|
||||
id: string,
|
||||
set: Partial<OmitAutoSetFields<CreateUser>>,
|
||||
jsonbMode: 'replace' | 'merge' = 'merge'
|
||||
) => updateUser({ set, where: { id }, jsonbMode });
|
||||
|
||||
export const deleteUserById = async (id: string) => {
|
||||
const { rowCount } = await envSet.pool.query(sql`
|
||||
delete from ${table}
|
||||
where ${fields.id}=${id}
|
||||
`);
|
||||
const deleteUserById = async (id: string) => {
|
||||
const { rowCount } = await pool.query(sql`
|
||||
delete from ${table}
|
||||
where ${fields.id}=${id}
|
||||
`);
|
||||
|
||||
if (rowCount < 1) {
|
||||
throw new DeletionError(Users.table, id);
|
||||
}
|
||||
if (rowCount < 1) {
|
||||
throw new DeletionError(Users.table, id);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteUserIdentity = async (userId: string, target: string) =>
|
||||
pool.one<User>(sql`
|
||||
update ${table}
|
||||
set ${fields.identities}=${fields.identities}::jsonb-${target}
|
||||
where ${fields.id}=${userId}
|
||||
returning *
|
||||
`);
|
||||
|
||||
const hasActiveUsers = async () =>
|
||||
pool.exists(sql`
|
||||
select ${fields.id}
|
||||
from ${table}
|
||||
limit 1
|
||||
`);
|
||||
|
||||
const getDailyNewUserCountsByTimeInterval = async (
|
||||
startTimeExclusive: number,
|
||||
endTimeInclusive: number
|
||||
) =>
|
||||
pool.any<{ date: string; count: number }>(sql`
|
||||
select date(${fields.createdAt}), count(*)
|
||||
from ${table}
|
||||
where ${fields.createdAt} > to_timestamp(${startTimeExclusive}::double precision / 1000)
|
||||
and ${fields.createdAt} <= to_timestamp(${endTimeInclusive}::double precision / 1000)
|
||||
group by date(${fields.createdAt})
|
||||
`);
|
||||
|
||||
const findUsersByRoleName = async (roleName: string) => {
|
||||
const role = await findRoleByRoleName(roleName);
|
||||
|
||||
if (!role) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const usersRoles = await findUsersRolesByRoleId(role.id);
|
||||
|
||||
if (usersRoles.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return findUsersByIds(usersRoles.map(({ userId }) => userId));
|
||||
};
|
||||
|
||||
return {
|
||||
findUserByUsername,
|
||||
findUserByEmail,
|
||||
findUserByPhone,
|
||||
findUserById,
|
||||
findUserByIdentity,
|
||||
hasUser,
|
||||
hasUserWithId,
|
||||
hasUserWithEmail,
|
||||
hasUserWithPhone,
|
||||
hasUserWithIdentity,
|
||||
countUsers,
|
||||
findUsers,
|
||||
findUsersByIds,
|
||||
updateUserById,
|
||||
deleteUserById,
|
||||
deleteUserIdentity,
|
||||
hasActiveUsers,
|
||||
getDailyNewUserCountsByTimeInterval,
|
||||
findUsersByRoleName,
|
||||
};
|
||||
};
|
||||
|
||||
export const deleteUserIdentity = async (userId: string, target: string) =>
|
||||
envSet.pool.one<User>(sql`
|
||||
update ${table}
|
||||
set ${fields.identities}=${fields.identities}::jsonb-${target}
|
||||
where ${fields.id}=${userId}
|
||||
returning *
|
||||
`);
|
||||
|
||||
export const hasActiveUsers = async () =>
|
||||
envSet.pool.exists(sql`
|
||||
select ${fields.id}
|
||||
from ${table}
|
||||
limit 1
|
||||
`);
|
||||
|
||||
export const getDailyNewUserCountsByTimeInterval = async (
|
||||
startTimeExclusive: number,
|
||||
endTimeInclusive: number
|
||||
) =>
|
||||
envSet.pool.any<{ date: string; count: number }>(sql`
|
||||
select date(${fields.createdAt}), count(*)
|
||||
from ${table}
|
||||
where ${fields.createdAt} > to_timestamp(${startTimeExclusive}::double precision / 1000)
|
||||
and ${fields.createdAt} <= to_timestamp(${endTimeInclusive}::double precision / 1000)
|
||||
group by date(${fields.createdAt})
|
||||
`);
|
||||
|
||||
export const findUsersByRoleName = async (roleName: string) => {
|
||||
const role = await findRoleByRoleName(roleName);
|
||||
|
||||
if (!role) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const usersRoles = await findUsersRolesByRoleId(role.id);
|
||||
|
||||
return findUsersByIds(usersRoles.map(({ userId }) => userId));
|
||||
};
|
||||
/** @deprecated Will be removed soon. Use createUserQueries() factory instead. */
|
||||
export const {
|
||||
findUserByUsername,
|
||||
findUserByEmail,
|
||||
findUserByPhone,
|
||||
findUserById,
|
||||
findUserByIdentity,
|
||||
hasUser,
|
||||
hasUserWithId,
|
||||
hasUserWithEmail,
|
||||
hasUserWithPhone,
|
||||
hasUserWithIdentity,
|
||||
countUsers,
|
||||
findUsers,
|
||||
findUsersByIds,
|
||||
updateUserById,
|
||||
deleteUserById,
|
||||
deleteUserIdentity,
|
||||
hasActiveUsers,
|
||||
getDailyNewUserCountsByTimeInterval,
|
||||
findUsersByRoleName,
|
||||
} = createUserQueries(envSet.pool);
|
||||
|
|
|
@ -1,57 +1,79 @@
|
|||
import type { UsersRole } from '@logto/schemas';
|
||||
import { UsersRoles } from '@logto/schemas';
|
||||
import { conditionalSql, convertToIdentifiers } from '@logto/shared';
|
||||
import type { CommonQueryMethods } from 'slonik';
|
||||
import { sql } from 'slonik';
|
||||
|
||||
import envSet from '#src/env-set/index.js';
|
||||
|
||||
const { table, fields } = convertToIdentifiers(UsersRoles);
|
||||
|
||||
export const findUsersRolesByUserId = async (userId: string) =>
|
||||
envSet.pool.any<UsersRole>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.userId}=${userId}
|
||||
`);
|
||||
export const createUsersRolesQueries = (pool: CommonQueryMethods) => {
|
||||
const countUsersRolesByRoleId = async (roleId: string) =>
|
||||
pool.one<{ count: number }>(sql`
|
||||
select count(*)
|
||||
from ${table}
|
||||
where ${fields.roleId}=${roleId}
|
||||
`);
|
||||
|
||||
export const findUsersRolesByRoleId = async (roleId: string, limit?: number) =>
|
||||
envSet.pool.any<UsersRole>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.roleId}=${roleId}
|
||||
${conditionalSql(limit, (value) => sql`limit ${value}`)}
|
||||
`);
|
||||
const findFirstUsersRolesByRoleIdAndUserIds = async (roleId: string, userIds: string[]) =>
|
||||
userIds.length > 0
|
||||
? pool.maybeOne<UsersRole>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.roleId}=${roleId}
|
||||
and ${fields.userId} in (${sql.join(userIds, sql`, `)})
|
||||
limit 1
|
||||
`)
|
||||
: null;
|
||||
|
||||
export const countUsersRolesByRoleId = async (roleId: string) =>
|
||||
envSet.pool.one<{ count: number }>(sql`
|
||||
select count(*)
|
||||
from ${table}
|
||||
where ${fields.roleId}=${roleId}
|
||||
`);
|
||||
const findUsersRolesByUserId = async (userId: string) =>
|
||||
pool.any<UsersRole>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.userId}=${userId}
|
||||
`);
|
||||
|
||||
export const findFirstUsersRolesByRoleIdAndUserIds = async (roleId: string, userIds: string[]) =>
|
||||
userIds.length > 0
|
||||
? envSet.pool.maybeOne<UsersRole>(sql`
|
||||
const findUsersRolesByRoleId = async (roleId: string, limit?: number) =>
|
||||
pool.any<UsersRole>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.roleId}=${roleId}
|
||||
and ${fields.userId} in (${sql.join(userIds, sql`, `)})
|
||||
limit 1
|
||||
`)
|
||||
: null;
|
||||
${conditionalSql(limit, (value) => sql`limit ${value}`)}
|
||||
`);
|
||||
|
||||
export const insertUsersRoles = async (usersRoles: UsersRole[]) =>
|
||||
envSet.pool.query(sql`
|
||||
insert into ${table} (${fields.userId}, ${fields.roleId}) values
|
||||
${sql.join(
|
||||
usersRoles.map(({ userId, roleId }) => sql`(${userId}, ${roleId})`),
|
||||
sql`, `
|
||||
)}
|
||||
`);
|
||||
const insertUsersRoles = async (usersRoles: UsersRole[]) =>
|
||||
pool.query(sql`
|
||||
insert into ${table} (${fields.userId}, ${fields.roleId}) values
|
||||
${sql.join(
|
||||
usersRoles.map(({ userId, roleId }) => sql`(${userId}, ${roleId})`),
|
||||
sql`, `
|
||||
)}
|
||||
`);
|
||||
|
||||
export const deleteUsersRolesByUserIdAndRoleId = async (userId: string, roleId: string) => {
|
||||
await envSet.pool.query(sql`
|
||||
delete from ${table}
|
||||
where ${fields.userId} = ${userId} and ${fields.roleId} = ${roleId}
|
||||
`);
|
||||
const deleteUsersRolesByUserIdAndRoleId = async (userId: string, roleId: string) => {
|
||||
await pool.query(sql`
|
||||
delete from ${table}
|
||||
where ${fields.userId} = ${userId} and ${fields.roleId} = ${roleId}
|
||||
`);
|
||||
};
|
||||
|
||||
return {
|
||||
countUsersRolesByRoleId,
|
||||
findFirstUsersRolesByRoleIdAndUserIds,
|
||||
findUsersRolesByUserId,
|
||||
findUsersRolesByRoleId,
|
||||
insertUsersRoles,
|
||||
deleteUsersRolesByUserIdAndRoleId,
|
||||
};
|
||||
};
|
||||
|
||||
/** @deprecated Will be removed soon. Use createUsersRolesQueries() factory instead. */
|
||||
export const {
|
||||
countUsersRolesByRoleId,
|
||||
findFirstUsersRolesByRoleIdAndUserIds,
|
||||
findUsersRolesByUserId,
|
||||
findUsersRolesByRoleId,
|
||||
insertUsersRoles,
|
||||
deleteUsersRolesByUserIdAndRoleId,
|
||||
} = createUsersRolesQueries(envSet.pool);
|
||||
|
|
Loading…
Reference in a new issue