joist-core 2.4.0-next.49 → 2.4.0-next.50

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.
@@ -41,9 +41,8 @@ function findPaginatedDataLoader(em, type, filter, hint) {
41
41
  const { query, findSettings } = entries[0];
42
42
  const { preloader } = require_EntityManager.getEmInternalApi(em);
43
43
  const preloadHydrator = preloader && hint && preloader.addPreloading(meta, require_loading_HintTree.buildHintTree(hint), query);
44
- const rows = await em["executePreparedFind"](meta, require_dataloaders_findDataLoader.findOperation, query, findSettings, false);
45
- const entities = em.hydrate(type, rows);
46
- preloadHydrator?.(rows, entities);
44
+ const rowData = await em["executePreparedFindRowData"](meta, require_dataloaders_findDataLoader.findOperation, query, findSettings, false);
45
+ const entities = em["hydrateAndFinalize"](type, rowData, { sidecars: (entities) => preloadHydrator?.(rowData, entities) });
47
46
  return [require_dataloaders_findDataLoader.filterDeletedEntities(em, entities)];
48
47
  }
49
48
  const { query, findSettings, limit, offset } = entries[0];
@@ -75,20 +74,19 @@ function findPaginatedDataLoader(em, type, filter, hint) {
75
74
  ctes: [require_queries_unnest.buildUnnestCte("_find", argsColumns, columnValues)],
76
75
  orderBys: []
77
76
  };
78
- const rows = await em["executePreparedFind"](meta, require_dataloaders_findDataLoader.findOperation, query2, {
77
+ const rowData = await em["executePreparedFindRowData"](meta, require_dataloaders_findDataLoader.findOperation, query2, {
79
78
  ...findSettings,
80
79
  limit: void 0,
81
80
  offset: void 0
82
81
  }, false);
83
- const entities = em.hydrate(type, rows);
84
- preloadHydrator?.(rows, entities);
85
82
  const results = entries.map(() => []);
86
- for (let i = 0; i < rows.length; i++) {
87
- const row = rows[i];
88
- const entity = entities[i];
89
- if (!entity.isDeletedEntity) results[row.tag].push(entity);
90
- delete row.tag;
91
- }
83
+ em["hydrateAndFinalize"](type, rowData, { sidecars: (entities) => {
84
+ preloadHydrator?.(rowData, entities);
85
+ for (let i = 0; i < entities.length; i++) {
86
+ const entity = entities[i];
87
+ if (!entity.isDeletedEntity) results[rowData.get(i, "tag")].push(entity);
88
+ }
89
+ } });
92
90
  return results;
93
91
  }, { cacheKeyFn: require_dataloaders_findDataLoader.queryFilterHash }).load(prepared);
94
92
  }
