mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-05 15:24:22 +00:00
Enum sorting (#2808)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
746f2a809f
commit
27a3264f9b
@ -27,7 +27,7 @@ import { toFindResult } from './utils'
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export abstract class MemDb extends TxProcessor {
|
||||
export abstract class MemDb extends TxProcessor implements Storage {
|
||||
private readonly objectsByClass = new Map<Ref<Class<Doc>>, Doc[]>()
|
||||
private readonly objectById = new Map<Ref<Doc>, Doc>()
|
||||
|
||||
@ -162,7 +162,7 @@ export abstract class MemDb extends TxProcessor {
|
||||
result = matchQuery(result, query, _class, this.hierarchy)
|
||||
}
|
||||
|
||||
if (options?.sort !== undefined) resultSort(result, options?.sort, _class, this.hierarchy)
|
||||
if (options?.sort !== undefined) await resultSort(result, options?.sort, _class, this.hierarchy, this)
|
||||
const total = result.length
|
||||
result = result.slice(0, options?.limit)
|
||||
const tresult = this.hierarchy.clone(result) as WithLookup<T>[]
|
||||
@ -194,7 +194,7 @@ export abstract class MemDb extends TxProcessor {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class TxDb extends MemDb implements Storage {
|
||||
export class TxDb extends MemDb {
|
||||
protected txCreateDoc (tx: TxCreateDoc<Doc>): Promise<TxResult> {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
@ -222,7 +222,7 @@ export class TxDb extends MemDb implements Storage {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class ModelDb extends MemDb implements Storage {
|
||||
export class ModelDb extends MemDb {
|
||||
protected override async txCreateDoc (tx: TxCreateDoc<Doc>): Promise<TxResult> {
|
||||
this.addDoc(TxProcessor.createDoc2Doc(tx))
|
||||
return {}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { DocumentQuery } from '.'
|
||||
import { Class, Doc, Ref } from './classes'
|
||||
import { Class, Doc, Enum, EnumOf, Ref } from './classes'
|
||||
import core from './component'
|
||||
import { Hierarchy } from './hierarchy'
|
||||
import { getObjectValue } from './objvalue'
|
||||
import { createPredicates, isPredicate } from './predicate'
|
||||
import { SortingOrder, SortingQuery } from './storage'
|
||||
import { SortingOrder, SortingQuery, Storage } from './storage'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -30,19 +31,37 @@ function isArrayValueCheck<T, P> (val: T, value: P): boolean {
|
||||
return Array.isArray(val) && !Array.isArray(value) && val.includes(value)
|
||||
}
|
||||
|
||||
function getEnumValue<T extends Doc> (
|
||||
key: string,
|
||||
_class: Ref<Class<T>>,
|
||||
hierarchy: Hierarchy,
|
||||
obj: any,
|
||||
_enum: Enum
|
||||
): number {
|
||||
const tkey = checkMixinKey(key, _class, hierarchy)
|
||||
const value = getObjectValue(tkey, obj)
|
||||
const index = _enum.enumValues.findIndex((p) => p === value)
|
||||
return index === -1 ? _enum.enumValues.length : index
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function resultSort<T extends Doc> (
|
||||
export async function resultSort<T extends Doc> (
|
||||
result: T[],
|
||||
sortOptions: SortingQuery<T>,
|
||||
_class: Ref<Class<T>>,
|
||||
hierarchy: Hierarchy
|
||||
): void {
|
||||
hierarchy: Hierarchy,
|
||||
modelDb: Storage
|
||||
): Promise<void> {
|
||||
const enums = await getEnums(_class, sortOptions, hierarchy, modelDb)
|
||||
const sortFunc = (a: any, b: any): number => {
|
||||
for (const key in sortOptions) {
|
||||
const aValue = getValue(key, a, _class, hierarchy)
|
||||
const bValue = getValue(key, b, _class, hierarchy)
|
||||
const _enum = enums[key]
|
||||
const aValue =
|
||||
_enum !== undefined ? getEnumValue(key, _class, hierarchy, a, _enum) : getValue(key, a, _class, hierarchy)
|
||||
const bValue =
|
||||
_enum !== undefined ? getEnumValue(key, _class, hierarchy, b, _enum) : getValue(key, b, _class, hierarchy)
|
||||
const result = getSortingResult(aValue, bValue, sortOptions[key])
|
||||
if (result !== 0) return result
|
||||
}
|
||||
@ -67,6 +86,28 @@ function getSortingResult (aValue: any, bValue: any, order: SortingOrder): numbe
|
||||
return res * order
|
||||
}
|
||||
|
||||
async function getEnums<T extends Doc> (
|
||||
_class: Ref<Class<T>>,
|
||||
sortOptions: SortingQuery<T>,
|
||||
hierarchy: Hierarchy,
|
||||
modelDb: Storage
|
||||
): Promise<Record<string, Enum>> {
|
||||
const res: Record<string, Enum> = {}
|
||||
for (const key in sortOptions) {
|
||||
const attr = hierarchy.findAttribute(_class, key)
|
||||
if (attr !== undefined) {
|
||||
if (attr !== undefined) {
|
||||
if (attr.type._class === core.class.EnumOf) {
|
||||
const ref = (attr.type as EnumOf).of
|
||||
const enu = await modelDb.findAll(core.class.Enum, { _id: ref })
|
||||
res[key] = enu[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function getValue<T extends Doc> (key: string, obj: any, _class: Ref<Class<T>>, hierarchy: Hierarchy): any {
|
||||
const tkey = checkMixinKey(key, _class, hierarchy)
|
||||
let value = getObjectValue(tkey, obj)
|
||||
|
@ -394,7 +394,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
if (currentRefresh) return {}
|
||||
}
|
||||
}
|
||||
this.sort(q, tx)
|
||||
await this.sort(q, tx)
|
||||
const udoc = q.result.find((p) => p._id === tx.objectId)
|
||||
await this.updatedDocCallback(udoc, q)
|
||||
} else if (isMixin) {
|
||||
@ -478,11 +478,11 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
if (currentRefresh) return
|
||||
}
|
||||
}
|
||||
this.sort(q, tx)
|
||||
await this.sort(q, tx)
|
||||
const udoc = q.result.find((p) => p._id === tx.objectId)
|
||||
await this.updatedDocCallback(udoc, q)
|
||||
} else if (await this.matchQuery(q, tx)) {
|
||||
this.sort(q, tx)
|
||||
await this.sort(q, tx)
|
||||
const udoc = q.result.find((p) => p._id === tx.objectId)
|
||||
await this.updatedDocCallback(udoc, q)
|
||||
}
|
||||
@ -500,7 +500,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
|
||||
if (needCallback) {
|
||||
if (q.options?.sort !== undefined) {
|
||||
resultSort(q.result, q.options?.sort, q._class, this.getHierarchy())
|
||||
await resultSort(q.result, q.options?.sort, q._class, this.getHierarchy(), this.client.getModel())
|
||||
}
|
||||
await this.callback(q)
|
||||
}
|
||||
@ -725,7 +725,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
q.total++
|
||||
|
||||
if (q.options?.sort !== undefined) {
|
||||
resultSort(q.result, q.options?.sort, q._class, this.getHierarchy())
|
||||
await resultSort(q.result, q.options?.sort, q._class, this.getHierarchy(), this.client.getModel())
|
||||
}
|
||||
|
||||
if (q.options?.limit !== undefined && q.result.length > q.options.limit) {
|
||||
@ -761,7 +761,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
|
||||
if (needCallback) {
|
||||
if (q.options?.sort !== undefined) {
|
||||
resultSort(q.result, q.options?.sort, q._class, this.getHierarchy())
|
||||
await resultSort(q.result, q.options?.sort, q._class, this.getHierarchy(), this.getModel())
|
||||
}
|
||||
await this.callback(q)
|
||||
}
|
||||
@ -863,7 +863,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
}
|
||||
if (needCallback) {
|
||||
if (q.options?.sort !== undefined) {
|
||||
resultSort(q.result, q.options?.sort, q._class, this.getHierarchy())
|
||||
await resultSort(q.result, q.options?.sort, q._class, this.getHierarchy(), this.getModel())
|
||||
}
|
||||
await this.callback(q)
|
||||
}
|
||||
@ -998,13 +998,13 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
await this.__updateLookup(q, updatedDoc, ops)
|
||||
}
|
||||
|
||||
private sort (q: Query, tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>): void {
|
||||
private async sort (q: Query, tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>): Promise<void> {
|
||||
const sort = q.options?.sort
|
||||
if (sort === undefined) return
|
||||
let needSort = sort.modifiedBy !== undefined || sort.modifiedOn !== undefined
|
||||
if (!needSort) needSort = this.checkNeedSort(sort, tx)
|
||||
|
||||
if (needSort) resultSort(q.result as Doc[], sort, q._class, this.getHierarchy())
|
||||
if (needSort) await resultSort(q.result as Doc[], sort, q._class, this.getHierarchy(), this.client.getModel())
|
||||
}
|
||||
|
||||
private checkNeedSort (sort: SortingQuery<Doc>, tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>): boolean {
|
||||
|
@ -41,7 +41,7 @@
|
||||
let applications: Map<Ref<Vacancy>, ApplicationInfo> = new Map<Ref<Vacancy>, ApplicationInfo>()
|
||||
|
||||
const applicantQuery = createQuery()
|
||||
$: applicantQuery.query(
|
||||
applicantQuery.query(
|
||||
recruit.class.Applicant,
|
||||
{},
|
||||
(res) => {
|
||||
|
@ -22,6 +22,8 @@ import core, {
|
||||
Domain,
|
||||
DOMAIN_MODEL,
|
||||
DOMAIN_TX,
|
||||
Enum,
|
||||
EnumOf,
|
||||
escapeLikeForRegexp,
|
||||
FindOptions,
|
||||
FindResult,
|
||||
@ -331,6 +333,39 @@ abstract class MongoAdapterBase implements DbAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private async fillSortPipeline<T extends Doc>(
|
||||
clazz: Ref<Class<T>>,
|
||||
options: FindOptions<T>,
|
||||
pipeline: any[]
|
||||
): Promise<void> {
|
||||
if (options.sort !== undefined) {
|
||||
const sort = {} as any
|
||||
for (const _key in options.sort) {
|
||||
const key = this.translateKey(_key, clazz)
|
||||
const enumOf = await this.isEnumSortKey(clazz, _key)
|
||||
if (enumOf === undefined) {
|
||||
sort[key] = options.sort[_key] === SortingOrder.Ascending ? 1 : -1
|
||||
} else {
|
||||
const branches = enumOf.enumValues.map((value, index) => {
|
||||
return { case: { $eq: [`$${key}`, value] }, then: index }
|
||||
})
|
||||
pipeline.push({
|
||||
$addFields: {
|
||||
[`sort_${key}`]: {
|
||||
$switch: {
|
||||
branches,
|
||||
default: enumOf.enumValues.length
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
sort[`sort_${key}`] = options.sort[_key] === SortingOrder.Ascending ? 1 : -1
|
||||
}
|
||||
}
|
||||
pipeline.push({ $sort: sort })
|
||||
}
|
||||
}
|
||||
|
||||
private async lookup<T extends Doc>(
|
||||
clazz: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
@ -347,14 +382,7 @@ abstract class MongoAdapterBase implements DbAdapter {
|
||||
}
|
||||
pipeline.push(match)
|
||||
const resultPipeline: any[] = []
|
||||
if (options.sort !== undefined) {
|
||||
const sort = {} as any
|
||||
for (const _key in options.sort) {
|
||||
const key: string = this.translateKey(_key, clazz)
|
||||
sort[key] = options.sort[_key] === SortingOrder.Ascending ? 1 : -1
|
||||
}
|
||||
pipeline.push({ $sort: sort })
|
||||
}
|
||||
await this.fillSortPipeline(clazz, options, pipeline)
|
||||
if (options.limit !== undefined) {
|
||||
resultPipeline.push({ $limit: options.limit })
|
||||
}
|
||||
@ -442,6 +470,30 @@ abstract class MongoAdapterBase implements DbAdapter {
|
||||
return key
|
||||
}
|
||||
|
||||
private async isEnumSortKey<T extends Doc>(_class: Ref<Class<T>>, key: string): Promise<Enum | undefined> {
|
||||
const attr = this.hierarchy.findAttribute(_class, key)
|
||||
if (attr !== undefined) {
|
||||
if (attr.type._class === core.class.EnumOf) {
|
||||
const ref = (attr.type as EnumOf).of
|
||||
const res = await this.modelDb.findAll(core.class.Enum, { _id: ref })
|
||||
return res[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private isEnumSort<T extends Doc>(_class: Ref<Class<T>>, options?: FindOptions<T>): boolean {
|
||||
if (options?.sort === undefined) return false
|
||||
for (const key in options.sort) {
|
||||
const attr = this.hierarchy.findAttribute(_class, key)
|
||||
if (attr !== undefined) {
|
||||
if (attr.type._class === core.class.EnumOf) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async findAll<T extends Doc>(
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
@ -449,7 +501,7 @@ abstract class MongoAdapterBase implements DbAdapter {
|
||||
): Promise<FindResult<T>> {
|
||||
// TODO: rework this
|
||||
if (options !== null && options !== undefined) {
|
||||
if (options.lookup !== undefined) {
|
||||
if (options.lookup !== undefined || this.isEnumSort(_class, options)) {
|
||||
return await this.lookup(_class, query, options)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user