mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-15 12:55:59 +00:00
Do not clone model requests on server if possible (#6353)
This commit is contained in:
parent
895a2b1bf6
commit
84cd3b6cbb
@ -189,6 +189,7 @@ export abstract class MemDb extends TxProcessor implements Storage {
|
||||
|
||||
/**
|
||||
* Only in model find without lookups and sorting.
|
||||
* Do not clone results, so be aware modifications are not allowed.
|
||||
*/
|
||||
findAllSync<T extends Doc>(_class: Ref<Class<T>>, query: DocumentQuery<T>, options?: FindOptions<T>): FindResult<T> {
|
||||
let result: WithLookup<Doc>[]
|
||||
@ -210,9 +211,13 @@ export abstract class MemDb extends TxProcessor implements Storage {
|
||||
}
|
||||
const total = result.length
|
||||
result = result.slice(0, options?.limit)
|
||||
const tresult = this.hierarchy.clone(result) as WithLookup<T>[]
|
||||
const res = tresult.map((it) => this.hierarchy.updateLookupMixin(_class, it, options))
|
||||
return toFindResult(res, total)
|
||||
|
||||
return toFindResult(
|
||||
result.map((it) => {
|
||||
return baseClass !== _class ? this.hierarchy.as(it, _class) : it
|
||||
}) as WithLookup<T>[],
|
||||
total
|
||||
)
|
||||
}
|
||||
|
||||
addDoc (doc: Doc): void {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { PlatformError, unknownError } from '@hcengineering/platform'
|
||||
import { Ref } from '.'
|
||||
import type { Doc, Mixin } from './classes'
|
||||
|
||||
@ -26,6 +27,46 @@ export function _createMixinProxy (mixin: Mixin<Doc>, ancestorProxy: ProxyHandle
|
||||
}
|
||||
}
|
||||
|
||||
export function freeze (value: any): any {
|
||||
if (value != null && typeof value === 'object') {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((it) => freeze(it))
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
throw new PlatformError(unknownError('Map is not allowed in model'))
|
||||
}
|
||||
if (value instanceof Set) {
|
||||
throw new PlatformError(unknownError('Set is not allowed in model'))
|
||||
}
|
||||
return new Proxy(value, _createFreezeProxy(value))
|
||||
}
|
||||
return value
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function _createFreezeProxy (doc: Doc): ProxyHandler<Doc> {
|
||||
return {
|
||||
get (target: any, property: string, receiver: any): any {
|
||||
const value = target[property]
|
||||
return freeze(value)
|
||||
},
|
||||
set (target, p, newValue, receiver): any {
|
||||
throw new PlatformError(unknownError('Modification is not allowed'))
|
||||
},
|
||||
defineProperty (target, property, attributes): any {
|
||||
throw new PlatformError(unknownError('Modification is not allowed'))
|
||||
},
|
||||
|
||||
deleteProperty (target, p): any {
|
||||
throw new PlatformError(unknownError('Modification is not allowed'))
|
||||
},
|
||||
setPrototypeOf (target, v): any {
|
||||
throw new PlatformError(unknownError('Modification is not allowed'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -111,6 +111,9 @@ export function escapeLikeForRegexp (value: string): string {
|
||||
*/
|
||||
export function toFindResult<T extends Doc> (docs: T[], total?: number, lookupMap?: Record<string, Doc>): FindResult<T> {
|
||||
const length = total ?? docs.length
|
||||
if (Object.keys(lookupMap ?? {}).length === 0) {
|
||||
lookupMap = undefined
|
||||
}
|
||||
return Object.assign(docs, { total: length, lookupMap })
|
||||
}
|
||||
|
||||
|
@ -352,10 +352,14 @@
|
||||
attr: client.getHierarchy().getAttribute(tracker.class.Issue, 'labels')
|
||||
}
|
||||
|
||||
$: spaceQuery.query(tracker.class.Project, { _id: _space }, (res) => {
|
||||
resetDefaultAssigneeId()
|
||||
currentProject = res[0]
|
||||
})
|
||||
$: if (_space !== undefined) {
|
||||
spaceQuery.query(tracker.class.Project, { _id: _space }, (res) => {
|
||||
resetDefaultAssigneeId()
|
||||
currentProject = res[0]
|
||||
})
|
||||
} else {
|
||||
currentProject = undefined
|
||||
}
|
||||
|
||||
const docCreateManager = DocCreateExtensionManager.create(tracker.class.Issue)
|
||||
|
||||
@ -758,7 +762,7 @@
|
||||
label={tracker.string.Project}
|
||||
bind:space={_space}
|
||||
on:object={(evt) => {
|
||||
currentProject = evt.detail
|
||||
currentProject = evt.detail ?? undefined
|
||||
}}
|
||||
kind={'regular'}
|
||||
size={'small'}
|
||||
|
@ -1,7 +1,7 @@
|
||||
FROM node:20
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
RUN npm install --ignore-scripts=false --verbose bufferutil utf-8-validate @mongodb-js/zstd snappy --unsafe-perm
|
||||
RUN npm install --ignore-scripts=false --verbose bufferutil utf-8-validate @mongodb-js/zstd snappy msgpackr msgpackr-extract --unsafe-perm
|
||||
RUN npm install --ignore-scripts=false --verbose uNetworking/uWebSockets.js#v20.47.0
|
||||
|
||||
RUN apt-get update
|
||||
@ -16,4 +16,4 @@ COPY bundle/bundle.js.map ./
|
||||
|
||||
EXPOSE 8080
|
||||
ENV UWS_HTTP_MAX_HEADERS_SIZE 32768
|
||||
CMD node --enable-source-maps --inspect bundle.js
|
||||
CMD node --enable-source-maps --inspect=0.0.0.0:9229 bundle.js
|
||||
|
@ -15,7 +15,7 @@
|
||||
"_phase:bundle": "rushx bundle",
|
||||
"_phase:docker-build": "rushx docker:build",
|
||||
"_phase:docker-staging": "rushx docker:staging",
|
||||
"bundle": "mkdir -p bundle && esbuild src/__start.ts --sourcemap=inline --bundle --keep-names --platform=node --external:*.node --external:bufferutil --external:snappy --external:utf-8-validate --define:process.env.MODEL_VERSION=$(node ../../common/scripts/show_version.js) --define:process.env.GIT_REVISION=$(../../common/scripts/git_version.sh) --outfile=bundle/bundle.js --log-level=error --sourcemap=external",
|
||||
"bundle": "mkdir -p bundle && esbuild src/__start.ts --sourcemap=inline --bundle --keep-names --platform=node --external:*.node --external:bufferutil --external:snappy --external:utf-8-validate --external:msgpackr-extract --define:process.env.MODEL_VERSION=$(node ../../common/scripts/show_version.js) --define:process.env.GIT_REVISION=$(../../common/scripts/git_version.sh) --outfile=bundle/bundle.js --log-level=error --sourcemap=external",
|
||||
"docker:build": "../../common/scripts/docker_build.sh hardcoreeng/transactor",
|
||||
"docker:tbuild": "docker build -t hardcoreeng/transactor . --platform=linux/amd64 && ../../common/scripts/docker_tag_push.sh hardcoreeng/transactor",
|
||||
"docker:abuild": "docker build -t hardcoreeng/transactor . --platform=linux/arm64 && ../../common/scripts/docker_tag_push.sh hardcoreeng/transactor",
|
||||
|
@ -71,7 +71,8 @@ export class LookupMiddleware extends BaseMiddleware implements Middleware {
|
||||
|
||||
for (const d of result) {
|
||||
if (d.$lookup !== undefined) {
|
||||
const newDoc = clone(d)
|
||||
const newDoc: any = { ...d }
|
||||
newDoc.$lookup = clone(d.$lookup)
|
||||
newResult.push(newDoc)
|
||||
for (const [k, v] of Object.entries(d.$lookup)) {
|
||||
if (!Array.isArray(v)) {
|
||||
@ -83,22 +84,36 @@ export class LookupMiddleware extends BaseMiddleware implements Middleware {
|
||||
}
|
||||
}
|
||||
const lookupMap = Object.fromEntries(Array.from(Object.values(idClassMap)).map((it) => [it.id, it.doc]))
|
||||
if (Object.keys(lookupMap).length > 0) {
|
||||
return toFindResult(newResult, result.total, lookupMap)
|
||||
}
|
||||
return this.cleanQuery<T>(toFindResult(newResult, result.total, lookupMap), query, lookupMap)
|
||||
}
|
||||
|
||||
// We need to get rid of simple query parameters matched in documents
|
||||
return this.cleanQuery<T>(result, query)
|
||||
}
|
||||
|
||||
private cleanQuery<T extends Doc>(
|
||||
result: FindResult<T>,
|
||||
query: DocumentQuery<T>,
|
||||
lookupMap?: Record<string, Doc>
|
||||
): FindResult<T> {
|
||||
const newResult: T[] = []
|
||||
for (const doc of result) {
|
||||
let _doc = doc
|
||||
let cloned = false
|
||||
for (const [k, v] of Object.entries(query)) {
|
||||
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {
|
||||
if ((doc as any)[k] === v) {
|
||||
if ((_doc as any)[k] === v) {
|
||||
if (!cloned) {
|
||||
_doc = { ...doc } as any
|
||||
cloned = true
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete (doc as any)[k]
|
||||
delete (_doc as any)[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
newResult.push(_doc)
|
||||
}
|
||||
return result
|
||||
return toFindResult(newResult, result.total, lookupMap)
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ export interface Response<R> {
|
||||
}
|
||||
|
||||
export class RPCHandler {
|
||||
packr = new Packr({ structuredClone: true, bundleStrings: true, copyBuffers: true })
|
||||
packr = new Packr({ structuredClone: true, bundleStrings: true, copyBuffers: false })
|
||||
protoSerialize (object: object, binary: boolean): any {
|
||||
if (!binary) {
|
||||
return JSON.stringify(object, replacer)
|
||||
|
@ -4,8 +4,6 @@ FROM node:20
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN npm install --ignore-scripts=false --verbose bufferutil utf-8-validate @mongodb-js/zstd snappy --unsafe-perm
|
||||
COPY bundle/bundle.js ./
|
||||
COPY bundle/bundle.js.map ./
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install libjemalloc2
|
||||
@ -13,5 +11,8 @@ RUN apt-get install libjemalloc2
|
||||
ENV LD_PRELOAD=libjemalloc.so.2
|
||||
ENV MALLOC_CONF=dirty_decay_ms:1000,narenas:2,background_thread:true
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
COPY bundle/bundle.js.map ./
|
||||
|
||||
EXPOSE 3078
|
||||
CMD [ "node", "--inspect", "--async-stack-traces", "--enable-source-maps", "bundle.js" ]
|
||||
|
@ -16,7 +16,7 @@ RUN apt-get update && \
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
RUN npm install --ignore-scripts=false --verbose bufferutil utf-8-validate @mongodb-js/zstd snappy --unsafe-perm
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
CMD [ "dumb-init", "node", "bundle.js" ]
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { expect, type Locator } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { createIssue, toTime } from '../../tracker/tracker.utils'
|
||||
import { attachScreenshot, iterateLocator } from '../../utils'
|
||||
import { CommonTrackerPage } from './common-tracker-page'
|
||||
import { NewIssue } from './types'
|
||||
import { createIssue, toTime } from '../../tracker/tracker.utils'
|
||||
|
||||
const retryOptions = { intervals: [1000, 1500, 2500], timeout: 60000 }
|
||||
export class IssuesPage extends CommonTrackerPage {
|
||||
modelSelectorAll = (): Locator => this.page.locator('label[data-id="tab-all"]')
|
||||
issues = (): Locator => this.page.locator('text="Issues"')
|
||||
@ -492,15 +493,14 @@ export class IssuesPage extends CommonTrackerPage {
|
||||
}
|
||||
|
||||
async searchIssueByName (issueName: string): Promise<void> {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await expect(async () => {
|
||||
await this.inputSearchIcon().click()
|
||||
await this.inputSearch().fill(issueName)
|
||||
const v = await this.inputSearch().inputValue()
|
||||
if (v === issueName) {
|
||||
await this.inputSearch().press('Enter')
|
||||
break
|
||||
}
|
||||
}
|
||||
}).toPass(retryOptions)
|
||||
}
|
||||
|
||||
async openIssueByName (issueName: string): Promise<void> {
|
||||
@ -557,9 +557,9 @@ export class IssuesPage extends CommonTrackerPage {
|
||||
}
|
||||
|
||||
async checkIssuesCount (issueName: string, count: number, timeout?: number): Promise<void> {
|
||||
await expect(this.issueAnchorByName(issueName)).toHaveCount(count, {
|
||||
timeout: timeout !== undefined ? timeout * 1000 : undefined
|
||||
})
|
||||
await expect(async () => {
|
||||
await expect(this.issueAnchorByName(issueName)).toHaveCount(count)
|
||||
}).toPass(retryOptions)
|
||||
}
|
||||
|
||||
async selectTemplate (templateName: string): Promise<void> {
|
||||
@ -573,7 +573,9 @@ export class IssuesPage extends CommonTrackerPage {
|
||||
}
|
||||
|
||||
async checkAttachmentsCount (issueName: string, count: string): Promise<void> {
|
||||
await expect(this.attachmentContentButton(issueName)).toHaveText(count)
|
||||
await expect(async () => {
|
||||
await expect(this.attachmentContentButton(issueName)).toHaveText(count)
|
||||
}).toPass(retryOptions)
|
||||
}
|
||||
|
||||
async addAttachmentToIssue (issueName: string, filePath: string): Promise<void> {
|
||||
|
Loading…
Reference in New Issue
Block a user