@@ -1 +1 @@
1
- {"version":3,"file":"findPaginatedDataLoader.cjs","names":["getMetadata","parseFindQuery","findOperation","isQueryProvablyEmpty","getBatchKeyFromGenericStructure","hintKey","getEmInternalApi","buildHintTree","filterDeletedEntities","collectAndReplaceArgs","createColumnValuesFromPrepared","buildUnnestCte","queryFilterHash"],"sources":["../../src/dataloaders/findPaginatedDataLoader.ts"],"sourcesContent":["import {\n collectAndReplaceArgs,\n collectValues,\n createColumnValuesFromPrepared,\n filterDeletedEntities,\n findOperation,\n getBatchKeyFromGenericStructure,\n queryFilterHash,\n} from \"src/dataloaders/findDataLoader.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityManager, type MaybeAbstractEntityConstructor, getEmInternalApi } from \"src/EntityManager.ts\";\nimport { getMetadata } from \"src/EntityMetadata.ts\";\nimport { buildHintTree } from \"src/loading/HintTree.ts\";\nimport type { LoadHint } from \"src/loading/loadHints.ts\";\nimport { hintKey } from \"src/normalizeHints.ts\";\nimport type { FilterAndSettings } from \"src/queries/find/EntityFilter.ts\";\nimport { type ParsedFindQuery, parseFindQuery } from \"src/queries/find/QueryParser.ts\";\nimport { isQueryProvablyEmpty } from \"src/queries/find/QueryVisitor.ts\";\nimport { buildUnnestCte } from \"src/queries/unnest.ts\";\n\ninterface PreparedPaginatedFindEntry<T extends Entity> {\n filter: FilterAndSettings<T>;\n query: ParsedFindQuery;\n bindings: any[];\n findSettings: any;\n limit: number | undefined;\n offset: number | undefined;\n}\n\n/** Returns a dataloader that batches paginated finds by applying pagination inside each lateral subquery. */\nexport function findPaginatedDataLoader<T extends Entity>(\n em: EntityManager,\n type: MaybeAbstractEntityConstructor<T>,\n filter: FilterAndSettings<T>,\n hint: LoadHint<T> | undefined,\n): Promise<T[]> {\n const { where, limit, offset, ...opts } = filter;\n const meta = getMetadata(type);\n const query = parseFindQuery(meta, where, opts);\n const { findSettings } = em[\"prepareFind\"](meta, findOperation, query, { ...opts, limit, offset, checkLimit: false });\n if (isQueryProvablyEmpty(query)) return Promise.resolve([]);\n\n const bindings: any[] = [];\n collectValues(bindings, query);\n const prepared = {\n filter,\n query,\n bindings,\n findSettings,\n limit: findSettings.limit,\n offset: findSettings.offset,\n };\n const batchKey = [\n getBatchKeyFromGenericStructure(meta, query),\n hintKey(hint),\n findSettings.limit,\n findSettings.offset,\n ].join(\"-\");\n\n return em\n .getLoader<PreparedPaginatedFindEntry<T>, T[]>(\n findOperation,\n batchKey,\n async (entries) => {\n if (entries.length === 1) {\n // Skip batching & just execute the query as-is\n const { query, findSettings } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n const rows = await em[\"executePreparedFind\"](meta, findOperation, query, findSettings, false);\n const entities = em.hydrate(type, rows);\n preloadHydrator?.(rows, entities);\n return [filterDeletedEntities(em, entities)];\n }\n\n const { query, findSettings, limit, offset } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n\n // Now craft the actual batched query\n const args = collectAndReplaceArgs(query, entries);\n const argsColumns = [{ columnName: \"tag\", dbType: \"int\" }, ...args.map((a) => a.column)];\n const columnValues = createColumnValuesFromPrepared(args, entries);\n const query2: ParsedFindQuery = {\n selects: [\"_find.tag as tag\", \"_data.*\"],\n tables: [\n { join: \"primary\", table: \"_find\", alias: \"_find\" },\n {\n join: \"lateral\",\n query,\n table: meta.tableName,\n alias: \"_data\",\n fromAlias: \"_find\",\n settings: { limit, offset },\n },\n ],\n ctes: [buildUnnestCte(\"_find\", argsColumns, columnValues)],\n orderBys: [],\n };\n\n const rows = await em[\"executePreparedFind\"](\n meta,\n findOperation,\n query2,\n { ...findSettings, limit: undefined, offset: undefined },\n false,\n );\n const entities = em.hydrate(type, rows);\n preloadHydrator?.(rows, entities);\n\n const results = entries.map(() => [] as T[]);\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n const entity = entities[i];\n if (!entity.isDeletedEntity) {\n results[row.tag].push(entity);\n }\n delete row.tag;\n }\n return results;\n },\n { cacheKeyFn: queryFilterHash },\n )\n .load(prepared);\n}\n"],"mappings":";;;;;;;;;;;AA8BA,SAAgB,wBACd,IACA,MACA,QACA,MACc;CACd,MAAM,EAAE,OAAO,OAAO,QAAQ,GAAG,SAAS;CAC1C,MAAM,OAAOA,uBAAAA,YAAY,IAAI;CAC7B,MAAM,QAAQC,iCAAAA,eAAe,MAAM,OAAO,IAAI;CAC9C,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAAC,MAAMC,mCAAAA,eAAe,OAAO;EAAE,GAAG;EAAM;EAAO;EAAQ,YAAY;CAAM,CAAC;CACpH,IAAIC,kCAAAA,qBAAqB,KAAK,GAAG,OAAO,QAAQ,QAAQ,CAAC,CAAC;CAE1D,MAAM,WAAkB,CAAC;CACzB,mCAAA,cAAc,UAAU,KAAK;CAC7B,MAAM,WAAW;EACf;EACA;EACA;EACA;EACA,OAAO,aAAa;EACpB,QAAQ,aAAa;CACvB;CACA,MAAM,WAAW;EACfC,mCAAAA,gCAAgC,MAAM,KAAK;EAC3CC,uBAAAA,QAAQ,IAAI;EACZ,aAAa;EACb,aAAa;CACf,CAAC,CAAC,KAAK,GAAG;CAEV,OAAO,GACJ,UACCH,mCAAAA,eACA,UACA,OAAO,YAAY;EACjB,IAAI,QAAQ,WAAW,GAAG;GAExB,MAAM,EAAE,OAAO,iBAAiB,QAAQ;GACxC,MAAM,EAAE,cAAcI,sBAAAA,iBAAiB,EAAE;GACzC,MAAM,kBAAkB,aAAa,QAAQ,UAAU,cAAc,MAAMC,yBAAAA,cAAc,IAAI,GAAG,KAAK;GACrG,MAAM,OAAO,MAAM,GAAG,sBAAsB,CAAC,MAAML,mCAAAA,eAAe,OAAO,cAAc,KAAK;GAC5F,MAAM,WAAW,GAAG,QAAQ,MAAM,IAAI;GACtC,kBAAkB,MAAM,QAAQ;GAChC,OAAO,CAACM,mCAAAA,sBAAsB,IAAI,QAAQ,CAAC;EAC7C;EAEA,MAAM,EAAE,OAAO,cAAc,OAAO,WAAW,QAAQ;EACvD,MAAM,EAAE,cAAcF,sBAAAA,iBAAiB,EAAE;EACzC,MAAM,kBAAkB,aAAa,QAAQ,UAAU,cAAc,MAAMC,yBAAAA,cAAc,IAAI,GAAG,KAAK;EAGrG,MAAM,OAAOE,mCAAAA,sBAAsB,OAAO,OAAO;EACjD,MAAM,cAAc,CAAC;GAAE,YAAY;GAAO,QAAQ;EAAM,GAAG,GAAG,KAAK,KAAK,MAAM,EAAE,MAAM,CAAC;EACvF,MAAM,eAAeC,mCAAAA,+BAA+B,MAAM,OAAO;EACjE,MAAM,SAA0B;GAC9B,SAAS,CAAC,oBAAoB,SAAS;GACvC,QAAQ,CACN;IAAE,MAAM;IAAW,OAAO;IAAS,OAAO;GAAQ,GAClD;IACE,MAAM;IACN;IACA,OAAO,KAAK;IACZ,OAAO;IACP,WAAW;IACX,UAAU;KAAE;KAAO;IAAO;GAC5B,CACF;GACA,MAAM,CAACC,uBAAAA,eAAe,SAAS,aAAa,YAAY,CAAC;GACzD,UAAU,CAAC;EACb;EAEA,MAAM,OAAO,MAAM,GAAG,sBAAsB,CAC1C,MACAT,mCAAAA,eACA,QACA;GAAE,GAAG;GAAc,OAAO,KAAA;GAAW,QAAQ,KAAA;EAAU,GACvD,KACF;EACA,MAAM,WAAW,GAAG,QAAQ,MAAM,IAAI;EACtC,kBAAkB,MAAM,QAAQ;EAEhC,MAAM,UAAU,QAAQ,UAAU,CAAC,CAAQ;EAC3C,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,MAAM,KAAK;GACjB,MAAM,SAAS,SAAS;GACxB,IAAI,CAAC,OAAO,iBACV,QAAQ,IAAI,IAAI,CAAC,KAAK,MAAM;GAE9B,OAAO,IAAI;EACb;EACA,OAAO;CACT,GACA,EAAE,YAAYU,mCAAAA,gBAAgB,CAChC,CAAC,CACA,KAAK,QAAQ;AAClB"}
1
+ {"version":3,"file":"findPaginatedDataLoader.cjs","names":["getMetadata","parseFindQuery","findOperation","isQueryProvablyEmpty","getBatchKeyFromGenericStructure","hintKey","getEmInternalApi","buildHintTree","filterDeletedEntities","collectAndReplaceArgs","createColumnValuesFromPrepared","buildUnnestCte","queryFilterHash"],"sources":["../../src/dataloaders/findPaginatedDataLoader.ts"],"sourcesContent":["import {\n collectAndReplaceArgs,\n collectValues,\n createColumnValuesFromPrepared,\n filterDeletedEntities,\n findOperation,\n getBatchKeyFromGenericStructure,\n queryFilterHash,\n} from \"src/dataloaders/findDataLoader.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityManager, type MaybeAbstractEntityConstructor, getEmInternalApi } from \"src/EntityManager.ts\";\nimport { getMetadata } from \"src/EntityMetadata.ts\";\nimport { buildHintTree } from \"src/loading/HintTree.ts\";\nimport type { LoadHint } from \"src/loading/loadHints.ts\";\nimport { hintKey } from \"src/normalizeHints.ts\";\nimport type { FilterAndSettings } from \"src/queries/find/EntityFilter.ts\";\nimport { type ParsedFindQuery, parseFindQuery } from \"src/queries/find/QueryParser.ts\";\nimport { isQueryProvablyEmpty } from \"src/queries/find/QueryVisitor.ts\";\nimport { buildUnnestCte } from \"src/queries/unnest.ts\";\n\ninterface PreparedPaginatedFindEntry<T extends Entity> {\n filter: FilterAndSettings<T>;\n query: ParsedFindQuery;\n bindings: any[];\n findSettings: any;\n limit: number | undefined;\n offset: number | undefined;\n}\n\n/** Returns a dataloader that batches paginated finds by applying pagination inside each lateral subquery. */\nexport function findPaginatedDataLoader<T extends Entity>(\n em: EntityManager,\n type: MaybeAbstractEntityConstructor<T>,\n filter: FilterAndSettings<T>,\n hint: LoadHint<T> | undefined,\n): Promise<T[]> {\n const { where, limit, offset, ...opts } = filter;\n const meta = getMetadata(type);\n const query = parseFindQuery(meta, where, opts);\n const { findSettings } = em[\"prepareFind\"](meta, findOperation, query, { ...opts, limit, offset, checkLimit: false });\n if (isQueryProvablyEmpty(query)) return Promise.resolve([]);\n\n const bindings: any[] = [];\n collectValues(bindings, query);\n const prepared = {\n filter,\n query,\n bindings,\n findSettings,\n limit: findSettings.limit,\n offset: findSettings.offset,\n };\n const batchKey = [\n getBatchKeyFromGenericStructure(meta, query),\n hintKey(hint),\n findSettings.limit,\n findSettings.offset,\n ].join(\"-\");\n\n return em\n .getLoader<PreparedPaginatedFindEntry<T>, T[]>(\n findOperation,\n batchKey,\n async (entries) => {\n if (entries.length === 1) {\n // Skip batching & just execute the query as-is\n const { query, findSettings } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n const rowData = await em[\"executePreparedFindRowData\"](meta, findOperation, query, findSettings, false);\n const entities = em[\"hydrateAndFinalize\"](type, rowData, {\n sidecars: (entities) => preloadHydrator?.(rowData, entities),\n });\n return [filterDeletedEntities(em, entities)];\n }\n\n const { query, findSettings, limit, offset } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n\n // Now craft the actual batched query\n const args = collectAndReplaceArgs(query, entries);\n const argsColumns = [{ columnName: \"tag\", dbType: \"int\" }, ...args.map((a) => a.column)];\n const columnValues = createColumnValuesFromPrepared(args, entries);\n const query2: ParsedFindQuery = {\n selects: [\"_find.tag as tag\", \"_data.*\"],\n tables: [\n { join: \"primary\", table: \"_find\", alias: \"_find\" },\n {\n join: \"lateral\",\n query,\n table: meta.tableName,\n alias: \"_data\",\n fromAlias: \"_find\",\n settings: { limit, offset },\n },\n ],\n ctes: [buildUnnestCte(\"_find\", argsColumns, columnValues)],\n orderBys: [],\n };\n\n const rowData = await em[\"executePreparedFindRowData\"](\n meta,\n findOperation,\n query2,\n { ...findSettings, limit: undefined, offset: undefined },\n false,\n );\n const results = entries.map(() => [] as T[]);\n em[\"hydrateAndFinalize\"](type, rowData, {\n sidecars: (entities) => {\n preloadHydrator?.(rowData, entities);\n // Read tags before compaction drops rows already present in the identity map.\n for (let i = 0; i < entities.length; i++) {\n const entity = entities[i];\n if (!entity.isDeletedEntity) {\n results[rowData.get(i, \"tag\")].push(entity);\n }\n }\n },\n });\n return results;\n },\n { cacheKeyFn: queryFilterHash },\n )\n .load(prepared);\n}\n"],"mappings":"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"}
@@ -40,9 +40,8 @@ function findPaginatedDataLoader(em, type, filter, hint) {
40
40
  const { query, findSettings } = entries[0];
41
41
  const { preloader } = getEmInternalApi(em);
42
42
  const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);
