@mikro-orm/sql 7.2.2-dev.27 → 7.2.2-dev.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { EntityManager, raw, Utils, } from '@mikro-orm/core';
1
+ import { EntityManager, QueryFlag, raw, Utils, } from '@mikro-orm/core';
2
2
  import { MikroKyselyPlugin } from './plugin/index.js';
3
3
  /**
4
4
  * @inheritDoc
@@ -87,6 +87,7 @@ export class SqlEntityManager extends EntityManager {
87
87
  // match `em.count()` semantics: an active transaction always wins over the requested connection type
88
88
  const connectionType = em.getTransactionContext() ? 'write' : options.connectionType;
89
89
  const qb = em.createQueryBuilder(meta.class, undefined, connectionType);
90
+ qb.unsetFlag(QueryFlag.CONVERT_CUSTOM_TYPES);
90
91
  qb
91
92
  .select([...fields, raw('count(*) as cnt')])
92
93
  .where(where)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.2.2-dev.27",
3
+ "version": "7.2.2-dev.29",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "keywords": [
6
6
  "data-mapper",
@@ -53,7 +53,7 @@
53
53
  "@mikro-orm/core": "^7.2.1"
54
54
  },
55
55
  "peerDependencies": {
56
- "@mikro-orm/core": "7.2.2-dev.27"
56
+ "@mikro-orm/core": "7.2.2-dev.29"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"
@@ -92,6 +92,7 @@ export declare class MikroTransformer extends OperationNodeTransformer {
92
92
  * This is called for SELECT queries when columnNamingStrategy is 'property'
93
93
  */
94
94
  transformResult(rows: Record<string, any>[] | undefined, entityMap: Map<string, EntityMetadata>): Record<string, any>[] | undefined;
95
+ private getResultMaps;
95
96
  buildGlobalFieldMap(entityMap: Map<string, EntityMetadata>): Record<string, EntityProperty>;
96
97
  buildGlobalRelationFieldMap(entityMap: Map<string, EntityMetadata>): Record<string, string>;
97
98
  /**
@@ -108,6 +109,6 @@ export declare class MikroTransformer extends OperationNodeTransformer {
108
109
  /**
109
110
  * Transform a single row by mapping column names to property names
110
111
  */
111
- transformRow(row: Record<string, any>, fieldToPropertyMap: Record<string, EntityProperty>, relationFieldMap: Record<string, string>): Record<string, any>;
112
+ transformRow(row: Record<string, any>, fieldEntries: [string, EntityProperty][], relationEntries: [string, string][]): Record<string, any>;
112
113
  prepareOutputValue(prop: EntityProperty | undefined, value: unknown): unknown;
113
114
  }
@@ -1,5 +1,12 @@
1
1
  import { ReferenceKind, isRaw, } from '@mikro-orm/core';
2
2
  import { AliasNode, ColumnNode, ColumnUpdateNode, IdentifierNode, OperationNodeTransformer, PrimitiveValueListNode, RawNode, ReferenceNode, SchemableIdentifierNode, SelectAllNode, SelectionNode, TableNode, ValueListNode, ValueNode, ValuesNode, } from 'kysely';
3
+ /** Past this many query shapes the cache of one metadata storage starts over, so generated aliases cannot grow it. */
4
+ const RESULT_MAPS_LIMIT = 1000;
5
+ /**
6
+ * Result maps per query shape (the aliases and entities of its entity map). They are derived from metadata alone, so
7
+ * they are built once and shared by every transformer, as `getKysely()` creates a new one per call.
8
+ */
9
+ const resultMapsCache = new WeakMap();
3
10
  const EXPANDABLE_KINDS = new Set([
4
11
  ReferenceKind.SCALAR,
5
12
  ReferenceKind.EMBEDDED,
@@ -884,12 +891,7 @@ export class MikroTransformer extends OperationNodeTransformer {
884
891
  if (byEntity) {
885
892
  return byEntity;
886
893
  }
887
- const allMetadata = Array.from(this.#metadata);
888
- const byTable = allMetadata.find(m => m.tableName === name);
889
- if (byTable) {
890
- return byTable;
891
- }
892
- return undefined;
894
+ return this.#metadata.getByTableName(name);
893
895
  }
894
896
  /**
895
897
  * Transform result rows by mapping database column names to property names
@@ -906,11 +908,35 @@ export class MikroTransformer extends OperationNodeTransformer {
906
908
  if (entityMap.size === 0) {
907
909
  return rows;
908
910
  }
909
- // Build a global mapping from database field names to property objects
910
- const fieldToPropertyMap = this.buildGlobalFieldMap(entityMap);
911
- const relationFieldMap = this.buildGlobalRelationFieldMap(entityMap);
911
+ // The global mapping from database field names to property objects, built once per query shape
912
+ const { fields, relations } = this.getResultMaps(entityMap);
912
913
  // Transform each row
913
- return rows.map(row => this.transformRow(row, fieldToPropertyMap, relationFieldMap));
914
+ return rows.map(row => this.transformRow(row, fields, relations));
915
+ }
916
+ getResultMaps(entityMap) {
917
+ let byShape = resultMapsCache.get(this.#metadata);
918
+ if (!byShape) {
919
+ byShape = new Map();
920
+ resultMapsCache.set(this.#metadata, byShape);
921
+ }
922
+ let shape = '';
923
+ for (const [alias, meta] of entityMap) {
924
+ shape += `${alias}\0${meta._id}\0`;
925
+ }
926
+ const cached = byShape.get(shape);
927
+ if (cached && Array.from(entityMap.values()).every((meta, i) => meta.props === cached.props[i])) {
928
+ return cached;
929
+ }
930
+ if (byShape.size >= RESULT_MAPS_LIMIT) {
931
+ byShape.clear();
932
+ }
933
+ const maps = {
934
+ props: Array.from(entityMap.values(), meta => meta.props),
935
+ fields: Object.entries(this.buildGlobalFieldMap(entityMap)),
936
+ relations: Object.entries(this.buildGlobalRelationFieldMap(entityMap)),
937
+ };
938
+ byShape.set(shape, maps);
939
+ return maps;
914
940
  }
915
941
  buildGlobalFieldMap(entityMap) {
916
942
  const map = {};
@@ -986,10 +1012,10 @@ export class MikroTransformer extends OperationNodeTransformer {
986
1012
  /**
987
1013
  * Transform a single row by mapping column names to property names
988
1014
  */
989
- transformRow(row, fieldToPropertyMap, relationFieldMap) {
1015
+ transformRow(row, fieldEntries, relationEntries) {
990
1016
  const transformed = { ...row };
991
1017
  // First pass: map regular fields from fieldName to propertyName and convert values
992
- for (const [fieldName, prop] of Object.entries(fieldToPropertyMap)) {
1018
+ for (const [fieldName, prop] of fieldEntries) {
993
1019
  if (!(fieldName in transformed)) {
994
1020
  continue;
995
1021
  }
@@ -1011,7 +1037,7 @@ export class MikroTransformer extends OperationNodeTransformer {
1011
1037
  // Second pass: handle relation fields
1012
1038
  // Only run if columnNamingStrategy is 'property', as we don't want to rename FKs otherwise
1013
1039
  if (this.#options.columnNamingStrategy === 'property') {
1014
- for (const [fieldName, relationPropertyName] of Object.entries(relationFieldMap)) {
1040
+ for (const [fieldName, relationPropertyName] of relationEntries) {
1015
1041
  if (fieldName in transformed && !(relationPropertyName in transformed)) {
1016
1042
  // Move the foreign key value to the relation property name
1017
1043
  transformed[relationPropertyName] = transformed[fieldName];