@m1212e/rumble 0.23.11 → 0.23.14

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.
package/out/index.mjs CHANGED
@@ -18,6 +18,7 @@ import DrizzlePlugin from "@pothos/plugin-drizzle";
18
18
  import SmartSubscriptionsPlugin, { subscribeOptionsFromIterator } from "@pothos/plugin-smart-subscriptions";
19
19
  import TracingPlugin, { isRootField, wrapResolver } from "@pothos/plugin-tracing";
20
20
  import { BigIntResolver, ByteResolver, DateResolver, DateTimeISOResolver, JSONResolver } from "graphql-scalars";
21
+ import DataLoader from "dataloader";
21
22
  //#region lib/types/rumbleError.ts
22
23
  /**
23
24
  * An error that gets raised by rumble whenever something does not go according to plan.
@@ -180,7 +181,7 @@ function mapNullFieldsToUndefined(obj) {
180
181
  }
181
182
  //#endregion
182
183
  //#region package.json
183
- var version = "0.23.11";
184
+ var version = "0.23.14";
184
185
  //#endregion
185
186
  //#region lib/helpers/mergeFilters.ts
186
187
  const EmptyFilter$1 = Symbol.for("drizzle:EmptyFilter");
@@ -390,6 +391,7 @@ function buildIndex(db) {
390
391
  columns,
391
392
  primaryKey,
392
393
  relations: entry.relations ?? {},
394
+ isTable: isTable(tableObj),
393
395
  foundRelation: entry
394
396
  };
395
397
  byTsName.set(resolved.name, resolved);
@@ -434,6 +436,7 @@ function tableHelper({ db, table }) {
434
436
  dbName: entry.dbName,
435
437
  tsName: entry.name,
436
438
  table: entry.table,
439
+ isTable: entry.isTable,
437
440
  foundRelation: entry.foundRelation
438
441
  };
439
442
  }
@@ -456,6 +459,10 @@ const makeNothingRegisteredWarner = (logger) => debounce((model, action) => {
456
459
  const createAbilityBuilder = ({ db, actions, defaultLimit, otel, logger: loggerConfig }) => {
457
460
  const log = loggerConfig?.enabled ? loggerConfig.logger : void 0;
458
461
  const nothingRegisteredWarningLogger = makeNothingRegisteredWarner(log);
462
+ const tableRelationNames = Object.keys(db.query).filter((name) => tableHelper({
463
+ db,
464
+ table: name
465
+ }).isTable);
459
466
  let hasBeenBuilt = false;
460
467
  const createBuilderForTable = () => {
461
468
  const queryFilters = /* @__PURE__ */ new Map();
@@ -541,7 +548,7 @@ by: (explicitFilter) => {
541
548
  }
542
549
  };
543
550
  };