43
- const rows = await em["executePreparedFind"](meta, findOperation, query, findSettings, false);
44
- const entities = em.hydrate(type, rows);
45
- preloadHydrator?.(rows, entities);
43
+ const rowData = await em["executePreparedFindRowData"](meta, findOperation, query, findSettings, false);
44
+ const entities = em["hydrateAndFinalize"](type, rowData, { sidecars: (entities) => preloadHydrator?.(rowData, entities) });
46
45
  return [filterDeletedEntities(em, entities)];
47
46
  }
48
47
  const { query, findSettings, limit, offset } = entries[0];
@@ -74,20 +73,19 @@ function findPaginatedDataLoader(em, type, filter, hint) {
74
73
  ctes: [buildUnnestCte("_find", argsColumns, columnValues)],
75
74
  orderBys: []
76
75
  };
77
- const rows = await em["executePreparedFind"](meta, findOperation, query2, {
76
+ const rowData = await em["executePreparedFindRowData"](meta, findOperation, query2, {
78
77
  ...findSettings,
79
78
  limit: void 0,
80
79
  offset: void 0
81
80
  }, false);
82
- const entities = em.hydrate(type, rows);
83
- preloadHydrator?.(rows, entities);
84
81
  const results = entries.map(() => []);
85
- for (let i = 0; i < rows.length; i++) {
86
- const row = rows[i];
87
- const entity = entities[i];
88
- if (!entity.isDeletedEntity) results[row.tag].push(entity);
89
- delete row.tag;
90
- }
82
+ em["hydrateAndFinalize"](type, rowData, { sidecars: (entities) => {
83
+ preloadHydrator?.(rowData, entities);
84
+ for (let i = 0; i < entities.length; i++) {
85
+ const entity = entities[i];
86
+ if (!entity.isDeletedEntity) results[rowData.get(i, "tag")].push(entity);
87
+ }
88
+ } });
91
89
  return results;
92
90
  }, { cacheKeyFn: queryFilterHash }).load(prepared);
