import { SelectQueryNode as SelectQueryNodeClass, InsertQueryNode as InsertQueryNodeClass, UpdateQueryNode as UpdateQueryNodeClass, DeleteQueryNode as DeleteQueryNodeClass, } from 'kysely'; import { MikroTransformer } from './transformer.js'; /** Kysely plugin that transforms queries and results to use MikroORM entity/property naming conventions. */ export class MikroKyselyPlugin { static #queryNodeCache = new WeakMap(); #transformer; #options; constructor(em, options = {}) { this.#options = options; this.#transformer = new MikroTransformer(em, options); } transformQuery(args) { this.#transformer.reset(); const result = this.#transformer.transformNode(args.node, args.queryId); // Cache the entity map if it is one we can process (for use in transformResult) if ( SelectQueryNodeClass.is(args.node) || InsertQueryNodeClass.is(args.node) || UpdateQueryNodeClass.is(args.node) || DeleteQueryNodeClass.is(args.node) ) { // clone the entityMap because the transformer's internal map will be cleared and reused by the next query const entityMap = new Map(this.#transformer.getOutputEntityMap()); MikroKyselyPlugin.#queryNodeCache.set(args.queryId, { entityMap }); } return result; } async transformResult(args) { // Only transform results if columnNamingStrategy is 'property' or convertValues is true if (this.#options.columnNamingStrategy !== 'property' && !this.#options.convertValues) { return args.result; } // Retrieve the cached query node and metadata const cache = MikroKyselyPlugin.#queryNodeCache.get(args.queryId); if (!cache) { return args.result; } // Transform the result rows using the transformer const transformedRows = this.#transformer.transformResult(args.result.rows ?? [], cache.entityMap); return { ...args.result, rows: transformedRows ?? [], }; } }