544
- const buildersPerTable = Object.fromEntries(Object.keys(db.query).map((tableName) => [tableName, createBuilderForTable()]));
551
+ const buildersPerTable = Object.fromEntries(tableRelationNames.map((tableName) => [tableName, createBuilderForTable()]));
545
552
  return {
546
553
  ...buildersPerTable,
547
554
  /**
@@ -569,7 +576,7 @@ by: (explicitFilter) => {
569
576
  db,
570
577
  table: tableName
571
578
  });
572
- if (Object.keys(tableSchema.primaryKey).length === 0) throw new RumbleError(`No primary key found for entity ${tableName.toString()}`);
579
+ if (Object.keys(tableSchema.primaryKey).length === 0) throw new RumbleError(`No primary key found for entity ${String(tableName)}`);
573
580
  const primaryKeyField = Object.values(tableSchema.primaryKey)[0];
574
581
  const distinctValues = createDistinctValuesFromSQLType(primaryKeyField.getSQLType());
575
582
  const blockEverythingFilter = { where: { AND: [{ [primaryKeyField.name]: distinctValues.value1 }, { [primaryKeyField.name]: distinctValues.value2 }] } };
@@ -719,7 +726,7 @@ by: (explicitFilter) => {
719
726
  }
720
727
  if (!filters) {
721
728
  span?.setAttribute("abilities.status", "blocked_everything");
722
- nothingRegisteredWarningLogger(tableName.toString(), action);
729
+ nothingRegisteredWarningLogger(String(tableName), action);
723
730
  return transformToResponse(blockEverythingFilter);
724
731
  }
725
732
  const dynamicResults = new Array(dynamicQueryFilters[action].length);
@@ -748,10 +755,10 @@ by: (explicitFilter) => {
748
755
  };
749
756
  if (otel?.enabled && otel.tracer) return otel.tracer.startActiveSpan(`rumble.abilities.prepare`, (span) => {
750
757
  span.setAttribute("rumble.action", action);
751
- span.setAttribute("rumble.table", tableName.toString());
758
+ span.setAttribute("rumble.table", String(tableName));
752
759
  try {
753
760
  const attrs = {
754
- "rumble.table": tableName.toString(),
761
+ "rumble.table": String(tableName),
755
762
  "rumble.action": action
756
763
  };
757
764
  const proxy = new Proxy(span, { get(target, prop) {
@@ -770,7 +777,7 @@ by: (explicitFilter) => {
770
777
  });
771
778
  else {
772
779
  const attrs = {
773
- "rumble.table": tableName.toString(),
780
+ "rumble.table": String(tableName),
774
781
  "rumble.action": action
775
782
  };
776
783
  const result = assembleAbilities(log ? { setAttribute: (k, v) => {
@@ -782,10 +789,10 @@ by: (explicitFilter) => {
782
789
  } };
783
790
  } };
784
791
  };
785
- const abilitiesPerTable = Object.fromEntries(Object.keys(db.query).map((tableName) => [tableName, createFilterForTable(tableName)]));
792
+ const abilitiesPerTable = Object.fromEntries(tableRelationNames.map((tableName) => [tableName, createFilterForTable(tableName)]));
786
793
  hasBeenBuilt = true;
787
794
  return (ctx) => {
788
- return Object.fromEntries(Object.keys(abilitiesPerTable).map((tableName) => [tableName, abilitiesPerTable[tableName].withContext(ctx)]));
795
+ return Object.fromEntries(tableRelationNames.map((tableName) => [tableName, abilitiesPerTable[tableName].withContext(ctx)]));
789
796
  };
790
797
  }
791
798
  }
@@ -1191,11 +1198,11 @@ const createCountQueryImplementer = ({ db, schemaBuilder, whereArgImplementer, m
1191
1198
  table
1192
1199
  });
1193
1200
  return schemaBuilder.queryFields((t) => {
1194
- return { [`${pluralize.plural(table.toString())}Count`]: t.field({
1201
+ return { [`${pluralize.plural(String(table))}Count`]: t.field({
1195
1202
  type: "Int",
1196
1203
  nullable: false,
1197
1204
  smartSubscription: true,
1198
- description: `Count all ${pluralize.plural(table.toString())}`,
1205
+ description: `Count all ${pluralize.plural(String(table))}`,
1199
1206
  subscribe: (subscriptions, _root, _args, _ctx, _info) => {
1200
1207
  registerOnInstance({
1201
1208
  instance: subscriptions,
@@ -1662,20 +1669,20 @@ const createObjectImplementer = ({ db, search, logger: loggerConfig, schemaBuild
1662
1669
  });
1663
1670
  if (Object.keys(tableSchema.primaryKey).length === 0) {
1664
1671
  const log = loggerConfig?.enabled ? loggerConfig.logger : void 0;
1665
- const msg = `Could not find primary key for ${table.toString()}. Cannot register subscriptions!`;
1666
- log ? log.warn({ "rumble.table": table.toString() }, msg) : console.warn(msg);
1672
+ const msg = `Could not find primary key for ${String(table)}. Cannot register subscriptions!`;
1673
+ log ? log.warn({ "rumble.table": String(table) }, msg) : console.warn(msg);
1667
1674
  }
1668
1675
  const primaryKey = Object.values(tableSchema.primaryKey)[0];
1669
1676
  const { registerOnInstance } = makePubSubInstance({ table });
1670
1677
  return schemaBuilder.drizzleObject(table, {
1671
- name: refName ?? capitalize(table.toString()),
1678
+ name: refName ?? capitalize(String(table)),
1672
1679
  subscribe: (subscriptions, element, _context) => {
1673
1680
  if (!primaryKey) return;
1674
1681
  const primaryKeyValue = element[primaryKey.name];
1675
1682
  if (!primaryKeyValue) {
1676
1683
  const log = loggerConfig?.enabled ? loggerConfig.logger : void 0;
1677
- const msg = `Could not find primary key value for element on ${table.toString()}. Cannot register subscription!`;
1678
- log ? log.warn({ "rumble.table": table.toString() }, msg) : console.warn(msg);
1684
+ const msg = `Could not find primary key value for element on ${String(table)}. Cannot register subscription!`;
1685
+ log ? log.warn({ "rumble.table": String(table) }, msg) : console.warn(msg);
1679
1686
  return;
1680
1687
  }
1681
1688
  registerOnInstance({
@@ -1921,10 +1928,10 @@ const createQueryImplementer = ({ db, schemaBuilder, search, logger: loggerConfi
1921
1928
  });
1922
1929
  const primaryKeyField = Object.values(tableSchema.primaryKey)[0];
1923
1930
  const { registerOnInstance } = makePubSubInstance({ table });
1924
- const pluralName = pluralize.plural(table.toString());
1925
- const singularName = pluralize.singular(table.toString());
1931
+ const pluralName = pluralize.plural(String(table));
1932
+ const singularName = pluralize.singular(String(table));
1926
1933
  for (const name of [pluralName, singularName]) {
1927
- if (registeredQueryFieldNames.has(name)) throw new RumbleError(`Duplicate query field "${name}": the table "${table.toString()}" generates a query field that collides with one already registered. Use unique table names (or refNames) to avoid plural/singular collisions (e.g. "post" and "posts").`);
1934
+ if (registeredQueryFieldNames.has(name)) throw new RumbleError(`Duplicate query field "${name}": the table "${String(table)}" generates a query field that collides with one already registered. Use unique table names (or refNames) to avoid plural/singular collisions (e.g. "post" and "posts").`);
1928
1935
  registeredQueryFieldNames.add(name);
1929
1936
  }
1930
1937
  return schemaBuilder.queryFields((t) => {
@@ -2275,6 +2282,30 @@ var RuntimeFiltersPlugin = class extends BasePlugin {
2275
2282
  tracer;
2276
2283
  tracerEnabled;
2277
2284
  logger;
2285
+ filterLoaders = /* @__PURE__ */ new WeakMap();
2286
+ getLoader(context, filter) {
2287
+ let perContext = this.filterLoaders.get(context);
2288
+ if (!perContext) {
2289
+ perContext = /* @__PURE__ */ new Map();
2290
+ this.filterLoaders.set(context, perContext);
2291
+ }
2292
+ let loader = perContext.get(filter);
2293
+ if (!loader) {
2294
+ const prefetchPromise = filter.prefetch ? filter.prefetch({ context }) : void 0;
2295
+ loader = new DataLoader(async (entities) => {
2296
+ const prefetched = prefetchPromise ? await prefetchPromise : void 0;
2297
+ const allowed = await filter.filter({
2298
+ context,
2299
+ entities,
2300
+ prefetched
2301
+ });
2302
+ const allowedSet = new Set(allowed);
2303
+ return entities.map((entity) => allowedSet.has(entity) ? entity : null);
2304
+ }, { cache: false });
2305
+ perContext.set(filter, loader);
2306
+ }
2307
+ return loader;
2308
+ }
2278
2309
  onTypeConfig(typeConfig) {
2279
2310
  this.tracer = this.builder.options.otel?.tracer;
2280
2311
  this.tracerEnabled = this.builder.options.otel?.enabled;
@@ -2291,44 +2322,20 @@ var RuntimeFiltersPlugin = class extends BasePlugin {
2291
2322
  const runFilters = async (span) => {
2292
2323
  const allFilters = Array.isArray(filters) ? filters : [filters];
2293
2324
  span?.setAttribute("filters.total", allFilters.length);
2294
- const prefetchedFiltersPromises = Promise.all(allFilters.map(async (filter) => {
2295
- if (filter.prefetch) {
2296
- const prefetched = await filter.prefetch({ context });
2297
- return ({ context, entities }) => filter.filter({
2298
- context,
2299
- entities,
2300
- prefetched
2301
- });
2325
+ const loaders = allFilters.map((filter) => this.getLoader(context, filter));
2326
+ let resolved;
2327
+ if (this.tracer && this.tracerEnabled) resolved = await this.tracer.startActiveSpan(`rumble.filter.resolve`, async (span) => {
2328
+ span.setAttribute("graphql.field.name", fieldConfig.name);
2329
+ try {
2330
+ return await resolver(parent, args, context, info);
2331
+ } finally {
2332
+ span.end();
2302
2333
  }
2303
- return ({ context, entities }) => filter.filter({
2304
- context,
2305
- entities
2306
- });
2307
- }));
2308
- let resolved, prefetchedFilters;
2309
- if (this.tracer && this.tracerEnabled) {
2310
- const o = await this.tracer.startActiveSpan(`rumble.filter.resolve`, async (span) => {
2311
- span.setAttribute("graphql.field.name", fieldConfig.name);
2312
- try {
2313
- return await Promise.all([resolver(parent, args, context, info), prefetchedFiltersPromises]);
2314
- } finally {
2315
- span.end();
2316
- }
2317
- });
2318
- resolved = o[0];
2319
- prefetchedFilters = o[1];
2320
- } else {
2321
- const o = await Promise.all([resolver(parent, args, context, info), prefetchedFiltersPromises]);
2322
- resolved = o[0];
2323
- prefetchedFilters = o[1];
2324
- }
2325
- const allowed = Array.from((await Promise.all(prefetchedFilters.map((f) => f({
2326
- context,
2327
- entities: Array.isArray(resolved) ? resolved : [resolved]
2328
- })))).reduce((acc, val) => {
2329
- for (const element of val) acc.add(element);
2330
- return acc;
2331
- }, /* @__PURE__ */ new Set()));
2334
+ });
2335
+ else resolved = await resolver(parent, args, context, info);
2336
+ const entities = Array.isArray(resolved) ? resolved : [resolved];
2337
+ const perFilterResults = await Promise.all(loaders.map((loader) => Promise.all(entities.map((entity) => loader.load(entity)))));
2338
+ const allowed = entities.filter((_, index) => perFilterResults.some((results) => results[index] != null));
2332
2339
  span?.setAttribute("filters.allowed", allowed.length);
2333
2340
  this.logger?.debug({
2334
2341
  "graphql.field.name": fieldConfig.name,