From efc044fe2ca69d5cadb9579adaf1f34d57762605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ad=C3=A1mek?= Date: Thu, 13 Aug 2020 15:22:42 +0200 Subject: [PATCH] perf(core): improve performance of QB a bit Related: #732 --- packages/core/src/drivers/DatabaseDriver.ts | 27 ++++++++++++++++++++- packages/core/src/utils/QueryHelper.ts | 2 +- packages/knex/src/query/QueryBuilder.ts | 8 ++++-- packages/mongodb/src/MongoDriver.ts | 27 +-------------------- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/packages/core/src/drivers/DatabaseDriver.ts b/packages/core/src/drivers/DatabaseDriver.ts index e51c5231436b..cf0d0cfba431 100644 --- a/packages/core/src/drivers/DatabaseDriver.ts +++ b/packages/core/src/drivers/DatabaseDriver.ts @@ -2,7 +2,7 @@ import { EntityManagerType, FindOneOptions, FindOptions, IDatabaseDriver } from import { EntityData, EntityMetadata, EntityProperty, FilterQuery, AnyEntity, Dictionary, Primary, PopulateOptions } from '../typings'; import { MetadataStorage } from '../metadata'; import { Connection, QueryResult, Transaction } from '../connections'; -import { Configuration, ConnectionOptions, Utils } from '../utils'; +import { Configuration, ConnectionOptions, Utils, ValidationError } from '../utils'; import { QueryOrder, QueryOrderMap } from '../enums'; import { Platform } from '../platforms'; import { Collection, ReferenceType } from '../entity'; @@ -125,6 +125,31 @@ export abstract class DatabaseDriver implements IDatabaseD throw new Error(`${this.constructor.name} does not use ensureIndexes`); } + protected inlineEmbeddables(meta: EntityMetadata, data: T): void { + Object.keys(data).forEach(k => { + if (Utils.isOperator(k)) { + Utils.asArray(data[k]).forEach(payload => this.inlineEmbeddables(meta, payload)); + } + }); + + Object.values(meta.properties).forEach(prop => { + if (prop.reference === ReferenceType.EMBEDDED && Utils.isObject(data[prop.name])) { + const props = prop.embeddedProps; + + Object.keys(data[prop.name]).forEach(kk => { + const operator = Object.keys(data[prop.name]).some(f => Utils.isOperator(f)); + + if (operator) { + throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.name, prop.name, data); + } + + data[props[kk].name] = data[prop.name][props[kk].embedded![1]]; + }); + delete data[prop.name]; + } + }); + } + protected getPivotOrderBy(prop: EntityProperty, orderBy?: QueryOrderMap): QueryOrderMap { if (orderBy) { return orderBy; diff --git a/packages/core/src/utils/QueryHelper.ts b/packages/core/src/utils/QueryHelper.ts index 0d8536502243..008221f87875 100644 --- a/packages/core/src/utils/QueryHelper.ts +++ b/packages/core/src/utils/QueryHelper.ts @@ -1,4 +1,4 @@ -import { Reference, wrap } from '../entity'; +import { Reference } from '../entity'; import { Utils } from './Utils'; import { AnyEntity, Dictionary, EntityMetadata, FilterDef, FilterQuery } from '../typings'; import { GroupOperator } from '../enums'; diff --git a/packages/knex/src/query/QueryBuilder.ts b/packages/knex/src/query/QueryBuilder.ts index b4fdd10a69a8..d1631225380e 100644 --- a/packages/knex/src/query/QueryBuilder.ts +++ b/packages/knex/src/query/QueryBuilder.ts @@ -1,4 +1,4 @@ -import { QueryBuilder as KnexQueryBuilder, Raw, Transaction, Value, Ref } from 'knex'; +import { QueryBuilder as KnexQueryBuilder, Raw, Ref, Transaction, Value } from 'knex'; import { AnyEntity, Dictionary, EntityMetadata, EntityProperty, FlatQueryOrderMap, GroupOperator, LockMode, MetadataStorage, QBFilterQuery, QueryFlag, QueryOrderMap, ReferenceType, QueryHelper, Utils, ValidationError, PopulateOptions, @@ -44,7 +44,7 @@ export class QueryBuilder = AnyEntity> { readonly alias = `e0`, private readonly connectionType?: 'read' | 'write', private readonly em?: SqlEntityManager) { - this.select('*'); + this._aliasMap[this.alias] = this.entityName; } select(fields: Field | Field[], distinct = false): this { @@ -461,6 +461,10 @@ export class QueryBuilder = AnyEntity> { return; } + if (!this.type) { + this.select('*'); + } + const meta = this.metadata.find(this.entityName); this._populate.forEach(({ field }) => { const [fromAlias, fromField] = this.helper.splitField(field); diff --git a/packages/mongodb/src/MongoDriver.ts b/packages/mongodb/src/MongoDriver.ts index f4efa1d78e57..5d32239c3eec 100644 --- a/packages/mongodb/src/MongoDriver.ts +++ b/packages/mongodb/src/MongoDriver.ts @@ -1,7 +1,7 @@ import { ClientSession, ObjectId } from 'mongodb'; import { DatabaseDriver, EntityData, AnyEntity, FilterQuery, EntityMetadata, EntityProperty, Configuration, Utils, ReferenceType, FindOneOptions, FindOptions, - QueryResult, Transaction, IDatabaseDriver, EntityManager, EntityManagerType, Dictionary, ValidationError, PopulateOptions, + QueryResult, Transaction, IDatabaseDriver, EntityManager, EntityManagerType, Dictionary, PopulateOptions, } from '@mikro-orm/core'; import { MongoConnection } from './MongoConnection'; import { MongoPlatform } from './MongoPlatform'; @@ -178,31 +178,6 @@ export class MongoDriver extends DatabaseDriver { })]; } - private inlineEmbeddables(meta: EntityMetadata, data: T): void { - Object.keys(data).forEach(k => { - if (Utils.isOperator(k)) { - Utils.asArray(data[k]).forEach(payload => this.inlineEmbeddables(meta, payload)); - } - }); - - Object.values(meta.properties).forEach(prop => { - if (prop.reference === ReferenceType.EMBEDDED && Utils.isObject(data[prop.name])) { - const props = prop.embeddedProps; - - Object.keys(data[prop.name]).forEach(kk => { - const operator = Object.keys(data[prop.name]).some(f => Utils.isOperator(f)); - - if (operator) { - throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.name, prop.name, data); - } - - data[props[kk].name] = data[prop.name][props[kk].embedded![1]]; - }); - delete data[prop.name]; - } - }); - } - private renameFields(entityName: string, data: T): T { data = Object.assign({}, data); // copy first Utils.renameKey(data, 'id', '_id');