@wepublish/api-db-mongodb
Version:
We.publish Database adapter for mongoDB
252 lines (214 loc) • 7 kB
text/typescript
import {
DBUserRoleAdapter,
CreateUserRoleArgs,
OptionalUserRole,
UserRole,
SortOrder,
UpdateUserRoleArgs,
DeleteUserRoleArgs,
GetUserRolesArgs,
ConnectionResult,
LimitType,
InputCursorType,
UserRoleSort
} from '@wepublish/api'
import {Collection, Db, FilterQuery, MongoCountPreferences} from 'mongodb'
import {CollectionName, DBUserRole} from './schema'
import {MaxResultsPerPage} from './defaults'
import {Cursor} from './cursor'
import {escapeRegExp, isNonNull} from '../utility'
export class MongoDBUserRoleAdapter implements DBUserRoleAdapter {
private userRoles: Collection<DBUserRole>
private locale: string
constructor(db: Db, locale: string) {
this.userRoles = db.collection(CollectionName.UserRoles)
this.locale = locale
}
async createUserRole({input}: CreateUserRoleArgs): Promise<OptionalUserRole> {
const {insertedId: id} = await this.userRoles.insertOne({
createdAt: new Date(),
modifiedAt: new Date(),
name: input.name,
description: input.description || '',
systemRole: false, //always False because only the system can create system roles
permissionIDs: input.permissionIDs // Test if they exist
})
const userRole = await this.userRoles.findOne({_id: id})
if (!userRole) {
throw new Error('Could not create UserRole')
}
return {
id: userRole._id,
name: userRole.name,
description: userRole.description,
systemRole: userRole.systemRole,
permissionIDs: userRole.permissionIDs
}
}
async updateUserRole({id, input}: UpdateUserRoleArgs): Promise<OptionalUserRole> {
const userRole = await this.getUserRoleByID(id)
if (userRole?.systemRole) {
throw new Error('Can not change SystemRoles')
}
const {value} = await this.userRoles.findOneAndUpdate(
{_id: id},
{
$set: {
modifiedAt: new Date(),
name: input.name,
description: input.description,
permissionIDs: input.permissionIDs
}
},
{returnOriginal: false}
)
if (!value) return null
const {_id: outID} = value
return this.getUserRoleByID(outID)
}
async deleteUserRole({id}: DeleteUserRoleArgs): Promise<string | null> {
const userRole = await this.getUserRoleByID(id)
if (userRole?.systemRole) {
throw new Error('Can not delete SystemRoles')
}
const {deletedCount} = await this.userRoles.deleteOne({_id: id})
return deletedCount !== 0 ? id : null
}
async getUserRole(name: string): Promise<OptionalUserRole> {
const userRole = await this.userRoles.findOne({name})
if (userRole) {
return {
id: userRole._id,
name: userRole.name,
description: userRole.description,
systemRole: userRole.systemRole,
permissionIDs: userRole.permissionIDs
}
} else {
return null
}
}
async getUserRoleByID(id: string): Promise<OptionalUserRole> {
const userRole = await this.userRoles.findOne({_id: id})
if (userRole) {
return {
id: userRole._id,
name: userRole.name,
description: userRole.description,
systemRole: userRole.systemRole,
permissionIDs: userRole.permissionIDs
}
} else {
return null
}
}
async getUserRolesByID(ids: string[]): Promise<OptionalUserRole[]> {
const userRoles = await this.userRoles.find({_id: {$in: ids}}).toArray()
return userRoles.map<OptionalUserRole>(userRole => ({
id: userRole._id,
name: userRole.name,
description: userRole.description,
systemRole: userRole.systemRole,
permissionIDs: userRole.permissionIDs
}))
}
async getNonOptionalUserRolesByID(ids: string[]): Promise<UserRole[]> {
const roles = await this.getUserRolesByID(ids)
return roles ? roles.filter(isNonNull) : []
}
async getUserRoles({
filter,
sort,
order,
cursor,
limit
}: GetUserRolesArgs): Promise<ConnectionResult<UserRole>> {
const limitCount = Math.min(limit.count, MaxResultsPerPage)
const sortDirection = limit.type === LimitType.First ? order : -order
const cursorData = cursor.type !== InputCursorType.None ? Cursor.from(cursor.data) : undefined
const expr =
order === SortOrder.Ascending
? cursor.type === InputCursorType.After
? '$gt'
: '$lt'
: cursor.type === InputCursorType.After
? '$lt'
: '$gt'
const sortField = userRoleSortFieldForSort(sort)
const cursorFilter = cursorData
? {
$or: [
{[sortField]: {[expr]: cursorData.date}},
{_id: {[expr]: cursorData.id}, [sortField]: cursorData.date}
]
}
: {}
let textFilter: FilterQuery<any> = {}
// TODO: Rename to search
if (filter?.name != undefined) {
textFilter['$or'] = [{name: {$regex: escapeRegExp(filter.name), $options: 'i'}}]
}
const [totalCount, userRoles] = await Promise.all([
this.userRoles.countDocuments(textFilter, {
collation: {locale: this.locale, strength: 2}
} as MongoCountPreferences), // MongoCountPreferences doesn't include collation
this.userRoles
.aggregate([], {collation: {locale: this.locale, strength: 2}})
.match(textFilter)
.match(cursorFilter)
.sort({[sortField]: sortDirection, _id: sortDirection})
.limit(limitCount + 1)
.toArray()
])
const nodes = userRoles.slice(0, limitCount)
if (limit.type === LimitType.Last) {
nodes.reverse()
}
const hasNextPage =
limit.type === LimitType.First
? userRoles.length > limitCount
: cursor.type === InputCursorType.Before
? true
: false
const hasPreviousPage =
limit.type === LimitType.Last
? userRoles.length > limitCount
: cursor.type === InputCursorType.After
? true
: false
const firstUserRole = nodes[0]
const lastUserRole = nodes[nodes.length - 1]
const startCursor = firstUserRole
? new Cursor(firstUserRole._id, userRoleDateForSort(firstUserRole, sort)).toString()
: null
const endCursor = lastUserRole
? new Cursor(lastUserRole._id, userRoleDateForSort(lastUserRole, sort)).toString()
: null
return {
nodes: nodes.map<UserRole>(({_id: id, ...userRole}) => ({id, ...userRole})),
pageInfo: {
startCursor,
endCursor,
hasNextPage,
hasPreviousPage
},
totalCount
}
}
}
function userRoleSortFieldForSort(sort: UserRoleSort) {
switch (sort) {
case UserRoleSort.CreatedAt:
return 'createdAt'
case UserRoleSort.ModifiedAt:
return 'modifiedAt'
}
}
function userRoleDateForSort(userRole: DBUserRole, sort: UserRoleSort): Date {
switch (sort) {
case UserRoleSort.CreatedAt:
return userRole.createdAt
case UserRoleSort.ModifiedAt:
return userRole.modifiedAt
}
}