// // Copyright © 2020, 2021 Anticrm Platform Contributors. // // Licensed under the Eclipse Public License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // limitations under the License. // import { Account, AnyAttribute, Class, Doc, DocIndexState, IndexKind, Obj, Ref } from './classes' import { FindResult } from './storage' import core from './component' function toHex (value: number, chars: number): string { const result = value.toString(16) if (result.length < chars) { return '0'.repeat(chars - result.length) + result } return result } let counter = (Math.random() * (1 << 24)) | 0 const random = toHex((Math.random() * (1 << 24)) | 0, 6) + toHex((Math.random() * (1 << 16)) | 0, 4) function timestamp (): string { const time = (Date.now() / 1000) | 0 return toHex(time, 8) } function count (): string { const val = counter++ & 0xffffff return toHex(val, 6) } /** * @public * @returns */ export function generateId (): Ref { return (timestamp() + random + count()) as Ref } let currentAccount: Account /** * @public * @returns */ export function getCurrentAccount (): Account { return currentAccount } /** * @public * @param account - */ export function setCurrentAccount (account: Account): void { currentAccount = account } /** * @public */ export function escapeLikeForRegexp (value: string): string { return value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') } /** * @public */ export function toFindResult (docs: T[], total?: number): FindResult { const length = total ?? docs.length return Object.assign(docs, { total: length }) } /** * @public */ export interface WorkspaceId { name: string productId: string } /** * @public * * Combine workspace with productId, if not equal '' */ export function getWorkspaceId (workspace: string, productId: string = ''): WorkspaceId { return { name: workspace, productId } } /** * @public */ export function toWorkspaceString (id: WorkspaceId, sep = '@'): string { return id.name + (id.productId === '' ? '' : sep + id.productId) } const attributesPrefix = 'attributes.' /** * @public */ export interface IndexKeyOptions { _class?: Ref> docId?: Ref extra?: string[] } /** * @public */ export function docUpdKey (name: string, opt?: IndexKeyOptions): string { return attributesPrefix + docKey(name, opt) } /** * @public */ export function docKey (name: string, opt?: IndexKeyOptions): string { const extra = opt?.extra !== undefined && opt?.extra?.length > 0 ? `#${opt.extra?.join('#') ?? ''}` : '' return ( (opt?.docId !== undefined ? opt.docId.split('.').join('_') + '|' : '') + (opt?._class === undefined ? name : `${opt?._class}%${name}${extra}`) ) } /** * @public */ export function extractDocKey (key: string): { _class?: Ref> attr: string docId?: Ref extra: string[] } { let k = key if (k.startsWith(attributesPrefix)) { k = k.slice(attributesPrefix.length) } let docId: Ref | undefined let _class: Ref> | undefined let attr = '' const docSepPos = k.indexOf('|') if (docSepPos !== -1) { docId = k.substring(0, docSepPos).replace('_', '.') as Ref k = k.substring(docSepPos + 1) } const clPos = k.indexOf('%') if (clPos !== -1) { _class = k.substring(0, clPos) as Ref> attr = k.substring(clPos + 1) } else { attr = k } const extra = attr.split('#') attr = extra.splice(0, 1)[0] return { docId, attr, _class, extra } } /** * @public */ export function isFullTextAttribute (attr: AnyAttribute): boolean { return attr.index === IndexKind.FullText || attr.type._class === core.class.TypeAttachment }