import {Repository} from '@orion-js/services'
import {createCollection, MongoFilter, typedId} from '@orion-js/mongodb'
import {schemaWithName, InferSchemaType} from '@orion-js/schema'
import {UsersListQueryParams} from './ListQueryParams'
import {isEqual} from 'lodash'
import {logger} from '@orion-js/logger'
import {getSearchTokens, getSearchQueryForTokens, shortenMongoId} from '@orion-js/helpers'
const UserSchema = schemaWithName('UserSchema', {
_id: {type: typedId('usr')},
firstName: {type: String},
lastName: {type: String},
email: {type: String},
role: {type: String},
status: {type: String},
searchTokens: {type: [String]}
})
type UserType = InferSchemaType<typeof UserSchema>
@Repository()
export class UsersRepo {
users = createCollection({
name: 'users',
schema: UserSchema,
indexes: [
{
keys: {
searchTokens: 1,
}
}
]
})
private getSearchTokens(doc: UserType) {
const texts = [
doc.firstName,
doc.lastName,
doc.email,
shortenMongoId(doc._id)
]
return getSearchTokens(texts, {
role: doc.role,
status: doc.status
})
}
async createUser(doc: Omit<UserType, '_id'>) {
const docWithTokens = {
...doc,
searchTokens: this.getSearchTokens({...doc, _id: `usr-temp`} as UserType)
}
return await this.users.insertAndFind(docWithTokens)
}
async updateUser(userId: string, doc: Partial<UserType>) {
const result = await this.users.updateAndFind(userId, {$set: doc})
this.ensureSearchTokensAreUpdated(result)
return result
}
private ensureSearchTokensAreUpdated(user: UserType) {
const searchTokens = this.getSearchTokens(user)
if (!isEqual(user.searchTokens, searchTokens)) {
this.users
.updateOne(user._id, {
$set: {searchTokens},
})
.catch(error => {
logger.error('Error updating search tokens', {error, userId: user._id, searchTokens})
})
}
}
private async getUsersListQuery(params: UsersListQueryParams) {
const queries: MongoFilter<UserType>[] = []
const searchTokensParams: Record<string, string> = {}
if (params.role) {
searchTokensParams.role = params.role
}
if (params.status) {
searchTokensParams.status = params.status
}
const searchTokens = getSearchQueryForTokens({
filter: params.filter,
...searchTokensParams,
})
if (searchTokens.$all.length) {
queries.push({searchTokens})
}
return {
$and: queries.length ? queries : [{}],
}
}
async getUsersListCursor(params: UsersListQueryParams) {
const query = await this.getUsersListQuery(params)
return this.users.find(query)
}
}