93
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"findPaginatedDataLoader.js","names":[],"sources":["../../src/dataloaders/findPaginatedDataLoader.ts"],"sourcesContent":["import {\n collectAndReplaceArgs,\n collectValues,\n createColumnValuesFromPrepared,\n filterDeletedEntities,\n findOperation,\n getBatchKeyFromGenericStructure,\n queryFilterHash,\n} from \"src/dataloaders/findDataLoader.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityManager, type MaybeAbstractEntityConstructor, getEmInternalApi } from \"src/EntityManager.ts\";\nimport { getMetadata } from \"src/EntityMetadata.ts\";\nimport { buildHintTree } from \"src/loading/HintTree.ts\";\nimport type { LoadHint } from \"src/loading/loadHints.ts\";\nimport { hintKey } from \"src/normalizeHints.ts\";\nimport type { FilterAndSettings } from \"src/queries/find/EntityFilter.ts\";\nimport { type ParsedFindQuery, parseFindQuery } from \"src/queries/find/QueryParser.ts\";\nimport { isQueryProvablyEmpty } from \"src/queries/find/QueryVisitor.ts\";\nimport { buildUnnestCte } from \"src/queries/unnest.ts\";\n\ninterface PreparedPaginatedFindEntry<T extends Entity> {\n filter: FilterAndSettings<T>;\n query: ParsedFindQuery;\n bindings: any[];\n findSettings: any;\n limit: number | undefined;\n offset: number | undefined;\n}\n\n/** Returns a dataloader that batches paginated finds by applying pagination inside each lateral subquery. */\nexport function findPaginatedDataLoader<T extends Entity>(\n em: EntityManager,\n type: MaybeAbstractEntityConstructor<T>,\n filter: FilterAndSettings<T>,\n hint: LoadHint<T> | undefined,\n): Promise<T[]> {\n const { where, limit, offset, ...opts } = filter;\n const meta = getMetadata(type);\n const query = parseFindQuery(meta, where, opts);\n const { findSettings } = em[\"prepareFind\"](meta, findOperation, query, { ...opts, limit, offset, checkLimit: false });\n if (isQueryProvablyEmpty(query)) return Promise.resolve([]);\n\n const bindings: any[] = [];\n collectValues(bindings, query);\n const prepared = {\n filter,\n query,\n bindings,\n findSettings,\n limit: findSettings.limit,\n offset: findSettings.offset,\n };\n const batchKey = [\n getBatchKeyFromGenericStructure(meta, query),\n hintKey(hint),\n findSettings.limit,\n findSettings.offset,\n ].join(\"-\");\n\n return em\n .getLoader<PreparedPaginatedFindEntry<T>, T[]>(\n findOperation,\n batchKey,\n async (entries) => {\n if (entries.length === 1) {\n // Skip batching & just execute the query as-is\n const { query, findSettings } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n const rows = await em[\"executePreparedFind\"](meta, findOperation, query, findSettings, false);\n const entities = em.hydrate(type, rows);\n preloadHydrator?.(rows, entities);\n return [filterDeletedEntities(em, entities)];\n }\n\n const { query, findSettings, limit, offset } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n\n // Now craft the actual batched query\n const args = collectAndReplaceArgs(query, entries);\n const argsColumns = [{ columnName: \"tag\", dbType: \"int\" }, ...args.map((a) => a.column)];\n const columnValues = createColumnValuesFromPrepared(args, entries);\n const query2: ParsedFindQuery = {\n selects: [\"_find.tag as tag\", \"_data.*\"],\n tables: [\n { join: \"primary\", table: \"_find\", alias: \"_find\" },\n {\n join: \"lateral\",\n query,\n table: meta.tableName,\n alias: \"_data\",\n fromAlias: \"_find\",\n settings: { limit, offset },\n },\n ],\n ctes: [buildUnnestCte(\"_find\", argsColumns, columnValues)],\n orderBys: [],\n };\n\n const rows = await em[\"executePreparedFind\"](\n meta,\n findOperation,\n query2,\n { ...findSettings, limit: undefined, offset: undefined },\n false,\n );\n const entities = em.hydrate(type, rows);\n preloadHydrator?.(rows, entities);\n\n const results = entries.map(() => [] as T[]);\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n const entity = entities[i];\n if (!entity.isDeletedEntity) {\n results[row.tag].push(entity);\n }\n delete row.tag;\n }\n return results;\n },\n { cacheKeyFn: queryFilterHash },\n )\n .load(prepared);\n}\n"],"mappings":";;;;;;;;;;AA8BA,SAAgB,wBACd,IACA,MACA,QACA,MACc;CACd,MAAM,EAAE,OAAO,OAAO,QAAQ,GAAG,SAAS;CAC1C,MAAM,OAAO,YAAY,IAAI;CAC7B,MAAM,QAAQ,eAAe,MAAM,OAAO,IAAI;CAC9C,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAAC,MAAM,eAAe,OAAO;EAAE,GAAG;EAAM;EAAO;EAAQ,YAAY;CAAM,CAAC;CACpH,IAAI,qBAAqB,KAAK,GAAG,OAAO,QAAQ,QAAQ,CAAC,CAAC;CAE1D,MAAM,WAAkB,CAAC;CACzB,cAAc,UAAU,KAAK;CAC7B,MAAM,WAAW;EACf;EACA;EACA;EACA;EACA,OAAO,aAAa;EACpB,QAAQ,aAAa;CACvB;CACA,MAAM,WAAW;EACf,gCAAgC,MAAM,KAAK;EAC3C,QAAQ,IAAI;EACZ,aAAa;EACb,aAAa;CACf,CAAC,CAAC,KAAK,GAAG;CAEV,OAAO,GACJ,UACC,eACA,UACA,OAAO,YAAY;EACjB,IAAI,QAAQ,WAAW,GAAG;GAExB,MAAM,EAAE,OAAO,iBAAiB,QAAQ;GACxC,MAAM,EAAE,cAAc,iBAAiB,EAAE;GACzC,MAAM,kBAAkB,aAAa,QAAQ,UAAU,cAAc,MAAM,cAAc,IAAI,GAAG,KAAK;GACrG,MAAM,OAAO,MAAM,GAAG,sBAAsB,CAAC,MAAM,eAAe,OAAO,cAAc,KAAK;GAC5F,MAAM,WAAW,GAAG,QAAQ,MAAM,IAAI;GACtC,kBAAkB,MAAM,QAAQ;GAChC,OAAO,CAAC,sBAAsB,IAAI,QAAQ,CAAC;EAC7C;EAEA,MAAM,EAAE,OAAO,cAAc,OAAO,WAAW,QAAQ;EACvD,MAAM,EAAE,cAAc,iBAAiB,EAAE;EACzC,MAAM,kBAAkB,aAAa,QAAQ,UAAU,cAAc,MAAM,cAAc,IAAI,GAAG,KAAK;EAGrG,MAAM,OAAO,sBAAsB,OAAO,OAAO;EACjD,MAAM,cAAc,CAAC;GAAE,YAAY;GAAO,QAAQ;EAAM,GAAG,GAAG,KAAK,KAAK,MAAM,EAAE,MAAM,CAAC;EACvF,MAAM,eAAe,+BAA+B,MAAM,OAAO;EACjE,MAAM,SAA0B;GAC9B,SAAS,CAAC,oBAAoB,SAAS;GACvC,QAAQ,CACN;IAAE,MAAM;IAAW,OAAO;IAAS,OAAO;GAAQ,GAClD;IACE,MAAM;IACN;IACA,OAAO,KAAK;IACZ,OAAO;IACP,WAAW;IACX,UAAU;KAAE;KAAO;IAAO;GAC5B,CACF;GACA,MAAM,CAAC,eAAe,SAAS,aAAa,YAAY,CAAC;GACzD,UAAU,CAAC;EACb;EAEA,MAAM,OAAO,MAAM,GAAG,sBAAsB,CAC1C,MACA,eACA,QACA;GAAE,GAAG;GAAc,OAAO,KAAA;GAAW,QAAQ,KAAA;EAAU,GACvD,KACF;EACA,MAAM,WAAW,GAAG,QAAQ,MAAM,IAAI;EACtC,kBAAkB,MAAM,QAAQ;EAEhC,MAAM,UAAU,QAAQ,UAAU,CAAC,CAAQ;EAC3C,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,MAAM,KAAK;GACjB,MAAM,SAAS,SAAS;GACxB,IAAI,CAAC,OAAO,iBACV,QAAQ,IAAI,IAAI,CAAC,KAAK,MAAM;GAE9B,OAAO,IAAI;EACb;EACA,OAAO;CACT,GACA,EAAE,YAAY,gBAAgB,CAChC,CAAC,CACA,KAAK,QAAQ;AAClB"}
1
+ {"version":3,"file":"findPaginatedDataLoader.js","names":[],"sources":["../../src/dataloaders/findPaginatedDataLoader.ts"],"sourcesContent":["import {\n collectAndReplaceArgs,\n collectValues,\n createColumnValuesFromPrepared,\n filterDeletedEntities,\n findOperation,\n getBatchKeyFromGenericStructure,\n queryFilterHash,\n} from \"src/dataloaders/findDataLoader.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityManager, type MaybeAbstractEntityConstructor, getEmInternalApi } from \"src/EntityManager.ts\";\nimport { getMetadata } from \"src/EntityMetadata.ts\";\nimport { buildHintTree } from \"src/loading/HintTree.ts\";\nimport type { LoadHint } from \"src/loading/loadHints.ts\";\nimport { hintKey } from \"src/normalizeHints.ts\";\nimport type { FilterAndSettings } from \"src/queries/find/EntityFilter.ts\";\nimport { type ParsedFindQuery, parseFindQuery } from \"src/queries/find/QueryParser.ts\";\nimport { isQueryProvablyEmpty } from \"src/queries/find/QueryVisitor.ts\";\nimport { buildUnnestCte } from \"src/queries/unnest.ts\";\n\ninterface PreparedPaginatedFindEntry<T extends Entity> {\n filter: FilterAndSettings<T>;\n query: ParsedFindQuery;\n bindings: any[];\n findSettings: any;\n limit: number | undefined;\n offset: number | undefined;\n}\n\n/** Returns a dataloader that batches paginated finds by applying pagination inside each lateral subquery. */\nexport function findPaginatedDataLoader<T extends Entity>(\n em: EntityManager,\n type: MaybeAbstractEntityConstructor<T>,\n filter: FilterAndSettings<T>,\n hint: LoadHint<T> | undefined,\n): Promise<T[]> {\n const { where, limit, offset, ...opts } = filter;\n const meta = getMetadata(type);\n const query = parseFindQuery(meta, where, opts);\n const { findSettings } = em[\"prepareFind\"](meta, findOperation, query, { ...opts, limit, offset, checkLimit: false });\n if (isQueryProvablyEmpty(query)) return Promise.resolve([]);\n\n const bindings: any[] = [];\n collectValues(bindings, query);\n const prepared = {\n filter,\n query,\n bindings,\n findSettings,\n limit: findSettings.limit,\n offset: findSettings.offset,\n };\n const batchKey = [\n getBatchKeyFromGenericStructure(meta, query),\n hintKey(hint),\n findSettings.limit,\n findSettings.offset,\n ].join(\"-\");\n\n return em\n .getLoader<PreparedPaginatedFindEntry<T>, T[]>(\n findOperation,\n batchKey,\n async (entries) => {\n if (entries.length === 1) {\n // Skip batching & just execute the query as-is\n const { query, findSettings } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n const rowData = await em[\"executePreparedFindRowData\"](meta, findOperation, query, findSettings, false);\n const entities = em[\"hydrateAndFinalize\"](type, rowData, {\n sidecars: (entities) => preloadHydrator?.(rowData, entities),\n });\n return [filterDeletedEntities(em, entities)];\n }\n\n const { query, findSettings, limit, offset } = entries[0];\n const { preloader } = getEmInternalApi(em);\n const preloadHydrator = preloader && hint && preloader.addPreloading(meta, buildHintTree(hint), query);\n\n // Now craft the actual batched query\n const args = collectAndReplaceArgs(query, entries);\n const argsColumns = [{ columnName: \"tag\", dbType: \"int\" }, ...args.map((a) => a.column)];\n const columnValues = createColumnValuesFromPrepared(args, entries);\n const query2: ParsedFindQuery = {\n selects: [\"_find.tag as tag\", \"_data.*\"],\n tables: [\n { join: \"primary\", table: \"_find\", alias: \"_find\" },\n {\n join: \"lateral\",\n query,\n table: meta.tableName,\n alias: \"_data\",\n fromAlias: \"_find\",\n settings: { limit, offset },\n },\n ],\n ctes: [buildUnnestCte(\"_find\", argsColumns, columnValues)],\n orderBys: [],\n };\n\n const rowData = await em[\"executePreparedFindRowData\"](\n meta,\n findOperation,\n query2,\n { ...findSettings, limit: undefined, offset: undefined },\n false,\n );\n const results = entries.map(() => [] as T[]);\n em[\"hydrateAndFinalize\"](type, rowData, {\n sidecars: (entities) => {\n preloadHydrator?.(rowData, entities);\n // Read tags before compaction drops rows already present in the identity map.\n for (let i = 0; i < entities.length; i++) {\n const entity = entities[i];\n if (!entity.isDeletedEntity) {\n results[rowData.get(i, \"tag\")].push(entity);\n }\n }\n },\n });\n return results;\n },\n { cacheKeyFn: queryFilterHash },\n )\n .load(prepared);\n}\n"],"mappings":";;;;;;;;;;AA8BA,SAAgB,wBACd,IACA,MACA,QACA,MACc;CACd,MAAM,EAAE,OAAO,OAAO,QAAQ,GAAG,SAAS;CAC1C,MAAM,OAAO,YAAY,IAAI;CAC7B,MAAM,QAAQ,eAAe,MAAM,OAAO,IAAI;CAC9C,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAAC,MAAM,eAAe,OAAO;EAAE,GAAG;EAAM;EAAO;EAAQ,YAAY;CAAM,CAAC;CACpH,IAAI,qBAAqB,KAAK,GAAG,OAAO,QAAQ,QAAQ,CAAC,CAAC;CAE1D,MAAM,WAAkB,CAAC;CACzB,cAAc,UAAU,KAAK;CAC7B,MAAM,WAAW;EACf;EACA;EACA;EACA;EACA,OAAO,aAAa;EACpB,QAAQ,aAAa;CACvB;CACA,MAAM,WAAW;EACf,gCAAgC,MAAM,KAAK;EAC3C,QAAQ,IAAI;EACZ,aAAa;EACb,aAAa;CACf,CAAC,CAAC,KAAK,GAAG;CAEV,OAAO,GACJ,UACC,eACA,UACA,OAAO,YAAY;EACjB,IAAI,QAAQ,WAAW,GAAG;GAExB,MAAM,EAAE,OAAO,iBAAiB,QAAQ;GACxC,MAAM,EAAE,cAAc,iBAAiB,EAAE;GACzC,MAAM,kBAAkB,aAAa,QAAQ,UAAU,cAAc,MAAM,cAAc,IAAI,GAAG,KAAK;GACrG,MAAM,UAAU,MAAM,GAAG,6BAA6B,CAAC,MAAM,eAAe,OAAO,cAAc,KAAK;GACtG,MAAM,WAAW,GAAG,qBAAqB,CAAC,MAAM,SAAS,EACvD,WAAW,aAAa,kBAAkB,SAAS,QAAQ,EAC7D,CAAC;GACD,OAAO,CAAC,sBAAsB,IAAI,QAAQ,CAAC;EAC7C;EAEA,MAAM,EAAE,OAAO,cAAc,OAAO,WAAW,QAAQ;EACvD,MAAM,EAAE,cAAc,iBAAiB,EAAE;EACzC,MAAM,kBAAkB,aAAa,QAAQ,UAAU,cAAc,MAAM,cAAc,IAAI,GAAG,KAAK;EAGrG,MAAM,OAAO,sBAAsB,OAAO,OAAO;EACjD,MAAM,cAAc,CAAC;GAAE,YAAY;GAAO,QAAQ;EAAM,GAAG,GAAG,KAAK,KAAK,MAAM,EAAE,MAAM,CAAC;EACvF,MAAM,eAAe,+BAA+B,MAAM,OAAO;EACjE,MAAM,SAA0B;GAC9B,SAAS,CAAC,oBAAoB,SAAS;GACvC,QAAQ,CACN;IAAE,MAAM;IAAW,OAAO;IAAS,OAAO;GAAQ,GAClD;IACE,MAAM;IACN;IACA,OAAO,KAAK;IACZ,OAAO;IACP,WAAW;IACX,UAAU;KAAE;KAAO;IAAO;GAC5B,CACF;GACA,MAAM,CAAC,eAAe,SAAS,aAAa,YAAY,CAAC;GACzD,UAAU,CAAC;EACb;EAEA,MAAM,UAAU,MAAM,GAAG,6BAA6B,CACpD,MACA,eACA,QACA;GAAE,GAAG;GAAc,OAAO,KAAA;GAAW,QAAQ,KAAA;EAAU,GACvD,KACF;EACA,MAAM,UAAU,QAAQ,UAAU,CAAC,CAAQ;EAC3C,GAAG,qBAAqB,CAAC,MAAM,SAAS,EACtC,WAAW,aAAa;GACtB,kBAAkB,SAAS,QAAQ;GAEnC,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;IACxC,MAAM,SAAS,SAAS;IACxB,IAAI,CAAC,OAAO,iBACV,QAAQ,QAAQ,IAAI,GAAG,KAAK,EAAE,CAAC,KAAK,MAAM;GAE9C;EACF,EACF,CAAC;EACD,OAAO;CACT,GACA,EAAE,YAAY,gBAAgB,CAChC,CAAC,CACA,KAAK,QAAQ;AAClB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joist-core",
3
- "version": "2.4.0-next.49",
3
+ "version": "2.4.0-next.50",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "build"
43
43
  ],
44
44
  "peerDependencies": {
45
- "joist-utils": "2.4.0-next.49"
45
+ "joist-utils": "2.4.0-next.50"
46
46
  },
47
47
  "dependencies": {
48
48
  "ansis": "^4.4.0",