0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-20 21:32:31 -05:00

refactor(core): reorg organization queries

This commit is contained in:
Gao Sun 2024-06-05 18:25:18 +08:00
parent ec6f1d39d8
commit ce911309da
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
3 changed files with 121 additions and 113 deletions

View file

@ -28,7 +28,8 @@ import { TwoRelationsQueries } from '#src/utils/RelationQueries.js';
import SchemaQueries from '#src/utils/SchemaQueries.js';
import { conditionalSql, convertToIdentifiers } from '#src/utils/sql.js';
import { RoleUserRelationQueries, UserRelationQueries } from './relations.js';
import { RoleUserRelationQueries } from './role-user-relations.js';
import { UserRelationQueries } from './user-relations.js';
/**
* The schema field keys that can be used for searching roles.

View file

@ -0,0 +1,117 @@
import {
Organizations,
OrganizationRoles,
OrganizationScopes,
OrganizationRoleScopeRelations,
Users,
OrganizationRoleUserRelations,
type OrganizationScope,
type ResourceScopeEntity,
Scopes,
OrganizationRoleResourceScopeRelations,
Resources,
} from '@logto/schemas';
import { sql, type CommonQueryMethods } from '@silverhand/slonik';
import RelationQueries from '#src/utils/RelationQueries.js';
import { conditionalSql, convertToIdentifiers } from '#src/utils/sql.js';
export class RoleUserRelationQueries extends RelationQueries<
[typeof Organizations, typeof OrganizationRoles, typeof Users]
> {
constructor(pool: CommonQueryMethods) {
super(pool, OrganizationRoleUserRelations.table, Organizations, OrganizationRoles, Users);
}
/** Get the available scopes of a user in an organization. */
async getUserScopes(
organizationId: string,
userId: string
): Promise<readonly OrganizationScope[]> {
const { fields } = convertToIdentifiers(OrganizationRoleUserRelations, true);
const roleScopeRelations = convertToIdentifiers(OrganizationRoleScopeRelations, true);
const scopes = convertToIdentifiers(OrganizationScopes, true);
return this.pool.any<OrganizationScope>(sql`
select distinct on (${scopes.fields.id})
${sql.join(Object.values(scopes.fields), sql`, `)}
from ${this.table}
join ${roleScopeRelations.table}
on ${roleScopeRelations.fields.organizationRoleId} = ${fields.organizationRoleId}
join ${scopes.table}
on ${scopes.fields.id} = ${roleScopeRelations.fields.organizationScopeId}
where ${fields.organizationId} = ${organizationId}
and ${fields.userId} = ${userId}
`);
}
/**
* Get the available resource scopes of a user in all organizations.
* If `organizationId` is provided, it will only search in that organization.
*/
async getUserResourceScopes(
userId: string,
resourceIndicator: string,
organizationId?: string
): Promise<readonly ResourceScopeEntity[]> {
const { fields } = convertToIdentifiers(OrganizationRoleUserRelations, true);
const roleScopeRelations = convertToIdentifiers(OrganizationRoleResourceScopeRelations, true);
const scopes = convertToIdentifiers(Scopes, true);
const resources = convertToIdentifiers(Resources, true);
return this.pool.any<ResourceScopeEntity>(sql`
select distinct on (${scopes.fields.id})
${scopes.fields.id}, ${scopes.fields.name}
from ${this.table}
join ${roleScopeRelations.table}
on ${roleScopeRelations.fields.organizationRoleId} = ${fields.organizationRoleId}
join ${scopes.table}
on ${scopes.fields.id} = ${roleScopeRelations.fields.scopeId}
join ${resources.table}
on ${resources.fields.id} = ${scopes.fields.resourceId}
where ${fields.userId} = ${userId}
and ${resources.fields.indicator} = ${resourceIndicator}
${conditionalSql(organizationId, (value) => sql`and ${fields.organizationId} = ${value}`)}
`);
}
/** Replace the roles of a user in an organization. */
async replace(organizationId: string, userId: string, roleIds: string[]) {
const users = convertToIdentifiers(Users);
const relations = convertToIdentifiers(OrganizationRoleUserRelations);
return this.pool.transaction(async (transaction) => {
// Lock user
await transaction.query(sql`
select id
from ${users.table}
where ${users.fields.id} = ${userId}
for update
`);
// Delete old relations
await transaction.query(sql`
delete from ${relations.table}
where ${relations.fields.userId} = ${userId}
and ${relations.fields.organizationId} = ${organizationId}
`);
// Insert new relations
if (roleIds.length === 0) {
return;
}
await transaction.query(sql`
insert into ${relations.table} (
${relations.fields.userId},
${relations.fields.organizationId},
${relations.fields.organizationRoleId}
)
values ${sql.join(
roleIds.map((roleId) => sql`(${userId}, ${organizationId}, ${roleId})`),
sql`, `
)}
`);
});
}
}

View file

@ -1,28 +1,18 @@
import {
Organizations,
OrganizationRoles,
OrganizationScopes,
OrganizationRoleScopeRelations,
Users,
OrganizationUserRelations,
OrganizationRoleUserRelations,
type OrganizationWithRoles,
type UserWithOrganizationRoles,
type FeaturedUser,
type OrganizationScope,
type ResourceScopeEntity,
Scopes,
OrganizationRoleResourceScopeRelations,
Resources,
} from '@logto/schemas';
import { sql, type CommonQueryMethods } from '@silverhand/slonik';
import { type SearchOptions, buildSearchSql, expandFields } from '#src/database/utils.js';
import RelationQueries, {
type GetEntitiesOptions,
TwoRelationsQueries,
} from '#src/utils/RelationQueries.js';
import { conditionalSql, convertToIdentifiers } from '#src/utils/sql.js';
import { type GetEntitiesOptions, TwoRelationsQueries } from '#src/utils/RelationQueries.js';
import { convertToIdentifiers } from '#src/utils/sql.js';
import { type userSearchKeys } from '../user.js';
@ -170,103 +160,3 @@ export class UserRelationQueries extends TwoRelationsQueries<typeof Organization
`;
}
}
export class RoleUserRelationQueries extends RelationQueries<
[typeof Organizations, typeof OrganizationRoles, typeof Users]
> {
constructor(pool: CommonQueryMethods) {
super(pool, OrganizationRoleUserRelations.table, Organizations, OrganizationRoles, Users);
}
/** Get the available scopes of a user in an organization. */
async getUserScopes(
organizationId: string,
userId: string
): Promise<readonly OrganizationScope[]> {
const { fields } = convertToIdentifiers(OrganizationRoleUserRelations, true);
const roleScopeRelations = convertToIdentifiers(OrganizationRoleScopeRelations, true);
const scopes = convertToIdentifiers(OrganizationScopes, true);
return this.pool.any<OrganizationScope>(sql`
select distinct on (${scopes.fields.id})
${sql.join(Object.values(scopes.fields), sql`, `)}
from ${this.table}
join ${roleScopeRelations.table}
on ${roleScopeRelations.fields.organizationRoleId} = ${fields.organizationRoleId}
join ${scopes.table}
on ${scopes.fields.id} = ${roleScopeRelations.fields.organizationScopeId}
where ${fields.organizationId} = ${organizationId}
and ${fields.userId} = ${userId}
`);
}
/**
* Get the available resource scopes of a user in all organizations.
* If `organizationId` is provided, it will only search in that organization.
*/
async getUserResourceScopes(
userId: string,
resourceIndicator: string,
organizationId?: string
): Promise<readonly ResourceScopeEntity[]> {
const { fields } = convertToIdentifiers(OrganizationRoleUserRelations, true);
const roleScopeRelations = convertToIdentifiers(OrganizationRoleResourceScopeRelations, true);
const scopes = convertToIdentifiers(Scopes, true);
const resources = convertToIdentifiers(Resources, true);
return this.pool.any<ResourceScopeEntity>(sql`
select distinct on (${scopes.fields.id})
${scopes.fields.id}, ${scopes.fields.name}
from ${this.table}
join ${roleScopeRelations.table}
on ${roleScopeRelations.fields.organizationRoleId} = ${fields.organizationRoleId}
join ${scopes.table}
on ${scopes.fields.id} = ${roleScopeRelations.fields.scopeId}
join ${resources.table}
on ${resources.fields.id} = ${scopes.fields.resourceId}
where ${fields.userId} = ${userId}
and ${resources.fields.indicator} = ${resourceIndicator}
${conditionalSql(organizationId, (value) => sql`and ${fields.organizationId} = ${value}`)}
`);
}
/** Replace the roles of a user in an organization. */
async replace(organizationId: string, userId: string, roleIds: string[]) {
const users = convertToIdentifiers(Users);
const relations = convertToIdentifiers(OrganizationRoleUserRelations);
return this.pool.transaction(async (transaction) => {
// Lock user
await transaction.query(sql`
select id
from ${users.table}
where ${users.fields.id} = ${userId}
for update
`);
// Delete old relations
await transaction.query(sql`
delete from ${relations.table}
where ${relations.fields.userId} = ${userId}
and ${relations.fields.organizationId} = ${organizationId}
`);
// Insert new relations
if (roleIds.length === 0) {
return;
}
await transaction.query(sql`
insert into ${relations.table} (
${relations.fields.userId},
${relations.fields.organizationId},
${relations.fields.organizationRoleId}
)
values ${sql.join(
roleIds.map((roleId) => sql`(${userId}, ${organizationId}, ${roleId})`),
sql`, `
)}
`);
});
}
}